Copy disabled (too large)
Download .txt
Showing preview only (12,518K chars total). Download the full file to get everything.
Repository: Coursemology/coursemology2
Branch: master
Commit: d82b31f13cd6
Files: 4409
Total size: 10.8 MB
Directory structure:
gitextract_31rkx6m_/
├── .circleci/
│ └── config.yml
├── .codecov.yml
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── 1-bug-report.yml
│ │ ├── 2-feature-request.yml
│ │ └── config.yml
│ └── dependabot.yml
├── .gitignore
├── .gitmodules
├── .hound.yml
├── .rspec
├── .rubocop.unhound.yml
├── .rubocop.yml
├── .yardopts
├── CONTRIBUTING.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── app/
│ ├── README.md
│ ├── assets/
│ │ └── config/
│ │ └── manifest.js
│ ├── channels/
│ │ ├── application_cable/
│ │ │ ├── channel.rb
│ │ │ └── connection.rb
│ │ ├── concerns/
│ │ │ ├── application_cable_ability_concern.rb
│ │ │ ├── application_cable_authentication_concern.rb
│ │ │ ├── application_cable_component_concern.rb
│ │ │ ├── application_cable_course_concern.rb
│ │ │ └── application_cable_multitenancy_concern.rb
│ │ └── course/
│ │ ├── channel.rb
│ │ └── monitoring/
│ │ ├── heartbeat_channel.rb
│ │ └── live_monitoring_channel.rb
│ ├── controllers/
│ │ ├── announcements_controller.rb
│ │ ├── application_controller.rb
│ │ ├── attachment_references_controller.rb
│ │ ├── components/
│ │ │ └── course/
│ │ │ ├── achievements_component.rb
│ │ │ ├── announcements_component.rb
│ │ │ ├── assessments_component.rb
│ │ │ ├── codaveri_component.rb
│ │ │ ├── controller_component_host.rb
│ │ │ ├── discussion/
│ │ │ │ └── topics_component.rb
│ │ │ ├── duplication_component.rb
│ │ │ ├── experience_points_component.rb
│ │ │ ├── forums_component.rb
│ │ │ ├── groups_component.rb
│ │ │ ├── koditsu_platform_component.rb
│ │ │ ├── leaderboard_component.rb
│ │ │ ├── learning_map_component.rb
│ │ │ ├── lesson_plan_component.rb
│ │ │ ├── levels_component.rb
│ │ │ ├── materials_component.rb
│ │ │ ├── monitoring_component.rb
│ │ │ ├── multiple_reference_timelines_component.rb
│ │ │ ├── plagiarism_component.rb
│ │ │ ├── rag_wise_component.rb
│ │ │ ├── scholaistic_component.rb
│ │ │ ├── settings_component.rb
│ │ │ ├── statistics_component.rb
│ │ │ ├── stories_component.rb
│ │ │ ├── survey_component.rb
│ │ │ ├── users_component.rb
│ │ │ └── videos_component.rb
│ │ ├── concerns/
│ │ │ ├── application_ability_concern.rb
│ │ │ ├── application_announcements_concern.rb
│ │ │ ├── application_authentication_concern.rb
│ │ │ ├── application_components_concern.rb
│ │ │ ├── application_controller_multitenancy_concern.rb
│ │ │ ├── application_instance_user_concern.rb
│ │ │ ├── application_internationalization_concern.rb
│ │ │ ├── application_multitenancy.rb
│ │ │ ├── application_pagination_concern.rb
│ │ │ ├── application_user_concern.rb
│ │ │ ├── application_user_time_zone_concern.rb
│ │ │ ├── codaveri_language_concern.rb
│ │ │ ├── course/
│ │ │ │ ├── achievement_conditional_concern.rb
│ │ │ │ ├── activity_feeds_concern.rb
│ │ │ │ ├── assessment/
│ │ │ │ │ ├── answer/
│ │ │ │ │ │ └── update_answer_concern.rb
│ │ │ │ │ ├── koditsu_assessment_concern.rb
│ │ │ │ │ ├── koditsu_assessment_invitation_concern.rb
│ │ │ │ │ ├── live_feedback/
│ │ │ │ │ │ ├── file_concern.rb
│ │ │ │ │ │ ├── message_concern.rb
│ │ │ │ │ │ ├── message_file_concern.rb
│ │ │ │ │ │ └── thread_concern.rb
│ │ │ │ │ ├── monitoring/
│ │ │ │ │ │ └── seb_payload_concern.rb
│ │ │ │ │ ├── monitoring_concern.rb
│ │ │ │ │ ├── question/
│ │ │ │ │ │ ├── codaveri_question_concern.rb
│ │ │ │ │ │ ├── koditsu_question_concern.rb
│ │ │ │ │ │ ├── multiple_responses_concern.rb
│ │ │ │ │ │ ├── rubric_based_response_controller_concern.rb
│ │ │ │ │ │ └── rubric_based_response_question_concern.rb
│ │ │ │ │ ├── question_bundle_assignment_concern.rb
│ │ │ │ │ ├── submission/
│ │ │ │ │ │ ├── koditsu/
│ │ │ │ │ │ │ ├── answers_concern.rb
│ │ │ │ │ │ │ ├── submission_times_concern.rb
│ │ │ │ │ │ │ ├── submissions_concern.rb
│ │ │ │ │ │ │ ├── test_cases_concern.rb
│ │ │ │ │ │ │ └── users_concern.rb
│ │ │ │ │ │ ├── monitoring_concern.rb
│ │ │ │ │ │ └── submissions_controller_service_concern.rb
│ │ │ │ │ └── submission_concern.rb
│ │ │ │ ├── assessment_conditional_concern.rb
│ │ │ │ ├── cikgo_chats_concern.rb
│ │ │ │ ├── cikgo_push_concern.rb
│ │ │ │ ├── discussion/
│ │ │ │ │ └── posts_concern.rb
│ │ │ │ ├── forum/
│ │ │ │ │ ├── auto_answering_concern.rb
│ │ │ │ │ ├── topic_controller_hiding_concern.rb
│ │ │ │ │ ├── topic_controller_locking_concern.rb
│ │ │ │ │ └── topic_controller_subscription_concern.rb
│ │ │ │ ├── group/
│ │ │ │ │ └── group_manager_concern.rb
│ │ │ │ ├── koditsu_workspace_concern.rb
│ │ │ │ ├── lesson_plan/
│ │ │ │ │ ├── acts_as_lesson_plan_item_concern.rb
│ │ │ │ │ ├── learning_rate_concern.rb
│ │ │ │ │ ├── personalization_concern.rb
│ │ │ │ │ ├── stories_concern.rb
│ │ │ │ │ └── strategies/
│ │ │ │ │ ├── base_personalization_strategy.rb
│ │ │ │ │ ├── fixed_personalization_strategy.rb
│ │ │ │ │ ├── fomo_personalization_strategy.rb
│ │ │ │ │ ├── otot_personalization_strategy.rb
│ │ │ │ │ └── stragglers_personalization_strategy.rb
│ │ │ │ ├── reminder_service_concern.rb
│ │ │ │ ├── scholaistic/
│ │ │ │ │ └── concern.rb
│ │ │ │ ├── ssid_folder_concern.rb
│ │ │ │ ├── statistics/
│ │ │ │ │ ├── counts_concern.rb
│ │ │ │ │ ├── grades_concern.rb
│ │ │ │ │ ├── reference_times_concern.rb
│ │ │ │ │ ├── submissions_concern.rb
│ │ │ │ │ ├── times_concern.rb
│ │ │ │ │ └── users_concern.rb
│ │ │ │ ├── survey/
│ │ │ │ │ └── reordering_concern.rb
│ │ │ │ ├── unread_counts_concern.rb
│ │ │ │ └── users_controller_management_concern.rb
│ │ │ └── signals/
│ │ │ ├── emission_concern.rb
│ │ │ └── slices/
│ │ │ ├── announcements.rb
│ │ │ ├── assessment_submissions.rb
│ │ │ ├── cikgo_mission_control.rb
│ │ │ ├── cikgo_open_threads_count.rb
│ │ │ ├── comments.rb
│ │ │ ├── enrol_requests.rb
│ │ │ ├── forums.rb
│ │ │ └── videos.rb
│ │ ├── course/
│ │ │ ├── achievement/
│ │ │ │ ├── achievements_controller.rb
│ │ │ │ ├── condition/
│ │ │ │ │ ├── achievements_controller.rb
│ │ │ │ │ ├── assessments_controller.rb
│ │ │ │ │ ├── levels_controller.rb
│ │ │ │ │ ├── scholaistic_assessments_controller.rb
│ │ │ │ │ └── surveys_controller.rb
│ │ │ │ └── controller.rb
│ │ │ ├── admin/
│ │ │ │ ├── admin_controller.rb
│ │ │ │ ├── announcement_settings_controller.rb
│ │ │ │ ├── assessment_settings_controller.rb
│ │ │ │ ├── assessments/
│ │ │ │ │ ├── categories_controller.rb
│ │ │ │ │ └── tabs_controller.rb
│ │ │ │ ├── codaveri_settings_controller.rb
│ │ │ │ ├── component_settings_controller.rb
│ │ │ │ ├── controller.rb
│ │ │ │ ├── discussion/
│ │ │ │ │ └── topic_settings_controller.rb
│ │ │ │ ├── forum_settings_controller.rb
│ │ │ │ ├── leaderboard_settings_controller.rb
│ │ │ │ ├── lesson_plan_settings_controller.rb
│ │ │ │ ├── material_settings_controller.rb
│ │ │ │ ├── notification_settings_controller.rb
│ │ │ │ ├── rag_wise_settings_controller.rb
│ │ │ │ ├── scholaistic_settings_controller.rb
│ │ │ │ ├── sidebar_settings_controller.rb
│ │ │ │ ├── stories_settings_controller.rb
│ │ │ │ ├── video_settings_controller.rb
│ │ │ │ └── videos/
│ │ │ │ └── tabs_controller.rb
│ │ │ ├── announcements_controller.rb
│ │ │ ├── assessment/
│ │ │ │ ├── assessments_controller.rb
│ │ │ │ ├── categories_controller.rb
│ │ │ │ ├── component_controller.rb
│ │ │ │ ├── condition/
│ │ │ │ │ ├── achievements_controller.rb
│ │ │ │ │ ├── assessments_controller.rb
│ │ │ │ │ ├── levels_controller.rb
│ │ │ │ │ ├── scholaistic_assessments_controller.rb
│ │ │ │ │ └── surveys_controller.rb
│ │ │ │ ├── controller.rb
│ │ │ │ ├── mock_answers_controller.rb
│ │ │ │ ├── question/
│ │ │ │ │ ├── controller.rb
│ │ │ │ │ ├── forum_post_responses_controller.rb
│ │ │ │ │ ├── multiple_responses_controller.rb
│ │ │ │ │ ├── programming_controller.rb
│ │ │ │ │ ├── rubric_based_responses_controller.rb
│ │ │ │ │ ├── scribing_controller.rb
│ │ │ │ │ ├── text_responses_controller.rb
│ │ │ │ │ └── voice_responses_controller.rb
│ │ │ │ ├── question_bundle_assignments_controller.rb
│ │ │ │ ├── question_bundle_questions_controller.rb
│ │ │ │ ├── question_bundles_controller.rb
│ │ │ │ ├── question_groups_controller.rb
│ │ │ │ ├── questions_controller.rb
│ │ │ │ ├── rubrics_controller.rb
│ │ │ │ ├── sessions_controller.rb
│ │ │ │ ├── skill_branches_controller.rb
│ │ │ │ ├── skills_controller.rb
│ │ │ │ ├── submission/
│ │ │ │ │ ├── answer/
│ │ │ │ │ │ ├── answers_controller.rb
│ │ │ │ │ │ ├── controller.rb
│ │ │ │ │ │ ├── forum_post_response/
│ │ │ │ │ │ │ └── posts_controller.rb
│ │ │ │ │ │ ├── programming/
│ │ │ │ │ │ │ ├── annotations_controller.rb
│ │ │ │ │ │ │ ├── controller.rb
│ │ │ │ │ │ │ └── programming_controller.rb
│ │ │ │ │ │ ├── scribing/
│ │ │ │ │ │ │ ├── controller.rb
│ │ │ │ │ │ │ └── scribbles_controller.rb
│ │ │ │ │ │ └── text_response/
│ │ │ │ │ │ ├── controller.rb
│ │ │ │ │ │ └── text_response_controller.rb
│ │ │ │ │ ├── controller.rb
│ │ │ │ │ ├── live_feedback_controller.rb
│ │ │ │ │ ├── logs_controller.rb
│ │ │ │ │ └── submissions_controller.rb
│ │ │ │ ├── submission_question/
│ │ │ │ │ ├── comments_controller.rb
│ │ │ │ │ ├── controller.rb
│ │ │ │ │ └── submission_questions_controller.rb
│ │ │ │ └── submissions_controller.rb
│ │ │ ├── component_controller.rb
│ │ │ ├── condition/
│ │ │ │ ├── achievements_controller.rb
│ │ │ │ ├── assessments_controller.rb
│ │ │ │ ├── levels_controller.rb
│ │ │ │ ├── scholaistic_assessments_controller.rb
│ │ │ │ └── surveys_controller.rb
│ │ │ ├── conditions_controller.rb
│ │ │ ├── controller.rb
│ │ │ ├── courses_controller.rb
│ │ │ ├── discussion/
│ │ │ │ ├── posts_controller.rb
│ │ │ │ └── topics_controller.rb
│ │ │ ├── duplications_controller.rb
│ │ │ ├── enrol_requests_controller.rb
│ │ │ ├── experience_points/
│ │ │ │ ├── disbursement_controller.rb
│ │ │ │ └── forum_disbursement_controller.rb
│ │ │ ├── experience_points_records_controller.rb
│ │ │ ├── forum/
│ │ │ │ ├── component_controller.rb
│ │ │ │ ├── controller.rb
│ │ │ │ ├── forums_controller.rb
│ │ │ │ ├── posts_controller.rb
│ │ │ │ └── topics_controller.rb
│ │ │ ├── group/
│ │ │ │ ├── group_categories_controller.rb
│ │ │ │ └── groups_controller.rb
│ │ │ ├── leaderboards_controller.rb
│ │ │ ├── learning_map_controller.rb
│ │ │ ├── lesson_plan/
│ │ │ │ ├── controller.rb
│ │ │ │ ├── events_controller.rb
│ │ │ │ ├── items_controller.rb
│ │ │ │ ├── milestones_controller.rb
│ │ │ │ └── todos_controller.rb
│ │ │ ├── levels_controller.rb
│ │ │ ├── material/
│ │ │ │ ├── controller.rb
│ │ │ │ ├── folders_controller.rb
│ │ │ │ └── materials_controller.rb
│ │ │ ├── object_duplications_controller.rb
│ │ │ ├── personal_times_controller.rb
│ │ │ ├── plagiarism/
│ │ │ │ ├── assessments_controller.rb
│ │ │ │ ├── controller.rb
│ │ │ │ └── plagiarism_controller.rb
│ │ │ ├── reference_timelines_controller.rb
│ │ │ ├── reference_times_controller.rb
│ │ │ ├── rubrics_controller.rb
│ │ │ ├── scholaistic/
│ │ │ │ ├── assistants_controller.rb
│ │ │ │ ├── controller.rb
│ │ │ │ ├── scholaistic_assessments_controller.rb
│ │ │ │ └── submissions_controller.rb
│ │ │ ├── statistics/
│ │ │ │ ├── aggregate_controller.rb
│ │ │ │ ├── assessments_controller.rb
│ │ │ │ ├── controller.rb
│ │ │ │ ├── statistics_controller.rb
│ │ │ │ └── users_controller.rb
│ │ │ ├── stories/
│ │ │ │ └── stories_controller.rb
│ │ │ ├── survey/
│ │ │ │ ├── controller.rb
│ │ │ │ ├── questions_controller.rb
│ │ │ │ ├── responses_controller.rb
│ │ │ │ ├── sections_controller.rb
│ │ │ │ └── surveys_controller.rb
│ │ │ ├── user_email_subscriptions_controller.rb
│ │ │ ├── user_invitations_controller.rb
│ │ │ ├── user_notifications_controller.rb
│ │ │ ├── user_registrations_controller.rb
│ │ │ ├── users_controller.rb
│ │ │ ├── video/
│ │ │ │ ├── controller.rb
│ │ │ │ ├── submission/
│ │ │ │ │ ├── controller.rb
│ │ │ │ │ ├── sessions_controller.rb
│ │ │ │ │ └── submissions_controller.rb
│ │ │ │ ├── topics_controller.rb
│ │ │ │ └── videos_controller.rb
│ │ │ └── video_submissions_controller.rb
│ │ ├── csrf_token_controller.rb
│ │ ├── health_check_controller.rb
│ │ ├── instance_user_role_requests_controller.rb
│ │ ├── jobs_controller.rb
│ │ ├── system/
│ │ │ └── admin/
│ │ │ ├── admin_controller.rb
│ │ │ ├── announcements_controller.rb
│ │ │ ├── controller.rb
│ │ │ ├── courses_controller.rb
│ │ │ ├── get_help_controller.rb
│ │ │ ├── instance/
│ │ │ │ ├── admin_controller.rb
│ │ │ │ ├── announcements_controller.rb
│ │ │ │ ├── components_controller.rb
│ │ │ │ ├── controller.rb
│ │ │ │ ├── courses_controller.rb
│ │ │ │ ├── get_help_controller.rb
│ │ │ │ ├── user_invitations_controller.rb
│ │ │ │ └── users_controller.rb
│ │ │ ├── instances_controller.rb
│ │ │ └── users_controller.rb
│ │ ├── test/
│ │ │ ├── controller.rb
│ │ │ ├── factories_controller.rb
│ │ │ └── mailer_controller.rb
│ │ ├── user/
│ │ │ ├── confirmations_controller.rb
│ │ │ ├── emails_controller.rb
│ │ │ ├── passwords_controller.rb
│ │ │ ├── profiles_controller.rb
│ │ │ ├── registrations_controller.rb
│ │ │ └── sessions_controller.rb
│ │ └── users_controller.rb
│ ├── helpers/
│ │ ├── application_formatters_helper.rb
│ │ ├── application_helper.rb
│ │ ├── application_html_formatters_helper.rb
│ │ ├── application_jobs_helper.rb
│ │ ├── application_mailer_helper.rb
│ │ ├── application_notifications_helper.rb
│ │ ├── consolidated_opening_reminder_mailer_helper.rb
│ │ ├── course/
│ │ │ ├── achievement/
│ │ │ │ ├── achievements_helper.rb
│ │ │ │ └── controller_helper.rb
│ │ │ ├── assessment/
│ │ │ │ ├── answer/
│ │ │ │ │ └── programming_test_case_helper.rb
│ │ │ │ ├── assessments_helper.rb
│ │ │ │ ├── question/
│ │ │ │ │ └── programming_helper.rb
│ │ │ │ ├── submission/
│ │ │ │ │ └── submissions_helper.rb
│ │ │ │ └── submissions_helper.rb
│ │ │ ├── condition/
│ │ │ │ └── conditions_helper.rb
│ │ │ ├── controller_helper.rb
│ │ │ ├── discussion/
│ │ │ │ └── topics_helper.rb
│ │ │ ├── forum/
│ │ │ │ └── controller_helper.rb
│ │ │ ├── group/
│ │ │ │ └── group_categories_helper.rb
│ │ │ ├── leaderboards_helper.rb
│ │ │ ├── material/
│ │ │ │ └── folders_helper.rb
│ │ │ ├── object_duplications_helper.rb
│ │ │ └── users_helper.rb
│ │ ├── route_overrides_helper.rb
│ │ └── tmp_cleanup_helper.rb
│ ├── jobs/
│ │ ├── application_job.rb
│ │ ├── consolidated_item_email_job.rb
│ │ ├── course/
│ │ │ ├── announcement/
│ │ │ │ └── opening_reminder_job.rb
│ │ │ ├── assessment/
│ │ │ │ ├── answer/
│ │ │ │ │ ├── auto_grading_job.rb
│ │ │ │ │ ├── base_auto_grading_job.rb
│ │ │ │ │ ├── programming_codaveri_feedback_job.rb
│ │ │ │ │ └── reduce_priority_auto_grading_job.rb
│ │ │ │ ├── closing_reminder_job.rb
│ │ │ │ ├── invite_to_koditsu_job.rb
│ │ │ │ ├── plagiarism_check_job.rb
│ │ │ │ ├── question/
│ │ │ │ │ ├── answers_evaluation_job.rb
│ │ │ │ │ ├── codaveri_import_job.rb
│ │ │ │ │ └── programming_import_job.rb
│ │ │ │ └── submission/
│ │ │ │ ├── auto_feedback_job.rb
│ │ │ │ ├── auto_grading_job.rb
│ │ │ │ ├── csv_download_job.rb
│ │ │ │ ├── deleting_job.rb
│ │ │ │ ├── fetch_submissions_from_koditsu_job.rb
│ │ │ │ ├── force_submit_timed_submission_job.rb
│ │ │ │ ├── force_submitting_job.rb
│ │ │ │ ├── publishing_job.rb
│ │ │ │ ├── statistics_download_job.rb
│ │ │ │ ├── unsubmitting_job.rb
│ │ │ │ └── zip_download_job.rb
│ │ │ ├── conditional/
│ │ │ │ ├── conditional_satisfiability_evaluation_job.rb
│ │ │ │ └── coursewide_conditional_satisfiability_evaluation_job.rb
│ │ │ ├── discussion/
│ │ │ │ └── post/
│ │ │ │ └── codaveri_feedback_rating_job.rb
│ │ │ ├── duplication_job.rb
│ │ │ ├── experience_points_download_job.rb
│ │ │ ├── forum/
│ │ │ │ ├── auto_answering_job.rb
│ │ │ │ └── importing_job.rb
│ │ │ ├── lesson_plan/
│ │ │ │ └── coursewide_personalized_timeline_update_job.rb
│ │ │ ├── material/
│ │ │ │ ├── text_chunk_job.rb
│ │ │ │ └── zip_download_job.rb
│ │ │ ├── object_duplication_job.rb
│ │ │ ├── rubric/
│ │ │ │ └── rubric_evaluation_export_job.rb
│ │ │ ├── statistics/
│ │ │ │ └── assessments_score_summary_download_job.rb
│ │ │ ├── survey/
│ │ │ │ ├── closing_reminder_job.rb
│ │ │ │ └── survey_download_job.rb
│ │ │ ├── user_deletion_job.rb
│ │ │ └── video/
│ │ │ └── closing_reminder_job.rb
│ │ ├── read_marks_clean_up_job.rb
│ │ ├── user_email_database_cleanup_job.rb
│ │ └── video_statistic_update_job.rb
│ ├── mailers/
│ │ ├── activity_mailer.rb
│ │ ├── application_mailer.rb
│ │ ├── consolidated_opening_reminder_mailer.rb
│ │ ├── course/
│ │ │ └── mailer.rb
│ │ ├── instance/
│ │ │ └── mailer.rb
│ │ └── instance_user_role_request_mailer.rb
│ ├── models/
│ │ ├── .rubocop.yml
│ │ ├── ability.rb
│ │ ├── activity.rb
│ │ ├── application_record.rb
│ │ ├── attachment.rb
│ │ ├── attachment_reference.rb
│ │ ├── cikgo_user.rb
│ │ ├── components/
│ │ │ ├── ability_host.rb
│ │ │ ├── course/
│ │ │ │ ├── achievements_ability_component.rb
│ │ │ │ ├── announcements_ability_component.rb
│ │ │ │ ├── assessments_ability_component.rb
│ │ │ │ ├── conditions_ability_component.rb
│ │ │ │ ├── course_ability_component.rb
│ │ │ │ ├── course_user_ability_component.rb
│ │ │ │ ├── discussions_ability_component.rb
│ │ │ │ ├── duplication_ability_component.rb
│ │ │ │ ├── experience_points_disbursement_ability_component.rb
│ │ │ │ ├── experience_points_records_ability_component.rb
│ │ │ │ ├── forums_ability_component.rb
│ │ │ │ ├── groups_ability_component.rb
│ │ │ │ ├── learning_map_ability_component.rb
│ │ │ │ ├── lesson_plan_ability_component.rb
│ │ │ │ ├── levels_ability_component.rb
│ │ │ │ ├── materials_ability_component.rb
│ │ │ │ ├── model_component_host.rb
│ │ │ │ ├── monitoring_ability_component.rb
│ │ │ │ ├── plagiarism_ability_component.rb
│ │ │ │ ├── rag_wise_setting_ability_component.rb
│ │ │ │ ├── scholaistic_ability_component.rb
│ │ │ │ ├── statistics_ability_component.rb
│ │ │ │ ├── stories_ability_component.rb
│ │ │ │ ├── surveys_ability_component.rb
│ │ │ │ ├── timelines_ability_component.rb
│ │ │ │ ├── user_email_unsubscriptions_ability_component.rb
│ │ │ │ └── videos_ability_component.rb
│ │ │ ├── system/
│ │ │ │ └── admin/
│ │ │ │ ├── instance_admin_ability_component.rb
│ │ │ │ ├── instance_announcements_ability_component.rb
│ │ │ │ ├── system_admin_ability_component.rb
│ │ │ │ └── system_announcements_ability_component.rb
│ │ │ ├── user_notifications_ability_component.rb
│ │ │ └── users_ability_component.rb
│ │ ├── concerns/
│ │ │ ├── announcement_concern.rb
│ │ │ ├── application_acts_as_concern.rb
│ │ │ ├── application_userstamp_concern.rb
│ │ │ ├── cikgo/
│ │ │ │ └── pushable_item_concern.rb
│ │ │ ├── component_settings_concern.rb
│ │ │ ├── course/
│ │ │ │ ├── assessment/
│ │ │ │ │ ├── new_submission_concern.rb
│ │ │ │ │ ├── questions_concern.rb
│ │ │ │ │ ├── submission/
│ │ │ │ │ │ ├── answers_concern.rb
│ │ │ │ │ │ ├── cikgo_task_completion_concern.rb
│ │ │ │ │ │ ├── notification_concern.rb
│ │ │ │ │ │ ├── todo_concern.rb
│ │ │ │ │ │ └── workflow_event_concern.rb
│ │ │ │ │ └── todo_concern.rb
│ │ │ │ ├── closing_reminder_concern.rb
│ │ │ │ ├── course_components_concern.rb
│ │ │ │ ├── course_user_type_concern.rb
│ │ │ │ ├── discussion/
│ │ │ │ │ ├── post/
│ │ │ │ │ │ ├── ordering_concern.rb
│ │ │ │ │ │ └── retrieval_concern.rb
│ │ │ │ │ └── topic/
│ │ │ │ │ └── posts_concern.rb
│ │ │ │ ├── duplication_concern.rb
│ │ │ │ ├── forum_participation_concern.rb
│ │ │ │ ├── lesson_plan/
│ │ │ │ │ ├── item/
│ │ │ │ │ │ └── cikgo_push_concern.rb
│ │ │ │ │ └── item_todo_concern.rb
│ │ │ │ ├── levels_concern.rb
│ │ │ │ ├── material/
│ │ │ │ │ └── folder/
│ │ │ │ │ └── ordering_concern.rb
│ │ │ │ ├── material_concern.rb
│ │ │ │ ├── opening_reminder_concern.rb
│ │ │ │ ├── sanitize_description_concern.rb
│ │ │ │ ├── search_concern.rb
│ │ │ │ ├── settings/
│ │ │ │ │ └── lesson_plan_settings_concern.rb
│ │ │ │ ├── survey/
│ │ │ │ │ └── response/
│ │ │ │ │ ├── cikgo_task_completion_concern.rb
│ │ │ │ │ └── todo_concern.rb
│ │ │ │ └── video/
│ │ │ │ ├── interval_query_concern.rb
│ │ │ │ ├── submission/
│ │ │ │ │ ├── notification_concern.rb
│ │ │ │ │ ├── statistic/
│ │ │ │ │ │ └── cikgo_task_completion_concern.rb
│ │ │ │ │ └── todo_concern.rb
│ │ │ │ ├── url_concern.rb
│ │ │ │ └── watch_statistics_concern.rb
│ │ │ ├── course_component_query_concern.rb
│ │ │ ├── course_user/
│ │ │ │ ├── achievements_concern.rb
│ │ │ │ ├── level_progress_concern.rb
│ │ │ │ ├── staff_concern.rb
│ │ │ │ └── todo_concern.rb
│ │ │ ├── duplication_state_tracking_concern.rb
│ │ │ ├── generic/
│ │ │ │ └── collection_concern.rb
│ │ │ ├── instance/
│ │ │ │ └── course_components_concern.rb
│ │ │ ├── instance_user_search_concern.rb
│ │ │ ├── safe_mark_as_read_concern.rb
│ │ │ ├── time_zone_concern.rb
│ │ │ ├── user_authentication_concern.rb
│ │ │ ├── user_notifications_concern.rb
│ │ │ └── user_search_concern.rb
│ │ ├── course/
│ │ │ ├── achievement.rb
│ │ │ ├── announcement.rb
│ │ │ ├── assessment/
│ │ │ │ ├── answer/
│ │ │ │ │ ├── auto_grading.rb
│ │ │ │ │ ├── forum_post.rb
│ │ │ │ │ ├── forum_post_response.rb
│ │ │ │ │ ├── multiple_response.rb
│ │ │ │ │ ├── multiple_response_option.rb
│ │ │ │ │ ├── programming.rb
│ │ │ │ │ ├── programming_ability.rb
│ │ │ │ │ ├── programming_auto_grading.rb
│ │ │ │ │ ├── programming_auto_grading_test_result.rb
│ │ │ │ │ ├── programming_file.rb
│ │ │ │ │ ├── programming_file_annotation.rb
│ │ │ │ │ ├── rubric_based_response.rb
│ │ │ │ │ ├── rubric_based_response_selection.rb
│ │ │ │ │ ├── rubric_playground_answer_adapter.rb
│ │ │ │ │ ├── scribing.rb
│ │ │ │ │ ├── scribing_scribble.rb
│ │ │ │ │ ├── text_response.rb
│ │ │ │ │ └── voice_response.rb
│ │ │ │ ├── answer.rb
│ │ │ │ ├── assessment_ability.rb
│ │ │ │ ├── category.rb
│ │ │ │ ├── link.rb
│ │ │ │ ├── live_feedback/
│ │ │ │ │ ├── file.rb
│ │ │ │ │ ├── message.rb
│ │ │ │ │ ├── message_file.rb
│ │ │ │ │ ├── message_option.rb
│ │ │ │ │ ├── option.rb
│ │ │ │ │ └── thread.rb
│ │ │ │ ├── live_feedback.rb
│ │ │ │ ├── live_feedback_code.rb
│ │ │ │ ├── live_feedback_comment.rb
│ │ │ │ ├── plagiarism_check.rb
│ │ │ │ ├── question/
│ │ │ │ │ ├── forum_post_response.rb
│ │ │ │ │ ├── mock_answer/
│ │ │ │ │ │ └── answer_adapter.rb
│ │ │ │ │ ├── mock_answer.rb
│ │ │ │ │ ├── multiple_response.rb
│ │ │ │ │ ├── multiple_response_option.rb
│ │ │ │ │ ├── programming.rb
│ │ │ │ │ ├── programming_template_file.rb
│ │ │ │ │ ├── programming_test_case.rb
│ │ │ │ │ ├── question_rubric.rb
│ │ │ │ │ ├── rubric_based_response.rb
│ │ │ │ │ ├── rubric_based_response_category.rb
│ │ │ │ │ ├── rubric_based_response_criterion.rb
│ │ │ │ │ ├── scribing.rb
│ │ │ │ │ ├── text_response.rb
│ │ │ │ │ ├── text_response_comprehension_group.rb
│ │ │ │ │ ├── text_response_comprehension_point.rb
│ │ │ │ │ ├── text_response_comprehension_solution.rb
│ │ │ │ │ ├── text_response_solution.rb
│ │ │ │ │ └── voice_response.rb
│ │ │ │ ├── question.rb
│ │ │ │ ├── question_bundle.rb
│ │ │ │ ├── question_bundle_assignment.rb
│ │ │ │ ├── question_bundle_question.rb
│ │ │ │ ├── question_group.rb
│ │ │ │ ├── skill.rb
│ │ │ │ ├── skill_ability.rb
│ │ │ │ ├── skill_branch.rb
│ │ │ │ ├── submission/
│ │ │ │ │ └── log.rb
│ │ │ │ ├── submission.rb
│ │ │ │ ├── submission_question.rb
│ │ │ │ └── tab.rb
│ │ │ ├── assessment.rb
│ │ │ ├── condition/
│ │ │ │ ├── achievement.rb
│ │ │ │ ├── assessment.rb
│ │ │ │ ├── level.rb
│ │ │ │ ├── scholaistic_assessment.rb
│ │ │ │ ├── survey.rb
│ │ │ │ └── video.rb
│ │ │ ├── condition.rb
│ │ │ ├── discussion/
│ │ │ │ ├── post/
│ │ │ │ │ ├── codaveri_feedback.rb
│ │ │ │ │ └── vote.rb
│ │ │ │ ├── post.rb
│ │ │ │ ├── topic/
│ │ │ │ │ └── subscription.rb
│ │ │ │ └── topic.rb
│ │ │ ├── discussion.rb
│ │ │ ├── enrol_request.rb
│ │ │ ├── experience_points/
│ │ │ │ ├── disbursement.rb
│ │ │ │ └── forum_disbursement.rb
│ │ │ ├── experience_points_record.rb
│ │ │ ├── forum/
│ │ │ │ ├── discussion.rb
│ │ │ │ ├── discussion_reference.rb
│ │ │ │ ├── import.rb
│ │ │ │ ├── rag_auto_answering.rb
│ │ │ │ ├── search.rb
│ │ │ │ ├── subscription.rb
│ │ │ │ ├── topic/
│ │ │ │ │ └── view.rb
│ │ │ │ └── topic.rb
│ │ │ ├── forum.rb
│ │ │ ├── group.rb
│ │ │ ├── group_category.rb
│ │ │ ├── group_user.rb
│ │ │ ├── learning_map.rb
│ │ │ ├── learning_rate_record.rb
│ │ │ ├── lesson_plan/
│ │ │ │ ├── event.rb
│ │ │ │ ├── event_material.rb
│ │ │ │ ├── item.rb
│ │ │ │ ├── milestone.rb
│ │ │ │ └── todo.rb
│ │ │ ├── lesson_plan.rb
│ │ │ ├── level.rb
│ │ │ ├── material/
│ │ │ │ ├── folder.rb
│ │ │ │ ├── text_chunk.rb
│ │ │ │ ├── text_chunk_reference.rb
│ │ │ │ └── text_chunking.rb
│ │ │ ├── material.rb
│ │ │ ├── monitoring/
│ │ │ │ ├── browser_authorization/
│ │ │ │ │ ├── base.rb
│ │ │ │ │ ├── seb_config_key.rb
│ │ │ │ │ └── user_agent.rb
│ │ │ │ ├── heartbeat.rb
│ │ │ │ ├── monitor.rb
│ │ │ │ └── session.rb
│ │ │ ├── monitoring.rb
│ │ │ ├── notification.rb
│ │ │ ├── personal_time.rb
│ │ │ ├── question_assessment.rb
│ │ │ ├── reference_time.rb
│ │ │ ├── reference_timeline.rb
│ │ │ ├── registration.rb
│ │ │ ├── rubric/
│ │ │ │ ├── answer_evaluation/
│ │ │ │ │ └── selection.rb
│ │ │ │ ├── answer_evaluation.rb
│ │ │ │ ├── category/
│ │ │ │ │ └── criterion.rb
│ │ │ │ ├── category.rb
│ │ │ │ ├── mock_answer_evaluation/
│ │ │ │ │ └── selection.rb
│ │ │ │ ├── mock_answer_evaluation.rb
│ │ │ │ └── rubric_adapter.rb
│ │ │ ├── rubric.rb
│ │ │ ├── scholaistic_assessment.rb
│ │ │ ├── scholaistic_submission.rb
│ │ │ ├── settings/
│ │ │ │ ├── announcements_component.rb
│ │ │ │ ├── assessments_component.rb
│ │ │ │ ├── codaveri_component.rb
│ │ │ │ ├── component.rb
│ │ │ │ ├── components.rb
│ │ │ │ ├── email.rb
│ │ │ │ ├── forums_component.rb
│ │ │ │ ├── leaderboard_component.rb
│ │ │ │ ├── learning_map_component.rb
│ │ │ │ ├── lesson_plan_component.rb
│ │ │ │ ├── lesson_plan_items.rb
│ │ │ │ ├── materials_component.rb
│ │ │ │ ├── pan_component.rb
│ │ │ │ ├── rag_wise_component.rb
│ │ │ │ ├── scholaistic_component.rb
│ │ │ │ ├── sidebar.rb
│ │ │ │ ├── sidebar_item.rb
│ │ │ │ ├── stories_component.rb
│ │ │ │ ├── survey_component.rb
│ │ │ │ ├── topics_component.rb
│ │ │ │ ├── users_component.rb
│ │ │ │ └── videos_component.rb
│ │ │ ├── settings.rb
│ │ │ ├── story.rb
│ │ │ ├── survey/
│ │ │ │ ├── answer.rb
│ │ │ │ ├── answer_option.rb
│ │ │ │ ├── question.rb
│ │ │ │ ├── question_option.rb
│ │ │ │ ├── response.rb
│ │ │ │ └── section.rb
│ │ │ ├── survey.rb
│ │ │ ├── user_achievement.rb
│ │ │ ├── user_email_unsubscription.rb
│ │ │ ├── user_invitation.rb
│ │ │ ├── video/
│ │ │ │ ├── event.rb
│ │ │ │ ├── session.rb
│ │ │ │ ├── statistic.rb
│ │ │ │ ├── submission/
│ │ │ │ │ └── statistic.rb
│ │ │ │ ├── submission.rb
│ │ │ │ ├── tab.rb
│ │ │ │ └── topic.rb
│ │ │ └── video.rb
│ │ ├── course.rb
│ │ ├── course_user.rb
│ │ ├── duplication_traceable/
│ │ │ ├── assessment.rb
│ │ │ └── course.rb
│ │ ├── duplication_traceable.rb
│ │ ├── generic_announcement.rb
│ │ ├── instance/
│ │ │ ├── announcement.rb
│ │ │ ├── settings/
│ │ │ │ └── components.rb
│ │ │ ├── settings.rb
│ │ │ ├── user_invitation.rb
│ │ │ └── user_role_request.rb
│ │ ├── instance.rb
│ │ ├── instance_user.rb
│ │ ├── settings.rb
│ │ ├── system/
│ │ │ └── announcement.rb
│ │ ├── user/
│ │ │ ├── email.rb
│ │ │ └── identity.rb
│ │ ├── user.rb
│ │ └── user_notification.rb
│ ├── notifiers/
│ │ ├── course/
│ │ │ ├── achievement_notifier.rb
│ │ │ ├── announcement_notifier.rb
│ │ │ ├── assessment/
│ │ │ │ ├── answer/
│ │ │ │ │ └── comment_notifier.rb
│ │ │ │ └── submission_question/
│ │ │ │ └── comment_notifier.rb
│ │ │ ├── assessment_notifier.rb
│ │ │ ├── consolidated_opening_reminder_notifier.rb
│ │ │ ├── forum/
│ │ │ │ ├── post_notifier.rb
│ │ │ │ └── topic_notifier.rb
│ │ │ ├── level_notifier.rb
│ │ │ └── video_notifier.rb
│ │ └── notifier/
│ │ └── base.rb
│ ├── services/
│ │ ├── authentication/
│ │ │ ├── authentication_service.rb
│ │ │ ├── jwt_verification_service.rb
│ │ │ ├── keycloak_verification_service.rb
│ │ │ └── verification_service.rb
│ │ ├── cikgo/
│ │ │ ├── chats_service.rb
│ │ │ ├── resources_service.rb
│ │ │ ├── service.rb
│ │ │ ├── timelines_service.rb
│ │ │ └── users_service.rb
│ │ ├── codaveri_async_api_service.rb
│ │ ├── concerns/
│ │ │ ├── cikgo/
│ │ │ │ └── course_concern.rb
│ │ │ ├── course/
│ │ │ │ └── user_invitation_service/
│ │ │ │ ├── email_invitation_concern.rb
│ │ │ │ ├── parse_invitation_concern.rb
│ │ │ │ └── process_invitation_concern.rb
│ │ │ └── instance/
│ │ │ └── user_invitation_service/
│ │ │ ├── email_invitation_concern.rb
│ │ │ ├── parse_invitation_concern.rb
│ │ │ └── process_invitation_concern.rb
│ │ ├── course/
│ │ │ ├── announcement/
│ │ │ │ └── reminder_service.rb
│ │ │ ├── assessment/
│ │ │ │ ├── achievement_preload_service.rb
│ │ │ │ ├── answer/
│ │ │ │ │ ├── ai_generated_post_service.rb
│ │ │ │ │ ├── auto_grading_service.rb
│ │ │ │ │ ├── live_feedback/
│ │ │ │ │ │ ├── feedback_service.rb
│ │ │ │ │ │ └── thread_service.rb
│ │ │ │ │ ├── multiple_response_auto_grading_service.rb
│ │ │ │ │ ├── programming_auto_grading_service.rb
│ │ │ │ │ ├── programming_codaveri_async_feedback_service.rb
│ │ │ │ │ ├── programming_codaveri_auto_grading_service.rb
│ │ │ │ │ ├── prompts/
│ │ │ │ │ │ ├── rubric_auto_grading_output_format.json
│ │ │ │ │ │ ├── rubric_auto_grading_system_prompt.json
│ │ │ │ │ │ └── rubric_auto_grading_user_prompt.json
│ │ │ │ │ ├── rubric_auto_grading_service.rb
│ │ │ │ │ ├── rubric_based_response/
│ │ │ │ │ │ └── answer_adapter.rb
│ │ │ │ │ ├── text_response_auto_grading_service.rb
│ │ │ │ │ └── text_response_comprehension_auto_grading_service.rb
│ │ │ │ ├── authentication_service.rb
│ │ │ │ ├── koditsu_assessment_invitation_service.rb
│ │ │ │ ├── koditsu_assessment_service.rb
│ │ │ │ ├── monitoring_service.rb
│ │ │ │ ├── programming_codaveri_evaluation_service.rb
│ │ │ │ ├── programming_evaluation_service.rb
│ │ │ │ ├── question/
│ │ │ │ │ ├── answers_evaluation_service.rb
│ │ │ │ │ ├── codaveri_problem_generation_service.rb
│ │ │ │ │ ├── koditsu_question_service.rb
│ │ │ │ │ ├── mrq_generation_service.rb
│ │ │ │ │ ├── programming/
│ │ │ │ │ │ ├── c_sharp/
│ │ │ │ │ │ │ ├── c_sharp_makefile
│ │ │ │ │ │ │ └── c_sharp_package_service.rb
│ │ │ │ │ │ ├── cpp/
│ │ │ │ │ │ │ ├── cpp_autograde_include.cc
│ │ │ │ │ │ │ ├── cpp_autograde_post.cc
│ │ │ │ │ │ │ ├── cpp_autograde_pre.cc
│ │ │ │ │ │ │ ├── cpp_makefile
│ │ │ │ │ │ │ └── cpp_package_service.rb
│ │ │ │ │ │ ├── go/
│ │ │ │ │ │ │ ├── go_makefile
│ │ │ │ │ │ │ └── go_package_service.rb
│ │ │ │ │ │ ├── java/
│ │ │ │ │ │ │ ├── RunTests.java
│ │ │ │ │ │ │ ├── java_autograde_pre.java
│ │ │ │ │ │ │ ├── java_build.xml
│ │ │ │ │ │ │ ├── java_package_service.rb
│ │ │ │ │ │ │ ├── java_simple_makefile
│ │ │ │ │ │ │ └── java_standard_makefile
│ │ │ │ │ │ ├── java_script/
│ │ │ │ │ │ │ ├── java_script_makefile
│ │ │ │ │ │ │ └── java_script_package_service.rb
│ │ │ │ │ │ ├── language_package_service.rb
│ │ │ │ │ │ ├── programming_package_service.rb
│ │ │ │ │ │ ├── python/
│ │ │ │ │ │ │ ├── python_autograde_post.py
│ │ │ │ │ │ │ ├── python_autograde_pre.py
│ │ │ │ │ │ │ ├── python_makefile
│ │ │ │ │ │ │ └── python_package_service.rb
│ │ │ │ │ │ ├── r/
│ │ │ │ │ │ │ ├── r_makefile
│ │ │ │ │ │ │ └── r_package_service.rb
│ │ │ │ │ │ ├── rust/
│ │ │ │ │ │ │ ├── rust_makefile
│ │ │ │ │ │ │ └── rust_package_service.rb
│ │ │ │ │ │ └── type_script/
│ │ │ │ │ │ ├── type_script_makefile
│ │ │ │ │ │ └── type_script_package_service.rb
│ │ │ │ │ ├── programming_codaveri/
│ │ │ │ │ │ ├── c_sharp/
│ │ │ │ │ │ │ └── c_sharp_package_service.rb
│ │ │ │ │ │ ├── go/
│ │ │ │ │ │ │ └── go_package_service.rb
│ │ │ │ │ │ ├── java/
│ │ │ │ │ │ │ └── java_package_service.rb
│ │ │ │ │ │ ├── java_script/
│ │ │ │ │ │ │ └── java_script_package_service.rb
│ │ │ │ │ │ ├── language_package_service.rb
│ │ │ │ │ │ ├── programming_codaveri_package_service.rb
│ │ │ │ │ │ ├── python/
│ │ │ │ │ │ │ └── python_package_service.rb
│ │ │ │ │ │ ├── r/
│ │ │ │ │ │ │ └── r_package_service.rb
│ │ │ │ │ │ ├── rust/
│ │ │ │ │ │ │ └── rust_package_service.rb
│ │ │ │ │ │ └── type_script/
│ │ │ │ │ │ └── type_script_package_service.rb
│ │ │ │ │ ├── programming_codaveri_service.rb
│ │ │ │ │ ├── programming_import_service.rb
│ │ │ │ │ ├── prompts/
│ │ │ │ │ │ ├── mcq_generation_system_prompt.json
│ │ │ │ │ │ ├── mcq_generation_user_prompt.json
│ │ │ │ │ │ ├── mcq_mrq_generation_output_format.json
│ │ │ │ │ │ ├── mrq_generation_system_prompt.json
│ │ │ │ │ │ └── mrq_generation_user_prompt.json
│ │ │ │ │ ├── question_adapter.rb
│ │ │ │ │ ├── rubric_based_response/
│ │ │ │ │ │ └── rubric_adapter.rb
│ │ │ │ │ ├── scribing_import_service.rb
│ │ │ │ │ └── text_response_lemma_service.rb
│ │ │ │ ├── reminder_service.rb
│ │ │ │ ├── session_authentication_service.rb
│ │ │ │ ├── session_log_service.rb
│ │ │ │ └── submission/
│ │ │ │ ├── auto_grading_service.rb
│ │ │ │ ├── base_zip_download_service.rb
│ │ │ │ ├── calculate_exp_service.rb
│ │ │ │ ├── csv_download_service.rb
│ │ │ │ ├── koditsu_submission_service.rb
│ │ │ │ ├── monitoring_service.rb
│ │ │ │ ├── ssid_plagiarism_service.rb
│ │ │ │ ├── ssid_zip_download_service.rb
│ │ │ │ ├── statistics_download_service.rb
│ │ │ │ ├── update_service.rb
│ │ │ │ └── zip_download_service.rb
│ │ │ ├── conditional/
│ │ │ │ ├── conditional_satisfiability_evaluation_service.rb
│ │ │ │ └── satisfiability_graph_build_service.rb
│ │ │ ├── course_owner_preload_service.rb
│ │ │ ├── course_user_preload_service.rb
│ │ │ ├── discussion/
│ │ │ │ └── post/
│ │ │ │ └── codaveri_feedback_rating_service.rb
│ │ │ ├── duplication/
│ │ │ │ ├── base_service.rb
│ │ │ │ ├── course_duplication_service.rb
│ │ │ │ └── object_duplication_service.rb
│ │ │ ├── experience_points_download_service.rb
│ │ │ ├── group_manager_preload_service.rb
│ │ │ ├── koditsu_workspace_service.rb
│ │ │ ├── material/
│ │ │ │ ├── preload_service.rb
│ │ │ │ └── zip_download_service.rb
│ │ │ ├── reference_time/
│ │ │ │ └── time_offset_service.rb
│ │ │ ├── rubric/
│ │ │ │ ├── llm_service/
│ │ │ │ │ ├── answer_adapter.rb
│ │ │ │ │ ├── question_adapter.rb
│ │ │ │ │ └── rubric_adapter.rb
│ │ │ │ └── llm_service.rb
│ │ │ ├── skills_mastery_preload_service.rb
│ │ │ ├── ssid_folder_service.rb
│ │ │ ├── statistics/
│ │ │ │ └── assessments_score_summary_download_service.rb
│ │ │ ├── survey/
│ │ │ │ ├── reminder_service.rb
│ │ │ │ └── survey_download_service.rb
│ │ │ ├── user_invitation_service.rb
│ │ │ ├── user_registration_service.rb
│ │ │ └── video/
│ │ │ └── reminder_service.rb
│ │ ├── instance/
│ │ │ └── user_invitation_service.rb
│ │ ├── koditsu_async_api_service.rb
│ │ ├── rag_wise/
│ │ │ ├── chunking_service.rb
│ │ │ ├── discussion_extraction_service.rb
│ │ │ ├── llm_service.rb
│ │ │ ├── prompts/
│ │ │ │ ├── forum_assistant_system_prompt.json
│ │ │ │ └── guess_course_material_name_system_prompt_template.json
│ │ │ ├── rag_workflow_service.rb
│ │ │ ├── response_evaluation_service.rb
│ │ │ └── tools/
│ │ │ ├── course_forum_discussions_tool.rb
│ │ │ └── course_materials_tool.rb
│ │ ├── scholaistic_api_service.rb
│ │ ├── sidekiq_api_service.rb
│ │ ├── ssid_async_api_service.rb
│ │ └── user/
│ │ └── instance_preload_service.rb
│ ├── uploaders/
│ │ ├── file_uploader.rb
│ │ └── image_uploader.rb
│ └── views/
│ ├── announcements/
│ │ ├── _announcement_data.json.jbuilder
│ │ ├── _announcement_list_data.json.jbuilder
│ │ └── index.json.jbuilder
│ ├── application/
│ │ └── index.json.jbuilder
│ ├── attachment_references/
│ │ └── create.json.jbuilder
│ ├── attachments/
│ │ └── _attachment_reference.json.jbuilder
│ ├── course/
│ │ ├── achievement/
│ │ │ └── achievements/
│ │ │ ├── _achievement.json.jbuilder
│ │ │ ├── _achievement_conditional.json.jbuilder
│ │ │ ├── _achievement_data.json.jbuilder
│ │ │ ├── _achievement_list_data.json.jbuilder
│ │ │ ├── index.json.jbuilder
│ │ │ └── show.json.jbuilder
│ │ ├── admin/
│ │ │ ├── admin/
│ │ │ │ ├── index.json.jbuilder
│ │ │ │ └── time_zones.json.jbuilder
│ │ │ ├── announcement_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── assessment_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── codaveri_settings/
│ │ │ │ ├── assessment.json.jbuilder
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── component_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── discussion/
│ │ │ │ └── topic_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── forum_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── leaderboard_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── lesson_plan_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── material_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── notification_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── rag_wise_settings/
│ │ │ │ ├── courses.json.jbuilder
│ │ │ │ ├── edit.json.jbuilder
│ │ │ │ ├── folders.json.jbuilder
│ │ │ │ ├── forums.json.jbuilder
│ │ │ │ └── materials.json.jbuilder
│ │ │ ├── scholaistic_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ ├── sidebar_settings/
│ │ │ │ ├── edit.json.jbuilder
│ │ │ │ └── show.json.jbuilder
│ │ │ ├── stories_settings/
│ │ │ │ └── edit.json.jbuilder
│ │ │ └── video_settings/
│ │ │ └── edit.json.jbuilder
│ │ ├── announcements/
│ │ │ └── index.json.jbuilder
│ │ ├── assessment/
│ │ │ ├── answer/
│ │ │ │ ├── forum_post_responses/
│ │ │ │ │ └── _forum_post_response.json.jbuilder
│ │ │ │ ├── multiple_responses/
│ │ │ │ │ └── _multiple_response.json.jbuilder
│ │ │ │ ├── programming/
│ │ │ │ │ ├── _annotations.json.jbuilder
│ │ │ │ │ └── _programming.json.jbuilder
│ │ │ │ ├── rubric_based_responses/
│ │ │ │ │ └── _rubric_based_response.json.jbuilder
│ │ │ │ ├── scribing/
│ │ │ │ │ └── _scribing.json.jbuilder
│ │ │ │ ├── text_responses/
│ │ │ │ │ └── _text_response.json.jbuilder
│ │ │ │ └── voice_responses/
│ │ │ │ └── _voice_response.json.jbuilder
│ │ │ ├── answers/
│ │ │ │ └── _answer.json.jbuilder
│ │ │ ├── assessments/
│ │ │ │ ├── _achievement_badges.json.jbuilder
│ │ │ │ ├── _assessment_actions.json.jbuilder
│ │ │ │ ├── _assessment_conditional.json.jbuilder
│ │ │ │ ├── _assessment_lesson_plan_item.json.jbuilder
│ │ │ │ ├── _assessment_list_data.json.jbuilder
│ │ │ │ ├── _assessment_question_bundle_buttons.html.slim
│ │ │ │ ├── _monitoring_details.json.jbuilder
│ │ │ │ ├── authenticate.json.jbuilder
│ │ │ │ ├── blocked_by_monitor.json.jbuilder
│ │ │ │ ├── edit.json.jbuilder
│ │ │ │ ├── index.json.jbuilder
│ │ │ │ ├── monitoring.json.jbuilder
│ │ │ │ └── show.json.jbuilder
│ │ │ ├── categories/
│ │ │ │ ├── _category.json.jbuilder
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── mock_answers/
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── programming_evaluations/
│ │ │ │ ├── _programming_evaluation.json.jbuilder
│ │ │ │ ├── allocate.json.jbuilder
│ │ │ │ ├── show.json.jbuilder
│ │ │ │ └── update_result.json.jbuilder
│ │ │ ├── question/
│ │ │ │ ├── _form.json.jbuilder
│ │ │ │ ├── _skills.json.jbuilder
│ │ │ │ ├── forum_post_responses/
│ │ │ │ │ ├── _form.json.jbuilder
│ │ │ │ │ ├── _forum_post_response.json.jbuilder
│ │ │ │ │ ├── edit.json.jbuilder
│ │ │ │ │ └── new.json.jbuilder
│ │ │ │ ├── multiple_responses/
│ │ │ │ │ ├── _form.json.jbuilder
│ │ │ │ │ ├── _multiple_response.json.jbuilder
│ │ │ │ │ ├── _multiple_response_details.json.jbuilder
│ │ │ │ │ ├── _switch_question_type_button.json.jbuilder
│ │ │ │ │ ├── edit.json.jbuilder
│ │ │ │ │ └── new.json.jbuilder
│ │ │ │ ├── programming/
│ │ │ │ │ ├── _form.json.jbuilder
│ │ │ │ │ ├── _import_result.json.jbuilder
│ │ │ │ │ ├── _languages.json.jbuilder
│ │ │ │ │ ├── _package_ui.json.jbuilder
│ │ │ │ │ ├── _programming.json.jbuilder
│ │ │ │ │ ├── _question.json.jbuilder
│ │ │ │ │ ├── _response.json.jbuilder
│ │ │ │ │ ├── _test_cases.json.jbuilder
│ │ │ │ │ ├── _test_ui.json.jbuilder
│ │ │ │ │ ├── edit.json.jbuilder
│ │ │ │ │ ├── import_result.json.jbuilder
│ │ │ │ │ ├── metadata/
│ │ │ │ │ │ ├── _c_cpp.json.jbuilder
│ │ │ │ │ │ ├── _csharp.json.jbuilder
│ │ │ │ │ │ ├── _default.json.jbuilder
│ │ │ │ │ │ ├── _golang.json.jbuilder
│ │ │ │ │ │ ├── _java.json.jbuilder
│ │ │ │ │ │ ├── _javascript.json.jbuilder
│ │ │ │ │ │ ├── _python.json.jbuilder
│ │ │ │ │ │ ├── _r.json.jbuilder
│ │ │ │ │ │ ├── _rust.json.jbuilder
│ │ │ │ │ │ ├── _typescript.json.jbuilder
│ │ │ │ │ │ └── partials/
│ │ │ │ │ │ ├── _file.json.jbuilder
│ │ │ │ │ │ └── _test_cases.json.jbuilder
│ │ │ │ │ └── new.json.jbuilder
│ │ │ │ ├── rubric_based_responses/
│ │ │ │ │ ├── _category_details.json.jbuilder
│ │ │ │ │ ├── _form.json.jbuilder
│ │ │ │ │ ├── _grade_details.json.jbuilder
│ │ │ │ │ ├── _rubric_based_response.json.jbuilder
│ │ │ │ │ ├── edit.json.jbuilder
│ │ │ │ │ └── new.json.jbuilder
│ │ │ │ ├── scribing/
│ │ │ │ │ ├── _scribing.json.jbuilder
│ │ │ │ │ └── _scribing_question.json.jbuilder
│ │ │ │ ├── text_responses/
│ │ │ │ │ ├── _form.json.jbuilder
│ │ │ │ │ ├── _solution_details.json.jbuilder
│ │ │ │ │ ├── _text_response.json.jbuilder
│ │ │ │ │ ├── edit.json.jbuilder
│ │ │ │ │ └── new.json.jbuilder
│ │ │ │ └── voice_responses/
│ │ │ │ ├── _form.json.jbuilder
│ │ │ │ ├── _voice_response.json.jbuilder
│ │ │ │ ├── edit.json.jbuilder
│ │ │ │ └── new.json.jbuilder
│ │ │ ├── question_bundle_assignments/
│ │ │ │ ├── _form.html.slim
│ │ │ │ ├── _validation_result.html.slim
│ │ │ │ ├── edit.html.slim
│ │ │ │ └── index.html.slim
│ │ │ ├── question_bundle_questions/
│ │ │ │ ├── _form.html.slim
│ │ │ │ ├── edit.html.slim
│ │ │ │ ├── index.html.slim
│ │ │ │ └── new.html.slim
│ │ │ ├── question_bundles/
│ │ │ │ ├── _form.html.slim
│ │ │ │ ├── edit.html.slim
│ │ │ │ ├── index.html.slim
│ │ │ │ └── new.html.slim
│ │ │ ├── question_groups/
│ │ │ │ ├── _form.html.slim
│ │ │ │ ├── edit.html.slim
│ │ │ │ ├── index.html.slim
│ │ │ │ └── new.html.slim
│ │ │ ├── questions/
│ │ │ │ └── show.json.jbuilder
│ │ │ ├── rubrics/
│ │ │ │ ├── fetch_answer_evaluations.json.jbuilder
│ │ │ │ ├── fetch_mock_answer_evaluations.json.jbuilder
│ │ │ │ ├── index.json.jbuilder
│ │ │ │ └── rubric_answers.json.jbuilder
│ │ │ ├── skill_branches/
│ │ │ │ ├── _skill_branch_list_data.json.jbuilder
│ │ │ │ └── _skill_branch_user_list_data.json.jbuilder
│ │ │ ├── skills/
│ │ │ │ ├── _options.json.jbuilder
│ │ │ │ ├── _skill_list_data.json.jbuilder
│ │ │ │ ├── _skill_user_list_data.json.jbuilder
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── submission/
│ │ │ │ ├── answer/
│ │ │ │ │ ├── answers/
│ │ │ │ │ │ └── show.json.jbuilder
│ │ │ │ │ └── forum_post_response/
│ │ │ │ │ └── posts/
│ │ │ │ │ ├── _post_packs.json.jbuilder
│ │ │ │ │ └── selected.json.jbuilder
│ │ │ │ ├── logs/
│ │ │ │ │ ├── _info.json.jbuilder
│ │ │ │ │ ├── _logs.json.jbuilder
│ │ │ │ │ └── index.json.jbuilder
│ │ │ │ └── submissions/
│ │ │ │ ├── _answers.json.jbuilder
│ │ │ │ ├── _history.json.jbuilder
│ │ │ │ ├── _question.json.jbuilder
│ │ │ │ ├── _questions.json.jbuilder
│ │ │ │ ├── _submission.json.jbuilder
│ │ │ │ ├── _topics.json.jbuilder
│ │ │ │ ├── create_live_feedback_chat.json.jbuilder
│ │ │ │ ├── edit.json.jbuilder
│ │ │ │ ├── fetch_live_feedback_chat.json.jbuilder
│ │ │ │ ├── fetch_live_feedback_status.json.jbuilder
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── submission_question/
│ │ │ │ └── submission_questions/
│ │ │ │ └── all_answers.json.jbuilder
│ │ │ └── submissions/
│ │ │ ├── _filter.json.jbuilder
│ │ │ ├── _submissions_list_data.json.jbuilder
│ │ │ ├── _tabs.json.jbuilder
│ │ │ ├── index.json.jbuilder
│ │ │ └── pending.json.jbuilder
│ │ ├── condition/
│ │ │ ├── _condition_data.json.jbuilder
│ │ │ ├── _condition_list_data.json.jbuilder
│ │ │ ├── _conditions.json.jbuilder
│ │ │ ├── _enabled_conditions.json.jbuilder
│ │ │ ├── achievements/
│ │ │ │ └── _achievement.json.jbuilder
│ │ │ ├── assessments/
│ │ │ │ ├── _assessment.json.jbuilder
│ │ │ │ ├── _assessment_condition.json.jbuilder
│ │ │ │ └── available_assessments.json.jbuilder
│ │ │ ├── levels/
│ │ │ │ └── _level.json.jbuilder
│ │ │ ├── scholaistic_assessments/
│ │ │ │ ├── _scholaistic_assessment.json.jbuilder
│ │ │ │ └── available_scholaistic_assessments.json.jbuilder
│ │ │ └── surveys/
│ │ │ ├── _survey.json.jbuilder
│ │ │ └── available_surveys.json.jbuilder
│ │ ├── courses/
│ │ │ ├── _course_data.json.jbuilder
│ │ │ ├── _course_list_data.json.jbuilder
│ │ │ ├── _course_user_progress.json.jbuilder
│ │ │ ├── _sidebar_items.json.jbuilder
│ │ │ ├── index.json.jbuilder
│ │ │ ├── show.json.jbuilder
│ │ │ └── sidebar.json.jbuilder
│ │ ├── discussion/
│ │ │ ├── posts/
│ │ │ │ └── _post.json.jbuilder
│ │ │ └── topics/
│ │ │ ├── _discussion_topic_programming_file_annotation.jbuilder
│ │ │ ├── _discussion_topic_submission_question.json.jbuilder
│ │ │ ├── _discussion_topic_video.json.jbuilder
│ │ │ ├── _tabs.json.jbuilder
│ │ │ ├── _topic.json.jbuilder
│ │ │ ├── discussion_topic_list_data.jbuilder
│ │ │ └── index.json.jbuilder
│ │ ├── enrol_requests/
│ │ │ ├── _enrol_request_list_data.json.jbuilder
│ │ │ └── index.json.jbuilder
│ │ ├── experience_points/
│ │ │ ├── disbursement/
│ │ │ │ └── new.json.jbuilder
│ │ │ └── forum_disbursement/
│ │ │ └── new.json.jbuilder
│ │ ├── experience_points_records/
│ │ │ ├── _experience_points_record.json.jbuilder
│ │ │ ├── index.jbuilder
│ │ │ └── show.jbuilder
│ │ ├── forum/
│ │ │ ├── forums/
│ │ │ │ ├── _forum_list_data.json.jbuilder
│ │ │ │ ├── all_posts.json.jbuilder
│ │ │ │ ├── index.json.jbuilder
│ │ │ │ ├── search.json.jbuilder
│ │ │ │ └── show.json.jbuilder
│ │ │ ├── posts/
│ │ │ │ ├── _post_creator_data.json.jbuilder
│ │ │ │ ├── _post_list_data.json.jbuilder
│ │ │ │ ├── _post_publish_data.json.jbuilder
│ │ │ │ └── create.json.jbuilder
│ │ │ └── topics/
│ │ │ ├── _topic_list_data.json.jbuilder
│ │ │ └── show.json.jbuilder
│ │ ├── group/
│ │ │ ├── _group.json.jbuilder
│ │ │ ├── group_categories/
│ │ │ │ ├── create_groups.json.jbuilder
│ │ │ │ ├── index.json.jbuilder
│ │ │ │ ├── show_info.json.jbuilder
│ │ │ │ └── show_users.json.jbuilder
│ │ │ └── groups/
│ │ │ └── update.json.jbuilder
│ │ ├── leaderboards/
│ │ │ ├── _leaderboard_achievement_list_data.json.jbuilder
│ │ │ ├── _leaderboard_group_list_data.json.jbuilder
│ │ │ ├── _leaderboard_list_data.json.jbuilder
│ │ │ └── index.json.jbuilder
│ │ ├── learning_map/
│ │ │ └── index.json.jbuilder
│ │ ├── lesson_plan/
│ │ │ ├── events/
│ │ │ │ └── _event_lesson_plan_item.json.jbuilder
│ │ │ ├── items/
│ │ │ │ ├── _item.json.jbuilder
│ │ │ │ ├── _personal_or_ref_time.json.jbuilder
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── milestones/
│ │ │ │ └── _milestone.json.jbuilder
│ │ │ └── todos/
│ │ │ └── _todo.json.jbuilder
│ │ ├── levels/
│ │ │ └── index.json.jbuilder
│ │ ├── mailer/
│ │ │ ├── assessment_closing_reminder_email.html.slim
│ │ │ ├── assessment_closing_reminder_email.text.erb
│ │ │ ├── assessment_closing_summary_email.html.slim
│ │ │ ├── assessment_closing_summary_email.text.erb
│ │ │ ├── course_duplicate_failed_email.html.slim
│ │ │ ├── course_duplicate_failed_email.text.erb
│ │ │ ├── course_duplicated_email.html.slim
│ │ │ ├── course_duplicated_email.text.erb
│ │ │ ├── course_user_deletion_failed_email.html.slim
│ │ │ ├── course_user_deletion_failed_email.text.erb
│ │ │ ├── submission_graded_email.html.slim
│ │ │ ├── submission_graded_email.text.erb
│ │ │ ├── survey_closing_reminder_email.html.slim
│ │ │ ├── survey_closing_reminder_email.text.erb
│ │ │ ├── survey_closing_summary_email.html.slim
│ │ │ ├── survey_closing_summary_email.text.erb
│ │ │ ├── user_added_email.html.slim
│ │ │ ├── user_added_email.text.erb
│ │ │ ├── user_enrol_request_received_email.html.slim
│ │ │ ├── user_enrol_request_received_email.text.erb
│ │ │ ├── user_enrol_requested_email.html.slim
│ │ │ ├── user_enrol_requested_email.text.erb
│ │ │ ├── user_invitation_email.html.slim
│ │ │ ├── user_invitation_email.text.erb
│ │ │ ├── user_rejected_email.html.slim
│ │ │ ├── user_rejected_email.text.erb
│ │ │ ├── user_suspended_email.html.slim
│ │ │ ├── user_suspended_email.text.erb
│ │ │ ├── user_unsuspended_email.html.slim
│ │ │ ├── user_unsuspended_email.text.erb
│ │ │ ├── video_closing_reminder_email.html.slim
│ │ │ └── video_closing_reminder_email.text.erb
│ │ ├── material/
│ │ │ ├── _material.json.jbuilder
│ │ │ └── folders/
│ │ │ ├── breadcrumbs.json.jbuilder
│ │ │ ├── show.json.jbuilder
│ │ │ └── upload_materials.json.jbuilder
│ │ ├── object_duplications/
│ │ │ ├── _course_duplication_data.json.jbuilder
│ │ │ └── new.json.jbuilder
│ │ ├── personal_times/
│ │ │ ├── _personal_time_list_data.json.jbuilder
│ │ │ └── index.json.jbuilder
│ │ ├── plagiarism/
│ │ │ └── assessments/
│ │ │ ├── _plagiarism_check.json.jbuilder
│ │ │ ├── _plagiarism_checks.json.jbuilder
│ │ │ ├── index.json.jbuilder
│ │ │ ├── linked_and_unlinked_assessments.json.jbuilder
│ │ │ └── plagiarism_data.json.jbuilder
│ │ ├── question_assessments/
│ │ │ └── _question_assessment.json.jbuilder
│ │ ├── reference_timelines/
│ │ │ ├── _reference_timeline.json.jbuilder
│ │ │ └── index.json.jbuilder
│ │ ├── rubrics/
│ │ │ ├── _answer_evaluation.json.jbuilder
│ │ │ ├── _mock_answer_evaluation.json.jbuilder
│ │ │ ├── _rubric.json.jbuilder
│ │ │ └── index.json.jbuilder
│ │ ├── scholaistic/
│ │ │ ├── assistants/
│ │ │ │ ├── index.json.jbuilder
│ │ │ │ └── show.json.jbuilder
│ │ │ ├── scholaistic_assessments/
│ │ │ │ ├── edit.json.jbuilder
│ │ │ │ ├── index.json.jbuilder
│ │ │ │ ├── new.json.jbuilder
│ │ │ │ └── show.json.jbuilder
│ │ │ └── submissions/
│ │ │ ├── index.json.jbuilder
│ │ │ └── show.json.jbuilder
│ │ ├── statistics/
│ │ │ ├── aggregate/
│ │ │ │ ├── activity_get_help.json.jbuilder
│ │ │ │ ├── all_assessments.json.jbuilder
│ │ │ │ ├── all_staff.json.jbuilder
│ │ │ │ ├── all_students.json.jbuilder
│ │ │ │ ├── course_performance.json.jbuilder
│ │ │ │ └── course_progression.json.jbuilder
│ │ │ ├── assessments/
│ │ │ │ ├── _answer.json.jbuilder
│ │ │ │ ├── _assessment.json.jbuilder
│ │ │ │ ├── _attempt_status.json.jbuilder
│ │ │ │ ├── _course_user.json.jbuilder
│ │ │ │ ├── _live_feedback_history_details.json.jbuilder
│ │ │ │ ├── _submission.json.jbuilder
│ │ │ │ ├── ancestor_info.json.jbuilder
│ │ │ │ ├── ancestor_statistics.json.jbuilder
│ │ │ │ ├── assessment_statistics.json.jbuilder
│ │ │ │ ├── live_feedback_history.json.jbuilder
│ │ │ │ ├── live_feedback_statistics.json.jbuilder
│ │ │ │ └── submission_statistics.json.jbuilder
│ │ │ ├── statistics/
│ │ │ │ └── index.json.jbuilder
│ │ │ └── users/
│ │ │ └── learning_rate_records.json.jbuilder
│ │ ├── survey/
│ │ │ ├── questions/
│ │ │ │ ├── _option.json.jbuilder
│ │ │ │ └── _question.json.jbuilder
│ │ │ ├── responses/
│ │ │ │ ├── _response.json.jbuilder
│ │ │ │ ├── _see_other.json.jbuilder
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── sections/
│ │ │ │ └── _section.json.jbuilder
│ │ │ └── surveys/
│ │ │ ├── _survey.json.jbuilder
│ │ │ ├── _survey_with_questions.json.jbuilder
│ │ │ ├── index.json.jbuilder
│ │ │ └── results.json.jbuilder
│ │ ├── surveys/
│ │ │ └── _survey_lesson_plan_item.json.jbuilder
│ │ ├── user_email_subscriptions/
│ │ │ └── _subscription_setting.json.jbuilder
│ │ ├── user_invitations/
│ │ │ ├── _course_user_invitation_list.json.jbuilder
│ │ │ ├── _course_user_invitation_list_data.json.jbuilder
│ │ │ ├── _invitation_result_data.json.jbuilder
│ │ │ ├── index.json.jbuilder
│ │ │ └── new.json.jbuilder
│ │ ├── user_registrations/
│ │ │ └── _registration.json.jbuilder
│ │ ├── users/
│ │ │ ├── _permissions_data.json.jbuilder
│ │ │ ├── _tabs_data.json.jbuilder
│ │ │ ├── _upgrade_to_staff_results.json.jbuilder
│ │ │ ├── _user.json.jbuilder
│ │ │ ├── _user_data.json.jbuilder
│ │ │ ├── _user_list_data.json.jbuilder
│ │ │ ├── index.json.jbuilder
│ │ │ ├── show.json.jbuilder
│ │ │ ├── staff.json.jbuilder
│ │ │ └── students.json.jbuilder
│ │ ├── video/
│ │ │ ├── sessions/
│ │ │ │ └── _session.json.jbuilder
│ │ │ ├── submission/
│ │ │ │ ├── sessions/
│ │ │ │ │ └── create.json.jbuilder
│ │ │ │ └── submissions/
│ │ │ │ ├── _watch_next_video_url.json.jbuilder
│ │ │ │ ├── edit.json.jbuilder
│ │ │ │ ├── index.json.jbuilder
│ │ │ │ └── show.json.jbuilder
│ │ │ ├── topics/
│ │ │ │ ├── _post.json.jbuilder
│ │ │ │ ├── _posts.json.jbuilder
│ │ │ │ ├── _topic.json.jbuilder
│ │ │ │ ├── _topics.json.jbuilder
│ │ │ │ ├── create.json.jbuilder
│ │ │ │ ├── index.json.jbuilder
│ │ │ │ └── show.json.jbuilder
│ │ │ └── videos/
│ │ │ ├── _video.json.jbuilder
│ │ │ ├── _video_data.json.jbuilder
│ │ │ ├── _video_lesson_plan_item.json.jbuilder
│ │ │ ├── _video_list_data.json.jbuilder
│ │ │ ├── _video_statistics.json.jbuilder
│ │ │ ├── index.json.jbuilder
│ │ │ └── show.json.jbuilder
│ │ └── video_submissions/
│ │ └── index.json.jbuilder
│ ├── instance/
│ │ └── mailer/
│ │ ├── user_added_email.html.slim
│ │ ├── user_added_email.text.erb
│ │ ├── user_invitation_email.html.slim
│ │ └── user_invitation_email.text.erb
│ ├── instance_user_role_request_mailer/
│ │ ├── new_role_request.html.slim
│ │ ├── new_role_request.text.erb
│ │ ├── role_request_approved.html.slim
│ │ ├── role_request_approved.text.erb
│ │ ├── role_request_rejected.html.slim
│ │ └── role_request_rejected.text.erb
│ ├── instance_user_role_requests/
│ │ ├── _instance_user_role_request_list_data.json.jbuilder
│ │ └── index.json.jbuilder
│ ├── jobs/
│ │ ├── _completed.json.jbuilder
│ │ ├── _errored.json.jbuilder
│ │ ├── _submitted.json.jbuilder
│ │ └── show.json.jbuilder
│ ├── layouts/
│ │ ├── _manage_email_subscription.html.slim
│ │ ├── _manage_email_subscription.text.erb
│ │ ├── _materials.json.jbuilder
│ │ ├── mailer.html.slim
│ │ ├── mailer.text.erb
│ │ ├── no_greeting_mailer.html.slim
│ │ └── no_greeting_mailer.text.erb
│ ├── notifiers/
│ │ └── course/
│ │ ├── achievement_notifier/
│ │ │ └── gained/
│ │ │ ├── course_notifications/
│ │ │ │ └── _feed.json.jbuilder
│ │ │ └── user_notifications/
│ │ │ └── popup.json.jbuilder
│ │ ├── announcement_notifier/
│ │ │ └── new/
│ │ │ └── course_notifications/
│ │ │ └── email.html.slim
│ │ ├── assessment/
│ │ │ ├── answer/
│ │ │ │ └── comment_notifier/
│ │ │ │ └── annotated/
│ │ │ │ └── user_notifications/
│ │ │ │ └── email.html.slim
│ │ │ └── submission_question/
│ │ │ └── comment_notifier/
│ │ │ └── replied/
│ │ │ └── user_notifications/
│ │ │ └── email.html.slim
│ │ ├── assessment_notifier/
│ │ │ ├── attempted/
│ │ │ │ └── course_notifications/
│ │ │ │ └── _feed.json.jbuilder
│ │ │ ├── opening/
│ │ │ │ └── course_notifications/
│ │ │ │ └── email.html.slim
│ │ │ └── submitted/
│ │ │ └── user_notifications/
│ │ │ └── email.html.slim
│ │ ├── consolidated_opening_reminder_notifier/
│ │ │ └── opening_reminder/
│ │ │ └── course_notifications/
│ │ │ ├── course/
│ │ │ │ ├── _assessment.html.slim
│ │ │ │ ├── _survey.html.slim
│ │ │ │ └── _video.html.slim
│ │ │ └── email.html.slim
│ │ ├── forum/
│ │ │ ├── post_notifier/
│ │ │ │ ├── replied/
│ │ │ │ │ ├── course_notifications/
│ │ │ │ │ │ └── _feed.json.jbuilder
│ │ │ │ │ └── user_notifications/
│ │ │ │ │ └── email.html.slim
│ │ │ │ └── voted/
│ │ │ │ └── course_notifications/
│ │ │ │ └── _feed.json.jbuilder
│ │ │ └── topic_notifier/
│ │ │ └── created/
│ │ │ ├── course_notifications/
│ │ │ │ └── _feed.json.jbuilder
│ │ │ └── user_notifications/
│ │ │ └── email.html.slim
│ │ ├── level_notifier/
│ │ │ └── reached/
│ │ │ ├── course_notifications/
│ │ │ │ └── _feed.json.jbuilder
│ │ │ └── user_notifications/
│ │ │ └── popup.json.jbuilder
│ │ └── video_notifier/
│ │ ├── attempted/
│ │ │ └── course_notifications/
│ │ │ └── _feed.json.jbuilder
│ │ ├── closing/
│ │ │ └── user_notifications/
│ │ │ └── email.html.slim
│ │ └── opening/
│ │ └── course_notifications/
│ │ └── email.html.slim
│ ├── system/
│ │ └── admin/
│ │ ├── announcements/
│ │ │ └── index.json.jbuilder
│ │ ├── courses/
│ │ │ ├── _course_list_data.json.jbuilder
│ │ │ └── index.json.jbuilder
│ │ ├── get_help/
│ │ │ └── index.json.jbuilder
│ │ ├── instance/
│ │ │ ├── admin/
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── announcements/
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── components/
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── courses/
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── get_help/
│ │ │ │ └── index.json.jbuilder
│ │ │ ├── user_invitations/
│ │ │ │ ├── _instance_user_invitation_list_data.json.jbuilder
│ │ │ │ ├── _invitation_result_data.json.jbuilder
│ │ │ │ └── index.json.jbuilder
│ │ │ └── users/
│ │ │ ├── _user_list_data.json.jbuilder
│ │ │ └── index.json.jbuilder
│ │ ├── instances/
│ │ │ ├── _instance_list_data.json.jbuilder
│ │ │ └── index.json.jbuilder
│ │ └── users/
│ │ ├── _user_list_data.json.jbuilder
│ │ └── index.json.jbuilder
│ ├── user/
│ │ ├── emails/
│ │ │ ├── _email_list_data.json.jbuilder
│ │ │ └── index.json.jbuilder
│ │ ├── profiles/
│ │ │ ├── edit.json.jbuilder
│ │ │ └── show.json.jbuilder
│ │ └── registrations/
│ │ └── create.json.jbuilder
│ └── users/
│ ├── _course_list_data.json.jbuilder
│ ├── _instance_list_data.json.jbuilder
│ └── show.json.jbuilder
├── authentication/
│ ├── Dockerfile
│ ├── README.md
│ ├── docker-compose.yml
│ ├── env
│ ├── import/
│ │ └── coursemology_realm.json
│ ├── script/
│ │ └── cm_db_federation.sql
│ └── theme/
│ └── coursemology-keycloakify-keycloak-theme-6.1.7.jar
├── bin/
│ ├── bundle
│ ├── rails
│ ├── rake
│ ├── setup
│ ├── spring
│ └── update
├── client/
│ ├── .babelrc
│ ├── .eslintignore
│ ├── .eslintrc.js
│ ├── .prettierignore
│ ├── .prettierrc.js
│ ├── .yarn-integrity
│ ├── CONTRIBUTING.md
│ ├── README.md
│ ├── app/
│ │ ├── App.tsx
│ │ ├── __test__/
│ │ │ ├── mocks/
│ │ │ │ ├── ResizeObserver.js
│ │ │ │ ├── axiosMock.js
│ │ │ │ ├── fileMock.js
│ │ │ │ ├── matchMedia.js
│ │ │ │ ├── requestAnimationFrame.js
│ │ │ │ └── svgMock.js
│ │ │ ├── setup.js
│ │ │ └── utils/
│ │ │ ├── __test__/
│ │ │ │ └── shallowUntil.test.js
│ │ │ └── shallowUntil.js
│ │ ├── api/
│ │ │ ├── Announcements.ts
│ │ │ ├── Attachments.ts
│ │ │ ├── Base.ts
│ │ │ ├── ErrorHandling.ts
│ │ │ ├── Home.ts
│ │ │ ├── Jobs.ts
│ │ │ ├── Users.ts
│ │ │ ├── course/
│ │ │ │ ├── Achievements.ts
│ │ │ │ ├── Admin/
│ │ │ │ │ ├── Announcements.ts
│ │ │ │ │ ├── Assessments.ts
│ │ │ │ │ ├── Base.ts
│ │ │ │ │ ├── Codaveri.ts
│ │ │ │ │ ├── Comments.ts
│ │ │ │ │ ├── Components.ts
│ │ │ │ │ ├── Course.ts
│ │ │ │ │ ├── Forums.ts
│ │ │ │ │ ├── Leaderboard.ts
│ │ │ │ │ ├── LessonPlan.ts
│ │ │ │ │ ├── Materials.ts
│ │ │ │ │ ├── Notifications.ts
│ │ │ │ │ ├── RagWise.ts
│ │ │ │ │ ├── Scholaistic.ts
│ │ │ │ │ ├── Sidebar.ts
│ │ │ │ │ ├── Stories.ts
│ │ │ │ │ ├── Videos.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Announcements.ts
│ │ │ │ ├── Assessment/
│ │ │ │ │ ├── AllAnswers.ts
│ │ │ │ │ ├── Assessments.js
│ │ │ │ │ ├── Base.js
│ │ │ │ │ ├── Categories.js
│ │ │ │ │ ├── Question/
│ │ │ │ │ │ ├── ForumPostResponse.ts
│ │ │ │ │ │ ├── McqMrq.ts
│ │ │ │ │ │ ├── MockAnswers.ts
│ │ │ │ │ │ ├── Programming.ts
│ │ │ │ │ │ ├── Questions.ts
│ │ │ │ │ │ ├── RubricBasedResponse.ts
│ │ │ │ │ │ ├── Rubrics.ts
│ │ │ │ │ │ ├── Scribing.js
│ │ │ │ │ │ ├── TextResponse.ts
│ │ │ │ │ │ ├── VoiceResponse.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── Sessions.ts
│ │ │ │ │ ├── Skills.ts
│ │ │ │ │ ├── Submission/
│ │ │ │ │ │ ├── Answer/
│ │ │ │ │ │ │ ├── Answer.ts
│ │ │ │ │ │ │ ├── ForumPostResponse.js
│ │ │ │ │ │ │ ├── Programming.js
│ │ │ │ │ │ │ ├── Scribing.js
│ │ │ │ │ │ │ ├── TextResponse.ts
│ │ │ │ │ │ │ └── index.js
│ │ │ │ │ │ └── Logs/
│ │ │ │ │ │ └── Logs.ts
│ │ │ │ │ ├── SubmissionQuestions.js
│ │ │ │ │ ├── Submissions/
│ │ │ │ │ │ └── Submissions.ts
│ │ │ │ │ ├── Submissions.js
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Base.js
│ │ │ │ ├── Comments.ts
│ │ │ │ ├── Conditions.ts
│ │ │ │ ├── Courses.ts
│ │ │ │ ├── Disbursement.ts
│ │ │ │ ├── Duplication.js
│ │ │ │ ├── EnrolRequests.ts
│ │ │ │ ├── ExperiencePointsRecord.ts
│ │ │ │ ├── Forum/
│ │ │ │ │ ├── Forums.ts
│ │ │ │ │ ├── Posts.ts
│ │ │ │ │ ├── Topics.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Groups.js
│ │ │ │ ├── Leaderboard.ts
│ │ │ │ ├── LearningMap.js
│ │ │ │ ├── LessonPlan.js
│ │ │ │ ├── Level.ts
│ │ │ │ ├── Material/
│ │ │ │ │ └── Folders.ts
│ │ │ │ ├── MaterialFolders.js
│ │ │ │ ├── Materials.ts
│ │ │ │ ├── PersonalTimes.ts
│ │ │ │ ├── Plagiarism.ts
│ │ │ │ ├── Posts.js
│ │ │ │ ├── ReferenceTimelines.ts
│ │ │ │ ├── Rubrics.ts
│ │ │ │ ├── Scholaistic.ts
│ │ │ │ ├── Statistics/
│ │ │ │ │ ├── AnswerStatistics.ts
│ │ │ │ │ ├── AssessmentStatistics.ts
│ │ │ │ │ ├── CourseStatistics.ts
│ │ │ │ │ ├── UserStatistics.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── Stories.ts
│ │ │ │ ├── Survey/
│ │ │ │ │ ├── Base.js
│ │ │ │ │ ├── Questions.js
│ │ │ │ │ ├── Responses.js
│ │ │ │ │ ├── Sections.js
│ │ │ │ │ ├── Surveys.js
│ │ │ │ │ └── index.js
│ │ │ │ ├── UserEmailSubscriptions.js
│ │ │ │ ├── UserInvitations.ts
│ │ │ │ ├── UserNotifications.ts
│ │ │ │ ├── Users.ts
│ │ │ │ ├── Video/
│ │ │ │ │ ├── Base.js
│ │ │ │ │ ├── Sessions.js
│ │ │ │ │ ├── Submissions.ts
│ │ │ │ │ ├── Topics.js
│ │ │ │ │ ├── Videos.ts
│ │ │ │ │ └── index.js
│ │ │ │ ├── VideoSubmissions.ts
│ │ │ │ └── index.js
│ │ │ ├── index.ts
│ │ │ ├── system/
│ │ │ │ ├── Admin.ts
│ │ │ │ ├── Base.ts
│ │ │ │ ├── InstanceAdmin.ts
│ │ │ │ └── index.js
│ │ │ └── types.ts
│ │ ├── assets/
│ │ │ └── templates/
│ │ │ └── course-user-invitation-template.csv
│ │ ├── bundles/
│ │ │ ├── announcements/
│ │ │ │ ├── GlobalAnnouncementIndex.tsx
│ │ │ │ ├── operations.ts
│ │ │ │ ├── selectors.ts
│ │ │ │ ├── store.ts
│ │ │ │ └── types.ts
│ │ │ ├── authentication/
│ │ │ │ └── pages/
│ │ │ │ └── AuthenticationRedirection/
│ │ │ │ └── index.tsx
│ │ │ ├── common/
│ │ │ │ ├── DashboardPage.tsx
│ │ │ │ ├── ErrorPage.tsx
│ │ │ │ ├── LandingPage.tsx
│ │ │ │ ├── PrivacyPolicyPage/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── privacy-policy.md
│ │ │ │ ├── TermsOfServicePage/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── terms-of-service.md
│ │ │ │ ├── components/
│ │ │ │ │ └── NewCourseButton.tsx
│ │ │ │ └── store.ts
│ │ │ ├── course/
│ │ │ │ ├── achievement/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ ├── AchievementManagementButtons.tsx
│ │ │ │ │ │ │ └── AwardButton.tsx
│ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ └── AchievementForm.tsx
│ │ │ │ │ │ ├── misc/
│ │ │ │ │ │ │ └── AchievementReordering.tsx
│ │ │ │ │ │ └── tables/
│ │ │ │ │ │ └── AchievementTable.tsx
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── AchievementAward/
│ │ │ │ │ │ │ ├── AchievementAwardManager.tsx
│ │ │ │ │ │ │ ├── AchievementAwardSummary.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── AchievementEdit/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── AchievementNew/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── AchievementShow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── AchievementsIndex/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── admin/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ └── SettingsNavigation.tsx
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── AnnouncementsSettings/
│ │ │ │ │ │ │ ├── AnnouncementsSettingsForm.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── AssessmentSettings/
│ │ │ │ │ │ │ ├── AssessmentCategoriesManager/
│ │ │ │ │ │ │ │ ├── Category.tsx
│ │ │ │ │ │ │ │ ├── MoveAssessmentsMenu.tsx
│ │ │ │ │ │ │ │ ├── MoveTabsMenu.tsx
│ │ │ │ │ │ │ │ ├── Tab.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ │ ├── AssessmentSettingsContext.ts
│ │ │ │ │ │ │ ├── AssessmentSettingsForm.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── CodaveriSettings/
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── AssessmentCategory.tsx
│ │ │ │ │ │ │ │ ├── AssessmentList.tsx
│ │ │ │ │ │ │ │ ├── AssessmentListItem.tsx
│ │ │ │ │ │ │ │ ├── AssessmentProgrammingQnList.tsx
│ │ │ │ │ │ │ │ ├── AssessmentTab.tsx
│ │ │ │ │ │ │ │ ├── CodaveriSettingsChip.tsx
│ │ │ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ │ │ ├── CodaveriEvaluatorToggleButton.tsx
│ │ │ │ │ │ │ │ │ ├── CodaveriToggleButtons.tsx
│ │ │ │ │ │ │ │ │ ├── ExpandAllSwitch.tsx
│ │ │ │ │ │ │ │ │ └── LiveFeedbackToggleButton.tsx
│ │ │ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ │ │ └── CodaveriSettingsForm.tsx
│ │ │ │ │ │ │ │ └── lists/
│ │ │ │ │ │ │ │ └── CollapsibleList.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── CommentsSettings/
│ │ │ │ │ │ │ ├── CommentsSettingsForm.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── ComponentSettings/
│ │ │ │ │ │ │ ├── ComponentSettingsForm.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── CourseSettings/
│ │ │ │ │ │ │ ├── CourseSettingsForm.tsx
│ │ │ │ │ │ │ ├── DeleteCoursePrompt.tsx
│ │ │ │ │ │ │ ├── OffsetTimesPrompt.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ ├── translations.ts
│ │ │ │ │ │ │ └── validationSchema.ts
│ │ │ │ │ │ ├── ForumsSettings/
│ │ │ │ │ │ │ ├── ForumsSettingsForm.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── LeaderboardSettings/
│ │ │ │ │ │ │ ├── LeaderboardSettingsForm.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── LessonPlanSettings/
│ │ │ │ │ │ │ ├── MilestoneGroupSettings.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.intl.js
│ │ │ │ │ │ ├── MaterialsSettings/
│ │ │ │ │ │ │ ├── MaterialsSettingsForm.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── NotificationSettings/
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.intl.js
│ │ │ │ │ │ ├── RagWiseSettings/
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── CourseTab.tsx
│ │ │ │ │ │ │ │ ├── FolderTab.tsx
│ │ │ │ │ │ │ │ ├── ForumItem.tsx
│ │ │ │ │ │ │ │ ├── ForumList.tsx
│ │ │ │ │ │ │ │ ├── MaterialItem.tsx
│ │ │ │ │ │ │ │ ├── MaterialList.tsx
│ │ │ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ │ │ ├── ExpandAllSwitch.tsx
│ │ │ │ │ │ │ │ │ ├── ForumKnowledgeBaseSwitch.tsx
│ │ │ │ │ │ │ │ │ └── MaterialKnowledgeBaseSwitch.tsx
│ │ │ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ │ │ └── RagWiseSettingsForm.tsx
│ │ │ │ │ │ │ │ └── lists/
│ │ │ │ │ │ │ │ └── CollapsibleList.tsx
│ │ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── ScholaisticSettings/
│ │ │ │ │ │ │ ├── PingResultAlert.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── loader.ts
│ │ │ │ │ │ │ └── operations.ts
│ │ │ │ │ │ ├── SidebarSettings/
│ │ │ │ │ │ │ ├── SidebarSettingsForm.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ ├── StoriesSettings/
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ └── Introduction.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── operations.ts
│ │ │ │ │ │ └── VideosSettings/
│ │ │ │ │ │ ├── VideosSettingsForm.tsx
│ │ │ │ │ │ ├── VideosTabsManager/
│ │ │ │ │ │ │ ├── Tab.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ └── translations.ts
│ │ │ │ │ ├── reducers/
│ │ │ │ │ │ ├── codaveriSettings.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── lessonPlanSettings.ts
│ │ │ │ │ │ ├── notificationSettings.ts
│ │ │ │ │ │ └── ragWiseSettings.ts
│ │ │ │ │ └── translations.ts
│ │ │ │ ├── announcements/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ └── NewAnnouncementButton.tsx
│ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ └── AnnouncementForm.tsx
│ │ │ │ │ │ └── misc/
│ │ │ │ │ │ ├── AnnouncementCard.tsx
│ │ │ │ │ │ └── AnnouncementsDisplay.tsx
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── AnnouncementEdit/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── AnnouncementNew/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── AnnouncementsIndex/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── assessment/
│ │ │ │ │ ├── attemptLoader.ts
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── AssessmentForm/
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ ├── translations.ts
│ │ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ │ └── useFormValidation.tsx
│ │ │ │ │ │ ├── ConvertMcqMrqButton/
│ │ │ │ │ │ │ ├── ConvertMcqMrqPrompt.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── FileManager/
│ │ │ │ │ │ │ ├── Toolbar.tsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── translations.intl.js
│ │ │ │ │ │ ├── Koditsu/
│ │ │ │ │ │ │ ├── KoditsuChip.tsx
│ │ │ │ │ │ │ └── KoditsuChipButton.tsx
│ │ │ │ │ │ └── monitoring/
│ │ │ │ │ │ ├── BlocksInvalidBrowserFormField.tsx
│ │ │ │ │ │ ├── BrowserAuthorizationMethodOptionsFormFields/
│ │ │ │ │ │ │ ├── SebConfigKeyOptionsFormFields.tsx
│ │ │ │ │ │ │ ├── UserAgentOptionsFormFields.tsx
│ │ │ │ │ │ │ ├── common.ts
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── BrowserAuthorizationOptionsFormFields.tsx
│ │ │ │ │ │ ├── EnableMonitoringFormField.tsx
│ │ │ │ │ │ ├── MonitoringIntervalsFormFields.tsx
│ │ │ │ │ │ ├── MonitoringOptionsFormFields.tsx
│ │ │ │ │ │ └── translations.ts
│ │ │ │ │ ├── constants.js
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── operations/
│ │ │ │ │ │ ├── assessments.ts
│ │ │ │ │ │ ├── history.ts
│ │ │ │ │ │ ├── liveFeedback.ts
│ │ │ │ │ │ ├── monitoring.ts
│ │ │ │ │ │ ├── plagiarism.ts
│ │ │ │ │ │ ├── questions.ts
│ │ │ │ │ │ └── statistics.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── AssessmentAuthenticate/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── AssessmentBlockedByMonitorPage.tsx
│ │ │ │ │ │ ├── AssessmentEdit/
│ │ │ │ │ │ │ ├── AssessmentEditPage.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── AssessmentGenerate/
│ │ │ │ │ │ │ ├── GenerateTabs.tsx
│ │ │ │ │ │ │ ├── LockableSection.tsx
│ │ │ │ │ │ │ ├── MultipleResponse/
│ │ │ │ │ │ │ │ ├── GenerateMcqMrqConversation.tsx
│ │ │ │ │ │ │ │ ├── GenerateMcqMrqExportDialog.tsx
│ │ │ │ │ │ │ │ ├── GenerateMcqMrqPrototypeForm.tsx
│ │ │ │ │ │ │ │ └── GenerateMcqMrqQuestionPage.tsx
│ │ │ │ │ │ │ ├── Programming/
│ │ │ │ │ │ │ │ ├── GenerateProgrammingConversation.tsx
│ │ │ │ │ │ │ │ ├── GenerateProgrammingExportDialog.tsx
│ │ │ │ │ │ │ │ ├── GenerateProgrammingPrototypeForm.tsx
│ │ │ │ │ │ │ │ ├── GenerateProgrammingQuestionPage.tsx
│ │ │ │ │ │ │ │ └── TestCasesManager.tsx
│ │ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── AssessmentMonitoring/
│ │ │ │ │ │ │ ├── PulseGrid.tsx
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── ActiveSessionBlob.tsx
│ │ │ │ │ │ │ │ ├── ActivityCenter.tsx
│ │ │ │ │ │ │ │ ├── ConnectionStatus.tsx
│ │ │ │ │ │ │ │ ├── FilterAutocomplete.tsx
│ │ │ │ │ │ │ │ ├── HeartbeatDetailCard.tsx
│ │ │ │ │ │ │ │ ├── HeartbeatsTimeline.tsx
│ │ │ │ │ │ │ │ ├── HeartbeatsTimelineChart.tsx
│ │ │ │ │ │ │ │ ├── SebPayloadDetail.tsx
│ │ │ │ │ │ │ │ ├── Session.tsx
│ │ │ │ │ │ │ │ ├── SessionBlob.tsx
│ │ │ │ │ │ │ │ ├── SessionBlobLegend.tsx
│ │ │ │ │ │ │ │ ├── SessionDetailsPopup.tsx
│ │ │ │ │ │ │ │ ├── SessionsGrid.tsx
│ │ │ │ │ │ │ │ ├── UserAgentDetail.tsx
│ │ │ │ │ │ │ │ └── ValidChip.tsx
│ │ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ │ ├── liveMonitoringChannel.ts
│ │ │ │ │ │ │ │ ├── useLiveMonitoringChannel.ts
│ │ │ │ │ │ │ │ ├── useMonitoring.ts
│ │ │ │ │ │ │ │ └── usePresence.ts
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── AssessmentPlagiarism/
│ │ │ │ │ │ │ ├── AssessmentPlagiarismPage.tsx
│ │ │ │ │ │ │ ├── PlagiarismCheckStatus.tsx
│ │ │ │ │ │ │ ├── PlagiarismResultsTable.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── selectors.ts
│ │ │ │ │ │ ├── AssessmentShow/
│ │ │ │ │ │ │ ├── AssessmentDetails.tsx
│ │ │ │ │ │ │ ├── AssessmentShowHeader.tsx
│ │ │ │ │ │ │ ├── AssessmentShowPage.tsx
│ │ │ │ │ │ │ ├── GenerateQuestionMenu.tsx
│ │ │ │ │ │ │ ├── McqWidget.tsx
│ │ │ │ │ │ │ ├── NewQuestionMenu.tsx
│ │ │ │ │ │ │ ├── Question.tsx
│ │ │ │ │ │ │ ├── QuestionsManager.tsx
│ │ │ │ │ │ │ ├── UnavailableAlert.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── prompts/
│ │ │ │ │ │ │ ├── DeleteQuestionButtonPrompt.tsx
│ │ │ │ │ │ │ └── DuplicationPrompt.tsx
│ │ │ │ │ │ ├── AssessmentStatistics/
│ │ │ │ │ │ │ ├── AncestorOptions.tsx
│ │ │ │ │ │ │ ├── AncestorStatistics.tsx
│ │ │ │ │ │ │ ├── AnswerDisplay/
│ │ │ │ │ │ │ │ └── LastAttempt.tsx
│ │ │ │ │ │ │ ├── AssessmentStatisticsPage.tsx
│ │ │ │ │ │ │ ├── DuplicationHistoryStatistics.tsx
│ │ │ │ │ │ │ ├── GradeDistribution/
│ │ │ │ │ │ │ │ ├── AncestorGradesChart.tsx
│ │ │ │ │ │ │ │ ├── GradesChart.tsx
│ │ │ │ │ │ │ │ └── MainGradesChart.tsx
│ │ │ │ │ │ │ ├── LiveFeedbackHistory/
│ │ │ │ │ │ │ │ ├── GetHelpSlider.tsx
│ │ │ │ │ │ │ │ ├── LiveFeedbackConversation.tsx
│ │ │ │ │ │ │ │ ├── LiveFeedbackDetails.tsx
│ │ │ │ │ │ │ │ ├── LiveFeedbackFiles.tsx
│ │ │ │ │ │ │ │ ├── LiveFeedbackHistoryTimelineView.tsx
│ │ │ │ │ │ │ │ ├── LiveFeedbackMessageHistory.tsx
│ │ │ │ │ │ │ │ ├── LiveFeedbackMessageOptionHistory.tsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── LiveFeedbackStatistics.tsx
│ │ │ │ │ │ │ ├── LiveFeedbackStatisticsTable.tsx
│ │ │ │ │ │ │ ├── StatisticsCharts.tsx
│ │ │ │ │ │ │ ├── StudentAttemptCountTable.tsx
│ │ │ │ │ │ │ ├── StudentGradesPerQuestionTable.tsx
│ │ │ │ │ │ │ ├── SubmissionStatus/
│ │ │ │ │ │ │ │ ├── AncestorSubmissionChart.tsx
│ │ │ │ │ │ │ │ ├── MainSubmissionChart.tsx
│ │ │ │ │ │ │ │ └── SubmissionStatusChart.tsx
│ │ │ │ │ │ │ ├── SubmissionTimeAndGradeStatistics/
│ │ │ │ │ │ │ │ ├── AncestorSubmissionTimeAndGradeStatistics.tsx
│ │ │ │ │ │ │ │ ├── MainSubmissionTimeAndGradeStatistics.tsx
│ │ │ │ │ │ │ │ └── SubmissionTimeAndGradeChart.tsx
│ │ │ │ │ │ │ ├── classNameUtils.ts
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ └── LiveFeedbackMetricsSelector.tsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ │ ├── translations.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ └── AssessmentsIndex/
│ │ │ │ │ │ ├── ActionButtons.tsx
│ │ │ │ │ │ ├── AssessmentsTable.tsx
│ │ │ │ │ │ ├── NewAssessmentFormButton.jsx
│ │ │ │ │ │ ├── StatusBadges.tsx
│ │ │ │ │ │ ├── UnavailableMessage.tsx
│ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── question/
│ │ │ │ │ │ ├── commons/
│ │ │ │ │ │ │ ├── useDirty.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── AIGradingPlaygroundAlert.tsx
│ │ │ │ │ │ │ ├── CommonQuestionFields.tsx
│ │ │ │ │ │ │ ├── QuestionFormOutlet.tsx
│ │ │ │ │ │ │ └── SkillsAutocomplete.tsx
│ │ │ │ │ │ ├── forum-post-responses/
│ │ │ │ │ │ │ ├── EditForumPostResponsePage.tsx
│ │ │ │ │ │ │ ├── NewForumPostResponsePage.tsx
│ │ │ │ │ │ │ ├── commons/
│ │ │ │ │ │ │ │ └── validations.ts
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ └── ForumPostResponseForm.tsx
│ │ │ │ │ │ │ └── operation.ts
│ │ │ │ │ │ ├── multiple-responses/
│ │ │ │ │ │ │ ├── EditMcqMrqPage.tsx
│ │ │ │ │ │ │ ├── NewMcqMrqPage.tsx
│ │ │ │ │ │ │ ├── commons/
│ │ │ │ │ │ │ │ ├── translationAdapter.tsx
│ │ │ │ │ │ │ │ └── validations.ts
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── AdaptedForm.tsx
│ │ │ │ │ │ │ │ ├── ConvertMcqMrqIllustration/
│ │ │ │ │ │ │ │ │ ├── McqIllustration.tsx
│ │ │ │ │ │ │ │ │ ├── MrqIllustration.tsx
│ │ │ │ │ │ │ │ │ ├── OptionSkeleton.tsx
│ │ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ │ ├── McqMrqForm.tsx
│ │ │ │ │ │ │ │ ├── Option.tsx
│ │ │ │ │ │ │ │ └── OptionsManager.tsx
│ │ │ │ │ │ │ └── operations.ts
│ │ │ │ │ │ ├── programming/
│ │ │ │ │ │ │ ├── EditProgrammingQuestionPage.tsx
│ │ │ │ │ │ │ ├── NewProgrammingQuestionPage.tsx
│ │ │ │ │ │ │ ├── ProgrammingForm.tsx
│ │ │ │ │ │ │ ├── commons/
│ │ │ │ │ │ │ │ ├── builder.ts
│ │ │ │ │ │ │ │ └── validation.ts
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── ReorderableTestCasesManager.tsx
│ │ │ │ │ │ │ │ ├── common/
│ │ │ │ │ │ │ │ │ ├── ControlledEditor.tsx
│ │ │ │ │ │ │ │ │ ├── DataFileRow.tsx
│ │ │ │ │ │ │ │ │ ├── DataFilesAccordion.tsx
│ │ │ │ │ │ │ │ │ ├── DataFilesManager.tsx
│ │ │ │ │ │ │ │ │ ├── EditorAccordion.tsx
│ │ │ │ │ │ │ │ │ ├── ExpressionField.tsx
│ │ │ │ │ │ │ │ │ ├── ImportResult.tsx
│ │ │ │ │ │ │ │ │ ├── InstalledDependenciesPrompt.tsx
│ │ │ │ │ │ │ │ │ ├── InstalledDependenciesTable.tsx
│ │ │ │ │ │ │ │ │ ├── PackageInfo.tsx
│ │ │ │ │ │ │ │ │ ├── PackageUploader.tsx
│ │ │ │ │ │ │ │ │ ├── ReorderableJavaTestCase.tsx
│ │ │ │ │ │ │ │ │ ├── ReorderableTestCase.tsx
│ │ │ │ │ │ │ │ │ ├── ReorderableTestCases.tsx
│ │ │ │ │ │ │ │ │ ├── StaticTestCase.tsx
│ │ │ │ │ │ │ │ │ ├── StaticTestCases.tsx
│ │ │ │ │ │ │ │ │ ├── StaticTestCasesTable.tsx
│ │ │ │ │ │ │ │ │ ├── TestCaseCell.tsx
│ │ │ │ │ │ │ │ │ └── TestCaseRow.tsx
│ │ │ │ │ │ │ │ ├── package/
│ │ │ │ │ │ │ │ │ ├── BasicPackageEditor.tsx
│ │ │ │ │ │ │ │ │ ├── CppPackageEditor.tsx
│ │ │ │ │ │ │ │ │ ├── CsharpPackageEditor.tsx
│ │ │ │ │ │ │ │ │ ├── GoPackageEditor.tsx
│ │ │ │ │ │ │ │ │ ├── JavaPackageEditor.tsx
│ │ │ │ │ │ │ │ │ ├── JavascriptPackageEditor.tsx
│ │ │ │ │ │ │ │ │ ├── PackageDetails.tsx
│ │ │ │ │ │ │ │ │ ├── PackageEditor.tsx
│ │ │ │ │ │ │ │ │ ├── PolyglotEditor.tsx
│ │ │ │ │ │ │ │ │ ├── PythonPackageEditor.tsx
│ │ │ │ │ │ │ │ │ ├── RPackageEditor.tsx
│ │ │ │ │ │ │ │ │ ├── RustPackageEditor.tsx
│ │ │ │ │ │ │ │ │ └── TypescriptPackageEditor.tsx
│ │ │ │ │ │ │ │ └── sections/
│ │ │ │ │ │ │ │ ├── BuildLog.tsx
│ │ │ │ │ │ │ │ ├── EvaluatorFields.tsx
│ │ │ │ │ │ │ │ ├── FeedbackFields.tsx
│ │ │ │ │ │ │ │ ├── LanguageFields.tsx
│ │ │ │ │ │ │ │ ├── PackageFields.tsx
│ │ │ │ │ │ │ │ ├── QuestionFields.tsx
│ │ │ │ │ │ │ │ └── SubmitWarningDialog.tsx
│ │ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ │ ├── ProgrammingFormDataContext.tsx
│ │ │ │ │ │ │ │ └── useLanguageMode.tsx
│ │ │ │ │ │ │ └── operations.ts
│ │ │ │ │ │ ├── reducers/
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ └── rubrics.ts
│ │ │ │ │ │ ├── rubric-based-responses/
│ │ │ │ │ │ │ ├── EditRubricBasedResponsePage.tsx
│ │ │ │ │ │ │ ├── NewRubricBasedResponsePage.tsx
│ │ │ │ │ │ │ ├── commons/
│ │ │ │ │ │ │ │ └── validation.ts
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── AIGradingFields.tsx
│ │ │ │ │ │ │ │ ├── CategoryManager.tsx
│ │ │ │ │ │ │ │ ├── QuestionFields.tsx
│ │ │ │ │ │ │ │ └── RubricBasedResponseForm.tsx
│ │ │ │ │ │ │ ├── hooks/
│ │ │ │ │ │ │ │ └── RubricBasedResponseFormDataContext.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── rubric-playground/
│ │ │ │ │ │ │ ├── AddAnswersPrompt.tsx
│ │ │ │ │ │ │ ├── AnswerEvaluationsTable/
│ │ │ │ │ │ │ │ ├── CategoryGradeCell.tsx
│ │ │ │ │ │ │ │ ├── PopoverContentCell.tsx
│ │ │ │ │ │ │ │ ├── TotalGradeCell.tsx
│ │ │ │ │ │ │ │ ├── UnevaluatedCell.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ │ ├── AnswerEvaluationsTableHeader.tsx
│ │ │ │ │ │ │ ├── RubricEditForm/
│ │ │ │ │ │ │ │ ├── PlaygroundCategoryManager.tsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── RubricHeader/
│ │ │ │ │ │ │ │ ├── HeaderButton.tsx
│ │ │ │ │ │ │ │ ├── VersionSlider.tsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── RubricPlaygroundPage.tsx
│ │ │ │ │ │ │ ├── operations/
│ │ │ │ │ │ │ │ ├── answers.ts
│ │ │ │ │ │ │ │ ├── mockAnswers.ts
│ │ │ │ │ │ │ │ ├── rowEvaluation.ts
│ │ │ │ │ │ │ │ └── rubric.ts
│ │ │ │ │ │ │ ├── translations.ts
│ │ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ ├── scribing/
│ │ │ │ │ │ │ ├── ScribingQuestion.tsx
│ │ │ │ │ │ │ ├── ScribingQuestionForm/
│ │ │ │ │ │ │ │ ├── ScribingQuestionForm.scss
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ │ │ └── responses.test.ts
│ │ │ │ │ │ │ ├── constants.js
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ ├── propTypes.js
│ │ │ │ │ │ │ ├── store.ts
│ │ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ ├── selectors/
│ │ │ │ │ │ │ └── rubrics.ts
│ │ │ │ │ │ ├── text-responses/
│ │ │ │ │ │ │ ├── EditTextResponsePage.tsx
│ │ │ │ │ │ │ ├── NewTextResponsePage.tsx
│ │ │ │ │ │ │ ├── commons/
│ │ │ │ │ │ │ │ └── validations.ts
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── FileUploadManager.tsx
│ │ │ │ │ │ │ │ ├── Solution.tsx
│ │ │ │ │ │ │ │ ├── SolutionsManager.tsx
│ │ │ │ │ │ │ │ └── TextResponseForm.tsx
│ │ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ └── voice-responses/
│ │ │ │ │ │ ├── EditVoicePage.tsx
│ │ │ │ │ │ ├── NewVoicePage.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ └── VoiceForm.tsx
│ │ │ │ │ │ └── operations.ts
│ │ │ │ │ ├── reducers/
│ │ │ │ │ │ ├── editPage.js
│ │ │ │ │ │ ├── formDialog.js
│ │ │ │ │ │ ├── generation.ts
│ │ │ │ │ │ ├── liveFeedback.ts
│ │ │ │ │ │ ├── monitoring.ts
│ │ │ │ │ │ ├── plagiarism.ts
│ │ │ │ │ │ └── statistics.ts
│ │ │ │ │ ├── sessions/
│ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ └── pages/
│ │ │ │ │ │ └── AssessmentSessionNew/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── skills/
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ │ └── SkillManagementButtons.tsx
│ │ │ │ │ │ │ ├── dialogs/
│ │ │ │ │ │ │ │ └── SkillDialog.tsx
│ │ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ │ └── SkillForm.tsx
│ │ │ │ │ │ │ └── tables/
│ │ │ │ │ │ │ └── SkillsTable.tsx
│ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ └── SkillsIndex/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ ├── store.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── submission/
│ │ │ │ │ │ ├── actions/
│ │ │ │ │ │ │ ├── annotations.js
│ │ │ │ │ │ │ ├── answers/
│ │ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ │ └── scribing.test.ts
│ │ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ │ ├── programming.js
│ │ │ │ │ │ │ │ ├── scribing.ts
│ │ │ │ │ │ │ │ ├── textResponse.js
│ │ │ │ │ │ │ │ └── voiceResponse.js
│ │ │ │ │ │ │ ├── comments.js
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── live_feedback.ts
│ │ │ │ │ │ │ ├── logs.ts
│ │ │ │ │ │ │ ├── submissions.js
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── AllAttempts/
│ │ │ │ │ │ │ │ ├── AllAttemptsQuestion.tsx
│ │ │ │ │ │ │ │ ├── AllAttemptsSequenceView.tsx
│ │ │ │ │ │ │ │ ├── AllAttemptsTimelineView.tsx
│ │ │ │ │ │ │ │ ├── Comment.tsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── AnswerDetails/
│ │ │ │ │ │ │ │ ├── AnswerDetails.tsx
│ │ │ │ │ │ │ │ ├── AttachmentDetails.tsx
│ │ │ │ │ │ │ │ ├── FileUploadDetails.tsx
│ │ │ │ │ │ │ │ ├── ForumPostResponseComponent/
│ │ │ │ │ │ │ │ │ ├── ParentPostPack.tsx
│ │ │ │ │ │ │ │ │ ├── PostContent.tsx
│ │ │ │ │ │ │ │ │ └── PostPack.tsx
│ │ │ │ │ │ │ │ ├── ForumPostResponseDetails.tsx
│ │ │ │ │ │ │ │ ├── MultipleChoiceDetails.tsx
│ │ │ │ │ │ │ │ ├── MultipleResponseDetails.tsx
│ │ │ │ │ │ │ │ ├── ProgrammingAnswerDetails.tsx
│ │ │ │ │ │ │ │ ├── ProgrammingComponent/
│ │ │ │ │ │ │ │ │ ├── CodaveriFeedbackStatus.tsx
│ │ │ │ │ │ │ │ │ ├── FileContent.tsx
│ │ │ │ │ │ │ │ │ ├── TestCaseRow.tsx
│ │ │ │ │ │ │ │ │ └── TestCases.tsx
│ │ │ │ │ │ │ │ ├── RubricBasedResponseDetails.tsx
│ │ │ │ │ │ │ │ └── TextResponseDetails.tsx
│ │ │ │ │ │ │ ├── DropzoneErrorComponent.tsx
│ │ │ │ │ │ │ ├── Editor.jsx
│ │ │ │ │ │ │ ├── EvaluatorErrorPanel.tsx
│ │ │ │ │ │ │ ├── FileInput.jsx
│ │ │ │ │ │ │ ├── GetHelpChatPage/
│ │ │ │ │ │ │ │ ├── ChatInputArea.tsx
│ │ │ │ │ │ │ │ ├── ChipButton.tsx
│ │ │ │ │ │ │ │ ├── ConversationArea.tsx
│ │ │ │ │ │ │ │ ├── Header.tsx
│ │ │ │ │ │ │ │ ├── SuggestionChips.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── utils.ts
│ │ │ │ │ │ │ ├── MarkdownText.tsx
│ │ │ │ │ │ │ ├── ProgressPanel.tsx
│ │ │ │ │ │ │ ├── ReadOnlyEditor/
│ │ │ │ │ │ │ │ ├── AddCommentIcon.jsx
│ │ │ │ │ │ │ │ ├── Checkbox.jsx
│ │ │ │ │ │ │ │ ├── NarrowEditor.jsx
│ │ │ │ │ │ │ │ ├── WideComments.jsx
│ │ │ │ │ │ │ │ ├── WideEditor.jsx
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ ├── ScribingView/
│ │ │ │ │ │ │ │ ├── LayersComponent.tsx
│ │ │ │ │ │ │ │ ├── ScribingCanvas.tsx
│ │ │ │ │ │ │ │ ├── ScribingToolbar.tsx
│ │ │ │ │ │ │ │ ├── ScribingView.scss
│ │ │ │ │ │ │ │ ├── ToolDropdown.jsx
│ │ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ │ ├── ScribingToolbar.test.tsx
│ │ │ │ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ │ │ │ ├── fields/
│ │ │ │ │ │ │ │ │ ├── ColorPickerField.jsx
│ │ │ │ │ │ │ │ │ ├── FontFamilyField.jsx
│ │ │ │ │ │ │ │ │ ├── FontSizeField.jsx
│ │ │ │ │ │ │ │ │ ├── LineStyleField.jsx
│ │ │ │ │ │ │ │ │ ├── LineThicknessField.jsx
│ │ │ │ │ │ │ │ │ ├── ShapeField.tsx
│ │ │ │ │ │ │ │ │ └── __test__/
│ │ │ │ │ │ │ │ │ └── ColorPickerField.test.js
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── popovers/
│ │ │ │ │ │ │ │ ├── DrawPopover.jsx
│ │ │ │ │ │ │ │ ├── LinePopover.jsx
│ │ │ │ │ │ │ │ ├── ShapePopover.jsx
│ │ │ │ │ │ │ │ └── TypePopover.jsx
│ │ │ │ │ │ │ ├── SubmissionWorkflowState.tsx
│ │ │ │ │ │ │ ├── TextResponseSolutions.jsx
│ │ │ │ │ │ │ ├── WarningDialog.tsx
│ │ │ │ │ │ │ ├── answers/
│ │ │ │ │ │ │ │ ├── Answer.tsx
│ │ │ │ │ │ │ │ ├── AnswerHeader.tsx
│ │ │ │ │ │ │ │ ├── AnswerNotImplemented.tsx
│ │ │ │ │ │ │ │ ├── FileUpload/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── ForumPostResponse/
│ │ │ │ │ │ │ │ │ ├── CardTitle.jsx
│ │ │ │ │ │ │ │ │ ├── Error.jsx
│ │ │ │ │ │ │ │ │ ├── ForumCard.jsx
│ │ │ │ │ │ │ │ │ ├── ForumPost.jsx
│ │ │ │ │ │ │ │ │ ├── ForumPostOption.jsx
│ │ │ │ │ │ │ │ │ ├── ForumPostSelect.jsx
│ │ │ │ │ │ │ │ │ ├── ForumPostSelectDialog.jsx
│ │ │ │ │ │ │ │ │ ├── Labels.jsx
│ │ │ │ │ │ │ │ │ ├── ParentPost.jsx
│ │ │ │ │ │ │ │ │ ├── SelectedPostCard.jsx
│ │ │ │ │ │ │ │ │ ├── TopicCard.jsx
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── MultipleChoice/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── MultipleResponse/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── Programming/
│ │ │ │ │ │ │ │ │ ├── ProgrammingFile.tsx
│ │ │ │ │ │ │ │ │ ├── ProgrammingFileDownloadChip.tsx
│ │ │ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ │ │ └── ProgrammingFile.test.tsx
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── RubricBasedResponse/
│ │ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ │ ├── TextResponse/
│ │ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ │ ├── adapters/
│ │ │ │ │ │ │ │ │ ├── FileUploadAdapter.tsx
│ │ │ │ │ │ │ │ │ ├── ForumPostResponseAdapter.tsx
│ │ │ │ │ │ │ │ │ ├── MultipleChoiceAdapter.tsx
│ │ │ │ │ │ │ │ │ ├── MultipleResponseAdapter.tsx
│ │ │ │ │ │ │ │ │ ├── ProgrammingAdapter.tsx
│ │ │ │ │ │ │ │ │ ├── RubricBasedResponseAdapter.tsx
│ │ │ │ │ │ │ │ │ ├── ScribingAdapter.tsx
│ │ │ │ │ │ │ │ │ ├── TextResponseAdapter.tsx
│ │ │ │ │ │ │ │ │ └── VoiceResponseAdapter.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ │ │ └── utils.tsx
│ │ │ │ │ │ │ └── comment/
│ │ │ │ │ │ │ ├── CodaveriCommentCard.jsx
│ │ │ │ │ │ │ ├── CommentCard.jsx
│ │ │ │ │ │ │ └── CommentField.jsx
│ │ │ │ │ │ ├── constants.ts
│ │ │ │ │ │ ├── containers/
│ │ │ │ │ │ │ ├── Annotations.jsx
│ │ │ │ │ │ │ ├── CodaveriFeedbackStatus.jsx
│ │ │ │ │ │ │ ├── Comments.jsx
│ │ │ │ │ │ │ ├── GradingPanel.jsx
│ │ │ │ │ │ │ ├── PostPreview.tsx
│ │ │ │ │ │ │ ├── ProgrammingImport/
│ │ │ │ │ │ │ │ ├── ImportedFileView.jsx
│ │ │ │ │ │ │ │ ├── ProgrammingImportEditor.jsx
│ │ │ │ │ │ │ │ └── ProgrammingImportHistoryView.jsx
│ │ │ │ │ │ │ ├── QuestionGrade.tsx
│ │ │ │ │ │ │ ├── ReadOnlyEditor.jsx
│ │ │ │ │ │ │ ├── RubricExplanation.tsx
│ │ │ │ │ │ │ ├── RubricGrade.tsx
│ │ │ │ │ │ │ ├── RubricPanel.tsx
│ │ │ │ │ │ │ ├── RubricPanelRow.tsx
│ │ │ │ │ │ │ ├── ScribingView.jsx
│ │ │ │ │ │ │ ├── TestCaseView/
│ │ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ │ └── index.test.js
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ ├── UploadedFileView.jsx
│ │ │ │ │ │ │ └── VoiceResponseAnswer.jsx
│ │ │ │ │ │ ├── localStorage/
│ │ │ │ │ │ │ └── liveFeedbackChat/
│ │ │ │ │ │ │ └── operations.ts
│ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ ├── LogsIndex/
│ │ │ │ │ │ │ │ ├── LogsContent.tsx
│ │ │ │ │ │ │ │ ├── LogsHead.tsx
│ │ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ │ └── translations.ts
│ │ │ │ │ │ │ ├── SubmissionEditIndex/
│ │ │ │ │ │ │ │ ├── BlockedSubmission.tsx
│ │ │ │ │ │ │ │ ├── ErrorHelper.tsx
│ │ │ │ │ │ │ │ ├── SubmissionEmptyForm.tsx
│ │ │ │ │ │ │ │ ├── SubmissionForm.tsx
│ │ │ │ │ │ │ │ ├── TimeLimitBanner.tsx
│ │ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ │ ├── ActionButtonsRow.tsx
│ │ │ │ │ │ │ │ │ ├── AutogradingErrorPanel.tsx
│ │ │ │ │ │ │ │ │ ├── ErrorMessages.tsx
│ │ │ │ │ │ │ │ │ ├── ExplanationPanel.tsx
│ │ │ │ │ │ │ │ │ ├── QuestionContent.tsx
│ │ │ │ │ │ │ │ │ ├── SinglePageQuestions.tsx
│ │ │ │ │ │ │ │ │ ├── TabbedViewQuestions.tsx
│ │ │ │ │ │ │ │ │ └── button/
│ │ │ │ │ │ │ │ │ ├── AutogradeSubmissionButton.tsx
│ │ │ │ │ │ │ │ │ ├── ContinueButton.tsx
│ │ │ │ │ │ │ │ │ ├── FinaliseButton.tsx
│ │ │ │ │ │ │ │ │ ├── LiveFeedbackButton.tsx
│ │ │ │ │ │ │ │ │ ├── MarkButton.tsx
│ │ │ │ │ │ │ │ │ ├── PublishButton.tsx
│ │ │ │ │ │ │ │ │ ├── ReevaluateButton.tsx
│ │ │ │ │ │ │ │ │ ├── ResetAnswerButton.tsx
│ │ │ │ │ │ │ │ │ ├── SaveDraftButton.tsx
│ │ │ │ │ │ │ │ │ ├── SaveGradeButton.tsx
│ │ │ │ │ │ │ │ │ ├── StepperButton.tsx
│ │ │ │ │ │ │ │ │ ├── SubmitButton.tsx
│ │ │ │ │ │ │ │ │ ├── SubmitEmptyFormButton.tsx
│ │ │ │ │ │ │ │ │ ├── UnmarkButton.tsx
│ │ │ │ │ │ │ │ │ └── UnsubmitButton.tsx
│ │ │ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ │ │ ├── useErrorTranslation.ts
│ │ │ │ │ │ │ │ └── validations/
│ │ │ │ │ │ │ │ ├── AllValidation.tsx
│ │ │ │ │ │ │ │ ├── AttachmentValidation.tsx
│ │ │ │ │ │ │ │ └── types.ts
│ │ │ │ │ │ │ └── SubmissionsIndex/
│ │ │ │ │ │ │ ├── SubmissionsTable.jsx
│ │ │ │ │ │ │ ├── SubmissionsTableRow.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── submissionsTable.test.jsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── translations.js
│ │ │ │ │ │ ├── propTypes.js
│ │ │ │ │ │ ├── reducers/
│ │ │ │ │ │ │ ├── annotations.js
│ │ │ │ │ │ │ ├── answerFlags/
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── answers.js
│ │ │ │ │ │ │ ├── assessment.js
│ │ │ │ │ │ │ ├── attachments.js
│ │ │ │ │ │ │ ├── codaveriFeedbackStatus.js
│ │ │ │ │ │ │ ├── commentForms.js
│ │ │ │ │ │ │ ├── explanations.js
│ │ │ │ │ │ │ ├── grading/
│ │ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ │ └── types.ts
│ │ │ │ │ │ │ ├── history/
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── liveFeedbackChats/
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── posts.js
│ │ │ │ │ │ │ ├── questions.js
│ │ │ │ │ │ │ ├── questionsFlags.js
│ │ │ │ │ │ │ ├── recorder.js
│ │ │ │ │ │ │ ├── scribing/
│ │ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ │ ├── submission.js
│ │ │ │ │ │ │ ├── submissionFlags.js
│ │ │ │ │ │ │ ├── submissions.js
│ │ │ │ │ │ │ ├── testCases.js
│ │ │ │ │ │ │ └── topics.js
│ │ │ │ │ │ ├── selectors/
│ │ │ │ │ │ │ ├── answerFlags.ts
│ │ │ │ │ │ │ ├── answers.ts
│ │ │ │ │ │ │ ├── assessments.ts
│ │ │ │ │ │ │ ├── attachments.ts
│ │ │ │ │ │ │ ├── codaveriFeedbackStatus.ts
│ │ │ │ │ │ │ ├── comments.ts
│ │ │ │ │ │ │ ├── explanations.ts
│ │ │ │ │ │ │ ├── grading.ts
│ │ │ │ │ │ │ ├── history.ts
│ │ │ │ │ │ │ ├── liveFeedbackChats.ts
│ │ │ │ │ │ │ ├── questionFlags.ts
│ │ │ │ │ │ │ ├── questions.ts
│ │ │ │ │ │ │ ├── submissionFlags.ts
│ │ │ │ │ │ │ ├── submissions.ts
│ │ │ │ │ │ │ └── topics.ts
│ │ │ │ │ │ ├── suggestionTranslations.ts
│ │ │ │ │ │ ├── translations.ts
│ │ │ │ │ │ ├── types.ts
│ │ │ │ │ │ └── utils/
│ │ │ │ │ │ ├── answers.ts
│ │ │ │ │ │ ├── rubrics.ts
│ │ │ │ │ │ └── timer.ts
│ │ │ │ │ ├── submissions/
│ │ │ │ │ │ ├── SubmissionsIndex.tsx
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ │ └── SubmissionsTableButton.tsx
│ │ │ │ │ │ │ ├── misc/
│ │ │ │ │ │ │ │ ├── SubmissionFilter.tsx
│ │ │ │ │ │ │ │ └── SubmissionTabs.tsx
│ │ │ │ │ │ │ └── tables/
│ │ │ │ │ │ │ └── SubmissionsTable.tsx
│ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ ├── store.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── translations.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── __test__/
│ │ │ │ │ │ └── index.test.js
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── recorderHelper.js
│ │ │ │ ├── container/
│ │ │ │ │ ├── Breadcrumbs/
│ │ │ │ │ │ ├── Breadcrumbs.tsx
│ │ │ │ │ │ ├── Crumb.tsx
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── sliders.tsx
│ │ │ │ │ ├── CourseContainer.tsx
│ │ │ │ │ ├── CourseLoader.ts
│ │ │ │ │ ├── Sidebar/
│ │ │ │ │ │ ├── CourseItem.tsx
│ │ │ │ │ │ ├── CourseUserItem.tsx
│ │ │ │ │ │ ├── CourseUserProgress.tsx
│ │ │ │ │ │ ├── LevelRing.tsx
│ │ │ │ │ │ ├── PinSidebarButton.tsx
│ │ │ │ │ │ ├── Sidebar.tsx
│ │ │ │ │ │ ├── SidebarAccordion.tsx
│ │ │ │ │ │ ├── SidebarContainer.tsx
│ │ │ │ │ │ ├── SidebarItem.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ └── unread.ts
│ │ │ │ ├── courses/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ ├── TodoAccessButton.tsx
│ │ │ │ │ │ │ └── TodoIgnoreButton.tsx
│ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ ├── CourseInvitationCodeForm.tsx
│ │ │ │ │ │ │ └── NewCourseForm.tsx
│ │ │ │ │ │ ├── misc/
│ │ │ │ │ │ │ ├── CourseAnnouncements.tsx
│ │ │ │ │ │ │ ├── CourseDisplay.tsx
│ │ │ │ │ │ │ ├── CourseEnrolOptions.tsx
│ │ │ │ │ │ │ ├── CourseInfoBox.tsx
│ │ │ │ │ │ │ ├── CourseNotifications.tsx
│ │ │ │ │ │ │ ├── CourseSuspendedAlert.tsx
│ │ │ │ │ │ │ └── NotificationCard.tsx
│ │ │ │ │ │ └── tables/
│ │ │ │ │ │ └── PendingTodosTable.tsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── CourseShow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── CoursesIndex/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── CoursesNew/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── discussion/
│ │ │ │ │ └── topics/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── cards/
│ │ │ │ │ │ │ ├── CodaveriCommentCard.tsx
│ │ │ │ │ │ │ ├── CommentCard.tsx
│ │ │ │ │ │ │ └── TopicCard.tsx
│ │ │ │ │ │ ├── fields/
│ │ │ │ │ │ │ └── CommentField.tsx
│ │ │ │ │ │ └── lists/
│ │ │ │ │ │ └── TopicList.tsx
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ └── CommentIndex/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── duplication/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── BulkSelectors.jsx
│ │ │ │ │ │ ├── CourseDropdownMenu.jsx
│ │ │ │ │ │ ├── IndentedCheckbox.jsx
│ │ │ │ │ │ ├── TypeBadge/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ └── UnpublishedIcon.jsx
│ │ │ │ │ ├── constants.js
│ │ │ │ │ ├── operations.js
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ └── Duplication/
│ │ │ │ │ │ ├── DestinationCourseSelector/
│ │ │ │ │ │ │ ├── InstanceDropdown.tsx
│ │ │ │ │ │ │ ├── NewCourseForm.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── DuplicateAllButton.jsx
│ │ │ │ │ │ ├── DuplicateButton.jsx
│ │ │ │ │ │ ├── DuplicateItemsConfirmation/
│ │ │ │ │ │ │ ├── AchievementsListing.jsx
│ │ │ │ │ │ │ ├── AssessmentsListing.jsx
│ │ │ │ │ │ │ ├── MaterialsListing.jsx
│ │ │ │ │ │ │ ├── SurveyListing.jsx
│ │ │ │ │ │ │ ├── VideosListing.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── ItemsSelector/
│ │ │ │ │ │ │ ├── AchievementsSelector.jsx
│ │ │ │ │ │ │ ├── AssessmentsSelector.jsx
│ │ │ │ │ │ │ ├── MaterialsSelector.jsx
│ │ │ │ │ │ │ ├── SurveysSelector.jsx
│ │ │ │ │ │ │ ├── VideosSelector.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── ItemsSelectorMenu/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ ├── DuplicateButton.test.tsx
│ │ │ │ │ │ │ └── ObjectDuplication.test.jsx
│ │ │ │ │ │ └── index.jsx
│ │ │ │ │ ├── propTypes.js
│ │ │ │ │ ├── selectors/
│ │ │ │ │ │ ├── destinationCourse.js
│ │ │ │ │ │ └── destinationInstance.ts
│ │ │ │ │ ├── store.js
│ │ │ │ │ └── utils.js
│ │ │ │ ├── enrol-requests/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ └── PendingEnrolRequestsButtons.tsx
│ │ │ │ │ │ └── tables/
│ │ │ │ │ │ └── EnrolRequestsTable.tsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ └── UserRequests/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── experience-points/
│ │ │ │ │ ├── ExperiencePointsDetails.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── ExperiencePointsDownload.tsx
│ │ │ │ │ │ ├── ExperiencePointsFiltering.tsx
│ │ │ │ │ │ ├── ExperiencePointsNumberField.tsx
│ │ │ │ │ │ ├── ExperiencePointsReasonField.tsx
│ │ │ │ │ │ ├── ExperiencePointsTable.tsx
│ │ │ │ │ │ └── ExperiencePointsTableRow.tsx
│ │ │ │ │ ├── disbursement/
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ │ ├── DuplicateButton.tsx
│ │ │ │ │ │ │ │ └── RemoveAllButton.tsx
│ │ │ │ │ │ │ ├── fields/
│ │ │ │ │ │ │ │ └── PointField.tsx
│ │ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ │ ├── DisbursementForm.tsx
│ │ │ │ │ │ │ │ ├── FilterForm.tsx
│ │ │ │ │ │ │ │ └── ForumDisbursementForm.tsx
│ │ │ │ │ │ │ └── tables/
│ │ │ │ │ │ │ ├── DisbursementTable.tsx
│ │ │ │ │ │ │ ├── ForumDisbursementTable.tsx
│ │ │ │ │ │ │ └── ForumPostTable.tsx
│ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ ├── ForumDisbursement/
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ └── GeneralDisbursement/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ ├── store.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ └── store.ts
│ │ │ │ ├── forum/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ ├── ForumManagementButtons.tsx
│ │ │ │ │ │ │ ├── ForumTopicManagementButtons.tsx
│ │ │ │ │ │ │ ├── ForumTopicPostEditActionButtons.tsx
│ │ │ │ │ │ │ ├── ForumTopicPostManagementButtons.tsx
│ │ │ │ │ │ │ ├── GenerateReplyButton.tsx
│ │ │ │ │ │ │ ├── HideButton.tsx
│ │ │ │ │ │ │ ├── LockButton.tsx
│ │ │ │ │ │ │ ├── MarkAllAsReadButton.tsx
│ │ │ │ │ │ │ ├── MarkAnswerAndPublishButton.tsx
│ │ │ │ │ │ │ ├── MarkAnswerButton.tsx
│ │ │ │ │ │ │ ├── NextUnreadButton.tsx
│ │ │ │ │ │ │ ├── ReplyButton.tsx
│ │ │ │ │ │ │ ├── SubscribeButton.tsx
│ │ │ │ │ │ │ └── VotePostButton.tsx
│ │ │ │ │ │ ├── cards/
│ │ │ │ │ │ │ ├── PostCard.tsx
│ │ │ │ │ │ │ └── ReplyCard.tsx
│ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ ├── ForumForm.tsx
│ │ │ │ │ │ │ ├── ForumTopicForm.tsx
│ │ │ │ │ │ │ └── ForumTopicPostForm.tsx
│ │ │ │ │ │ ├── misc/
│ │ │ │ │ │ │ └── PostCreatorObject.tsx
│ │ │ │ │ │ └── tables/
│ │ │ │ │ │ ├── ForumTable.tsx
│ │ │ │ │ │ └── ForumTopicTable.tsx
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── ForumEdit/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── ForumNew/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── ForumShow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── ForumTopicEdit/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── ForumTopicNew/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── ForumTopicPostNew/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── ForumTopicShow/
│ │ │ │ │ │ │ ├── TopicPostTrees.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── ForumsIndex/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── translations.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── group/
│ │ │ │ │ ├── actions/
│ │ │ │ │ │ ├── categories.js
│ │ │ │ │ │ ├── general.js
│ │ │ │ │ │ ├── groups.js
│ │ │ │ │ │ └── index.js
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── GroupCard.tsx
│ │ │ │ │ │ └── GroupRoleChip.tsx
│ │ │ │ │ ├── constants.js
│ │ │ │ │ ├── forms/
│ │ │ │ │ │ ├── GroupCreationForm.jsx
│ │ │ │ │ │ ├── GroupFormDialog.jsx
│ │ │ │ │ │ └── NameDescriptionForm.jsx
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── GroupIndex/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── GroupNew/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ └── GroupShow/
│ │ │ │ │ │ ├── CategoryCard.tsx
│ │ │ │ │ │ ├── GroupManager/
│ │ │ │ │ │ │ ├── ChangeSummaryTable.jsx
│ │ │ │ │ │ │ ├── GroupManager.jsx
│ │ │ │ │ │ │ ├── GroupUserManager.jsx
│ │ │ │ │ │ │ ├── GroupUserManagerList.jsx
│ │ │ │ │ │ │ └── index.js
│ │ │ │ │ │ ├── GroupTableCard.tsx
│ │ │ │ │ │ └── index.jsx
│ │ │ │ │ ├── propTypes.js
│ │ │ │ │ ├── reducers/
│ │ │ │ │ │ ├── groupsDialog.js
│ │ │ │ │ │ ├── groupsFetch.js
│ │ │ │ │ │ └── groupsManage.js
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── groups.js
│ │ │ │ │ └── sort.js
│ │ │ │ ├── helper/
│ │ │ │ │ ├── achievements.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── leaderboard/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ └── tables/
│ │ │ │ │ │ └── LeaderboardTable.tsx
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ └── LeaderboardIndex/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── learning-map/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── ConnectionPoint/
│ │ │ │ │ │ │ ├── ConnectionPoint.scss
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── Gate/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── Node/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── NodeMenu/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── UnlockRateDisplay/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ └── ZoomActionElements/
│ │ │ │ │ │ └── index.jsx
│ │ │ │ │ ├── constants.js
│ │ │ │ │ ├── containers/
│ │ │ │ │ │ ├── ArrowOverlay/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── Canvas/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── Dashboard/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── GateToNodeArrows/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── LearningMap/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── Levels/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ └── NodeToGateArrows/
│ │ │ │ │ │ └── index.jsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── propTypes.js
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── translations.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── lesson-plan/
│ │ │ │ │ ├── constants.js
│ │ │ │ │ ├── containers/
│ │ │ │ │ │ ├── ColumnVisibilityDropdown/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── EventFormDialog/
│ │ │ │ │ │ │ ├── EventForm.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── LessonPlanFilter/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── LessonPlanLayout/
│ │ │ │ │ │ │ ├── EnterEditModeButton.jsx
│ │ │ │ │ │ │ ├── NewEventButton.jsx
│ │ │ │ │ │ │ ├── NewMilestoneButton.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ ├── NewEventButton.test.jsx
│ │ │ │ │ │ │ │ ├── NewMilestoneButton.test.jsx
│ │ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── LessonPlanNav/
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── MilestoneFormDialog/
│ │ │ │ │ │ │ ├── MilestoneForm.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ └── TranslatedItemType.tsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── LessonPlanEdit/
│ │ │ │ │ │ │ ├── ItemRow/
│ │ │ │ │ │ │ │ ├── DateCell.jsx
│ │ │ │ │ │ │ │ ├── PublishedCell.jsx
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ ├── MilestoneRow.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ ├── ItemRow.test.jsx
│ │ │ │ │ │ │ │ ├── MilestoneRow.test.jsx
│ │ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ └── LessonPlanShow/
│ │ │ │ │ │ ├── LessonPlanGroup.jsx
│ │ │ │ │ │ ├── LessonPlanItem/
│ │ │ │ │ │ │ ├── AdminTools.jsx
│ │ │ │ │ │ │ ├── Details/
│ │ │ │ │ │ │ │ ├── Chips.jsx
│ │ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ │ ├── Material.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── AdminTools.test.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── MilestoneAdminTools.jsx
│ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ ├── LessonPlanShow.test.jsx
│ │ │ │ │ │ │ └── MilestoneAdminTools.test.jsx
│ │ │ │ │ │ └── index.jsx
│ │ │ │ │ ├── reducers/
│ │ │ │ │ │ ├── eventForm.js
│ │ │ │ │ │ ├── flags.js
│ │ │ │ │ │ ├── lessonPlan.js
│ │ │ │ │ │ ├── milestoneForm.js
│ │ │ │ │ │ └── utils.js
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── translations.ts
│ │ │ │ ├── level/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── LevelsTable.tsx
│ │ │ │ │ │ └── LevelsTableRow.tsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ └── LevelsIndex/
│ │ │ │ │ │ ├── LevelsManager.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selector.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── material/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ └── MaterialStatusPage.tsx
│ │ │ │ │ ├── files/
│ │ │ │ │ │ ├── DownloadingFilePage.tsx
│ │ │ │ │ │ └── ErrorRetrievingFilePage.tsx
│ │ │ │ │ ├── folders/
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ │ ├── DownloadFolderButton.tsx
│ │ │ │ │ │ │ │ ├── KnowledgeBaseSwitch.tsx
│ │ │ │ │ │ │ │ ├── NewSubfolderButton.tsx
│ │ │ │ │ │ │ │ ├── UploadFilesButton.tsx
│ │ │ │ │ │ │ │ └── WorkbinTableButtons.tsx
│ │ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ │ ├── FolderForm.tsx
│ │ │ │ │ │ │ │ ├── MaterialForm.tsx
│ │ │ │ │ │ │ │ └── MaterialUploadForm.tsx
│ │ │ │ │ │ │ ├── misc/
│ │ │ │ │ │ │ │ ├── MaterialEdit.tsx
│ │ │ │ │ │ │ │ ├── MaterialUpload.tsx
│ │ │ │ │ │ │ │ └── MultipleFileInput.tsx
│ │ │ │ │ │ │ └── tables/
│ │ │ │ │ │ │ ├── TableMaterialRow.tsx
│ │ │ │ │ │ │ ├── TableSubfolderRow.tsx
│ │ │ │ │ │ │ └── WorkbinTable.tsx
│ │ │ │ │ │ ├── handles.ts
│ │ │ │ │ │ ├── operations.ts
│ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ ├── ErrorRetrievingFolderPage.tsx
│ │ │ │ │ │ │ ├── FolderEdit/
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── FolderNew/
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ └── FolderShow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── selectors.ts
│ │ │ │ │ │ ├── store.ts
│ │ │ │ │ │ └── types.ts
│ │ │ │ │ └── materialLoader.ts
│ │ │ │ ├── plagiarism/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── AssessmentLinkDialog.tsx
│ │ │ │ │ │ └── AssessmentLinkList.tsx
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ └── PlagiarismIndex/
│ │ │ │ │ │ ├── assessments/
│ │ │ │ │ │ │ └── AssessmentsPlagiarismTable.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── reducers/
│ │ │ │ │ │ └── assessments.ts
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ └── store.ts
│ │ │ │ ├── reference-timelines/
│ │ │ │ │ ├── TimelineDesigner.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── CreateRenameTimelinePrompt.tsx
│ │ │ │ │ │ ├── DayCalendar/
│ │ │ │ │ │ │ ├── DayCalendar.tsx
│ │ │ │ │ │ │ ├── DayColumn.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── DeleteTimelinePrompt.tsx
│ │ │ │ │ │ ├── HorizontallyDraggable.tsx
│ │ │ │ │ │ ├── HorizontallyResizable.tsx
│ │ │ │ │ │ ├── SeriouslyAnchoredPopup.tsx
│ │ │ │ │ │ ├── SubmitIndicator.tsx
│ │ │ │ │ │ ├── TimeBar/
│ │ │ │ │ │ │ ├── DurationBar.tsx
│ │ │ │ │ │ │ ├── TimeBar.tsx
│ │ │ │ │ │ │ ├── TimeBarHandle.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── TimePopup/
│ │ │ │ │ │ │ ├── TimePopup.tsx
│ │ │ │ │ │ │ ├── TimePopupForm.tsx
│ │ │ │ │ │ │ ├── TimePopupTopBar.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ ├── TimelinesOverview/
│ │ │ │ │ │ │ ├── TimelinesOverview.tsx
│ │ │ │ │ │ │ ├── TimelinesOverviewItem.tsx
│ │ │ │ │ │ │ └── index.ts
│ │ │ │ │ │ └── TimelinesStack/
│ │ │ │ │ │ ├── AssignableTimeline.tsx
│ │ │ │ │ │ ├── AssignedTimeline.tsx
│ │ │ │ │ │ ├── Timeline.tsx
│ │ │ │ │ │ ├── TimelinesStack.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── contexts/
│ │ │ │ │ │ ├── LastSavedContext.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── translations.ts
│ │ │ │ │ ├── types.ts
│ │ │ │ │ ├── utils.ts
│ │ │ │ │ └── views/
│ │ │ │ │ └── DayView/
│ │ │ │ │ ├── DayView.tsx
│ │ │ │ │ ├── ItemsSidebar.tsx
│ │ │ │ │ ├── TimelineSidebarItem.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── scholaistic/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── ScholaisticAsyncContainer.tsx
│ │ │ │ │ │ ├── ScholaisticErrorPage.tsx
│ │ │ │ │ │ └── ScholaisticFramePage.tsx
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ └── pages/
│ │ │ │ │ ├── ScholaisticAssessmentEdit/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── loader.ts
│ │ │ │ │ │ └── operations.ts
│ │ │ │ │ ├── ScholaisticAssessmentNew/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── loader.ts
│ │ │ │ │ ├── ScholaisticAssessmentSubmissionEdit/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── loader.ts
│ │ │ │ │ ├── ScholaisticAssessmentSubmissionsIndex/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── loader.ts
│ │ │ │ │ ├── ScholaisticAssessmentView/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── loader.ts
│ │ │ │ │ ├── ScholaisticAssessmentsIndex/
│ │ │ │ │ │ ├── ActionButtons.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── loader.ts
│ │ │ │ │ ├── ScholaisticAssistantEdit/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── loader.ts
│ │ │ │ │ └── ScholaisticAssistantsIndex/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── loader.ts
│ │ │ │ ├── statistics/
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ └── StatisticsIndex/
│ │ │ │ │ │ ├── assessments/
│ │ │ │ │ │ │ ├── AssessmentsScoreSummaryDownload.tsx
│ │ │ │ │ │ │ ├── AssessmentsStatistics.tsx
│ │ │ │ │ │ │ └── AssessmentsStatisticsTable.tsx
│ │ │ │ │ │ ├── course/
│ │ │ │ │ │ │ ├── CourseStatistics.tsx
│ │ │ │ │ │ │ ├── StudentPerformanceTable.tsx
│ │ │ │ │ │ │ ├── StudentProgressionChart.tsx
│ │ │ │ │ │ │ └── utils.js
│ │ │ │ │ │ ├── get_help/
│ │ │ │ │ │ │ ├── CourseGetHelpFilter.tsx
│ │ │ │ │ │ │ ├── CourseGetHelpStatistics.tsx
│ │ │ │ │ │ │ └── CourseGetHelpStatisticsTable.tsx
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ ├── staff/
│ │ │ │ │ │ │ ├── StaffStatistics.tsx
│ │ │ │ │ │ │ └── StaffStatisticsTable.tsx
│ │ │ │ │ │ └── students/
│ │ │ │ │ │ ├── StudentStatisticsTable.tsx
│ │ │ │ │ │ └── StudentsStatistics.tsx
│ │ │ │ │ ├── types.ts
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── parseCourseResponse.js
│ │ │ │ │ ├── parseStaffResponse.js
│ │ │ │ │ └── parseStudentsResponse.js
│ │ │ │ ├── stories/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── CikgoChatsPage.tsx
│ │ │ │ │ │ ├── CikgoErrorPage.tsx
│ │ │ │ │ │ ├── CikgoFramePage.tsx
│ │ │ │ │ │ ├── CikgoSidebarItems.tsx
│ │ │ │ │ │ └── LearnRedirect.tsx
│ │ │ │ │ └── pages/
│ │ │ │ │ ├── LearnPage.tsx
│ │ │ │ │ └── MissionControlPage.tsx
│ │ │ │ ├── survey/
│ │ │ │ │ ├── __test__/
│ │ │ │ │ │ └── index.test.tsx
│ │ │ │ │ ├── actions/
│ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ └── responses.test.ts
│ │ │ │ │ │ ├── questions.js
│ │ │ │ │ │ ├── responses.js
│ │ │ │ │ │ ├── sections.js
│ │ │ │ │ │ └── surveys.js
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── Dialogs.jsx
│ │ │ │ │ │ └── OptionsListItem.jsx
│ │ │ │ │ ├── constants.js
│ │ │ │ │ ├── containers/
│ │ │ │ │ │ ├── QuestionFormDialogue/
│ │ │ │ │ │ │ ├── QuestionForm.jsx
│ │ │ │ │ │ │ ├── QuestionFormDeletedOptions.jsx
│ │ │ │ │ │ │ ├── QuestionFormOption.jsx
│ │ │ │ │ │ │ ├── QuestionFormOptions.jsx
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ └── ImageField.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── RespondButton/
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── ResponseForm/
│ │ │ │ │ │ │ ├── ResponseAnswer.jsx
│ │ │ │ │ │ │ ├── ResponseSection.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ │ ├── MultipleChoiceOptionsField.jsx
│ │ │ │ │ │ │ │ └── MultipleResponseOptionsField.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── SectionFormDialogue/
│ │ │ │ │ │ │ ├── SectionForm.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── SurveyFormDialogue/
│ │ │ │ │ │ │ ├── SurveyForm.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── SurveyLayout/
│ │ │ │ │ │ │ ├── AdminMenu.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ ├── AdminMenu.test.jsx
│ │ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ └── UnsubmitButton.jsx
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── ResponseEdit/
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── ResponseIndex/
│ │ │ │ │ │ │ ├── RemindButton.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ ├── RemindButton.test.tsx
│ │ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ │ └── translations.js
│ │ │ │ │ │ ├── ResponseShow/
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── SurveyIndex/
│ │ │ │ │ │ │ ├── NewSurveyButton.jsx
│ │ │ │ │ │ │ ├── SurveyBadges.jsx
│ │ │ │ │ │ │ ├── SurveysTable.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── NewSurveyButton.test.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── SurveyResults/
│ │ │ │ │ │ │ ├── OptionsQuestionResults.jsx
│ │ │ │ │ │ │ ├── ResultsQuestion.jsx
│ │ │ │ │ │ │ ├── ResultsSection.jsx
│ │ │ │ │ │ │ ├── TextResponseResults.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ ├── ResultsQuestion.test.tsx
│ │ │ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── SurveyShow/
│ │ │ │ │ │ ├── DownloadResponsesButton.jsx
│ │ │ │ │ │ ├── NewSectionButton.jsx
│ │ │ │ │ │ ├── Section/
│ │ │ │ │ │ │ ├── DeleteSectionButton.jsx
│ │ │ │ │ │ │ ├── EditSectionButton.jsx
│ │ │ │ │ │ │ ├── MoveDownButton.jsx
│ │ │ │ │ │ │ ├── MoveUpButton.jsx
│ │ │ │ │ │ │ ├── NewQuestionButton.jsx
│ │ │ │ │ │ │ ├── Question.jsx
│ │ │ │ │ │ │ ├── QuestionCard.jsx
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ ├── DeleteSectionButton.test.tsx
│ │ │ │ │ │ │ │ ├── EditSectionButton.test.jsx
│ │ │ │ │ │ │ │ ├── MoveDownButton.test.tsx
│ │ │ │ │ │ │ │ ├── MoveUpButton.test.jsx
│ │ │ │ │ │ │ │ └── NewQuestionButton.test.jsx
│ │ │ │ │ │ │ └── index.jsx
│ │ │ │ │ │ ├── SurveyDetails.jsx
│ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ ├── DownloadResponsesButton.test.tsx
│ │ │ │ │ │ │ └── NewSectionButton.test.jsx
│ │ │ │ │ │ └── index.jsx
│ │ │ │ │ ├── propTypes.js
│ │ │ │ │ ├── reducers/
│ │ │ │ │ │ ├── questionForm.js
│ │ │ │ │ │ ├── responseForm.js
│ │ │ │ │ │ ├── responses.js
│ │ │ │ │ │ ├── results.js
│ │ │ │ │ │ ├── section.js
│ │ │ │ │ │ ├── sectionForm.js
│ │ │ │ │ │ ├── survey.js
│ │ │ │ │ │ ├── surveyForm.js
│ │ │ │ │ │ ├── surveys.js
│ │ │ │ │ │ └── surveysFlags.js
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── translations.js
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── __test__/
│ │ │ │ │ │ └── index.test.js
│ │ │ │ │ └── index.js
│ │ │ │ ├── translations.ts
│ │ │ │ ├── user-email-subscriptions/
│ │ │ │ │ ├── UserEmailSubscriptions.tsx
│ │ │ │ │ ├── UserEmailSubscriptionsTable.jsx
│ │ │ │ │ ├── __test__/
│ │ │ │ │ │ └── index.test.jsx
│ │ │ │ │ ├── constants.js
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── translations.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── user-invitations/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ ├── InvitationActionButtons.tsx
│ │ │ │ │ │ │ ├── RegistrationCodeButton.tsx
│ │ │ │ │ │ │ ├── ResendAllInvitationsButton.tsx
│ │ │ │ │ │ │ └── UploadFileButton.tsx
│ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ ├── IndividualInvitation.tsx
│ │ │ │ │ │ │ ├── IndividualInvitations.tsx
│ │ │ │ │ │ │ ├── IndividualInviteForm.tsx
│ │ │ │ │ │ │ └── InviteUsersFileUploadForm.tsx
│ │ │ │ │ │ ├── misc/
│ │ │ │ │ │ │ ├── InvitationResultDialog.tsx
│ │ │ │ │ │ │ └── InvitationsBarChart.tsx
│ │ │ │ │ │ └── tables/
│ │ │ │ │ │ ├── InvitationResultInvitationsTable.tsx
│ │ │ │ │ │ ├── InvitationResultUsersTable.tsx
│ │ │ │ │ │ └── UserInvitationsTable.tsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── InvitationsIndex/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── InviteUsers/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── InviteUsersFileUpload/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── InviteUsersRegistrationCode/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── translations.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── user-notification/
│ │ │ │ │ ├── PopupNotifier.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── AchievementGainedPopup.tsx
│ │ │ │ │ │ ├── LevelReachedPopup.tsx
│ │ │ │ │ │ ├── PopupDialog.tsx
│ │ │ │ │ │ └── __test__/
│ │ │ │ │ │ └── LevelReachedPopup.test.tsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ └── translations.ts
│ │ │ │ ├── users/
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ ├── PointManagementButtons.tsx
│ │ │ │ │ │ │ └── UserManagementButtons.tsx
│ │ │ │ │ │ ├── misc/
│ │ │ │ │ │ │ ├── PersonalTimeEditor.tsx
│ │ │ │ │ │ │ ├── SelectCourseUser.tsx
│ │ │ │ │ │ │ ├── UpgradeToStaff.tsx
│ │ │ │ │ │ │ ├── UserProfileAchievements.tsx
│ │ │ │ │ │ │ ├── UserProfileCard.scss
│ │ │ │ │ │ │ ├── UserProfileCard.tsx
│ │ │ │ │ │ │ ├── UserProfileCardStats.tsx
│ │ │ │ │ │ │ ├── UserProfileSkills.tsx
│ │ │ │ │ │ │ └── __test__/
│ │ │ │ │ │ │ └── UserProfileCard.test.tsx
│ │ │ │ │ │ ├── navigation/
│ │ │ │ │ │ │ └── UserManagementTabs.tsx
│ │ │ │ │ │ └── tables/
│ │ │ │ │ │ ├── ManageUsersTable/
│ │ │ │ │ │ │ ├── ActiveTableToolbar.tsx
│ │ │ │ │ │ │ ├── AlgorithmMenu.tsx
│ │ │ │ │ │ │ ├── BulkActionsButton.tsx
│ │ │ │ │ │ │ ├── BulkAssignTimelineMenu.tsx
│ │ │ │ │ │ │ ├── PhantomSwitch.tsx
│ │ │ │ │ │ │ ├── RoleMenu.tsx
│ │ │ │ │ │ │ ├── TimelineMenu.tsx
│ │ │ │ │ │ │ ├── UserNameField.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── PersonalTimesTable.tsx
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── ExperiencePointsRecords/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── ManageStaff/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── ManageStudents/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── PersonalTimes/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── PersonalTimesShow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── UserShow/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── UserStatistics/
│ │ │ │ │ │ │ ├── LearningRateRecords/
│ │ │ │ │ │ │ │ ├── LearningRateRecordsChart.tsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── UsersIndex/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── translations.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── video/
│ │ │ │ │ ├── attemptLoader.ts
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ ├── VideoManagementButtons.tsx
│ │ │ │ │ │ │ └── WatchVideoButton.tsx
│ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ └── VideoForm.tsx
│ │ │ │ │ │ ├── misc/
│ │ │ │ │ │ │ ├── VideoBadges.tsx
│ │ │ │ │ │ │ └── VideoTabs.tsx
│ │ │ │ │ │ └── tables/
│ │ │ │ │ │ └── VideoTable.tsx
│ │ │ │ │ ├── handles.ts
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── VideoEdit/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── VideoNew/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── VideoShow/
│ │ │ │ │ │ │ ├── VideoDetails.tsx
│ │ │ │ │ │ │ ├── VideoPlayerWithStore.jsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ └── VideosIndex/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ ├── submission/
│ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ └── store.test.js
│ │ │ │ │ │ ├── actions/
│ │ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ │ └── video.test.js
│ │ │ │ │ │ │ ├── discussion.js
│ │ │ │ │ │ │ └── video.js
│ │ │ │ │ │ ├── components/
│ │ │ │ │ │ │ └── tables/
│ │ │ │ │ │ │ └── VideoSubmissionsTable.tsx
│ │ │ │ │ │ ├── containers/
│ │ │ │ │ │ │ ├── Charts/
│ │ │ │ │ │ │ │ ├── HeatMap.jsx
│ │ │ │ │ │ │ │ └── ProgressGraph.jsx
│ │ │ │ │ │ │ ├── Discussion.jsx
│ │ │ │ │ │ │ ├── Discussion.scss
│ │ │ │ │ │ │ ├── DiscussionElements/
│ │ │ │ │ │ │ │ ├── Controls.jsx
│ │ │ │ │ │ │ │ ├── EditPostContainer.jsx
│ │ │ │ │ │ │ │ ├── Editor.jsx
│ │ │ │ │ │ │ │ ├── NewPostContainer.jsx
│ │ │ │ │ │ │ │ ├── NewReplyContainer.jsx
│ │ │ │ │ │ │ │ ├── PostContainer.jsx
│ │ │ │ │ │ │ │ ├── PostMenu.jsx
│ │ │ │ │ │ │ │ ├── PostPresentation.jsx
│ │ │ │ │ │ │ │ ├── Reply.jsx
│ │ │ │ │ │ │ │ └── Topic.jsx
│ │ │ │ │ │ │ ├── Statistics.jsx
│ │ │ │ │ │ │ ├── Statistics.scss
│ │ │ │ │ │ │ ├── Submission.jsx
│ │ │ │ │ │ │ ├── VideoControls/
│ │ │ │ │ │ │ │ ├── CaptionsButton.jsx
│ │ │ │ │ │ │ │ ├── NextVideoButton.jsx
│ │ │ │ │ │ │ │ ├── PlayBackRateSelector.jsx
│ │ │ │ │ │ │ │ ├── PlayButton.jsx
│ │ │ │ │ │ │ │ ├── VideoPlayerSlider.jsx
│ │ │ │ │ │ │ │ ├── VideoTimestamp.jsx
│ │ │ │ │ │ │ │ ├── VolumeButton.jsx
│ │ │ │ │ │ │ │ ├── VolumeSlider.jsx
│ │ │ │ │ │ │ │ └── index.js
│ │ │ │ │ │ │ ├── VideoPlayer.jsx
│ │ │ │ │ │ │ └── VideoPlayer.scss
│ │ │ │ │ │ ├── pages/
│ │ │ │ │ │ │ ├── VideoSubmissionEdit/
│ │ │ │ │ │ │ │ ├── SubmissionEditWithStore.jsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ ├── VideoSubmissionShow/
│ │ │ │ │ │ │ │ ├── StatisticsWithStore.jsx
│ │ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ │ └── VideoSubmissionsIndex/
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── reducers/
│ │ │ │ │ │ │ ├── discussion.js
│ │ │ │ │ │ │ ├── index.js
│ │ │ │ │ │ │ ├── oldSessions.js
│ │ │ │ │ │ │ └── video.js
│ │ │ │ │ │ ├── selectors/
│ │ │ │ │ │ │ └── discussion.js
│ │ │ │ │ │ ├── store.js
│ │ │ │ │ │ └── translations.js
│ │ │ │ │ └── types.ts
│ │ │ │ └── video-submissions/
│ │ │ │ ├── components/
│ │ │ │ │ └── tables/
│ │ │ │ │ └── UserVideoSubmissionTable.tsx
│ │ │ │ ├── operations.ts
│ │ │ │ └── pages/
│ │ │ │ └── UserVideoSubmissionsIndex/
│ │ │ │ └── index.tsx
│ │ │ ├── system/
│ │ │ │ └── admin/
│ │ │ │ ├── admin/
│ │ │ │ │ ├── AdminNavigator.tsx
│ │ │ │ │ ├── components/
│ │ │ │ │ │ ├── buttons/
│ │ │ │ │ │ │ ├── CoursesButtons.tsx
│ │ │ │ │ │ │ ├── InstancesButtons.tsx
│ │ │ │ │ │ │ └── UsersButtons.tsx
│ │ │ │ │ │ ├── forms/
│ │ │ │ │ │ │ └── InstanceForm.tsx
│ │ │ │ │ │ ├── misc/
│ │ │ │ │ │ │ └── SystemGetHelpFilter.tsx
│ │ │ │ │ │ └── tables/
│ │ │ │ │ │ ├── CoursesTable.tsx
│ │ │ │ │ │ ├── InstancesTable/
│ │ │ │ │ │ │ ├── InstanceField.tsx
│ │ │ │ │ │ │ └── index.tsx
│ │ │ │ │ │ ├── SystemGetHelpActivityTable.tsx
│ │ │ │ │ │ └── UsersTable.tsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── pages/
│ │ │ │ │ │ ├── AnnouncementsIndex.tsx
│ │ │ │ │ │ ├── CoursesIndex.tsx
│ │ │ │ │ │ ├── InstanceNew.tsx
│ │ │ │ │ │ ├── InstancesIndex.tsx
│ │ │ │ │ │ ├── SystemGetHelpActivityIndex.tsx
│ │ │ │ │ │ └── UsersIndex.tsx
│ │ │ │ │ ├── selectors.ts
│ │ │ │ │ ├── store.ts
│ │ │ │ │ └── types.ts
│ │ │ │ ├── components/
│ │ │ │ │ └── AdminNavigablePage.tsx
│ │ │ │ └── instance/
│ │ │ │ └── instance/
│ │ │ │ ├── InstanceAdminNavigator.tsx
│ │ │ │ ├── components/
│ │ │ │ │ ├── buttons/
│ │ │ │ │ │ ├── InvitationActionButtons.tsx
│ │ │ │ │ │ ├── PendingRoleRequestsButtons.tsx
│ │ │ │ │ │ ├── ResendAllInvitationsButton.tsx
│ │ │ │ │ │ └── UsersButtons.tsx
│ │ │ │ │ ├── forms/
│ │ │ │ │ │ ├── IndividualInvitation.tsx
│ │ │ │ │ │ ├── IndividualInvitations.tsx
│ │ │ │ │ │ ├── IndividualInviteForm.tsx
│ │ │ │ │ │ ├── InstanceUserRoleRequestForm.tsx
│ │ │ │ │ │ └── RejectWithMessageForm.tsx
│ │ │ │ │ ├── misc/
│ │ │ │ │ │ ├── InstanceGetHelpFilter.tsx
│ │ │ │ │ │ └── InvitationResultDialog.tsx
│ │ │ │ │ ├── navigation/
│ │ │ │ │ │ └── InstanceUsersTabs.tsx
│ │ │ │ │ └── tables/
│ │ │ │ │ ├── InstanceGetHelpActivityTable.tsx
│ │ │ │ │ ├── InstanceUserRoleRequestsTable.tsx
│ │ │ │ │ ├── InvitationResultInvitationsTable.tsx
│ │ │ │ │ ├── InvitationResultUsersTable.tsx
│ │ │ │ │ ├── UserInvitationsTable.tsx
│ │ │ │ │ ├── UsersTable.tsx
│ │ │ │ │ └── __test__/
│ │ │ │ │ └── InstanceUserRoleRequestsTable.test.tsx
│ │ │ │ ├── operations.ts
│ │ │ │ ├── pages/
│ │ │ │ │ ├── InstanceAnnouncementsIndex.tsx
│ │ │ │ │ ├── InstanceComponentsIndex.tsx
│ │ │ │ │ ├── InstanceCoursesIndex.tsx
│ │ │ │ │ ├── InstanceGetHelpActivityIndex.tsx
│ │ │ │ │ ├── InstanceUserRoleRequestsIndex.tsx
│ │ │ │ │ ├── InstanceUsersIndex.tsx
│ │ │ │ │ ├── InstanceUsersInvitations.tsx
│ │ │ │ │ └── InstanceUsersInvite.tsx
│ │ │ │ ├── selectors.ts
│ │ │ │ ├── store.ts
│ │ │ │ └── types.ts
│ │ │ ├── user/
│ │ │ │ ├── AccountSettings/
│ │ │ │ │ ├── AccountSettingsForm.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── components/
│ │ │ │ │ ├── AddEmailSubsection.tsx
│ │ │ │ │ └── EmailsList.tsx
│ │ │ │ ├── operations.ts
│ │ │ │ └── translations.ts
│ │ │ └── users/
│ │ │ ├── components/
│ │ │ │ ├── Widget.tsx
│ │ │ │ └── tables/
│ │ │ │ ├── CoursesTable.tsx
│ │ │ │ ├── InstancesTable.tsx
│ │ │ │ └── __test__/
│ │ │ │ └── InstancesTable.test.tsx
│ │ │ ├── operations.ts
│ │ │ ├── pages/
│ │ │ │ ├── ConfirmEmailPage.tsx
│ │ │ │ ├── ForgotPasswordLandingPage.tsx
│ │ │ │ ├── ForgotPasswordPage.tsx
│ │ │ │ ├── ResendConfirmationEmailLandingPage.tsx
│ │ │ │ ├── ResendConfirmationEmailPage.tsx
│ │ │ │ ├── ResetPasswordPage.tsx
│ │ │ │ ├── SignUpLandingPage.tsx
│ │ │ │ ├── SignUpPage.tsx
│ │ │ │ ├── UserShow.tsx
│ │ │ │ └── __test__/
│ │ │ │ └── UserShow.test.tsx
│ │ │ ├── selectors.ts
│ │ │ ├── store.ts
│ │ │ ├── translations.ts
│ │ │ ├── types.ts
│ │ │ └── validations.ts
│ │ ├── declaration.d.ts
│ │ ├── index.tsx
│ │ ├── lib/
│ │ │ ├── actions/
│ │ │ │ └── index.js
│ │ │ ├── components/
│ │ │ │ ├── core/
│ │ │ │ │ ├── AvatarSelector.tsx
│ │ │ │ │ ├── AvatarWithLabel.tsx
│ │ │ │ │ ├── BarChart.jsx
│ │ │ │ │ ├── BetaChip.tsx
│ │ │ │ │ ├── CourseUserTypeFragment.tsx
│ │ │ │ │ ├── CourseUserTypeTabs.tsx
│ │ │ │ │ ├── CustomTooltip.tsx
│ │ │ │ │ ├── DescriptionCard.tsx
│ │ │ │ │ ├── ErrorText.jsx
│ │ │ │ │ ├── Expandable.tsx
│ │ │ │ │ ├── ExpandableCode.tsx
│ │ │ │ │ ├── ExperimentalChip.tsx
│ │ │ │ │ ├── Hint.tsx
│ │ │ │ │ ├── ImageCropper/
│ │ │ │ │ │ ├── index.tsx
│ │ │ │ │ │ └── utils.ts
│ │ │ │ │ ├── InfoLabel.tsx
│ │ │ │ │ ├── LinearProgressWithLabel.tsx
│ │ │ │ │ ├── Link.tsx
│ │ │ │ │ ├── LoadingEllipsis.tsx
│ │ │ │ │ ├── LoadingIndicator.tsx
│ │ │ │ │ ├── LoadingOverlay.tsx
│ │ │ │ │ ├── Note.tsx
│ │ │ │ │ ├── NotificationBar.jsx
│ │ │ │ │ ├── PopupMenu.tsx
│ │ │ │ │ ├── Thumbnail.jsx
│ │ │ │ │ ├── UserHTMLText.tsx
│ │ │ │ │ ├── __test__/
│ │ │ │ │ │ ├── ErrorText.test.tsx
│ │ │ │ │ │ ├── LoadingIndicator.test.tsx
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ ├── ErrorText.test.tsx.snap
│ │ │ │ │ │ └── LoadingIndicator.test.tsx.snap
│ │ │ │ │ ├── buttons/
│ │ │ │ │ │ ├── AcceptButton.tsx
│ │ │ │ │ │ ├── AddButton.tsx
│ │ │ │ │ │ ├── Checkbox.tsx
│ │ │ │ │ │ ├── DeleteButton.tsx
│ │ │ │ │ │ ├── DownloadButton.tsx
│ │ │ │ │ │ ├── EditButton.tsx
│ │ │ │ │ │ ├── EmailButton.tsx
│ │ │ │ │ │ ├── IconRadio.tsx
│ │ │ │ │ │ ├── RadioButton.tsx
│ │ │ │ │ │ ├── SaveButton.tsx
│ │ │ │ │ │ └── __test__/
│ │ │ │ │ │ ├── DeleteButton.test.tsx
│ │ │ │ │ │ ├── EditButton.test.tsx
│ │ │ │ │ │ └── __snapshots__/
│ │ │ │ │ │ ├── DeleteButton.test.tsx.snap
│ │ │ │ │ │ └── EditButton.test.tsx.snap
│ │ │ │ │ ├── charts/
│ │ │ │ │ │ ├── GeneralChart.tsx
│ │ │ │ │ │ ├── LineChart.tsx
│ │ │ │ │ │ └── emptyChartPlugin.ts
│ │ │ │ │ ├── dialogs/
│ │ │ │ │ │ ├── ConfirmationDialog.jsx
│ │ │ │ │ │ ├── ImageCropDialog.tsx
│ │ │ │ │ │ ├── Prompt.tsx
│ │ │ │ │ │ └── RailsConfirmationDialog.jsx
│ │ │ │ │ ├── fields/
│ │ │ │ │ │ ├── AceEditor.css
│ │ │ │ │ │ ├── CAPTCHAField.tsx
│ │ │ │ │ │ ├── CKEditor.css
│ │ │ │ │ │ ├── CKEditorField.tsx
│ │ │ │ │ │ ├── CKEditorRichText.tsx
│ │ │ │ │ │ ├── DateTimePicker.jsx
│ │ │ │ │ │ ├── EditorField.tsx
│ │ │ │ │ │ ├── NumberTextField.tsx
│ │ │ │ │ │ ├── PasswordTextField.tsx
│ │ │ │ │ │ ├── SearchField.tsx
│ │ │ │ │ │ ├── SwitchableTextField.tsx
│ │ │ │ │ │ └── TextField.tsx
│ │ │ │ │ ├── indicators/
│ │ │ │ │ │ └── SavingIndicator/
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ └── layouts/
│ │ │ │ │ ├── Accordion.tsx
│ │ │ │ │ ├── BackendPagination.tsx
│ │ │ │ │ ├── Banner.tsx
│ │ │ │ │ ├── ContactableErrorAlert.tsx
│ │ │ │ │ ├── ContextualErrorPage.tsx
│ │ │ │ │ ├── DataTable.jsx
│ │ │ │ │ ├── Footer.tsx
│ │ │ │ │ ├── MarkdownPage.tsx
│ │ │ │ │ ├── Page.tsx
│ │ │ │ │ ├── Pagination.tsx
│ │ │ │ │ ├── Section.tsx
│ │ │ │ │ ├── Subsection.tsx
│ │ │ │ │ ├── SummaryCard.tsx
│ │ │ │ │ ├── TableContainer.tsx
│ │ │ │ │ └── layout.scss
│ │ │ │ ├── extensions/
│ │ │ │ │ ├── CustomBadge.tsx
│ │ │ │ │ ├── CustomSlider.tsx
│ │ │ │ │ ├── PersonalStartEndTime.tsx
│ │ │ │ │ ├── PersonalTimeBooleanIcon.tsx
│ │ │ │ │ ├── StackedBadges.tsx
│ │ │ │ │ └── conditions/
│ │ │ │ │ ├── AnyCondition.ts
│ │ │ │ │ ├── ConditionRow.tsx
│ │ │ │ │ ├── ConditionsManager.tsx
│ │ │ │ │ ├── conditions/
│ │ │ │ │ │ ├── AchievementCondition.tsx
│ │ │ │ │ │ ├── AssessmentCondition.tsx
│ │ │ │ │ │ ├── LevelCondition.tsx
│ │ │ │ │ │ ├── ScholaisticAssessmentCondition.tsx
│ │ │ │ │ │ └── SurveyCondition.tsx
│ │ │ │ │ ├── operations.ts
│ │ │ │ │ ├── specifiers.ts
│ │ │ │ │ └── translations.ts
│ │ │ │ ├── form/
│ │ │ │ │ ├── Form.tsx
│ │ │ │ │ ├── FormDialogue.jsx
│ │ │ │ │ ├── dialog/
│ │ │ │ │ │ └── FormDialog.tsx
│ │ │ │ │ └── fields/
│ │ │ │ │ ├── AutoCompleteField.jsx
│ │ │ │ │ ├── CheckboxField.tsx
│ │ │ │ │ ├── DataTableInlineEditable/
│ │ │ │ │ │ └── TextField.tsx
│ │ │ │ │ ├── DateTimePickerField.jsx
│ │ │ │ │ ├── EditorField.jsx
│ │ │ │ │ ├── MultiSelectField.jsx
│ │ │ │ │ ├── RichTextField.jsx
│ │ │ │ │ ├── SelectField.jsx
│ │ │ │ │ ├── SingleFileInput/
│ │ │ │ │ │ ├── BadgePreview.jsx
│ │ │ │ │ │ ├── DeleteButton.jsx
│ │ │ │ │ │ ├── FilePreview.jsx
│ │ │ │ │ │ ├── ImagePreview.jsx
│ │ │ │ │ │ ├── __test__/
│ │ │ │ │ │ │ ├── BadgePreview.test.js
│ │ │ │ │ │ │ ├── ImagePreview.test.js
│ │ │ │ │ │ │ └── index.test.js
│ │ │ │ │ │ ├── index.jsx
│ │ │ │ │ │ └── translations.js
│ │ │ │ │ ├── TextField.tsx
│ │ │ │ │ ├── ToggleField.jsx
│ │ │ │ │ └── utils/
│ │ │ │ │ ├── mapError.js
│ │ │ │ │ └── propsAreEqual.js
│ │ │ │ ├── icons/
│ │ │ │ │ ├── GhostIcon.tsx
│ │ │ │ │ └── PointerIcon.tsx
│ │ │ │ ├── navigation/
│ │ │ │ │ ├── AdminPopupMenuList.tsx
│ │ │ │ │ ├── BrandingHead.tsx
│ │ │ │ │ ├── CourseSwitcherPopupMenu.tsx
│ │ │ │ │ ├── UserPopupMenuList.tsx
│ │ │ │ │ └── withRouter.jsx
│ │ │ │ ├── table/
│ │ │ │ │ ├── MuiTableAdapter/
│ │ │ │ │ │ ├── MuiFilterMenu.tsx
│ │ │ │ │ │ ├── MuiFilterMenuItem.tsx
│ │ │ │ │ │ ├── MuiTable.tsx
│ │ │ │ │ │ ├── MuiTableBody.tsx
│ │ │ │ │ │ ├── MuiTableHeader.tsx
│ │ │ │ │ │ ├── MuiTablePagination.tsx
│ │ │ │ │ │ ├── MuiTableRow.tsx
│ │ │ │ │ │ ├── MuiTableRowSelector.tsx
│ │ │ │ │ │ ├── MuiTableToolbar.tsx
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── translations.ts
│ │ │ │ │ ├── Table.tsx
│ │ │ │ │ ├── TanStackTableBuilder/
│ │ │ │ │ │ ├── columnsBuilder.ts
│ │ │ │ │ │ ├── csvGenerator.ts
│ │ │ │ │ │ ├── customFlexRender.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ └── useTanStackTableBuilder.tsx
│ │ │ │ │ ├── adapters/
│ │ │ │ │ │ ├── Body.ts
│ │ │ │ │ │ ├── Filter.ts
│ │ │ │ │ │ ├── Handlers.ts
│ │ │ │ │ │ ├── Header.ts
│ │ │ │ │ │ ├── Pagination.ts
│ │ │ │ │ │ ├── RowSelector.ts
│ │ │ │ │ │ ├── Sort.ts
│ │ │ │ │ │ ├── Table.ts
│ │ │ │ │ │ ├── Toolbar.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── builder/
│ │ │ │ │ │ ├── ColumnTemplate.ts
│ │ │ │ │ │ ├── TableTemplate.ts
│ │ │ │ │ │ ├── buildColumns.ts
│ │ │ │ │ │ ├── featureTemplates.ts
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── utils.ts
│ │ │ │ └── wrappers/
│ │ │ │ ├── AttributionsProvider.tsx
│ │ │ │ ├── AuthProvider.tsx
│ │ │ │ ├── ErrorBoundary.tsx
│ │ │ │ ├── FooterProvider.tsx
│ │ │ │ ├── I18nProvider.tsx
│ │ │ │ ├── Preload.tsx
│ │ │ │ ├── Providers.tsx
│ │ │ │ ├── RollbarWrapper.tsx
│ │ │ │ ├── StoreProvider.tsx
│ │ │ │ ├── ThemeProvider.tsx
│ │ │ │ └── ToastProvider.tsx
│ │ │ ├── constants/
│ │ │ │ ├── icons.ts
│ │ │ │ ├── index.js
│ │ │ │ ├── sharedConstants.ts
│ │ │ │ └── videoConstants.js
│ │ │ ├── containers/
│ │ │ │ ├── AppContainer/
│ │ │ │ │ ├── AppContainer.tsx
│ │ │ │ │ ├── AppLoader.ts
│ │ │ │ │ ├── GlobalAnnouncements.tsx
│ │ │ │ │ ├── ServerUnreachableBanner.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── AuthPagesContainer.tsx
│ │ │ │ ├── CourselessContainer.tsx
│ │ │ │ ├── DeleteConfirmation/
│ │ │ │ │ └── index.jsx
│ │ │ │ ├── NotificationPopup/
│ │ │ │ │ └── index.jsx
│ │ │ │ └── TableLegends.tsx
│ │ │ ├── helpers/
│ │ │ │ ├── __test__/
│ │ │ │ │ └── htmlFormatHelpers.test.js
│ │ │ │ ├── htmlFormatHelpers.js
│ │ │ │ ├── jobHelpers.ts
│ │ │ │ ├── mui-datatables-helpers.ts
│ │ │ │ ├── react-hook-form-helper.js
│ │ │ │ ├── reducer-helpers.js
│ │ │ │ ├── url-builders.js
│ │ │ │ ├── url-helpers.ts
│ │ │ │ └── videoHelpers.js
│ │ │ ├── history.js
│ │ │ ├── hooks/
│ │ │ │ ├── items/
│ │ │ │ │ ├── useItems.ts
│ │ │ │ │ ├── usePaginate.ts
│ │ │ │ │ ├── useSearch.ts
│ │ │ │ │ └── useSort.ts
│ │ │ │ ├── router/
│ │ │ │ │ ├── dynamicNest.ts
│ │ │ │ │ ├── redirect.tsx
│ │ │ │ │ └── usePrompt.tsx
│ │ │ │ ├── session.ts
│ │ │ │ ├── store.ts
│ │ │ │ ├── toast/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── loadingToast.ts
│ │ │ │ │ └── toast.tsx
│ │ │ │ ├── unread.ts
│ │ │ │ ├── useDebounce.ts
│ │ │ │ ├── useEffectOnce.ts
│ │ │ │ ├── useMedia.ts
│ │ │ │ └── useTranslation.ts
│ │ │ ├── moment.ts
│ │ │ ├── reducers/
│ │ │ │ ├── deleteConfirmation.js
│ │ │ │ └── notificationPopup.js
│ │ │ ├── translations/
│ │ │ │ ├── course/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── users/
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── roles.ts
│ │ │ │ ├── form.ts
│ │ │ │ ├── getHelp.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── messages.ts
│ │ │ │ └── table.ts
│ │ │ └── types.js
│ │ ├── routers/
│ │ │ ├── AuthenticatableApp.tsx
│ │ │ ├── AuthenticatedApp.tsx
│ │ │ ├── UnauthenticatedApp.tsx
│ │ │ ├── course/
│ │ │ │ ├── achievements.tsx
│ │ │ │ ├── admin.tsx
│ │ │ │ ├── assessments/
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ ├── questions.tsx
│ │ │ │ │ └── submissions.tsx
│ │ │ │ ├── forums.tsx
│ │ │ │ ├── groups.tsx
│ │ │ │ ├── index.tsx
│ │ │ │ ├── lessonPlan.tsx
│ │ │ │ ├── materials.tsx
│ │ │ │ ├── plagiarism.tsx
│ │ │ │ ├── scholaistic.tsx
│ │ │ │ ├── statistics.tsx
│ │ │ │ ├── surveys.tsx
│ │ │ │ ├── users.tsx
│ │ │ │ └── videos.tsx
│ │ │ ├── courseless/
│ │ │ │ ├── index.tsx
│ │ │ │ ├── instanceAdmin.tsx
│ │ │ │ ├── systemAdmin.tsx
│ │ │ │ └── users.tsx
│ │ │ ├── index.ts
│ │ │ ├── redirects.tsx
│ │ │ └── router.tsx
│ │ ├── store.ts
│ │ ├── theme/
│ │ │ ├── bouncing-dot.css
│ │ │ ├── colors.js
│ │ │ ├── github.css
│ │ │ ├── index.css
│ │ │ ├── mui-style.ts
│ │ │ ├── palette.js
│ │ │ ├── sidebar.css
│ │ │ └── syntax-highlighting.css
│ │ ├── types/
│ │ │ ├── channels/
│ │ │ │ ├── heartbeat.ts
│ │ │ │ └── liveMonitoring.ts
│ │ │ ├── components/
│ │ │ │ └── DataTable.ts
│ │ │ ├── course/
│ │ │ │ ├── achievements.ts
│ │ │ │ ├── admin/
│ │ │ │ │ ├── announcements.ts
│ │ │ │ │ ├── assessments.ts
│ │ │ │ │ ├── codaveri.ts
│ │ │ │ │ ├── comments.ts
│ │ │ │ │ ├── components.ts
│ │ │ │ │ ├── course.ts
│ │ │ │ │ ├── forums.ts
│ │ │ │ │ ├── leaderboard.ts
│ │ │ │ │ ├── lessonPlan.ts
│ │ │ │ │ ├── materials.ts
│ │ │ │ │ ├── notifications.ts
│ │ │ │ │ ├── ragWise.ts
│ │ │ │ │ ├── scholaistic.ts
│ │ │ │ │ ├── sidebar.ts
│ │ │ │ │ ├── stories.ts
│ │ │ │ │ └── videos.ts
│ │ │ │ ├── announcements.ts
│ │ │ │ ├── assessment/
│ │ │ │ │ ├── assessments.ts
│ │ │ │ │ ├── monitoring.ts
│ │ │ │ │ ├── question/
│ │ │ │ │ │ ├── forum-post-responses.ts
│ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ ├── multiple-responses.ts
│ │ │ │ │ │ ├── programming.ts
│ │ │ │ │ │ ├── rubric-based-responses.ts
│ │ │ │ │ │ ├── scribing.ts
│ │ │ │ │ │ ├── text-responses.ts
│ │ │ │ │ │ └── voice-responses.ts
│ │ │ │ │ ├── question-generation.ts
│ │ │ │ │ ├── questions.ts
│ │ │ │ │ ├── sessions.ts
│ │ │ │ │ ├── skills/
│ │ │ │ │ │ ├── skills.ts
│ │ │ │ │ │ └── userSkills.ts
│ │ │ │ │ ├── submission/
│ │ │ │ │ │ ├── annotations.ts
│ │ │ │ │ │ ├── answer/
│ │ │ │ │ │ │ ├── answer.ts
│ │ │ │ │ │ │ ├── forumPostResponse.ts
│ │ │ │ │ │ │ ├── index.ts
│ │ │ │ │ │ │ ├── multipleResponse.ts
│ │ │ │ │ │ │ ├── programming.ts
│ │ │ │ │ │ │ ├── rubricBasedResponse.ts
│ │ │ │ │ │ │ ├── scribing.ts
│ │ │ │ │ │ │ ├── textResponse.ts
│ │ │ │ │ │ │ └── voiceResponse.ts
│ │ │ │ │ │ ├── liveFeedback.ts
│ │ │ │ │ │ ├── logs.ts
│ │ │ │ │ │ ├── question/
│ │ │ │ │ │ │ └── types.ts
│ │ │ │ │ │ ├── submission-question.ts
│ │ │ │ │ │ └── submission.ts
│ │ │ │ │ └── submissions.ts
│ │ │ │ ├── comments.ts
│ │ │ │ ├── conditions.ts
│ │ │ │ ├── courseUsers.ts
│ │ │ │ ├── courses.ts
│ │ │ │ ├── disbursement.ts
│ │ │ │ ├── duplication.ts
│ │ │ │ ├── enrolRequests.ts
│ │ │ │ ├── experiencePointsRecords.ts
│ │ │ │ ├── forums.ts
│ │ │ │ ├── leaderboard.ts
│ │ │ │ ├── learn.ts
│ │ │ │ ├── lesson-plan/
│ │ │ │ │ └── todos.ts
│ │ │ │ ├── material/
│ │ │ │ │ ├── files.ts
│ │ │ │ │ └── folders.ts
│ │ │ │ ├── notifications.ts
│ │ │ │ ├── personalTimes.ts
│ │ │ │ ├── plagiarism.ts
│ │ │ │ ├── referenceTimelines.ts
│ │ │ │ ├── rubrics.ts
│ │ │ │ ├── scholaistic.ts
│ │ │ │ ├── statistics/
│ │ │ │ │ ├── answer.ts
│ │ │ │ │ └── assessmentStatistics.ts
│ │ │ │ ├── subscriptions.ts
│ │ │ │ ├── userInvitations.ts
│ │ │ │ ├── userNotifications.ts
│ │ │ │ ├── video/
│ │ │ │ │ └── submissions.ts
│ │ │ │ ├── videoSubmissions.ts
│ │ │ │ └── videos.ts
│ │ │ ├── home.ts
│ │ │ ├── index.ts
│ │ │ ├── jobs.ts
│ │ │ ├── store.ts
│ │ │ ├── system/
│ │ │ │ ├── courses.ts
│ │ │ │ ├── instance/
│ │ │ │ │ ├── components.ts
│ │ │ │ │ ├── invitations.ts
│ │ │ │ │ ├── roleRequests.ts
│ │ │ │ │ └── users.ts
│ │ │ │ └── instances.ts
│ │ │ └── users.ts
│ │ ├── utilities/
│ │ │ ├── ResizeObserver.ts
│ │ │ ├── TestApp.tsx
│ │ │ ├── array.ts
│ │ │ ├── authentication.ts
│ │ │ ├── downloadFile.ts
│ │ │ ├── index.ts
│ │ │ ├── mirrorCreator.ts
│ │ │ ├── socket.ts
│ │ │ ├── store.ts
│ │ │ └── test-utils.tsx
│ │ └── workers/
│ │ ├── constructors.ts
│ │ ├── heartbeat.sharedworker.ts
│ │ ├── heartbeat.worker.ts
│ │ ├── heartbeatChannel.ts
│ │ ├── listeners.ts
│ │ ├── monitoringDatabase.ts
│ │ ├── types.ts
│ │ └── withHeartbeatWorker.tsx
│ ├── css-includes.json
│ ├── env
│ ├── env.test
│ ├── jest.config.js
│ ├── locales/
│ │ ├── en.json
│ │ ├── ko.json
│ │ └── zh.json
│ ├── package.json
│ ├── postcss.config.js
│ ├── public/
│ │ └── index.html
│ ├── tailwind.config.ts
│ ├── tsconfig.eslint.json
│ ├── tsconfig.json
│ ├── webpack.common.js
│ ├── webpack.dev.js
│ ├── webpack.prod.js
│ └── webpack.profile.js
├── config/
│ ├── application.rb
│ ├── boot.rb
│ ├── cable.yml
│ ├── credentials/
│ │ ├── README.md
│ │ ├── test.key
│ │ └── test.yml.enc
│ ├── database.yml
│ ├── environment.rb
│ ├── environments/
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── i18n-js.yml
│ ├── i18n-tasks.yml
│ ├── image_optim.yml
│ ├── initializers/
│ │ ├── action_cable_acts_as_tenant.rb
│ │ ├── acts_as_tenant.rb
│ │ ├── application_controller_renderer.rb
│ │ ├── argument_deserializer.rb
│ │ ├── aws.rb
│ │ ├── backtrace_silencers.rb
│ │ ├── bullet.rb
│ │ ├── carrier_wave.rb
│ │ ├── content_security_policy.rb
│ │ ├── cookies_serializer.rb
│ │ ├── coverage.rb
│ │ ├── devise.rb
│ │ ├── extensions.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── formats_filter.rb
│ │ ├── inflections.rb
│ │ ├── keycloak.rb
│ │ ├── llm_langchain.rb
│ │ ├── locale.rb
│ │ ├── lograge.rb
│ │ ├── mail_delivery_job.rb
│ │ ├── mime_types.rb
│ │ ├── oembed.rb
│ │ ├── rack_mini_profiler.rb
│ │ ├── recaptcha.rb
│ │ ├── redis.rb
│ │ ├── send_file.rb
│ │ ├── session_store.rb
│ │ ├── sidekiq.rb
│ │ ├── userstamp.rb
│ │ ├── worker_http_listener.rb
│ │ └── wrap_parameters.rb
│ ├── locales/
│ │ ├── en/
│ │ │ ├── activemodel/
│ │ │ │ └── course/
│ │ │ │ └── experience_points/
│ │ │ │ └── forum_disbursement.yml
│ │ │ ├── activerecord/
│ │ │ │ ├── attributes.yml
│ │ │ │ └── errors.yml
│ │ │ ├── course/
│ │ │ │ └── assessment/
│ │ │ │ ├── answer/
│ │ │ │ │ └── text_response_comprehension_auto_grading.yml
│ │ │ │ ├── assessments.yml
│ │ │ │ ├── question/
│ │ │ │ │ ├── forum_post_response.yml
│ │ │ │ │ ├── multiple_responses.yml
│ │ │ │ │ ├── programming.yml
│ │ │ │ │ ├── scribing.yml
│ │ │ │ │ └── voice_responses.yml
│ │ │ │ └── question_bundle_assignments.yml
│ │ │ ├── csv.yml
│ │ │ ├── devise.yml
│ │ │ ├── errors.yml
│ │ │ ├── jobs.yml
│ │ │ ├── mailers.yml
│ │ │ └── time.yml
│ │ ├── ko/
│ │ │ ├── activemodel/
│ │ │ │ └── course/
│ │ │ │ └── experience_points/
│ │ │ │ └── forum_disbursement.yml
│ │ │ ├── activerecord/
│ │ │ │ ├── attributes.yml
│ │ │ │ └── errors.yml
│ │ │ ├── course/
│ │ │ │ └── assessment/
│ │ │ │ ├── answer/
│ │ │ │ │ └── text_response_comprehension_auto_grading.yml
│ │ │ │ ├── assessments.yml
│ │ │ │ ├── question/
│ │ │ │ │ ├── forum_post_response.yml
│ │ │ │ │ ├── multiple_responses.yml
│ │ │ │ │ ├── programming.yml
│ │ │ │ │ ├── scribing.yml
│ │ │ │ │ └── voice_responses.yml
│ │ │ │ └── question_bundle_assignments.yml
│ │ │ ├── csv.yml
│ │ │ ├── devise.yml
│ │ │ ├── errors.yml
│ │ │ ├── instance_user_role_request_mailer.yml
│ │ │ ├── jobs.yml
│ │ │ ├── mailers.yml
│ │ │ └── time.yml
│ │ └── zh/
│ │ ├── activemodel/
│ │ │ └── course/
│ │ │ └── experience_points/
│ │ │ └── forum_disbursement.yml
│ │ ├── activerecord/
│ │ │ ├── attributes.yml
│ │ │ └── errors.yml
│ │ ├── course/
│ │ │ └── assessment/
│ │ │ ├── answer/
│ │ │ │ └── text_response_comprehension_auto_grading.yml
│ │ │ ├── assessments.yml
│ │ │ ├── question/
│ │ │ │ ├── forum_post_response.yml
│ │ │ │ ├── multiple_responses.yml
│ │ │ │ ├── programming.yml
│ │ │ │ ├── scribing.yml
│ │ │ │ └── voice_responses.yml
│ │ │ └── question_bundle_assignments.yml
│ │ ├── csv.yml
│ │ ├── devise.yml
│ │ ├── errors.yml
│ │ ├── instance_user_role_request_mailer.yml
│ │ ├── jobs.yml
│ │ ├── mailers.yml
│ │ └── time.yml
│ ├── puma.rb
│ ├── routes.rb
│ ├── schedule.yml
│ ├── spring.rb
│ └── storage.yml
├── config.ru
├── db/
│ ├── migrate/
│ │ ├── .rubocop.yml
│ │ ├── 20141203044211_create_instances.rb
│ │ ├── 20141204122534_devise_create_users.rb
│ │ ├── 20141204122851_create_user_emails.rb
│ │ ├── 20141205065248_create_instance_users.rb
│ │ ├── 20141210044557_add_role_to_users_and_instance_users.rb
│ │ ├── 20141210105742_create_courses.rb
│ │ ├── 20141210133147_create_course_users.rb
│ │ ├── 20141222074908_add_userstamps_to_courses.rb
│ │ ├── 20150106073750_add_name_to_instances.rb
│ │ ├── 20150114024350_create_course_announcements.rb
│ │ ├── 20150114025131_create_instance_announcements.rb
│ │ ├── 20150116102204_add_name_to_users.rb
│ │ ├── 20150126080047_add_sticky_to_course_announcements.rb
│ │ ├── 20150129040648_create_system_announcements.rb
│ │ ├── 20150204075501_create_course_achievements.rb
│ │ ├── 20150206020132_create_course_levels.rb
│ │ ├── 20150309030221_create_attachments.rb
│ │ ├── 20150314025251_add_logo_to_courses.rb
│ │ ├── 20150316080645_unread_migration.rb
│ │ ├── 20150411065243_create_course_lesson_plan_items.rb
│ │ ├── 20150413043822_add_settings_to_instances_and_courses.rb
│ │ ├── 20150415033008_create_course_experience_points_records.rb
│ │ ├── 20150422152756_create_course_condition_levels.rb
│ │ ├── 20150425030128_set_timestamps_nullity.rb
│ │ ├── 20150426062119_create_course_conditions.rb
│ │ ├── 20150426062133_create_course_conditions_achievements.rb
│ │ ├── 20150512014731_add_workflow_state_to_course_users.rb
│ │ ├── 20150512015621_add_userstamps_to_course_users.rb
│ │ ├── 20150513110737_create_course_groups.rb
│ │ ├── 20150513111716_create_course_group_users.rb
│ │ ├── 20150614024340_combine_instance_system_announcements.rb
│ │ ├── 20150615014716_create_course_invitations.rb
│ │ ├── 20150615073135_add_fields_to_course_lesson_plan_item.rb
│ │ ├── 20150615075515_create_course_events.rb
│ │ ├── 20150616120237_create_activities_and_notifications.rb
│ │ ├── 20150617021911_create_course_lesson_plan_milestones.rb
│ │ ├── 20150624230355_add_course_registration_key_to_course.rb
│ │ ├── 20150702122955_instance_users_change_user_id_unique.rb
│ │ ├── 20150713125423_create_assessments.rb
│ │ ├── 20150721051322_add_course_assessment_logic.rb
│ │ ├── 20150721055754_change_experience_points_record_points_null.rb
│ │ ├── 20150721070705_create_user_identities.rb
│ │ ├── 20150726062900_create_course_assessment_question_multiple_response.rb
│ │ ├── 20150726130555_set_achievement_condition_nullity.rb
│ │ ├── 20150726130922_set_conditional_nullity.rb
│ │ ├── 20150728020832_add_schema_nullity.rb
│ │ ├── 20150728022835_rename_published_to_draft.rb
│ │ ├── 20150729133128_rename_course_events_to_course_lesson_plan_events.rb
│ │ ├── 20150730074301_rename_start_end_time_to_start_end_at.rb
│ │ ├── 20150731010032_rename_valid_from_to_start_end_at.rb
│ │ ├── 20150803065430_change_multiple_response_question_option_option_explanation_column_type.rb
│ │ ├── 20150803065716_create_materials.rb
│ │ ├── 20150803080715_add_assessment_answer_workflow_state.rb
│ │ ├── 20150812024950_add_fields_to_course_material_folders.rb
│ │ ├── 20151011151130_create_course_user_achievements.rb
│ │ ├── 20151016094007_create_discussions_and_forums.rb
│ │ ├── 20151016094008_create_forums.rb
│ │ ├── 20151016151834_add_root_folder_to_courses.rb
│ │ ├── 20151018122902_add_grade_to_course_assessment_answer.rb
│ │ ├── 20151021014315_create_course_assessment_question_text_response.rb
│ │ ├── 20151022105653_add_unique_index_to_forum_and_topic.rb
│ │ ├── 20151027050627_add_submission_grading_statistics.rb
│ │ ├── 20151028151258_add_unique_index_to_materials.rb
│ │ ├── 20151030063045_add_unique_index_to_course_material_folders.rb
│ │ ├── 20151031044810_add_course_assessment_answer_auto_grading.rb
│ │ ├── 20151101050627_create_folder_for_categories_and_assessments.rb
│ │ ├── 20151114043545_create_jobs.rb
│ │ ├── 20151114093538_link_course_assessment_answer_auto_grading_to_jobs.rb
│ │ ├── 20151117141053_unread_polymorphic_reader_migration.rb
│ │ ├── 20151119020459_create_course_assessment_programming_questions.rb
│ │ ├── 20151121070719_create_polyglot_languages.rb
│ │ ├── 20151121082432_integrate_assessments_with_polyglot_framework.rb
│ │ ├── 20151122011709_create_course_assessment_programming_evaluations.rb
│ │ ├── 20151202030421_add_profile_photo_to_users.rb
│ │ ├── 20151210055839_create_course_condition_assessments.rb
│ │ ├── 20151212091754_normalise_programming_question_file_names.rb
│ │ ├── 20151212232827_add_token_authentication_to_user.rb
│ │ ├── 20151214080700_add_package_to_programming_evaluation.rb
│ │ ├── 20151214081508_add_unique_index_to_course_levels.rb
│ │ ├── 20151224034135_add_display_mode_to_assessments.rb
│ │ ├── 20151228030006_add_weight_to_questions.rb
│ │ ├── 20160119055307_add_correct_to_assessment_answers.rb
│ │ ├── 20160124054745_add_exit_code_to_programming_evaluation.rb
│ │ ├── 20160126094510_add_badge_to_course_achievements.rb
│ │ ├── 20160220081731_rename_assessment_tags_to_skills.rb
│ │ ├── 20160220092350_add_course_to_skill_and_skill_branch.rb
│ │ ├── 20160226013208_create_course_assessment_answer_programming_file_annotations.rb
│ │ ├── 20160229082515_create_attachment_references.rb
│ │ ├── 20160330031839_create_course_discussion_post_votes.rb
│ │ ├── 20160420005403_change_course_groups_from_user_to_course_user.rb
│ │ ├── 20160429135101_add_attributes_to_course_discussion_topics.rb
│ │ ├── 20160523093423_add_field_to_course_discussion_topics.rb
│ │ ├── 20160628052136_add_staff_only_comments_to_questions.rb
│ │ ├── 20160714053644_add_timestamps_to_course_assessment_answers.rb
│ │ ├── 20160716091234_add_autograded_to_course_assessments.rb
│ │ ├── 20160722020938_add_time_zone_to_users.rb
│ │ ├── 20160729022656_add_fields_to_course_assessment_question_programming_test_cases.rb
│ │ ├── 20160730044448_chang_attachment_references.rb
│ │ ├── 20160801084814_rename_question_type_to_grading_scheme.rb
│ │ ├── 20160808023535_change_course_assessment_questions_title_nullity.rb
│ │ ├── 20160811064336_change_test_cases_expected_type.rb
│ │ ├── 20160815141617_prevent_duplicate_submissions.rb
│ │ ├── 20160822092000_add_publisher_to_submissions.rb
│ │ ├── 20160823091240_add_unique_index_to_read_marks.rb
│ │ ├── 20160823094126_add_unique_index_to_multiple_response_answer_options.rb
│ │ ├── 20160830023835_alter_grade_type.rb
│ │ ├── 20160906091734_add_fields_to_course_assessment_answer_text_responses.rb
│ │ ├── 20160908100211_rename_programming_auto_grading_test_result_messages.rb
│ │ ├── 20160916101014_change_discussion_posts_title.rb
│ │ ├── 20160920101847_add_hide_text_to_course_assessment_question_text_responses.rb
│ │ ├── 20161003094742_create_lesson_plan_todos.rb
│ │ ├── 20161006063146_rename_assessments_display_mode.rb
│ │ ├── 20161007061116_add_fields_to_assessments.rb
│ │ ├── 20161013115452_migrate_graded_submissions_to_published.rb
│ │ ├── 20161020020353_add_todos_for_existing_lesson_plan_items.rb
│ │ ├── 20161027020646_add_package_type_to_course_assessment_question_programming.rb
│ │ ├── 20161027074807_add_session_id_to_submissions.rb
│ │ ├── 20161102022455_add_stdout_stderr_to_course_assessment_answer_programming_auto_grading.rb
│ │ ├── 20161107023238_add_attempt_limit_to_programming_questions.rb
│ │ ├── 20161108030759_add_gamified_to_courses.rb
│ │ ├── 20161116075305_add_tabbed_view_to_course_assessments.rb
│ │ ├── 20161202071856_add_skippable_to_assessments.rb
│ │ ├── 20161206101644_remove_mode_and_invert_draft.rb
│ │ ├── 20161207013914_create_course_survey_tables.rb
│ │ ├── 20161214050848_add_sent_at_to_course_user_invitations.rb
│ │ ├── 20161219105620_change_course_user_invitations.rb
│ │ ├── 20161223123359_create_course_enrol_requests.rb
│ │ ├── 20161227125455_remove_workflow_state_from_course_users.rb
│ │ ├── 20170102053335_create_course_video_tables.rb
│ │ ├── 20170103104020_create_course_lectures.rb
│ │ ├── 20170110022335_remove_extra_bonus_exp_from_lesson_plan.rb
│ │ ├── 20170115105609_add_delayed_grade_publication_to_course_assessments.rb
│ │ ├── 20170116103602_add_tokens_to_course_lesson_plan_items.rb
│ │ ├── 20170117145558_add_fields_to_courses.rb
│ │ ├── 20170117164747_add_awarded_at_and_draft_exp_to_course_experience_points_records.rb
│ │ ├── 20170120063357_change_default_value_of_assessment_questions_weight.rb
│ │ ├── 20170128041649_change_survey_tables.rb
│ │ ├── 20170203020915_add_weight_to_course_assessment_question_multiple_response_options.rb
│ │ ├── 20170210073247_add_selected_to_survey_answer_options.rb
│ │ ├── 20170214062036_add_index_for_survey_response_user.rb
│ │ ├── 20170217041431_add_survey_booleans.rb
│ │ ├── 20170220123952_remove_image_from_survey_question_option.rb
│ │ ├── 20170222101701_remove_default_from_groups.rb
│ │ ├── 20170302054635_add_submitted_at_to_submissions.rb
│ │ ├── 20170306051518_rename_lectures_to_virtual_classrooms.rb
│ │ ├── 20170307043218_add_instructor_id_to_virtual_classrooms.rb
│ │ ├── 20170307080839_add_timestamp_to_trackable_jobs.rb
│ │ ├── 20170307090147_add_time_limit_to_existing_programming_questions.rb
│ │ ├── 20170308044737_add_recorded_videos_to_virtual_classrooms.rb
│ │ ├── 20170308073855_create_course_assessment_submission_logs.rb
│ │ ├── 20170308074359_add_course_assessment_submission_question.rb
│ │ ├── 20170309094211_add_section_id_to_survey_questions.rb
│ │ ├── 20170407083553_add_reminded_at_and_allow_responsee_to_surveys.rb
│ │ ├── 20170420063829_remove_length_limit_of_expression.rb
│ │ ├── 20170426024809_remove_constraint_in_skills.rb
│ │ ├── 20170506010828_create_course_assessment_question_scribings.rb
│ │ ├── 20170510233359_remove_selected_from_survey_answer_options.rb
│ │ ├── 20170515061739_add_more_options_to_course_assessments.rb
│ │ ├── 20170522104534_regroup_course_settings.rb
│ │ ├── 20170528035408_create_course_asse
================================================
FILE CONTENTS
================================================
================================================
FILE: .circleci/config.yml
================================================
version: 2.1
orbs:
codecov: codecov/codecov@5.4.3
executors:
node:
docker:
- image: cimg/node:22.22.0
working_directory: ~/repo
resource_class: large
ruby_with_postgres:
parameters:
collects_rails_coverage:
type: boolean
default: false
docker:
- image: cimg/ruby:3.3.5-browsers
environment:
PG_HOST: localhost
PG_USER: ubuntu
RAILS_ENV: test
BUNDLE_APP_CONFIG: ~/repo/.bundle
DATABASE_URL: 'postgres://ubuntu@localhost:5432/coursemology_test'
COLLECT_COVERAGE: << parameters.collects_rails_coverage >>
- image: pgvector/pgvector:pg16
environment:
POSTGRES_USER: ubuntu
POSTGRES_DB: coursemology_test
POSTGRES_PASSWORD: Testing1234
- image: cimg/redis:7.2.3
working_directory: ~/repo
resource_class: large
commands:
checkout_with_submodules:
steps:
- checkout
- run:
name: Checkout submodules
command: git submodule update --init --recursive
rehydrate_ruby_deps:
steps:
- restore_cache:
name: Restore Ruby dependencies cache
keys:
- v3.3.5-ruby-{{ checksum "Gemfile.lock" }}
- v3.3.5-ruby-
- run:
name: Install Bundler
command: gem install bundler:2.5.9
- run:
name: Install Ruby dependencies
command: bundle install --jobs=4 --retry=3 --path vendor/bundle --without development:production --deployment
- save_cache:
paths:
- ./vendor/bundle
- ./.bundle
key: v3.3.5-ruby-{{ checksum "Gemfile.lock" }}
rehydrate_node_deps:
steps:
- restore_cache:
name: Restore client Yarn dependencies cache
keys:
- v22.22.0-node-{{ checksum "client/yarn.lock" }}-{{ checksum "client/vendor/recorderjs/package.json" }}
- v22.22.0-node-
- run:
name: Install client Yarn dependencies
working_directory: client
command: yarn run clean-install
- save_cache:
paths:
- ./client/node_modules
- ./client/vendor/recorderjs/node_modules
key: v22.22.0-node-{{ checksum "client/yarn.lock" }}-{{ checksum "client/vendor/recorderjs/package.json" }}
restore_client_cache:
steps:
- restore_cache:
name: Restore client cache
keys:
- v1-yarn-build-{{ .Revision }}
build_and_cache_client:
steps:
- restore_client_cache
- run:
name: Add env file to client folder
working_directory: client
command: |
touch .env.test
echo GOOGLE_RECAPTCHA_SITE_KEY="${GOOGLE_RECAPTCHA_SITE_KEY}" >> .env.test
echo ROLLBAR_POST_CLIENT_ITEM_KEY="${ROLLBAR_POST_CLIENT_ITEM_KEY}" >> .env.test
echo SUPPORT_EMAIL="${SUPPORT_EMAIL}" >> .env.test
echo DEFAULT_LOCALE="${DEFAULT_LOCALE}" >> .env.test
echo DEFAULT_TIME_ZONE="${DEFAULT_TIME_ZONE}" >> .env.test
echo OIDC_AUTHORITY="${OIDC_AUTHORITY}" >> .env.test
echo OIDC_CLIENT_ID="${OIDC_CLIENT_ID}" >> .env.test
echo OIDC_REDIRECT_URI="${OIDC_REDIRECT_URI}" >> .env.test
- run:
name: Build client
working_directory: client
command: yarn build:test
environment:
AVAILABLE_CPUS: 4
- save_cache:
paths:
- ./client/build
key: v1-yarn-build-{{ .Revision }}
build_and_run_auth_server:
steps:
- run:
name: Create coursemology_keycloak db
command: |
DB_CONTAINER_ID=$(docker ps -q --filter ancestor=pgvector/pgvector:pg16)
docker exec $DB_CONTAINER_ID psql -c "CREATE DATABASE coursemology_keycloak OWNER ubuntu;" -U ubuntu -d postgres
docker exec $DB_CONTAINER_ID psql -c "CREATE DATABASE coursemology OWNER ubuntu;" -U ubuntu -d postgres
- run:
name: Update docker compose file
working_directory: authentication
command: |
sed -i '/ports:/,+1d' docker-compose.yml
- run:
name: Update realm config files
working_directory: authentication/import
command: |
sed -i 's/host.docker.internal/localhost/g' coursemology_realm.json
sed -i 's/\"postgres\"/\"ubuntu\"/g' coursemology_realm.json
- run:
name: Add env file to authentication folder
working_directory: authentication
command: |
touch .env
echo KC_NETWORK_MODE="container:$(docker ps -q --filter ancestor=pgvector/pgvector:pg16)" >> .env
echo KC_DB="postgres" >> .env
echo KC_DB_URL="jdbc:postgresql://localhost:5432/coursemology_keycloak" >> .env
echo KC_DB_USERNAME="ubuntu" >> .env
echo KC_DB_PASSWORD="" >> .env
echo KC_HOSTNAME="localhost" >> .env
echo KEYCLOAK_ADMIN="admin" >> .env
echo KEYCLOAK_ADMIN_PASSWORD="password" >> .env
- run:
name: Build authentication image
working_directory: authentication
command: docker build -t coursemology_auth .
- run:
name: Run authentication server
working_directory: authentication
command: docker compose up
background: true
- run:
name: Wait for Auth server
command: |
curl -s --retry 1000 --retry-delay 1 --retry-connrefused -4 http://localhost:8443
setup_db:
steps:
- run:
name: Set up test database
command: bundle exec rake db:setup
environment:
COLLECT_COVERAGE: false
serve_static_site:
steps:
- run:
name: Download dirt-cheap-rocket
command: curl https://github.com/Coursemology/dirt-cheap-rocket/releases/latest/download/dirt-cheap-rocket.cjs -o dirt-cheap-rocket.cjs -L
- run:
name: Serve static site
command: node dirt-cheap-rocket.cjs
background: true
environment:
DCR_CLIENT_PORT: 3200
DCR_SERVER_PORT: 7979
DCR_PUBLIC_PATH: /static
DCR_ASSETS_DIR: client/build
serve_rails_server:
steps:
- run:
name: Add env file to main folder
command: |
touch .env
echo RAILS_HOSTNAME="localhost:3000" >> .env
echo KEYCLOAK_AUTH_SERVER_URL="http://localhost:8443/" >> .env
echo KEYCLOAK_AUTH_JWKS_URL="http://localhost:8443/realms/coursemology_test/protocol/openid-connect/certs" >> .env
echo KEYCLOAK_AUTH_INSTROPECTION_URL="http://localhost:8443/realms/coursemology_test/protocol/openid-connect/token/introspect" >> .env
echo KEYCLOAK_ISS="http://localhost:8443/realms/coursemology_test" >> .env
echo KEYCLOAK_AUD="account" >> .env
echo KEYCLOAK_REALM="coursemology_test" >> .env
- run:
name: Serve Rails server
command: bundle exec rails s -p 7979
background: true
- run:
name: Wait for Rails server
command: |
curl -s --retry 1000 --retry-delay 1 --retry-connrefused -4 http://localhost:7979
terminate_rails_and_wait_for_coverage_results:
steps:
- run:
name: Terminate Rails server
command: pkill -SIGINT -f puma
- run:
name: Wait for Rails coverage results
no_output_timeout: 5m
command: until [ -f coverage/coursemology.lcov ]; do sleep 1; done
persist_coverage_reports:
steps:
- run:
name: Assign unique coverage filename
command: |
mv coverage/coursemology.lcov coverage/cov-<< parameters.prefix >>-${CIRCLE_NODE_INDEX}.lcov
- persist_to_workspace:
root: coverage
paths:
- cov-*.lcov
parameters:
prefix:
type: string
setup_docker_layer_cache:
steps:
- setup_remote_docker:
version: docker26
docker_layer_caching: true
# Install Ghostscript so `identify` in ImageMagick works with PDF files.
# To remove PDF security policy for ImageMagick (Ubuntu 20.04), see https://stackoverflow.com/questions/52998331/imagemagick-security-policy-pdf-blocking-conversion
# This is currently not used as CircleCI would fail to install occasionally.
install_ghostscript_and_imagemagick:
steps:
- run:
name: Install Ghostscript and ImageMagick
command: |
sudo apt update
sudo apt install imagemagick
sudo apt install ghostscript
sudo sed -i '/disable ghostscript format types/,+6d' /etc/ImageMagick-6/policy.xml
jobs:
build_client:
executor: node
steps:
- checkout_with_submodules
- rehydrate_node_deps
- build_and_cache_client
test_playwright:
executor:
name: ruby_with_postgres
collects_rails_coverage: true
parallelism: 10
steps:
- checkout_with_submodules
- setup_docker_layer_cache
- rehydrate_ruby_deps
- restore_client_cache
- setup_db
- serve_static_site
- serve_rails_server
- build_and_run_auth_server
# Replace both archive and security repositories
# https://support.circleci.com/hc/en-us/articles/37474192881179-Resolving-Unable-to-connect-to-archive-ubuntu-com-Error-in-CircleCI
- run:
name: Change Ubuntu archive mirrors
command: |
sudo sed -i 's|http://archive.ubuntu.com|http://mirrors.rit.edu|g' /etc/apt/sources.list
sudo sed -i 's|http://security.ubuntu.com|http://mirrors.rit.edu|g' /etc/apt/sources.list
- run:
name: Install Playwright dependencies
working_directory: tests
command: |
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo tee /etc/apt/trusted.gpg.d/google.asc >/dev/null
yarn run clean-install
yarn prepare
- run:
name: Run Playwright tests
working_directory: tests
command: |
SHARD="$((${CIRCLE_NODE_INDEX}+1))"; npx playwright test --shard=${SHARD}/${CIRCLE_NODE_TOTAL} --reporter=junit
environment:
PLAYWRIGHT_JUNIT_OUTPUT_NAME: results.xml
- run:
name: Generate code coverage
working_directory: tests
command: yarn coverage
- terminate_rails_and_wait_for_coverage_results
- persist_coverage_reports:
prefix: playwright-rails
- store_test_results:
path: ~/repo/tests/results.xml
- run:
name: Assign unique test results filename
when: always
working_directory: tests
command: |
mv test-results test-results-${CIRCLE_NODE_INDEX}
- persist_to_workspace:
root: tests
paths:
- test-results-*
test_rspec:
executor:
name: ruby_with_postgres
collects_rails_coverage: true
parallelism: 30
steps:
- checkout_with_submodules
- setup_docker_layer_cache
- rehydrate_ruby_deps
- restore_client_cache
- setup_db
- serve_static_site
- build_and_run_auth_server
- run:
name: Run RSpec tests
no_output_timeout: 10m
command: |
mkdir ~/rspec
circleci tests glob "spec/**/*_spec.rb" | circleci tests run --command="xargs bundle exec rspec --format progress --format RspecJunitFormatter -o ~/rspec/rspec.xml" --verbose --split-by=timings
- persist_coverage_reports:
prefix: rspec-rails
- store_test_results:
path: ~/rspec
process_test_results:
docker:
- image: cimg/base:2025.06
steps:
# Need the source code to be present in the workspace for codecov to accept the report
- checkout
- attach_workspace:
at: workspace
- run:
name: Combine all lcov reports
command: |
sudo apt-get update
sudo apt-get install lcov
lcov $(printf -- '--add-tracefile %s ' workspace/cov-*.lcov) --output-file workspace/coverage-combined.lcov --branch-coverage --ignore-errors inconsistent
- codecov/upload:
upload_name: coverage-combined
disable_search: true
files: workspace/coverage-combined.lcov
flags: backend
- run:
name: Zip all test results
command: |
zip -r test-results.zip workspace/*
- store_artifacts:
path: test-results.zip
factorybot_lint:
executor: ruby_with_postgres
steps:
- checkout
- rehydrate_ruby_deps
- setup_db
- run:
name: Run FactoryBot lint
command: bundle exec rake factory_bot:lint
jslint:
executor: node
steps:
- checkout_with_submodules
- rehydrate_node_deps
- run:
name: Run ESLint and Prettier checks
working_directory: client
command: yarn lint
jstest:
executor: node
steps:
- checkout_with_submodules
- rehydrate_node_deps
- run:
name: Build translations
working_directory: client
command: yarn run build:translations
- run:
name: Run Jest tests
working_directory: client
command: yarn testci
i18n_en:
executor: ruby_with_postgres
steps:
- checkout
- rehydrate_ruby_deps
- setup_db
- run:
name: Check for unused translations (English)
command: bundle exec i18n-tasks unused --locales en
- run:
name: Check for missing translations (English)
command: bundle exec i18n-tasks missing --locales en
i18n_zh:
executor: ruby_with_postgres
steps:
- checkout
- rehydrate_ruby_deps
- setup_db
- run:
name: Check for unused translations (Mandarin)
command: bundle exec i18n-tasks unused --locales zh
- run:
name: Check for missing translations (Mandarin)
command: bundle exec i18n-tasks missing --locales zh
i18n_ko:
executor: ruby_with_postgres
steps:
- checkout
- rehydrate_ruby_deps
- setup_db
- run:
name: Check for unused translations (Korean)
command: bundle exec i18n-tasks unused --locales ko
- run:
name: Check for missing translations (Korean)
command: bundle exec i18n-tasks missing --locales ko
workflows:
build_and_test_and_lint:
jobs:
- jslint
- jstest
- build_client
- i18n_en
- i18n_zh
- i18n_ko
- factorybot_lint
- test_rspec:
requires:
- build_client
- factorybot_lint
- test_playwright:
requires:
- build_client
- process_test_results:
requires:
- test_rspec
- test_playwright
================================================
FILE: .codecov.yml
================================================
codecov:
notify:
require_ci_to_pass: no
flags:
frontend:
paths:
- client/app/
backend:
paths:
- app/
- lib/
coverage:
precision: 2
round: up
range: '70...100'
status:
project:
default: off
frontend:
target: auto
threshold: 0.1%
flags:
- frontend
backend:
target: auto
threshold: 0.1%
flags:
- backend
patch: yes
changes: no
parsers:
gcov:
branch_detection:
conditional: yes
loop: yes
method: no
macro: no
comment: false
================================================
FILE: .github/ISSUE_TEMPLATE/1-bug-report.yml
================================================
name: 🐞 Bug Report
description: File a bug/issue
labels: ["Bug"]
assignees:
- cysjonathan
- adi-herwana-nus
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: Current Behavior
description: A concise description of what you're experiencing.
validations:
required: false
- type: textarea
attributes:
label: Expected Behavior
description: A concise description of what you expected to happen.
validations:
required: false
- type: textarea
attributes:
label: Steps To Reproduce
description: Steps to reproduce the behavior.
placeholder: |
1. In this environment...
2. With this configuration...
3. Run '...'
4. See error...
validations:
required: false
- type: textarea
attributes:
label: Anything else?
description: |
Links? References? Error Messages? Screenshots? Anything that will give us more context about the issue you are encountering!
Tip: You can attach images or files by clicking this area to highlight it and then dragging files in.
validations:
required: false
================================================
FILE: .github/ISSUE_TEMPLATE/2-feature-request.yml
================================================
name: 💡 Feature Request
description: Suggest a new feature or enhancement
labels: ["Feature"]
assignees:
- cysjonathan
- adi-herwana-nus
body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if a feature request already exists for what you're proposing.
options:
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
label: Problem Statement
description: What problem would this feature solve? What is the current limitation?
placeholder: "As a [user type], I want [goal] so that [reason]..."
validations:
required: false
- type: textarea
attributes:
label: Proposed Solution
description: Describe the feature you'd like to see implemented.
placeholder: "I would like to see..."
validations:
required: false
- type: textarea
attributes:
label: Alternative Solutions
description: Have you considered any alternative solutions or workarounds?
validations:
required: false
- type: textarea
attributes:
label: Anything else?
description: |
Mockups? Screenshots? Anything that will give us more context about the feature you are requesting!
Tip: You can attach images or files by clicking this area to highlight it and then dragging files in.
validations:
required: false
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: true
contact_links:
- name: User Guide
url: https://coursemology.github.io/coursemology-help/
about: Please refer to the User Guide for help on using Coursemology
- name: Developer Guide
url: https://github.com/Coursemology/coursemology2/wiki
about: Please refer to the Developer Guide for help on developing Coursemology
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: bundler
directory: '/'
schedule:
interval: daily
open-pull-requests-limit: 10
cooldown:
default-days: 5
semver-major-days: 30
semver-minor-days: 7
semver-patch-days: 3
groups:
dev-dependencies:
dependency-type: development
aws-dependencies:
patterns:
- 'aws-*'
- 'fog-aws'
- package-ecosystem: npm
directory: '/client'
schedule:
interval: daily
open-pull-requests-limit: 10
cooldown:
default-days: 5
semver-major-days: 30
semver-minor-days: 7
semver-patch-days: 3
- package-ecosystem: npm
directory: '/tests'
schedule:
interval: daily
open-pull-requests-limit: 10
cooldown:
default-days: 5
semver-major-days: 30
semver-minor-days: 7
semver-patch-days: 3
groups:
all-dependencies:
patterns:
- '*'
================================================
FILE: .gitignore
================================================
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'
# Ignore bundler config and gems.
/.bundle
/vendor/bundle
# Ignore user-specific Intellij project files
/.idea/*
# Ignore user-specific VSCode project files
.vscode
# Ignore credentials files which may contain sensitive information
/config/credentials/*.crt
/config/credentials/*.key
/config/credentials/*.yml.enc
!/config/credentials/test.key
!/config/credentials/test.yml.enc
# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal
# Ignore all logfiles and tempfiles.
/log/*.log
/log/*.log.[0-9]*
/tmp
# Ignore ruby-version file
/.ruby-version
# Ignore byebug_history file
/.byebug_history
# Ignore generated documentation
/.yardoc/*
/doc/*
# Ignore generated code coverage information
/spec/coverage/*
/coverage/*
/client/coverage/*
# Ignore public download/upload folders
/public/downloads/*
/public/uploads/*
# Ignore installed node libraries and log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
node_modules
# Ignore generated js bundles
/public/webpack/*
# Ignore eslint cache
/client/.eslintcache
# Ignore build for client
/client/build
.DS_Store
# Ignore local node version
.node-version
# Ignore env files
.env
.env.*
# Ignore Playwright results
test-results/
playwright-report/
playwright/.cache/
.nyc_output
coverage/
dump.rdb
compiled-locales
================================================
FILE: .gitmodules
================================================
[submodule "vendor/assets/javascripts/recorderjs"]
path = client/vendor/recorderjs
url = https://github.com/mattdiamond/Recorderjs.git
ignore = dirty
[submodule "authentication/singular-keycloak-database-federation"]
path = authentication/singular-keycloak-database-federation
url = https://github.com/Coursemology/singular-keycloak-database-federation.git
================================================
FILE: .hound.yml
================================================
fail_on_violations: true
rubocop:
config_file: .rubocop.yml
version: 1.22.1
javascript:
enabled: false
================================================
FILE: .rspec
================================================
--color
--format progress
--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log
================================================
FILE: .rubocop.unhound.yml
================================================
Style/CollectionMethods:
Enabled: true
PreferredMethods:
reduce:
inject: 'reduce'
find:
detect: 'find'
Lint/AssignmentInCondition:
Enabled: true
Lint/EachWithObjectArgument:
Enabled: true
Lint/LiteralAsCondition:
Description: Checks of literals used in conditions.
Enabled: true
Lint/LiteralInInterpolation:
Description: Checks for literals used in interpolation.
Enabled: true
Lint/SuppressedException:
Enabled: true
Metrics/AbcSize:
Enabled: true
Metrics/ClassLength:
Enabled: true
Metrics/CyclomaticComplexity:
Enabled: true
Metrics/MethodLength:
Enabled: true
Metrics/ModuleLength:
Enabled: true
Metrics/ParameterLists:
Enabled: true
Metrics/PerceivedComplexity:
Enabled: true
Naming/AccessorMethodName:
Enabled: true
Naming/FileName:
Enabled: true
Style/Alias:
Enabled: true
EnforcedStyle: prefer_alias_method
Style/Documentation:
Enabled: true
Style/DoubleNegation:
Enabled: true
Style/EachWithObject:
Enabled: true
Style/EmptyLiteral:
Enabled: true
Style/GuardClause:
Enabled: true
Style/IfUnlessModifier:
Enabled: true
Style/ModuleFunction:
Enabled: true
Style/OneLineConditional:
Enabled: true
Style/PercentLiteralDelimiters:
Enabled: true
Style/PerlBackrefs:
Enabled: true
Style/SignalException:
Enabled: true
Style/SingleLineBlockParams:
Enabled: true
Style/SingleLineMethods:
Enabled: true
Style/SpecialGlobalVars:
Enabled: true
Style/TrailingCommaInArguments:
Enabled: true
Style/TrailingCommaInArrayLiteral:
Enabled: true
Style/TrailingCommaInHashLiteral:
Enabled: true
Style/VariableInterpolation:
Enabled: true
Style/WhenThen:
Enabled: true
================================================
FILE: .rubocop.yml
================================================
inherit_from:
- .rubocop.unhound.yml
AllCops:
NewCops: enable
Exclude:
- 'bin/*'
- 'db/seeds.rb'
- 'db/schema.rb'
- 'db/migrate/*'
- 'vendor/bundle/**/*'
- 'client/**/*'
TargetRubyVersion: 3.0
Bundler/OrderedGems:
Enabled: false
Layout/DotPosition:
EnforcedStyle: trailing
Layout/EmptyLineAfterMagicComment:
Enabled: false
Layout/FirstHashElementIndentation:
EnforcedStyle: consistent
Layout/LineLength:
Max: 120
Lint/ConstantDefinitionInBlock:
Enabled: false
Metrics/AbcSize:
Max: 20
Metrics/BlockLength:
Enabled: false
Metrics/MethodLength:
Max: 15
CountAsOne: ['array', 'hash', 'heredoc']
Style/AsciiComments:
AllowedChars: ['©', '├', '─', '└']
Style/ClassAndModuleChildren:
EnforcedStyle: compact
Style/Documentation:
Enabled: false
Style/EmptyMethod:
Enabled: false
Style/HashAsLastArrayItem:
EnforcedStyle: no_braces
Style/LambdaCall:
Exclude:
- '**/*.json.jbuilder'
Style/NumericPredicate:
EnforcedStyle: comparison
Style/ParallelAssignment:
Enabled: false
Style/RegexpLiteral:
AllowInnerSlashes: true
Style/SignalException:
EnforcedStyle: only_raise
Style/StringLiterals:
EnforcedStyle: single_quotes
Style/SymbolArray:
Enabled: false
Style/TernaryParentheses:
EnforcedStyle: require_parentheses_when_complex
Style/WordArray:
Enabled: false
================================================
FILE: .yardopts
================================================
--protected
--no-private
--embed-mixin ClassMethods
--markup markdown
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing
We have shifted our contributing guides to our [Wiki](https://github.com/Coursemology/coursemology2/wiki).
Please consult the guide before submitting a pull request to this repository.
================================================
FILE: Gemfile
================================================
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '3.3.5'
# These gems are included in Ruby defaults for now,
# but they will have to be included separately in future versions.
gem 'ostruct'
gem 'csv'
# For Windows devs
gem 'tzinfo-data', platforms: [:mswin, :mswin64]
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 7.2.2'
# Use PostgreSQL for the backend
gem 'pg'
# Enables CORS configuration to allow sharing resources with client on another domain
gem 'rack-cors'
# Instance/Course settings
gem 'settings_on_rails', git: 'https://github.com/Coursemology/settings_on_rails'
# Manage read/unread status
gem 'unread', '~> 0.14.0'
# Extension for validating hostnames and domain names
gem 'validates_hostname'
# A Ruby state machine library
gem 'workflow'
gem 'workflow-activerecord', '>= 4.1', '< 7.0'
# Add creator_id and updater_id attributes to models
gem 'activerecord-userstamp', git: 'https://github.com/Coursemology/activerecord-userstamp.git'
# Allow actions to be deferred until after a record is committed.
gem 'after_commit_action'
# Allow declaring the calculated attributes of a record
gem 'calculated_attributes', git: 'https://github.com/Coursemology/calculated_attributes.git'
# For multiple table inheritance
# TODO: Figure out breaking changes in v2 as polymorphism is not working correctly.
gem 'active_record-acts_as', git: 'https://github.com/Coursemology/active_record-acts_as.git'
# Organise ActiveRecord model into a tree structure
gem 'edge'
# Upsert action for Postgres with validations
gem 'active_record_upsert', git: 'https://github.com/jesjos/active_record_upsert', ref: 'c3e07ae'
# Create pretty URLs and work with human-friendly strings
gem 'friendly_id'
# HTML Pipeline and dependencies
gem 'html-pipeline'
gem 'htmlentities'
gem 'sanitize', '>= 4.6.3'
gem 'rinku'
gem 'rouge', '~> 3'
gem 'ruby-oembed'
# to help obtaining app wide URI that uniquely identifies model instance
# (used in notify_identifier for NOTIFY/LISTEN to jobs)
gem 'globalid'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder'
# Slim as the templating language
gem 'slim-rails'
# Paginator for Rails
gem 'kaminari'
# Work with Docker
gem 'docker-api'
gem 'recaptcha'
gem 'rexml'
gem 'yajl-ruby', '~> 1.4'
# Page profiler
gem 'rack-mini-profiler'
gem 'redis-rails'
group :development do
# Spring speeds up development by keeping your application running in the background.
# Read more: https://github.com/rails/spring
gem 'spring', platforms: [:ruby]
gem 'listen'
# Helps to prevent database slowdowns
gem 'lol_dba', require: false
# General cleanliness
gem 'traceroute', require: false
# bundle exec yardoc generates the API under doc/.
# Use yard stats --list-undoc to find what needs documenting.
gem 'yard', group: :doc
end
group :test do
gem 'email_spec'
gem 'rspec-html-matchers'
gem 'should_not'
gem 'shoulda-matchers'
# Capybara for feature testing
gem 'capybara'
gem 'capybara-selenium'
# Make screen shots in tests, helps with the debugging of JavaScript tests.
gem 'capybara-screenshot'
end
group :development, :test do
# Use RSpec for Behaviour testing
gem 'rspec-rails', '~> 8'
gem 'rubocop', '~> 1.86'
# Factory Bot for factories
# fix for https://github.com/thoughtbot/factory_bot/issues/1690
gem 'factory_bot', '~> 6.6.0'
gem 'factory_bot_rails'
# Checks that all translations are used and defined
gem 'i18n-tasks', require: false
# Helps to prevent database consistency mistakes
gem 'consistency_fail', require: false
# Prevent N+1 queries.
gem 'bullet', '>= 4.14.9'
gem 'parallel_tests'
# Call 'byebug' anywhere in the code to stop execution and get a debugger console
gem 'byebug', platform: :mri
# Code coverage reporter and formatter
gem 'simplecov'
gem 'simplecov-lcov', '>= 0.8.0'
gem 'dotenv-rails'
end
group :ci do
gem 'rspec-retry'
gem 'rspec_junit_formatter'
gem 'rubocop-rails'
end
# This is used only when producing Production assets. Deals with things like minifying JavaScript
# source files/image assets.
group :assets do
# Compress image assets
gem 'image_optim_rails'
end
group :production, :test do
# Puma will be our app server
gem 'puma'
end
group :production, :test, :ci do
gem 'aws-sdk-s3'
end
group :production do
gem 'aws-sdk-cloudwatch'
gem 'aws-sdk-core'
# Use fog-aws as CarrierWave's storage provider
gem 'fog-aws', '>= 3.19'
gem 'flamegraph'
gem 'stackprof'
gem 'sidekiq', '~> 7.3.10'
gem 'sidekiq-cron'
gem 'rollbar', '>= 1.5.3'
# better log format
gem 'lograge'
gem 'lograge-sql'
end
# Multitenancy
gem 'acts_as_tenant'
# Internationalization
gem 'http_accept_language'
# User authentication
gem 'devise', '4.9.4'
gem 'devise-multi_email'
gem 'keycloak'
gem 'jwt'
# Use cancancan for authorization
gem 'cancancan'
# Using CarrierWave for file uploads
gem 'carrierwave', '~> 3'
# Generate sequential filenames
gem 'filename'
# Required by CarrierWave, for image resizing
gem 'mini_magick'
# Library for reading and writing zip files
gem 'rubyzip', '~> 3.0', require: 'zip'
# Manipulating XML files, needed for programming evaluation test report parsing.
gem 'nokogiri', '>= 1.18.8'
# Polyglot support
gem 'coursemology-polyglot', git: 'https://github.com/Coursemology/polyglot'
# To assist with bulk inserts into database
gem 'activerecord-import', '>= 0.2.0'
gem 'record_tag_helper'
gem 'rails-controller-testing'
# WordNet corpus to obtain lemma form of words, for comprehension questions.
gem 'rwordnet', git: 'https://github.com/Coursemology/rwordnet'
gem 'loofah', '>= 2.2.1'
gem 'rails-html-sanitizer', '>= 1.0.4'
gem 'mimemagic', '0.4.3'
gem 'ffi', '>= 1.14.2'
# Retreival Augmented Generation (RAG) Support
gem 'pgvector'
gem 'neighbor'
gem 'langchainrb'
gem 'ruby-openai'
gem 'pdf-reader'
gem 'docx'
================================================
FILE: LICENSE
================================================
The MIT License (MIT)
http://opensource.org/licenses/MIT
Copyright (c) 2023 Coursemology.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
<!-- markdownlint-disable MD033 MD014 -->
# Coursemology [](https://circleci.com/gh/Coursemology/coursemology2)
[](https://codeclimate.com/github/Coursemology/coursemology2)
[](https://codecov.io/gh/Coursemology/coursemology2)
[](http://inch-ci.org/github/Coursemology/coursemology2)
[](http://coursemology-slack.herokuapp.com)
<a href="http://coursemology.org"><img src="https://raw.githubusercontent.com/Coursemology/coursemology.org/development/public/images/coursemology_logo_landscape_100.png" alt="Coursemology logo" title="Coursemology" align="right" /></a>
Coursemology is an open source gamified learning platform that enables educators to increase student engagement and make learning fun.
## Setting up Coursemology
### System Requirements
1. **Ruby** (= 3.3.5)
2. **Ruby on Rails** (= 7.2.3.1)
3. **PostgreSQL** (= 16) with **PGVector extension**
4. **ImageMagick** or **GraphicsMagick** (For [MiniMagick](https://github.com/minimagick/minimagick) - if PDF processing doesn't work for the import of scribing questions, download **Ghostscript**)
5. **Node.js** (v22 LTS)
6. **Yarn**
7. **Docker** (installed and running)
8. **Redis**
### Getting Started
We use Git submodules. Run the following command to initialize them before proceeding:
```sh
$ git submodule update --init --recursive
```
Coursemology consists of three main components:
1. [Keycloak authentication provider](./authentication/README.md)
2. [Ruby on Rails application server](./app/README.md)
3. [React frontend client](./client/README.md)
Set up and run each component sequentially by following the linked documentation pages. As you proceed, open a new terminal window for each component after the previous component has been fully set up and started running.
Once each component has been set up and is running on their own terminals, you can access the app by visiting [http://localhost:8080](http://localhost:8080), and log in using the default user email and password:
email: `test@example.org`
password: `Coursemology!`
### Running using HTTPS locally
These commands should be run from the repository root directory, unless otherwise noted.
`lvh.me` is a public domain that resolves to `127.0.0.1`. It is used instead of `localhost` because browsers enforce stricter security policies on `localhost` that can break the OAuth redirect flow over HTTPS.
1. Generate a self-signed certificate and key for `lvh.me`:
```sh
openssl req -x509 -newkey rsa:4096 -sha256 -days 365 -nodes \
-keyout config/credentials/server.key \
-out config/credentials/server.crt \
-subj "/CN=lvh.me" \
-addext "subjectAltName=DNS:lvh.me,DNS:*.lvh.me"
```
Puma and the webpack dev server both use these files automatically on startup.
2. Update the Keycloak redirect URIs to use HTTPS:
```sh
bundle exec rake "keycloak:push_redirect_uris[https://lvh.me:8080]"
```
3. Start the app server with the public hostname:
```sh
RAILS_HOSTNAME=lvh.me:8080 RAILS_ENV=development bundle exec puma
```
4. Start the client in HTTPS mode (from the `client/` directory):
```sh
yarn build:development-https
```
Access the app at `https://lvh.me:8080`. Your browser will show a certificate warning for the self-signed cert — ignore it or add a security exception.
#### Reverting to HTTP
1. Remove the certificate files so Puma falls back to HTTP:
```sh
rm config/credentials/server.crt config/credentials/server.key
```
2. Restore the Keycloak redirect URIs:
```sh
bundle exec rake "keycloak:push_redirect_uris"
```
3. Restart both the app server and client using the standard commands.
## Found Boogs?
Create an issue on the Github [issue tracker](https://github.com/Coursemology/coursemology2/issues) or come talk to us over at our [Slack channels](https://coursemology-slack.herokuapp.com/).
## Contributing
We welcome contributions to Coursemology! Check out the [issue tracker](https://github.com/coursemology/coursemology2/issues) and pick something you'll like to work on. Please read our [Contributor's Guide](https://github.com/Coursemology/coursemology2/blob/master/CONTRIBUTING.md) for guidance on our conventions.
If you are a student from NUS Computing looking for an FYP project, do check with [Prof Ben Leong](http://www.comp.nus.edu.sg/~bleong/).
## License
Copyright (c) 2015-2023 Coursemology.org. This software is licensed under the MIT License.
## Using Coursemology
You're more than welcome to use Coursemology for your own school or organization. If you need more help, [join](http://coursemology-slack.herokuapp.com/) our Slack channel to reach our core developers.
We are actively running [Coursemology](https://coursemology.org) and can provide free use of our infrastructure on a case by case basis. Please contact [Prof Ben Leong](http://www.comp.nus.edu.sg/~bleong/) if you would like to explore this option.
## Acknowledgments
The Coursemology.org Project was made possible by a number of teaching development grants from the National University of Singapore over the years. This project is currently supported by the [AI Centre for Educational Technologies](https://www.aicet.aisingapore.org/).
================================================
FILE: Rakefile
================================================
# frozen_string_literal: true
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('config/application', __dir__)
# Development dependencies, may fail. See Gemfile.
begin
require 'lol_dba'
require 'traceroute'
rescue LoadError # rubocop:disable Lint/SuppressedException
end
Rails.application.load_tasks
================================================
FILE: app/README.md
================================================
# Coursemology App Server
Coursemology uses [Ruby on Rails](http://rubyonrails.org/) as its backend app server. This [guide](https://gorails.com/setup/) written by the awesome people at GoRails should help you to get started on Ruby on Rails (however, be careful about the Rails version you are going to install here, and make sure your system meets its requirements).
## Getting Started
These commands should be run with the repository root directory (one level up from where this README file is) as the working directory.
1. Download bundler to install dependencies
```sh
gem install bundler:2.5.9
```
2. Install ruby dependencies
```sh
bundle config set --local without 'ci:production'
bundle install
```
3. Create and seed the database
```sh
bundle exec rake db:setup
```
4. Initialize .env file
```sh
cp env .env
```
You may need to add specific API keys (such as the [GOOGLE_RECAPTCHA_SITE_KEY](https://developers.google.com/recaptcha/docs/faq#id-like-to-run-automated-tests-with-recaptcha.-what-should-i-do)) to the .env files for testing specific features.
5. To start the app server, run
```
bundle exec rails s -p 3000
```
## Configuration
### Multi Tenancy
To make sure that multi tenancy works correctly for you, change the default host in `config/application.rb` before deploying:
```ruby
config.x.default_host = 'your_domain.com'
```
### Opening Reminder Emails
Email reminders for items which are about to start are sent via a cronjob which should be run once an hour. See [config/initializers/sidekiq.rb](../config/initializers/sidekiq.rb) and [config/schedule.yml](../config/schedule.yml) for sample configuration which assumes that the [Sidekiq](https://github.com/mperham/sidekiq) and [Sidekiq-Cron](https://github.com/ondrejbartas/sidekiq-cron) gems are used.
If you use a different job scheduler, edit those files so your favourite job scheduler invokes the `ConsolidatedItemEmailJob` job once an hour.
================================================
FILE: app/assets/config/manifest.js
================================================
================================================
FILE: app/channels/application_cable/channel.rb
================================================
# frozen_string_literal: true
class ApplicationCable::Channel < ActionCable::Channel::Base
include ApplicationCableMultitenancyConcern
protected
def request
ActionDispatch::Request.new(connection.env)
end
def session
request.session
end
def ip_address_and_user_agent
ip_address = request.remote_ip
user_agent = request.headers['User-Agent']
[ip_address, user_agent]
end
end
================================================
FILE: app/channels/application_cable/connection.rb
================================================
# frozen_string_literal: true
class ApplicationCable::Connection < ActionCable::Connection::Base
identified_by :current_user, :current_session_id
include ApplicationCableAuthenticationConcern
def connect
self.current_user = current_user_from_token || reject_unauthorized_connection
self.current_session_id = retrieve_current_session_id
end
end
================================================
FILE: app/channels/concerns/application_cable_ability_concern.rb
================================================
# frozen_string_literal: true
module ApplicationCableAbilityConcern
extend ActiveSupport::Concern
included do
before_subscribe :load_current_ability
end
def current_ability
@current_ability ||= Ability.new(current_user, current_course, current_course_user, nil, current_session_id)
end
def can?(*args)
current_ability.can?(*args)
end
def cannot?(*args)
current_ability.cannot?(*args)
end
alias_method :load_current_ability, :current_ability
end
================================================
FILE: app/channels/concerns/application_cable_authentication_concern.rb
================================================
# frozen_string_literal: true
module ApplicationCableAuthenticationConcern
def current_user_from_token
token = authenticate_token
User.joins(:emails).where('user_emails.email = ?', token[:email]).first if token
end
def retrieve_current_session_id
@current_session_id ||= current_decoded_token&.[](:session_state)
end
def current_decoded_token
@current_decoded_token ||= @decoded_token&.decoded_token
end
private
def authenticate_token
access_token = token_from_request
@decoded_token ||= Authentication::AuthenticationService.validate_token(access_token, :local)
return nil if @decoded_token.error
@decoded_token.decoded_token
end
def token_from_request
request.params['token']
end
end
================================================
FILE: app/channels/concerns/application_cable_component_concern.rb
================================================
# frozen_string_literal: true
module ApplicationCableComponentConcern
extend ActiveSupport::Concern
included do
before_subscribe :load_current_component_host
before_subscribe :check_component
end
def current_component_host
@current_component_host ||= Course::ControllerComponentHost.new(self)
end
private
alias_method :load_current_component_host, :current_component_host
def component
raise ComponentNotFoundError
end
# TODO: Raise and use `rescue_from` in `included` once in Rails 6.1+
def check_component
reject unless component
rescue ComponentNotFoundError
reject
end
end
================================================
FILE: app/channels/concerns/application_cable_course_concern.rb
================================================
# frozen_string_literal: true
module ApplicationCableCourseConcern
extend ActiveSupport::Concern
included do
before_subscribe :find_course
end
def find_course
course_id = params[:course_id]
reject unless @course ||= Course.find(course_id)
end
def current_course
@course
end
def current_course_user
return nil unless current_course
@current_course_user ||= current_course.course_users.find_by(user: current_user)
end
end
================================================
FILE: app/channels/concerns/application_cable_multitenancy_concern.rb
================================================
# frozen_string_literal: true
module ApplicationCableMultitenancyConcern
extend ActiveSupport::Concern
include ApplicationMultitenancy
included do
set_current_tenant_through_filter
before_subscribe :deduce_and_set_current_tenant
end
end
================================================
FILE: app/channels/course/channel.rb
================================================
# frozen_string_literal: true
#
# The base channel for all `Course`-related channels. Subclasses of this channel
# must receive `course_id` as a parameter in the subscription request message.
#
# By default, it will expose, in chronological order:
# - `current_course`
# - `current_course_user`
# - `current_component_host`
# - `current_ability`
# - `can?` and `cannot?` from `CanCan::Ability`
#
# Note that the more inclusions are added, the more queries and operations are executed
# during subscriptions or actions, depending on the callbacks used in each included modules.
# These features are broken up into concerns so that future channels can opt in to only the
# capabilities they need.
class Course::Channel < ApplicationCable::Channel
include ApplicationCableCourseConcern
include ApplicationCableComponentConcern
include ApplicationCableAbilityConcern
end
================================================
FILE: app/channels/course/monitoring/heartbeat_channel.rb
================================================
# frozen_string_literal: true
class Course::Monitoring::HeartbeatChannel < Course::Channel
ACTIONS = { next: :next, terminate: :terminate, flushed: :flushed }.freeze
def subscribed
session_id = params[:session_id]
@session = Course::Monitoring::Session.find(session_id)
@monitor = @session.monitor
reject unless @session.present? && can?(:read, @session) && listening?
stream_for @session
end
def pulse(data)
@monitor.reload && @session.reload
unless can_pulse? && listening?
# TODO: Use `stop_stream_from @session` once in Rails 6.1+
# In particular, use `stop_stream_from @session unless can_pulse?`
broadcast_terminate
broadcast_terminate_to_live_monitoring
return
end
ip_address, user_agent = ip_address_and_user_agent
timestamp = data['timestamp']
heartbeat = Course::Monitoring::Heartbeat.new(
session: @session,
user_agent: user_agent,
ip_address: ip_address,
generated_at: time_from(timestamp),
seb_payload: data['sebPayload']
)
return unless heartbeat.save
broadcast_next timestamp, rand(@monitor.min_interval_ms..@monitor.max_interval_ms)
broadcast_pulse_to_live_monitoring heartbeat
end
def flush(data)
ip_address, user_agent = ip_address_and_user_agent
heartbeats_data = filter_and_sort_heartbeats(data['heartbeats'])
heartbeats = heartbeats_data.map do |heartbeat_data|
{
session_id: @session.id,
user_agent: user_agent,
ip_address: ip_address,
generated_at: time_from(heartbeat_data['timestamp']),
stale: true,
created_at: Time.zone.now,
updated_at: Time.zone.now
}
end
flushed = Course::Monitoring::Heartbeat.insert_all(heartbeats)
broadcast_flushed heartbeats_data.first['timestamp'], heartbeats_data.last['timestamp'] if flushed
end
class << self
def broadcast_terminate(session)
broadcast_to session, { action: ACTIONS[:terminate] }
end
end
private
def listening?
@monitor.enabled? && @session.listening?
end
def filter_and_sort_heartbeats(heartbeats)
start_time = @session.created_at
end_time = listening? ? @session.expiry : @session.heartbeats.last&.generated_at
heartbeats.filter { |h| time_from(h['timestamp']).between?(start_time, end_time) }.sort_by { |h| h['timestamp'] }
end
def time_from(milliseconds)
Time.zone.at(0, milliseconds, :millisecond)
end
def broadcast_pulse_to_live_monitoring(heartbeat)
Course::Monitoring::LiveMonitoringChannel.broadcast_pulse_to @monitor, @session, {
sessionId: @session.id,
status: @session.status,
misses: @session.misses,
lastHeartbeatAt: heartbeat.generated_at,
isValid: valid_heartbeat?(heartbeat)
}.compact
end
def broadcast_terminate_to_live_monitoring
Course::Monitoring::LiveMonitoringChannel.broadcast_terminate @monitor, @session
end
def broadcast_terminate
Course::Monitoring::HeartbeatChannel.broadcast_terminate @session
end
def broadcast_flushed(first_timestamp, last_timestamp)
Course::Monitoring::HeartbeatChannel.broadcast_to @session, {
action: ACTIONS[:flushed],
from: first_timestamp,
to: last_timestamp
}
end
def broadcast_next(received_timestamp, next_timeout)
Course::Monitoring::HeartbeatChannel.broadcast_to @session, {
action: ACTIONS[:next],
nextTimeout: next_timeout,
received: received_timestamp
}
end
def component
current_component_host[:course_monitoring_component]
end
def can_pulse?
@can_pulse ||= can? :create, Course::Monitoring::Heartbeat.new(session: @session)
end
def assessment_id
@assessment_id ||= @monitor.assessment.id
end
def valid_heartbeat?(heartbeat)
heartbeat.valid_heartbeat? || Course::Assessment::MonitoringService.unblocked?(assessment_id, session)
end
end
================================================
FILE: app/channels/course/monitoring/live_monitoring_channel.rb
================================================
# frozen_string_literal: true
class Course::Monitoring::LiveMonitoringChannel < Course::Channel
include Course::UsersHelper
DEFAULT_VIEW_HEARTBEATS_LIMIT = 10
ACTIONS = { pulse: :pulse, terminate: :terminate, viewed: :viewed, watch: :watch }.freeze
def subscribed
monitor_id = params[:monitor_id]
@monitor = Course::Monitoring::Monitor.find(monitor_id)
reject unless @monitor.present? && can?(:read, @monitor)
stream_for @monitor
end
class << self
def broadcast_pulse_to(monitor, session, snapshot)
broadcast_from monitor, :pulse, { userId: session.creator_id, snapshot: snapshot }
end
def broadcast_terminate(monitor, session)
broadcast_from monitor, :terminate, session.creator_id
end
def broadcast_from(monitor, action, payload)
broadcast_to monitor, { action: ACTIONS[action], payload: payload }.compact
end
end
def watch
active_snapshots = active_sessions_snapshots
students = current_course.students.order(:phantom, :name)
snapshots = students.to_h do |student|
user_id = student.user_id
[user_id, active_snapshots[user_id] || { userName: student.name }]
end
broadcast_watch students.map(&:user_id), snapshots, groups
end
def view(data)
session_id, limit = data['session_id'], data['limit'] || DEFAULT_VIEW_HEARTBEATS_LIMIT
return unless (session = @monitor.sessions.find(session_id))
recent_heartbeats = (limit == -1 ? session.heartbeats : session.heartbeats.last(limit)).map do |heartbeat|
{
stale: heartbeat.stale,
userAgent: heartbeat.user_agent,
ipAddress: heartbeat.ip_address,
generatedAt: heartbeat.generated_at,
isValid: heartbeat.valid_heartbeat?,
sebPayload: heartbeat.seb_payload
}.compact
end
broadcast_viewed recent_heartbeats
end
private
def active_sessions_snapshots
@monitor.sessions.includes(:heartbeats, :creator).to_h do |session|
last_heartbeat = session.heartbeats.last
course_user = course_users_hash[session.creator_id]
# This technically shouldn't happen, but can happen if someone is removed from
# the course after they finish a monitored assessment.
next [nil, nil] unless course_user
snapshot = {
sessionId: session.id,
status: session.status,
misses: session.misses,
lastHeartbeatAt: last_heartbeat&.generated_at,
isValid: last_heartbeat&.valid_heartbeat?,
userName: course_user.name,
submissionId: submission_ids_hash[session.creator_id],
stale: last_heartbeat&.stale
}.compact
[session.creator_id, snapshot]
end.compact
end
def groups
current_course.groups.ordered_by_name.includes(:group_category, :course_users).map do |group|
{
id: group.id,
name: group.name,
category: group.group_category.name,
userIds: group.course_users&.filter_map { |course_user| course_user.user_id if course_user.student? }
}
end
end
def broadcast(action, payload)
Course::Monitoring::LiveMonitoringChannel.broadcast_from @monitor, action, payload
end
def broadcast_watch(users, snapshots, groups)
broadcast :watch, {
userIds: users,
snapshots: snapshots,
groups: groups,
monitor: {
maxIntervalMs: @monitor.max_interval_ms,
offsetMs: @monitor.offset_ms,
validates: @monitor.browser_authorization?,
browserAuthorizationMethod: @monitor.browser_authorization_method
}
}
end
def broadcast_viewed(recent_heartbeats)
broadcast :viewed, recent_heartbeats
end
def component
current_component_host[:course_monitoring_component]
end
def course_users_hash
@course_users_hash ||= preload_course_users_hash(current_course)
end
def submission_ids_hash
@submission_ids_hash ||= @monitor.assessment.submissions.to_h do |submission|
[submission.creator_id, submission.id]
end
end
end
================================================
FILE: app/controllers/announcements_controller.rb
================================================
# frozen_string_literal: true
class AnnouncementsController < ApplicationController
load_resource :announcement, class: 'GenericAnnouncement', only: :mark_as_read, id_param: :announcement_id
def index
respond_to do |format|
format.json do
announcements = requesting_unread? ? unread_global_announcements : global_announcements
@announcements = announcements.includes(:creator)
end
end
end
def mark_as_read
if current_user
@announcement.mark_as_read! for: current_user
head :ok
else
head :no_content
end
end
protected
def publicly_accessible?
requesting_unread? || action_name.to_sym == :mark_as_read
end
private
def requesting_unread?
params[:unread] == 'true'
end
end
================================================
FILE: app/controllers/application_controller.rb
================================================
# frozen_string_literal: true
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by providing a null session when the token is missing from the request.
protect_from_forgery(prepend: true, with: :exception)
include ApplicationControllerMultitenancyConcern
include ApplicationAuthenticationConcern
include ApplicationComponentsConcern
include ApplicationInternationalizationConcern
include ApplicationUserConcern
include ApplicationUserTimeZoneConcern
include ApplicationInstanceUserConcern
include ApplicationAbilityConcern
include ApplicationAnnouncementsConcern
include ApplicationPaginationConcern
rescue_from AuthenticationError, with: :handle_authentication_error
rescue_from IllegalStateError, with: :handle_illegal_state_error
rescue_from ActionController::InvalidAuthenticityToken, with: :handle_csrf_error
def index
end
protected
# Runs the provided block with Bullet disabled.
#
# @note Bullet will not be enabled again after this block returns until the next Rack request.
# The block syntax is in anticipation of Bullet eventually supporting temporary disabling,
# which currently does not work. See flyerhzm/bullet#247.
def without_bullet
old_bullet_enable = Bullet.enable?
Bullet.enable = false
yield
ensure
Bullet.enable = old_bullet_enable
end
private
def handle_illegal_state_error(exception)
@exception = exception
render json: { error: exception.message }, status: :unprocessable_entity
end
def handle_csrf_error(exception)
@exception = exception
render json: { error: "Can't verify CSRF token authenticity - #{exception.message}" }, status: :forbidden
end
def handle_authentication_error(exception)
cookies.delete(:access_token)
@exception = exception
render json: { error: exception.message }, status: :unauthorized
end
# lograge
def append_info_to_payload(payload)
super
payload[:level] = case payload[:status]
when 200
'INFO'
when 302
'WARN'
else
'ERROR'
end
payload[:remote_ip] = request.ip
payload[:current_user_id] = current_user.id if current_user.present?
end
end
================================================
FILE: app/controllers/attachment_references_controller.rb
================================================
# frozen_string_literal: true
class AttachmentReferencesController < ApplicationController
load_resource :attachment_reference
def create
attachment = Attachment.find_or_create_by(file: file_params[:file]) if file_params[:file]
return unless attachment
@attachment_reference = AttachmentReference.create(attachment: attachment, name: file_params[:name])
end
def show
name = @attachment_reference.name
uploader = @attachment_reference.attachment.file_upload
# if case is only for local storage, since there is no S3 URL to redirect to. In prod, it always goes to else.
if uploader.class.storage == CarrierWave::Storage::File # under Dev/test, config.storage = :file
raise ActiveRecord::RecordNotFound, "File not found at path: #{uploader.path}" unless uploader.file&.exists?
send_file uploader.path,
filename: name,
type: uploader.content_type
else
redirect_to @attachment_reference.url(filename: name), allow_other_host: true
end
end
private
def file_params
params.permit(:file, :name)
end
end
================================================
FILE: app/controllers/components/course/achievements_component.rb
================================================
# frozen_string_literal: true
class Course::AchievementsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.gamified?
true
end
def sidebar_items
[
{
key: :achievements,
icon: :achievement,
weight: 4,
path: course_achievements_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/announcements_component.rb
================================================
# frozen_string_literal: true
class Course::AnnouncementsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
include Course::UnreadCountsConcern
def sidebar_items
main_sidebar_items + settings_sidebar_items
end
private
def main_sidebar_items
[
{
key: :announcements,
icon: :announcement,
title: settings.title,
weight: 1,
path: course_announcements_path(current_course),
unread: unread_announcements_count
}
]
end
def settings_sidebar_items
[
{
key: self.class.key,
title: settings.title,
type: :settings,
weight: 4,
path: course_admin_announcements_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/assessments_component.rb
================================================
# frozen_string_literal: true
class Course::AssessmentsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
include Course::UnreadCountsConcern
def self.lesson_plan_item_actable_names
[Course::Assessment.name]
end
def sidebar_items
main_sidebar_items + admin_sidebar_items + admin_settings_items
end
private
def main_sidebar_items
assessment_categories + assessment_submissions
end
def assessment_categories
current_course.assessment_categories.select(&:persisted?).map do |category|
{
key: "assessments_#{category.id}",
icon: :assessment, # TODO: category.icon in db that user can select and set
title: category.title,
weight: 2,
path: course_assessments_path(current_course, category: category)
}
end
end
def assessment_submissions
[
{
key: :assessments_submissions,
icon: :submission,
weight: 3,
path: course_submissions_path(current_course),
unread: pending_assessment_submissions_count
}
]
end
def admin_sidebar_items
return [] unless can?(:read, Course::Assessment::Skill.new(course: current_course))
[
{
key: :sidebar_assessments_skills,
icon: :skills,
type: :admin,
weight: 8,
path: course_assessments_skills_path(current_course)
}
]
end
def admin_settings_items
[
{
key: self.class.key,
type: :settings,
weight: 5,
path: course_admin_assessments_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/codaveri_component.rb
================================================
# frozen_string_literal: true
class Course::CodaveriComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def sidebar_items
settings_sidebar_items
end
private
def settings_sidebar_items
[
{
key: self.class.key,
type: :settings,
weight: 6,
path: course_admin_codaveri_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/controller_component_host.rb
================================================
# frozen_string_literal: true
#
# The course component framework isolates features as components. The intent is to allow
# each feature to be enabled / disabled indepenedently within a course.
#
# When creating a component:
#
# - Your component class should `include Course::ControllerComponentHost::Component`.
# This injects the methods found in the {Course::ControllerComponentHost::Sidebar Sidebar}
# and {Course::ControllerComponentHost::Settings Settings} modules
# into the component. Override these methods to customise your component.
#
# - Your component class's initializer should take in the component host's context (a controller)
# as its only argument. You may do this by having your component inherit from `SimpleDelegator`.
# This allows you to call methods on the given context from your component, e.g. a call to
# {Course::Controller#current_course} will be delegated to the controller.
#
# - If your component has settings, you may define a settings model for it.
# (See {Course::ControllerComponentHost::Settings::ClassMethods#settings_class} for
# conventions to follow.)
#
# - You will also need to associate controllers for a component with the component class
# in order for it to be automatically enabled / disabled based on the course's settings
# (see {Course::ComponentController}).
#
class Course::ControllerComponentHost
include Componentize
module Sidebar
extend ActiveSupport::Concern
# Get the sidebar items and admin menu tab items from this component.
#
# @return [Array] An array of hashes containing the sidebar items exposed by this component.
# See {Course::ControllerComponentHost#sidebar_items} for the format.
def sidebar_items
[]
end
end
module Settings
extend ActiveSupport::Concern
delegate :enabled_by_default?, to: :class
delegate :key, to: :class
delegate :settings_class, to: :class
module ClassMethods
# @return [Boolean] the default enabled status of the component
def enabled_by_default?
true
end
# Unique key of the component, to serve as the key in settings and translations.
#
# @return [Symbol] the key
def key
name.underscore.tr('/', '_').to_sym
end
# Override this to customise the display name of the component.
# The module name is the default display name.
#
# @return [String]
def display_name
name
end
# @return [Boolean] The gamfied status of the component. If true, the component will be
# disabled when the gamified flag in the course is false. Value is false by default.
def gamified?
false
end
# @return [Boolean] true if component can be disabled (or enabled) for individual courses.
# Otherwise, the component can only perhaps be disabled instance-wide.
def can_be_disabled_for_course?
true
end
# Returns a model which the current component can use to interface with its persisted
# settings. The class initializer should take an instance of the component as its only
# argument.
#
# Example:
# If the component Course::FoobarComponent has settings, define a class
# Course::Settings::FoobarComponent in the file
# app/models/course/settings/foobar_component.rb.
#
# @return [Class] The settings interface class
# @return [nil] if the class does not exist
def settings_class
@settings_class ||= "Course::Settings::#{name.demodulize}".safe_constantize
end
# Override in the component definition with the names of the actable types
# if the component adds lesson plan items.
# A component can specify multiple actable types for display on the lesson plan page.
#
# @return [Array<String>] actable types as an array of strings
def lesson_plan_item_actable_names
[]
end
end
# The settings interface instance for this component.
#
# @return An instance of the settings interface for the current component.
# @return [nil] if the settings interface is not implemented.
def settings
@settings ||= settings_class&.new(self)
end
end
# Open the Componentize Base Component.
const_get(:Component).module_eval do
const_set(:ClassMethods, ::Module.new) unless const_defined?(:ClassMethods)
include Sidebar
include Settings
end
# Eager load all the components declared.
eager_load_components(File.join(__dir__, '../'))
# Initializes the component host instance. This loads all components.
#
# @param context The context to execute all component instance methods on.
def initialize(context)
@context = context
components
end
# @return [Array<Class>] Classes of effectively enabled components.
def enabled_components
@enabled_components ||= @context.current_course.enabled_components
end
# Instantiates the enabled components.
#
# @return [Array] The instantiated enabled components.
def components
@components ||= enabled_components.map { |component| component.new(@context) }
end
# Gets the component instance with the given key.
#
# @param [String|Symbol] component_key The key of the component to find.
# @return [Object] The component with the given key.
# @return [nil] If component is not enabled.
def [](component_key)
validate_component_key!(component_key)
components.find { |component| component.key == component_key.to_sym }
end
# Gets the sidebar elements.
#
# Sidebar elements have the given format:
#
# ```
# {
# key: :item_key, # The unique key of the item to identify it among others. Can be nil if
# # there is no need to distinguish between items.
# # +normal+ type elements must have a key because their ordering is a
# # user setting.
# title: 'Sidebar Item Title',
# type: :admin, # Will be considered as +:normal+ if not set. Currently +:normal+, +:admin+,
# # and +:settings+ are used.
# weight: 100, # The default weight of the item. Larger weights (heavier items) sink.
# path: path_to_the_component,
# unread: 0 # Number of unread items. Can be +nil+, if not needed.
# }
# ```
#
# The elements are rendered on all Course controller subclasses as part of a nested template.
def sidebar_items
@sidebar_items ||= components.flat_map(&:sidebar_items)
end
private
# @param [String|Symbol] component_key The key of the component to validate.
def validate_component_key!(key)
raise ArgumentError, "Invalid component key: #{key}" unless component_key_set.include?(key.to_sym)
end
def component_key_set
@component_key_set ||= Course::ControllerComponentHost.components.map(&:key).to_set
end
end
================================================
FILE: app/controllers/components/course/discussion/topics_component.rb
================================================
# frozen_string_literal: true
class Course::Discussion::TopicsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
include Course::UnreadCountsConcern
def sidebar_items
main_sidebar_items + settings_sidebar_items
end
private
def main_sidebar_items
[
{
key: :discussion_topics,
icon: :comments,
title: settings.title,
weight: 5,
path: course_topics_path(current_course),
unread: unread_comments_count
}
]
end
def settings_sidebar_items
[
{
key: :sidebar_discussion_topics,
title: settings.title,
type: :settings,
weight: 7,
path: course_admin_topics_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/duplication_component.rb
================================================
# frozen_string_literal: true
class Course::DuplicationComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def sidebar_items
return [] unless can?(:duplicate_from, current_course)
[
{
key: :admin_duplication,
icon: :duplication,
type: :admin,
weight: 5,
path: course_duplication_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/experience_points_component.rb
================================================
# frozen_string_literal: true
class Course::ExperiencePointsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.gamified?
true
end
def sidebar_items
return [] unless can_create_experience_points_record?
[
{
key: :sidebar_experience_points,
icon: :experience,
type: :admin,
weight: 4,
path: course_experience_points_records_path(current_course)
}
]
end
private
def can_create_experience_points_record?
can?(:create, Course::ExperiencePointsRecord.
new(course_user: CourseUser.new(course: current_course)))
end
end
================================================
FILE: app/controllers/components/course/forums_component.rb
================================================
# frozen_string_literal: true
class Course::ForumsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
include Course::UnreadCountsConcern
def sidebar_items
main_sidebar_items + settings_sidebar_items
end
private
def main_sidebar_items
[
{
key: :forums,
icon: :forum,
title: settings.title,
weight: 10,
path: course_forums_path(current_course),
unread: unread_forum_topics_count
}
]
end
def settings_sidebar_items
[
{
key: self.class.key,
title: settings.title,
type: :settings,
weight: 11,
path: course_admin_forums_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/groups_component.rb
================================================
# frozen_string_literal: true
class Course::GroupsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
include Course::Group::GroupManagerConcern
def sidebar_items
return [] unless show_group_sidebar_item?
[
{
key: self.class.key,
icon: :groups,
type: :admin,
weight: 7,
path: group_category_url
}
]
end
private
def group_category_url
if viewable_group_categories.empty?
course_group_categories_path(current_course)
else
course_group_category_path(current_course, viewable_group_categories.ordered_by_name.first)
end
end
# Only show if the user can view all categories or can manage any particular group.
def show_group_sidebar_item?
category = Course::GroupCategory.new(course: current_course)
return true if can?(:read, category)
!manageable_groups.empty?
end
end
================================================
FILE: app/controllers/components/course/koditsu_platform_component.rb
================================================
# frozen_string_literal: true
class Course::KoditsuPlatformComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.enabled_by_default?
false
end
end
================================================
FILE: app/controllers/components/course/leaderboard_component.rb
================================================
# frozen_string_literal: true
class Course::LeaderboardComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.gamified?
true
end
def sidebar_items
main_sidebar_items + settings_sidebar_items
end
private
def main_sidebar_items
[
{
key: :leaderboard,
icon: :leaderboard,
title: settings.title,
weight: 6,
path: course_leaderboard_path(current_course)
}
]
end
def settings_sidebar_items
[
{
key: self.class.key,
title: settings.title,
type: :settings,
weight: 8,
path: course_admin_leaderboard_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/learning_map_component.rb
================================================
# frozen_string_literal: true
class Course::LearningMapComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.enabled_by_default?
false
end
def sidebar_items
[
{
key: :learning_map,
icon: :map,
weight: 5,
path: course_learning_map_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/lesson_plan_component.rb
================================================
# frozen_string_literal: true
class Course::LessonPlanComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.lesson_plan_item_actable_names
[Course::LessonPlan::Event.name]
end
def sidebar_items
main_sidebar_items + settings_sidebar_items
end
private
def main_sidebar_items
[
{
key: :lesson_plan,
icon: :lessonPlan,
weight: 8,
path: course_lesson_plan_path(current_course)
}
]
end
def settings_sidebar_items
[
{
key: self.class.key,
type: :settings,
weight: 9,
path: course_admin_lesson_plan_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/levels_component.rb
================================================
# frozen_string_literal: true
class Course::LevelsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.gamified?
true
end
def sidebar_items
return [] unless can?(:read, Course::Level.new(course: current_course))
[
{
key: self.class.key,
icon: :levels,
type: :admin,
weight: 6,
path: course_levels_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/materials_component.rb
================================================
# frozen_string_literal: true
class Course::MaterialsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def sidebar_items
main_sidebar_items + settings_sidebar_items
end
private
def main_sidebar_items
[
{
key: :materials,
icon: :material,
title: settings.title,
weight: 9,
path: course_material_folders_path(current_course)
}
]
end
def settings_sidebar_items
[
{
key: self.class.key,
title: settings.title,
type: :settings,
weight: 10,
path: course_admin_materials_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/monitoring_component.rb
================================================
# frozen_string_literal: true
class Course::MonitoringComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.enabled_by_default?
false
end
end
================================================
FILE: app/controllers/components/course/multiple_reference_timelines_component.rb
================================================
# frozen_string_literal: true
class Course::MultipleReferenceTimelinesComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.enabled_by_default?
false
end
def sidebar_items
return [] unless can?(:manage, Course::ReferenceTimeline.new(course: current_course))
[
{
key: :admin_multiple_reference_timelines,
icon: :timelines,
type: :admin,
weight: 9,
path: course_reference_timelines_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/plagiarism_component.rb
================================================
# frozen_string_literal: true
class Course::PlagiarismComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.enabled_by_default?
false
end
def sidebar_items
return [] unless can?(:manage_plagiarism, current_course)
[
{
key: :admin_plagiarism,
icon: :plagiarism,
type: :admin,
weight: 3,
path: course_plagiarism_assessments_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/rag_wise_component.rb
================================================
# frozen_string_literal: true
class Course::RagWiseComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.enabled_by_default?
false
end
def sidebar_items
settings_sidebar_items
end
private
def settings_sidebar_items
[
{
key: self.class.key,
type: :settings,
weight: 6,
path: course_admin_rag_wise_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/scholaistic_component.rb
================================================
# frozen_string_literal: true
class Course::ScholaisticComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
include Course::Scholaistic::Concern
def self.enabled_by_default?
false
end
def sidebar_items
main_sidebar_items + settings_sidebar_items
end
private
def main_sidebar_items
return [] unless scholaistic_course_linked?
student_sidebar_items + admin_sidebar_items
end
def student_sidebar_items
[
{
key: :scholaistic_assessments,
icon: :chatbot,
title: settings.assessments_title,
weight: 4,
path: course_scholaistic_assessments_path(current_course)
}
] + assistant_sidebar_items
end
def assistant_sidebar_items
ScholaisticApiService.assistants!(current_course).map do |assistant|
{
key: "scholaistic_assistant_#{assistant[:id]}",
icon: :chatbot,
title: assistant[:sidebar_title] || assistant[:title],
weight: 4.5,
path: course_scholaistic_assistant_path(current_course, assistant[:id])
}
end
rescue StandardError => e
Rails.logger.error("Failed to load Scholaistic assistants: #{e.message}")
raise e unless Rails.env.production?
[]
end
def admin_sidebar_items
return [] unless can?(:manage_scholaistic_assistants, current_course)
[
{
key: :admin_scholaistic_assistants,
type: :admin,
icon: :chatbot,
weight: 9,
path: course_scholaistic_assistants_path(current_course),
exact: true
}
]
end
def settings_sidebar_items
[
{
type: :settings,
key: self.class.key,
weight: 5,
path: course_admin_scholaistic_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/settings_component.rb
================================================
# frozen_string_literal: true
class Course::SettingsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
# Prevent user from locking him/herself out of settings.
def self.can_be_disabled_for_course?
false
end
def sidebar_items
admin_sidebar_items + settings_sidebar_items
end
private
def admin_sidebar_items
return [] unless can?(:manage, current_course)
[
{
key: :admin_settings,
icon: :settings,
type: :admin,
weight: 100,
path: course_admin_path(current_course)
}
]
end
def settings_sidebar_items
[
settings_index_item,
settings_components_item,
settings_sidebar_item,
settings_notifications
]
end
def settings_index_item
{
key: :admin_settings_general,
type: :settings,
weight: 1,
path: course_admin_path(current_course)
}
end
def settings_components_item
{
key: :admin_settings_component_settings,
type: :settings,
weight: 2,
path: course_admin_components_path(current_course)
}
end
def settings_sidebar_item
{
key: :admin_settings_sidebar_settings,
type: :settings,
weight: 3,
path: course_admin_sidebar_path(current_course)
}
end
def settings_notifications
{
key: :admin_settings_notifications,
type: :settings,
weight: 12,
path: course_admin_notifications_path(current_course)
}
end
end
================================================
FILE: app/controllers/components/course/statistics_component.rb
================================================
# frozen_string_literal: true
class Course::StatisticsComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def sidebar_items
return [] unless can?(:read_statistics, current_course)
[
{
key: self.class.key,
icon: :statistics,
type: :admin,
weight: 3,
path: course_statistics_students_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/stories_component.rb
================================================
# frozen_string_literal: true
class Course::StoriesComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.enabled_by_default?
false
end
def sidebar_items
main_sidebar_items + settings_sidebar_items
end
private
def main_sidebar_items
return [] unless
current_course_user.present? &&
current_component_host[:course_stories_component] &&
current_course.settings(:course_stories_component).push_key.present?
student_sidebar_items + staff_sidebar_items
end
def student_sidebar_items
[
{
key: :learn,
icon: :learn,
title: settings.title,
weight: 0,
path: course_learn_path(current_course)
}
]
end
def staff_sidebar_items
return [] unless can?(:access_mission_control, current_course)
[
{
key: :sidebar_stories_mission_control,
icon: :mission_control,
type: :admin,
weight: 1,
path: course_mission_control_path(current_course)
}
]
end
def settings_sidebar_items
[
{
key: self.class.key,
type: :settings,
weight: 5,
path: course_admin_stories_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/survey_component.rb
================================================
# frozen_string_literal: true
class Course::SurveyComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
def self.lesson_plan_item_actable_names
[Course::Survey.name]
end
def sidebar_items
[
{
key: :surveys,
icon: :survey,
weight: 11,
path: course_surveys_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/components/course/users_component.rb
================================================
# frozen_string_literal: true
class Course::UsersComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
include Course::UnreadCountsConcern
def self.can_be_disabled_for_course?
false
end
def sidebar_items
main_sidebar_items + admin_sidebar_items
end
private
def main_sidebar_items
[
{
key: :users,
icon: :users,
weight: 7,
path: course_users_path(current_course)
}
]
end
# Direct the 'Manage Users' link to the usual course_users_students_path if current course user is a manager,
# otherwise direct it to manage personalized timelines.
def admin_sidebar_items
can_manage_users = can?(:manage_users, current_course)
can_manage_personal_times =
current_course.show_personalized_timeline_features? && can?(:manage_personal_times, current_course)
return [] unless can_manage_users || can_manage_personal_times
[
{
key: :admin_users_manage_users,
icon: :manageUsers,
type: :admin,
weight: 2,
path:
if can_manage_users
course_users_students_path(current_course)
else
personal_times_course_users_path(current_course)
end,
unread: pending_enrol_requests_count
}
]
end
end
================================================
FILE: app/controllers/components/course/videos_component.rb
================================================
# frozen_string_literal: true
class Course::VideosComponent < SimpleDelegator
include Course::ControllerComponentHost::Component
include Course::UnreadCountsConcern
def self.lesson_plan_item_actable_names
[Course::Video.name]
end
def sidebar_items
main_sidebar_items + settings_sidebar_items
end
private
def main_sidebar_items
[
{
key: :videos,
icon: :video,
title: settings.title,
weight: 12,
path: course_videos_path(current_course, tab: current_course.default_video_tab),
unread: unwatched_videos_count
}
]
end
def settings_sidebar_items
[
{
key: self.class.key,
title: settings.title,
type: :settings,
weight: 13,
path: course_admin_videos_path(current_course)
}
]
end
end
================================================
FILE: app/controllers/concerns/application_ability_concern.rb
================================================
# frozen_string_literal: true
module ApplicationAbilityConcern
# Override of Cancancan#current_ability to provide current course.
def current_ability
@current_ability ||= Ability.new(current_user, nil, nil, current_instance_user, current_session_id)
end
end
================================================
FILE: app/controllers/concerns/application_announcements_concern.rb
================================================
# frozen_string_literal: true
module ApplicationAnnouncementsConcern
extend ActiveSupport::Concern
# Returns active global announcements unread by the current user, if one is signed in.
#
# @return [Array<GenericAnnouncement>] Unread announcements
def unread_global_announcements
user_signed_in? ? global_announcements.unread_by(current_user) : global_announcements
end
# Returns all active global announcements.
#
# @return [Array<GenericAnnouncement>] Active announcements
def global_announcements
GenericAnnouncement.for_instance(current_tenant).currently_active
end
end
================================================
FILE: app/controllers/concerns/application_authentication_concern.rb
================================================
# frozen_string_literal: true
module ApplicationAuthenticationConcern
extend ActiveSupport::Concern
REQUIRES_AUTHENTICATION = { message: 'Requires authentication' }.freeze
BAD_CREDENTIALS = {
message: 'Bad credentials'
}.freeze
MALFORMED_AUTHORIZATION_HEADER = {
error: 'invalid_request',
error_description: 'Authorization header value must follow this format: Bearer access-token',
message: 'Bad credentials'
}.freeze
def current_user_from_token
token = authenticate_token
User.joins(:emails).where('user_emails.email = ?', token[:email]).first if token
end
def current_session_id
@current_session_id ||= current_decoded_token&.[](:session_state)
end
def token_from_request
@token_from_request ||= get_token_from_bearer || get_token_from_cookies
end
def current_decoded_token
@current_decoded_token ||= @decoded_token&.decoded_token
end
private
def authenticate_token
access_token = token_from_request
return if performed?
@decoded_token ||= Authentication::AuthenticationService.validate_token(access_token, :local)
if @decoded_token.error
# render json: { message: @decoded_token.error.message }, status: @decoded_token.error.status and return
return nil
end
@decoded_token.decoded_token
end
def get_token_from_bearer
authorization_header_elements = request.headers['Authorization']&.split
# render json: REQUIRES_AUTHENTICATION, status: :unauthorized and return unless authorization_header_elements
return nil unless authorization_header_elements
unless authorization_header_elements.length == 2
# render json: MALFORMED_AUTHORIZATION_HEADER, status: :unauthorized and return
return nil
end
scheme, token = authorization_header_elements
# render json: BAD_CREDENTIALS, status: :unauthorized and return unless scheme.downcase == 'bearer'
return nil unless scheme.downcase == 'bearer'
token
end
def get_token_from_cookies
cookies.encrypted[:access_token]
end
end
================================================
FILE: app/controllers/concerns/application_components_concern.rb
================================================
# frozen_string_literal: true
module ApplicationComponentsConcern
extend ActiveSupport::Concern
included do
rescue_from ComponentNotFoundError, with: :handle_component_not_found
end
protected
def handle_component_not_found(exception)
@exception = exception
render json: { error: 'Component not found' }, status: :not_found
end
end
================================================
FILE: app/controllers/concerns/application_controller_multitenancy_concern.rb
================================================
# frozen_string_literal: true
module ApplicationControllerMultitenancyConcern
extend ActiveSupport::Concern
include ApplicationMultitenancy
included do
set_current_tenant_through_filter
before_action :deduce_and_set_current_tenant
helper_method :current_tenant
end
end
================================================
FILE: app/controllers/concerns/application_instance_user_concern.rb
================================================
# frozen_string_literal: true
module ApplicationInstanceUserConcern
extend ActiveSupport::Concern
included do
before_action :track_instance_user
end
def current_instance_user
return nil unless current_user
@current_instance_user ||= current_tenant.instance_users.find_by(user: current_user)
end
private
def track_instance_user
return if current_instance_user.nil?
# Only update the timestamp every hour
return if current_instance_user.last_active_at && current_instance_user.last_active_at > 1.hour.ago
current_instance_user.update_column(:last_active_at, Time.zone.now)
end
end
================================================
FILE: app/controllers/concerns/application_internationalization_concern.rb
================================================
# frozen_string_literal: true
module ApplicationInternationalizationConcern
extend ActiveSupport::Concern
included do
before_action :set_locale
end
# Sets current locale to http accept(or compatible) language or default locale.
def set_locale
@client_language = @current_user&.locale&.to_sym || http_accept_language.
compatible_language_from(I18n.available_locales)
I18n.locale = @client_language
end
end
================================================
FILE: app/controllers/concerns/application_multitenancy.rb
================================================
# frozen_string_literal: true
module ApplicationMultitenancy
private
def deduce_and_set_current_tenant
tenant = deduce_tenant
ActsAsTenant.current_tenant = tenant
ActsAsTenant.test_tenant = tenant
end
# Deduces the tenant from the host specified in the HTTP Request.
# @return [Instance] The current tenant.
# @return [nil] If there is no current tenant.
def deduce_tenant
tenant_host = deduce_tenant_host
instance = Instance.find_tenant_by_host_or_default(tenant_host)
if Rails.env.production? && instance.default? && instance.host.casecmp(tenant_host) != 0
raise ActionController::RoutingError, 'Instance Not Found'
end
instance
end
# Deduces the current host. We strip any leading www from the host.
# @return [String] The host, with www removed.
def deduce_tenant_host
if Rails.env.development?
default_app_host = Application::Application.config.x.default_app_host
if request.host.downcase.ends_with?(default_app_host)
request.host.sub(default_app_host, 'coursemology.org')
else
'coursemology.org'
end
elsif request.host.downcase.start_with?('www.')
request.host[4..]
else
request.host
end
end
module ClassMethods
def set_current_tenant_through_filter
super
class_eval do
private :set_current_tenant
end
end
end
end
================================================
FILE: app/controllers/concerns/application_pagination_concern.rb
================================================
# frozen_string_literal: true
module ApplicationPaginationConcern
extend ActiveSupport::Concern
protected
# Retrieves page number and length from the GET request.
# Note: this is meant to be used for backend pagination with React pages.
def page_param
return {} if params[:filter].blank?
params[:filter].permit(:page_num, :length)
end
end
================================================
FILE: app/controllers/concerns/application_user_concern.rb
================================================
# frozen_string_literal: true
module ApplicationUserConcern
extend ActiveSupport::Concern
include ApplicationAuthenticationConcern
included do
before_action :authenticate!, unless: :publicly_accessible?
rescue_from CanCan::AccessDenied, with: :handle_access_denied
helper_method :url_to_user_or_course_user
end
# URL to the profile page of the given +CourseUser+ or +User+ in the current course
#
# @param [CourseUser|User] course_user The CourseUser/User to link to
# @return [String | nil] A URL that points to the +CourseUser+ or +User+ profile page
def url_to_user_or_course_user(course, user)
return course_user_path(course, user) if user.is_a?(CourseUser)
return user_path(user) if user.is_a?(User)
nil
end
def current_user
@current_user ||= current_user_from_token
end
protected
def publicly_accessible?
action_name.to_sym == :index && controller_name == 'application'
end
def handle_access_denied(exception)
render json: { errors: exception.message }, status: :forbidden
end
private
def authenticate!
raise AuthenticationError unless devise_controller? || current_user
update_user_tracked_fields
add_token_to_cookie
end
def add_token_to_cookie
cookies.encrypted[:access_token] =
{ value: token_from_request, httponly: true, expires: 1.hour.from_now }
end
def update_user_tracked_fields
return if !current_user || current_user.session_id == current_session_id
update_tracked_fields
end
def update_tracked_fields
old_current, new_current = current_user.current_sign_in_at, Time.now.utc
current_user.last_sign_in_at = old_current || new_current
current_user.current_sign_in_at = new_current
old_current, new_current = current_user.current_sign_in_ip, request.remote_ip
current_user.last_sign_in_ip = old_current || new_current
current_user.current_sign_in_ip = new_current
current_user.sign_in_count ||= 0
current_user.sign_in_count += 1
current_user.session_id = current_session_id
current_user.save
end
end
================================================
FILE: app/controllers/concerns/application_user_time_zone_concern.rb
================================================
# frozen_string_literal: true
module ApplicationUserTimeZoneConcern
extend ActiveSupport::Concern
included do
around_action :set_time_zone, if: :current_user
end
protected
# Set the time_zone for current request.
def set_time_zone(&block) # rubocop:disable Naming/AccessorMethodName
Time.use_zone(current_user.time_zone, &block)
end
end
================================================
FILE: app/controllers/concerns/codaveri_language_concern.rb
================================================
# frozen_string_literal: true
module CodaveriLanguageConcern
def codaveri_language
programming_language_map[type.constantize]&.fetch(:language) || polyglot_name
end
def codaveri_version
programming_language_map[type.constantize]&.fetch(:version) || polyglot_version
end
private
# We only need to list the special cases here, any others will fall back to the default
# name and version we are already using on our side.
def programming_language_map
{
Coursemology::Polyglot::Language::CPlusPlus::CPlusPlus11 => {
language: 'cpp',
version: '10.2'
},
Coursemology::Polyglot::Language::CPlusPlus::CPlusPlus17 => {
language: 'cpp',
version: '10.2'
},
Coursemology::Polyglot::Language::Java::Java17 => {
language: 'java',
version: '17.0'
},
Coursemology::Polyglot::Language::Java::Java21 => {
language: 'java',
version: '21.0'
},
Coursemology::Polyglot::Language::CSharp::CSharp5Point0 => {
language: 'csharp',
version: '5.0.201'
}
}
end
end
================================================
FILE: app/controllers/concerns/course/achievement_conditional_concern.rb
================================================
# frozen_string_literal: true
module Course::AchievementConditionalConcern
extend ActiveSupport::Concern
def success_action
render partial: 'course/condition/conditions', locals: { conditional: @conditional }
end
def set_conditional
@conditional = Course::Achievement.find(params[:achievement_id])
end
end
================================================
FILE: app/controllers/concerns/course/activity_feeds_concern.rb
================================================
# frozen_string_literal: true
module Course::ActivityFeedsConcern
extend ActiveSupport::Concern
# Loads recent activity feeds of a given course.
#
# @return [Array<Course::Notification>] Recent activity feed notifications
def recent_activity_feeds
return [] if current_course.nil?
current_course.notifications.feed.order(created_at: :desc)
end
end
================================================
FILE: app/controllers/concerns/course/assessment/answer/update_answer_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Answer::UpdateAnswerConcern
extend ActiveSupport::Concern
private
def update_answer(answer, answer_params)
update_answer_params = update_answer_params(answer, answer_params)
specific_answer = answer.specific
specific_answer.assign_params(update_answer_params)
# Saving the specific_answer to forward validation errors
return true if specific_answer.save
answer.errors.merge!(specific_answer.errors)
false
end
protected
def update_answer_params(answer, update_params)
update_params.
permit([:id, :client_version] + additional_answer_params(answer)).
merge(last_session_id: current_session_id)
end
def additional_answer_params(answer)
[].tap do |result|
result.push(*update_specific_answer_type_params(answer)) if can?(:update, answer)
result.push(:grade) if can?(:grade, answer) && !answer.submission.attempting?
end
end
def update_specific_answer_type_params(answer) # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity
answer_actable_class = answer.actable.class.name
scalar_params = []
array_params = {}
case answer_actable_class
when 'Course::Assessment::Answer::MultipleResponse'
update_multiple_response_params(array_params)
when 'Course::Assessment::Answer::Programming'
update_programming_params(array_params)
when 'Course::Assessment::Answer::TextResponse'
update_text_response_params(scalar_params)
when 'Course::Assessment::Answer::RubricBasedResponse'
update_rubric_based_response_params(scalar_params, array_params, answer)
when 'Course::Assessment::Answer::VoiceResponse'
update_voice_response_params(scalar_params)
when 'Course::Assessment::Answer::Scribing'
nil
when 'Course::Assessment::Answer::ForumPostResponse'
update_forum_post_response_params(scalar_params, array_params)
end
scalar_params.push(array_params)
end
def update_multiple_response_params(array_params)
array_params[:option_ids] = []
end
def update_programming_params(array_params)
array_params[:files_attributes] = [:id, :filename, :content]
end
def update_text_response_params(scalar_params)
scalar_params.push(:answer_text)
scalar_params.push(attachments_params)
end
def update_voice_response_params(scalar_params)
scalar_params.push(attachments_params)
end
def update_rubric_based_response_params(scalar_params, array_params, answer)
scalar_params.push(:answer_text)
return unless can?(:grade, answer) && !answer.submission.attempting?
array_params[:selections_attributes] = [:id, :answer_id, :category_id, :criterion_id, :grade, :explanation]
end
def update_forum_post_response_params(scalar_params, array_params)
scalar_params.push(:answer_text)
forum_post_attributes = [:id, :text, :creatorId, :updatedAt]
array_params[:selected_post_packs] =
[core_post: forum_post_attributes, parent_post: forum_post_attributes, topic: [:id]]
end
end
================================================
FILE: app/controllers/concerns/course/assessment/koditsu_assessment_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::KoditsuAssessmentConcern
extend ActiveSupport::Concern
def create_assessment_in_koditsu
workspace_id = current_course.koditsu_workspace_id
monitoring_object, seb_config_key = monitoring_configuration
assessment_service = Course::Assessment::KoditsuAssessmentService.
new(@assessment, [], workspace_id, monitoring_object, seb_config_key)
status, response = assessment_service.run_create_koditsu_assessment
adjust_assessment_from_koditsu_response(status, response)
end
def adjust_assessment_from_koditsu_response(status, response)
if status == 201
@assessment.update!({
is_synced_with_koditsu: true,
koditsu_assessment_id: response['id']
})
else
@assessment.update!(is_synced_with_koditsu: false)
end
end
def update_assessment_in_koditsu
assessment_id = @assessment.koditsu_assessment_id
get_question_status, questions = questions_in_koditsu(assessment_id)
unless get_question_status == 200
raise KoditsuError,
{ status: get_question_status, body: questions }
end
status = edit_koditsu_assessment(@assessment, questions, current_course, monitoring_configuration)
@assessment.update!(is_synced_with_koditsu: status == 200)
end
def create_or_update_assessment_in_koditsu
if @assessment.koditsu_assessment_id
update_assessment_in_koditsu
else
create_assessment_in_koditsu
end
end
def flag_assessment_not_synced_with_koditsu
@assessment.update!(is_synced_with_koditsu: false)
end
def remove_question_from_assessment_in_koditsu(question_id)
assessment_id = @assessment.koditsu_assessment_id
get_question_status, questions = questions_in_koditsu(assessment_id)
return unless get_question_status == 200
new_questions = questions.reject do |question|
question['id'] == question_id
end
status = edit_koditsu_assessment(@assessment, new_questions, current_course, monitoring_configuration)
return unless status == 200 && @assessment.questions.reload.all?(&:is_synced_with_koditsu)
@assessment.update!(is_synced_with_koditsu: true)
end
def questions_in_koditsu(koditsu_assessment_id)
service = KoditsuAsyncApiService.new("api/assessment/#{koditsu_assessment_id}", nil)
status, response = service.get
if status == 200
[status, response['data']['questions']]
else
[status, nil]
end
end
def monitoring_configuration
if @assessment.monitor_id
monitoring = @assessment.monitor
monitoring_object = {
heartbeatIntervalMs: monitoring.max_interval_ms,
isEnabled: monitoring.enabled
}
is_using_seb = @assessment.monitor.browser_authorization? &&
@assessment.monitor.browser_authorization_method == 'seb_config_key'
seb_config_key = is_using_seb ? @assessment.monitor.seb_config_key : nil
else
monitoring_object = {
heartbeatIntervalMs: 0,
isEnabled: false
}
seb_config_key = nil
end
[monitoring_object, seb_config_key]
end
def edit_koditsu_assessment(assessment, questions, course, monitoring_config)
assessment_id = assessment.koditsu_assessment_id
workspace_id = course.koditsu_workspace_id
monitoring_object, seb_config_key = monitoring_config
service = Course::Assessment::KoditsuAssessmentService.
new(assessment, questions, workspace_id, monitoring_object, seb_config_key)
status, = service.run_edit_koditsu_assessment(assessment_id)
status
end
end
================================================
FILE: app/controllers/concerns/course/assessment/koditsu_assessment_invitation_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::KoditsuAssessmentInvitationConcern
extend ActiveSupport::Concern
def send_invitation_for_koditsu_assessment(assessment)
invitation_validity_period = {
startAt: assessment.start_at - 12.hours,
endAt: assessment.end_at
}
course_users = assessment.course.course_users.preload(user: :emails)
users = course_users.map { |cu| [cu, cu.user] }
invitation_service = Course::Assessment::KoditsuAssessmentInvitationService.
new(assessment, users, invitation_validity_period)
status, response = invitation_service.run_invite_users_to_koditsu_assessment
[status, response]
end
def all_invitation_successful?(invitation_response)
failure_count = invitation_response.filter do |invitation|
invitation['status'] == 'errorOther'
end.length
failure_count == 0
end
end
================================================
FILE: app/controllers/concerns/course/assessment/live_feedback/file_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::LiveFeedback::FileConcern
extend ActiveSupport::Concern
def snapshot_files_hash(file_ids)
Course::Assessment::LiveFeedback::File.where(id: file_ids).to_h do |file|
[file.filename, file]
end
end
def answer_files_hash
@answer.actable.files.to_h do |file|
[file.filename, file]
end
end
def fetch_all_unchanged_files(file_hash, current_answer_file_hash)
file_hash.each_with_object([]) do |(filename, file), unchanged|
if current_answer_file_hash[filename] && current_answer_file_hash[filename].content == file.content
unchanged << file
end
end
end
def fetch_all_modified_files(file_hash, current_answer_file_hash)
current_answer_file_hash.each_with_object([]) do |(filename, file), modified|
if !file_hash[filename] || file_hash[filename].content != file.content
modified << { filename: file.filename,
content: file.content }
end
end
end
def fetch_all_files_to_be_associated(file_ids)
file_hash = snapshot_files_hash(file_ids)
current_answer_file_hash = answer_files_hash
unchanged_files = fetch_all_unchanged_files(file_hash, current_answer_file_hash)
modified_files = fetch_all_modified_files(file_hash, current_answer_file_hash)
[unchanged_files, modified_files]
end
end
================================================
FILE: app/controllers/concerns/course/assessment/live_feedback/message_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::LiveFeedback::MessageConcern
extend ActiveSupport::Concern
include Course::Assessment::LiveFeedback::MessageFileConcern
def handle_save_user_message
@thread = Course::Assessment::LiveFeedback::Thread.where(codaveri_thread_id: @thread_id).first
@thread.class.transaction do
new_message = create_new_message
new_options = @options.map do |option_id|
{
message_id: new_message.id,
option_id: option_id
}
end
options = Course::Assessment::LiveFeedback::MessageOption.insert_all(new_options)
raise ActiveRecord::Rollback if !new_options.empty? && (options.nil? || options.rows.empty?)
associate_new_message_with_new_or_existing_files(new_message)
end
end
def create_new_message
new_message = Course::Assessment::LiveFeedback::Message.create({
thread_id: @thread.id,
is_error: false,
content: @message,
creator_id: current_user.id,
created_at: Time.zone.now,
option_id: @option_id
})
raise ActiveRecord::Rollback unless new_message.persisted?
new_message
end
end
================================================
FILE: app/controllers/concerns/course/assessment/live_feedback/message_file_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::LiveFeedback::MessageFileConcern
extend ActiveSupport::Concern
include Course::Assessment::LiveFeedback::FileConcern
def associate_new_message_with_new_or_existing_files(new_message)
file_ids = associated_file_ids_with_last_message(new_message)
unchanged_files, modified_files = fetch_all_files_to_be_associated(file_ids)
new_files = Course::Assessment::LiveFeedback::File.insert_all(modified_files)
raise ActiveRecord::Rollback if !modified_files.empty? && (new_files.nil? || new_files.rows.empty?)
associated_file_ids = unchanged_files.map(&:id) + new_files.rows.flatten
save_message_file_association(new_message, associated_file_ids)
end
def associated_file_ids_with_last_message(new_message)
last_message = @thread.messages.where.not(id: new_message.id).order(id: :desc).first
if last_message
Course::Assessment::LiveFeedback::MessageFile.where(message_id: last_message.id).pluck(:file_id)
else
[]
end
end
def save_message_file_association(new_message, associated_file_ids)
new_message_files = associated_file_ids.map do |file_id|
{
message_id: new_message.id,
file_id: file_id
}
end
files = Course::Assessment::LiveFeedback::MessageFile.insert_all(new_message_files)
raise ActiveRecord::Rollback if !new_message_files.empty? && (files.nil? || files.rows.empty?)
end
end
================================================
FILE: app/controllers/concerns/course/assessment/live_feedback/thread_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::LiveFeedback::ThreadConcern
extend ActiveSupport::Concern
def safe_create_and_save_thread_info
submission_question = Course::Assessment::SubmissionQuestion.where(
submission_id: @submission, question_id: @answer.question
).first
submission_question.with_lock do
existing_active_threads = Course::Assessment::LiveFeedback::Thread.
where(submission_question_id: submission_question.id, is_active: true)
return existing_thread_status(existing_active_threads.first) unless existing_active_threads.empty?
create_and_save_thread_if_empty(submission_question)
end
end
def existing_thread_status(thread)
thread_status = thread.is_active? ? 'active' : 'expired'
[
200,
'thread' => { 'id' => thread.codaveri_thread_id, 'status' => thread_status }
]
end
def create_and_save_thread_if_empty(submission_question)
status, body = @answer.create_live_feedback_chat
new_thread = save_thread_info(body['thread'], submission_question.id)
[status, body]
end
def save_thread_info(thread_info, submission_question_id)
Course::Assessment::LiveFeedback::Thread.create!({
submission_question_id: submission_question_id,
codaveri_thread_id: thread_info['id'],
is_active: thread_info['status'] == 'active',
submission_creator_id: @submission.creator_id,
created_at: Time.zone.now
})
end
end
================================================
FILE: app/controllers/concerns/course/assessment/monitoring/seb_payload_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Monitoring::SebPayloadConcern
extend ActiveSupport::Concern
private
def seb_payload_from_request(request)
url = request.headers['X-SafeExamBrowser-Url']
seb_config_key_hash = request.headers['X-SafeExamBrowser-ConfigKeyHash']
return unless url && seb_config_key_hash
# It's safe to not strip URL fragments (#) here because fragments are never sent to the server.
{ config_key_hash: seb_config_key_hash, url: url }
end
def stub_heartbeat_from_request(request)
Course::Monitoring::Heartbeat.new(
user_agent: request.user_agent,
seb_payload: seb_payload_from_request(request)
)
end
end
================================================
FILE: app/controllers/concerns/course/assessment/monitoring_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::MonitoringConcern
extend ActiveSupport::Concern
include Course::Assessment::Monitoring::SebPayloadConcern
included do
alias_method :load_monitor, :monitor
alias_method :load_can_manage_monitor?, :can_manage_monitor?
alias_method :load_monitoring_component_enabled?, :monitoring_component_enabled?
before_action :load_monitor, only: [:edit, :show]
before_action :load_can_manage_monitor?, only: [:index, :edit]
before_action :load_monitoring_component_enabled?, only: [:index, :edit]
before_action :raise_if_no_monitor, only: [:monitoring, :unblock_monitor, :seb_payload]
before_action :check_blocked_by_monitor, only: [:show]
end
def monitoring
authorize! :read, @monitor
end
# We need this endpoint because Safe Exam Browser (SEB) doesn't append keys in request headers
# of WebSocket connections.
def seb_payload
payload = seb_payload_from_request(request)
return head(:ok) unless payload
render json: payload
end
def unblock_monitor
session_password = unblock_monitor_params[:password]
if monitoring_service&.unblock(session_password)
render json: { redirectUrl: course_assessment_path(current_course, @assessment) }
else
render json: { errors: t('course.assessment.assessments.unblock_monitor.invalid_password') }, status: :bad_request
end
end
def upsert_monitoring!
monitoring_service&.upsert!(monitoring_params.merge({
enabled: @assessment.view_password_protected? ? monitoring_params[:enabled] : false,
blocks: should_disable_block? ? false : monitoring_params[:blocks]
}))
end
private
def monitoring_params
params.require(:assessment).permit(monitoring: Course::Assessment::MonitoringService.params)[:monitoring]
end
def unblock_monitor_params
params.require(:assessment).permit(:password)
end
def raise_if_no_monitor
raise ComponentNotFoundError if monitor.nil?
end
def check_blocked_by_monitor
render 'blocked_by_monitor' if blocked_by_monitor?
end
def blocked_by_monitor?
cannot?(:read, monitor) && monitoring_service&.should_block?(request) && !submitted_assessment?
end
def monitoring_service
return unless monitoring_component_enabled?
@monitoring_service ||= Course::Assessment::MonitoringService.new(@assessment, session)
end
def monitoring_component_enabled?
@monitoring_component_enabled ||= current_component_host[:course_monitoring_component].present?
end
def can_manage_monitor?
@can_manage_monitor ||= can?(:manage, Course::Monitoring::Monitor.new)
end
def monitor
@monitor ||= monitoring_service&.monitor
end
def should_disable_block?
!@assessment.session_password_protected? || !monitor&.browser_authorization?
end
def submitted_assessment?
@submissions.find { |submission| !submission.attempting? }.present?
end
end
================================================
FILE: app/controllers/concerns/course/assessment/question/codaveri_question_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Question::CodaveriQuestionConcern
extend ActiveSupport::Concern
def safe_create_or_update_codaveri_question(question)
question.with_lock do
next if question.is_synced_with_codaveri
# we bypass the processing of the package since this function is called only when
# we create the Codaveri question from duplicate on-demand, which means that
# the question has already been created; we just need to propagate this question
# to Codaveri
question.skip_process_package = true
Course::Assessment::Question::ProgrammingCodaveriService.
create_or_update_question(question, question.attachment)
end
end
def extract_pathname_from_java_file(file_content)
# extracts pathname based on public class of java file
class_name_extractor = /(?:^|;)\s*public\s+class\s+([A-Za-z_][A-Za-z0-9_]*)/
match = file_content.match(class_name_extractor)
match ? "#{match[1]}.java" : nil
end
end
================================================
FILE: app/controllers/concerns/course/assessment/question/koditsu_question_concern.rb
================================================
# frozen_string_literal: true
# rubocop:disable Metrics/ModuleLength
module Course::Assessment::Question::KoditsuQuestionConcern
extend ActiveSupport::Concern
include Course::Assessment::KoditsuAssessmentConcern
def create_koditsu_question
workspace_id = current_course.koditsu_workspace_id
service = Course::Assessment::Question::KoditsuQuestionService.
new(@programming_question, workspace_id, @meta, current_course)
status, response = service.run_create_koditsu_question
adjust_question_from_koditsu_response(status, response)
end
def adjust_question_from_koditsu_response(status, response)
@question = @programming_question.acting_as
if status == 201
@question.update!({
koditsu_question_id: response['id'],
is_synced_with_koditsu: true
})
@assessment.update!(is_synced_with_koditsu: false)
else
@question.update!(is_synced_with_koditsu: false)
end
end
def arrange_questions_in_assessment_in_koditsu
@assessment.reload && @assessment.questions.reload
koditsu_questions = @assessment.questions.map do |question|
{
id: question.koditsu_question_id,
type: 'QuestionCoding',
score: question.maximum_grade.to_i,
maxAttempts: question.specific.attempt_limit&.to_i
}
end
status = edit_koditsu_assessment(@assessment, koditsu_questions, current_course, monitoring_configuration)
return unless status == 200 && @assessment.questions.reload.all?(&:is_synced_with_koditsu)
@assessment.update!(is_synced_with_koditsu: true)
end
def edit_koditsu_question
koditsu_question_id = @question.koditsu_question_id
service = Course::Assessment::Question::KoditsuQuestionService.
new(@programming_question, nil, @meta, current_course)
status = service.run_edit_koditsu_question(koditsu_question_id)
@question.update!(is_synced_with_koditsu: true) if status == 200
end
def delete_koditsu_question(id)
api_service = KoditsuAsyncApiService.new("api/question/coding/#{id}", nil)
response_status, = api_service.delete
response_status
end
def create_or_edit_question_in_koditsu
extract_programming_question_metadata
if @programming_question.acting_as.koditsu_question_id
edit_koditsu_question
else
create_koditsu_question
end
end
def extract_programming_question_metadata
return unless @programming_question.edit_online?
@meta = programming_package_service.extract_meta
end
def programming_package_service
@service = Course::Assessment::Question::Programming::ProgrammingPackageService.new(
@programming_question, nil
)
end
def koditsu_programming_language_map
{
Coursemology::Polyglot::Language::CPlusPlus => {
language: 'cpp',
version: '10.2',
filename: 'template.cpp'
},
Coursemology::Polyglot::Language::CPlusPlus::CPlusPlus11 => {
language: 'cpp',
version: '10.2',
filename: 'template.cpp'
},
Coursemology::Polyglot::Language::Python::Python3Point4 => {
language: 'python',
version: '3.4',
filename: 'main.py'
},
Coursemology::Polyglot::Language::Python::Python3Point5 => {
language: 'python',
version: '3.5',
filename: 'main.py'
},
Coursemology::Polyglot::Language::Python::Python3Point6 => {
language: 'python',
version: '3.6',
filename: 'main.py'
},
Coursemology::Polyglot::Language::Python::Python3Point7 => {
language: 'python',
version: '3.7',
filename: 'main.py'
},
Coursemology::Polyglot::Language::Python::Python3Point9 => {
language: 'python',
version: '3.9',
filename: 'main.py'
},
Coursemology::Polyglot::Language::Python::Python3Point10 => {
language: 'python',
version: '3.10',
filename: 'main.py'
},
Coursemology::Polyglot::Language::Python::Python3Point12 => {
language: 'python',
version: '3.12',
filename: 'main.py'
},
Coursemology::Polyglot::Language::Python::Python3Point13 => {
language: 'python',
version: '3.13',
filename: 'main.py'
}
}
end
end
# rubocop:enable Metrics/ModuleLength
================================================
FILE: app/controllers/concerns/course/assessment/question/multiple_responses_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Question::MultipleResponsesConcern
extend ActiveSupport::Concern
def switch_mcq_mrq_type(is_mcq, unsubmit)
grading_scheme = is_mcq ? :any_correct : :all_correct
result = @multiple_response_question.update(grading_scheme: grading_scheme)
if result
unsubmit_submissions if unsubmit
else
@multiple_response_question.reload
end
result
end
def unsubmit_submissions
submission_ids = @question_assessment.assessment.submissions.pluck(:id)
Course::Assessment::Submission::UnsubmittingJob.
perform_later(current_user,
submission_ids,
@assessment,
@multiple_response_question.question).job
end
end
================================================
FILE: app/controllers/concerns/course/assessment/question/rubric_based_response_controller_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Question::RubricBasedResponseControllerConcern
include Course::Assessment::Question::RubricBasedResponseQuestionConcern
extend ActiveSupport::Concern
def create_new_category_grade_instances(new_category_ids)
answers = Course::Assessment::Answer.where(
actable_type: 'Course::Assessment::Answer::RubricBasedResponse',
question_id: @rubric_based_response_question.acting_as.id
).includes(:actable).map(&:actable)
new_category_selections = answers.product(new_category_ids).map do |answer, category_id|
{
answer_id: answer.id,
category_id: category_id,
criterion_id: nil,
grade: nil,
explanation: nil
}
end
selections = Course::Assessment::Answer::RubricBasedResponseSelection.insert_all(new_category_selections)
raise ActiveRecord::Rollback if !new_category_selections.empty? && (selections.nil? || selections.rows.empty?)
true
end
def update_all_submission_answer_grades
all_assessment_submission_ids = @assessment.submissions.map(&:id)
@all_rubric_based_response_answers = Course::Assessment::Answer.where(
submission_id: all_assessment_submission_ids,
actable_type: 'Course::Assessment::Answer::RubricBasedResponse'
).includes(:question, actable: [selections: :criterion])
answer_score_array = construct_answer_score_array
raise ActiveRecord::Rollback unless Course::Assessment::Answer.upsert_all(answer_score_array, update_only: :grade,
unique_by: :id)
true
end
def preload_criterions_per_category
@rubric_based_response_question = Course::Assessment::Question::RubricBasedResponse.
includes(categories: :criterions).
find(@rubric_based_response_question.id)
end
end
================================================
FILE: app/controllers/concerns/course/assessment/question/rubric_based_response_question_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Question::RubricBasedResponseQuestionConcern
extend ActiveSupport::Concern
def construct_answer_score_array
@all_rubric_based_response_answers.filter_map do |answer|
selections = answer.actable&.selections
next unless selections
answer_object(answer, total_grade_for(selections, answer.question.maximum_grade))
end
end
def total_grade_for(selections, maximum_grade)
total_grade = selections.sum { grade_value(_1) }
total_grade.clamp(0, maximum_grade)
end
def grade_value(selection)
selection.grade.presence || selection.criterion&.grade.to_i
end
def answer_object(answer, total_grade)
{ id: answer.id, submission_id: answer.submission_id, question_id: answer.question_id, grade: total_grade,
workflow_state: answer.workflow_state, correct: answer.correct, submitted_at: answer.submitted_at }
end
end
================================================
FILE: app/controllers/concerns/course/assessment/question_bundle_assignment_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::QuestionBundleAssignmentConcern
extend ActiveSupport::Concern
# All validations need to present a ValidationResult of this form, which will be consumed by the view.
# This struct is loosely inspired by Rails' model validation, but heavily extended.
# rubocop:disable Layout/CommentIndentation
ValidationResult = Struct.new(
:type, # Hard or soft
:pass, # Whether this should be displayed as a tick or cross on the validation summary
:score_penalty, # For selecting the best randomized outcome
:info, # For displaying additional information. I18n string.
:offending_cells, # For highlighting the cell and displaying the error in a tooltip. I18n string.
# E.g. { (student, group): 'Lift: 1.4' }
keyword_init: true
)
# rubocop:enable Layout/CommentIndentation
# Computations on a large set of QBAs are expensive, and we need a lean in-memory representation of a set of QBAs.
#
# An AssignmentSet is a (thin) abstraction over a set of QBAs for an assessment which assumes consistency of the
# underlying data. The constructing code is responsible for data translation / validation.
#
# Essentially a nested hash of Student -> Group -> Bundle. Group is nil if assigned bundle is extraneous. Everything
# is identified by an integer ID.
class AssignmentSet
attr_accessor :assignments, :group_bundles
def initialize(students, group_bundles)
@assignments = students.to_h { |x| [x, nil => []] }
@group_bundles = group_bundles
@group_bundles_lookup = group_bundles.flat_map do |group, bundles|
bundles.map { |bundle| [bundle, group] }
end.to_h
end
def add_assignment(student, bundle)
group = @group_bundles_lookup[bundle]
@assignments[student] ||= { nil => [] }
if @assignments[student][group].nil?
@assignments[student][group] = bundle
else
@assignments[student][nil].append(bundle)
end
end
end
class AssignmentRandomizer
attr_accessor :assignments, :students, :group_bundles, :name_lookup
def initialize(assessment)
@assessment = assessment
@students = assessment.course.user_ids
@group_bundles = assessment.question_group_ids.to_h { |x| [x, []] }
assessment.question_bundles.each { |bundle| @group_bundles[bundle.group_id].append(bundle.id) }
# Reverse lookup of user_id -> course_user.name or user.name
# Retrieve for current course users, users with submissions, and users with bundle assignments
@name_lookup = User.where(id: @assessment.question_bundle_assignments.select(:user_id)).
pluck(:id, :name).to_h.
merge(@assessment.course.course_users.pluck(:user_id, :name).to_h)
end
def load
AssignmentSet.new(@students, @group_bundles).tap do |assignment_set|
@assessment.question_bundle_assignments.where(submission: nil).each do |qba|
assignment_set.add_assignment(qba.user_id, qba.bundle_id)
end
end
end
def save(assignment_set)
# Deletion must be done atomically to prevent race conditions
@assessment.question_bundle_assignments.where(submission: nil).delete_all
new_question_bundle_assignments = []
assignment_set.assignments.each do |student_id, assigned_group_bundles|
assigned_group_bundles.each do |group_id, bundle_id|
next if group_id.nil? || bundle_id.nil?
new_question_bundle_assignments << Course::Assessment::QuestionBundleAssignment.new(
user_id: student_id,
assessment_id: @assessment.id,
bundle_id: bundle_id
)
end
end
Course::Assessment::QuestionBundleAssignment.import! new_question_bundle_assignments
end
def randomize
# Naive strategy: For each group, add a random bundle
AssignmentSet.new(@students, @group_bundles).tap do |assignment_set|
@students.each do |student|
@group_bundles.each do |_, bundles|
assignment_set.add_assignment(student, bundles.sample)
end
end
end
end
def validate(assignment_set)
[
validate_no_overlapping_questions,
validate_no_empty_groups,
validate_one_bundle_assigned(assignment_set),
validate_no_repeat_bundles(assignment_set)
].reduce(&:merge)
end
private
def validate_no_overlapping_questions
questions = Course::Assessment::Question.
where(id: @assessment.question_bundle_questions.group(:question_id).
having('count(*) > 1').
select(:question_id)).
pluck(:title).
to_sentence
{
no_overlapping_questions:
ValidationResult.new(
type: :hard,
pass: questions.empty?,
info: questions.empty? ? nil : t_scoped('.no_overlapping_questions.fail', questions: questions)
)
}
end
def validate_no_empty_groups
groups = @assessment.question_groups.
where.not(id: @assessment.question_bundles.select(:group_id)).
pluck(:title).to_sentence
{
no_empty_groups:
ValidationResult.new(
type: :hard,
pass: groups.empty?,
info: groups.empty? ? nil : t_scoped('.no_empty_groups.fail', groups: groups)
)
}
end
def validate_one_bundle_assigned(assignment_set)
student_ids = Set.new
offending_cells = {}
assignment_set.assignments.each do |student_id, assignment|
assignment_set.group_bundles.each_key do |group_bundle|
if assignment[group_bundle].nil?
student_ids << student_id
offending_cells[[student_id, group_bundle]] = t_scoped('.one_bundle_assigned.missing_bundle')
end
end
if assignment[nil].present?
student_ids << student_id
offending_cells[[student_id, nil]] = t_scoped('.one_bundle_assigned.unbundled')
end
end
students = student_ids.map { |student_id| @name_lookup[student_id] }.to_sentence
{
one_bundle_assigned:
ValidationResult.new(
type: :hard,
pass: students.empty?,
info: students.empty? ? nil : t_scoped('.one_bundle_assigned.fail', students: students),
offending_cells: offending_cells
)
}
end
def validate_no_repeat_bundles(assignment_set)
attempted_questions = {}
@assessment.question_bundle_assignments.where.not(submission: nil).pluck(:user_id, :bundle_id).
each do |user_id, bundle_id|
attempted_questions[user_id] ||= Set.new
attempted_questions[user_id] << bundle_id
end
student_ids = Set.new
offending_cells = {}
assignment_set.assignments.each do |student_id, assignment|
assignment_set.group_bundles.each_key do |group_bundle|
if assignment[group_bundle].present? && assignment[group_bundle].in?(attempted_questions[student_id] || [])
student_ids << student_id
offending_cells[[student_id, group_bundle]] = t_scoped('.no_repeat_bundles.repeat_bundle')
end
end
if assignment[nil].present? && assignment[nil].any? { |b| b.in?(attempted_questions[student_id] || []) }
student_ids << student_id
offending_cells[[student_id, nil]] = t_scoped('.no_repeat_bundles.repeat_bundle')
end
end
students = student_ids.map { |student_id| @name_lookup[student_id] }.to_sentence
{
no_repeat_bundles:
ValidationResult.new(
type: :hard,
pass: students.empty?,
info: students.empty? ? nil : t_scoped('.no_repeat_bundles.fail', students: students),
offending_cells: offending_cells
)
}
end
# We can't use the default I18n lazy lookups because this is a concern, so we roll our own.
def t_scoped(key, *args, **kwargs)
I18n.t("course.assessment.question_bundle_assignments.validations#{key}", *args, **kwargs)
end
end
end
================================================
FILE: app/controllers/concerns/course/assessment/submission/koditsu/answers_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Submission::Koditsu::AnswersConcern
extend ActiveSupport::Concern
def build_answer_hash(answers)
@answer_hash = answers.to_h do |answer|
question = answer.question
koditsu_question_id = question.koditsu_question_id
[koditsu_question_id, [question, answer]]
end
end
def destroy_all_existing_autogradings(answers)
Course::Assessment::Answer::ProgrammingAutoGrading.where(answer: answers).destroy_all
end
def destroy_all_existing_files(answers)
answer_ids = answers.map(&:actable_id)
Course::Assessment::Answer::ProgrammingFile.where(answer_id: answer_ids).destroy_all
end
def update_all_submission_files(submission_answers)
updated_files = submission_answers.flat_map do |submission_answer|
_, answer = @answer_hash[submission_answer['questionId']]
submission_answer['files'].map do |file|
{
filename: file['path'],
content: file['content'],
answer_id: answer.actable_id
}
end
end
raise ActiveRecord::Rollback unless Course::Assessment::Answer::ProgrammingFile.
insert_all(updated_files)
end
def process_all_answers(submission_answers)
update_all_submission_files(submission_answers)
process_all_test_case_results(submission_answers)
end
def process_all_test_case_results(submission_answers)
submission_with_test_case_results = submission_answers.reject do |sa|
sa['exprTestcaseResults'].empty?
end
@autograding_id_hash = submission_with_test_case_results.to_h do |submission_answer|
_, answer = @answer_hash[submission_answer['questionId']]
autograding_id = new_autograding_id(answer)
[answer.id, autograding_id]
end
update_all_answer_status(submission_with_test_case_results)
save_all_test_case_results(submission_with_test_case_results)
end
def update_all_answer_status(submission_answers)
submitted_answers = submission_answers.filter { |answer| answer['status'] == 'submitted' }
updated_answer_objects = submitted_answers.map do |submitted_answer|
question, answer = @answer_hash[submitted_answer['questionId']]
build_answer_object(question, answer, submitted_answer)
end
raise ActiveRecord::Rollback unless Course::Assessment::Answer.upsert_all(updated_answer_objects)
end
def build_answer_object(question, answer, submitted_answer)
{
id: answer.id,
submission_id: answer.submission_id,
question_id: question.id,
workflow_state: 'submitted',
correct: submitted_answer['exprTestcaseResults'].all? { |tc| tc['result']['success'] },
submitted_at: DateTime.parse(submitted_answer['filesSavedAt']).in_time_zone&.iso8601 ||
Time.now.utc
}
end
def save_all_test_case_results(submission_answers)
test_case_result_objects = submission_answers.flat_map do |submission_answer|
question, answer = @answer_hash[submission_answer['questionId']]
test_case_index_id_hash = @test_cases_order[question.id]
test_case_results = submission_answer['exprTestcaseResults']
test_case_results.map do |tc_result|
{
auto_grading_id: @autograding_id_hash[answer.id],
test_case_id: test_case_index_id_hash[tc_result['testcase']['index']],
passed: tc_result['result']['success'],
messages: { output: tc_result['result']['display'] }
}
end
end
raise ActiveRecord::Rollback unless Course::Assessment::Answer::ProgrammingAutoGradingTestResult.
insert_all(test_case_result_objects)
end
def new_autograding_id(answer)
autograding = Course::Assessment::Answer::ProgrammingAutoGrading.new(answer: answer)
raise ActiveRecord::Rollback unless autograding.save!
autograding.id
end
end
================================================
FILE: app/controllers/concerns/course/assessment/submission/koditsu/submission_times_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Submission::Koditsu::SubmissionTimesConcern
extend ActiveSupport::Concern
def calculate_submission_time(state, questions)
return nil unless state == 'submitted'
attempted_questions = questions.reject do |question|
question['status'] == 'notStarted'
end
final_submission_time(attempted_questions)
end
private
def final_submission_time(attempted_questions)
return @assessment.end_at&.iso8601 || Time.now.utc if attempted_questions.empty?
attempted_questions.map do |question|
DateTime.parse(question['filesSavedAt']).in_time_zone
end.max&.iso8601
end
end
================================================
FILE: app/controllers/concerns/course/assessment/submission/koditsu/submissions_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Submission::Koditsu::SubmissionsConcern
extend ActiveSupport::Concern
include Course::Assessment::Question::KoditsuQuestionConcern
include Course::Assessment::Submission::Koditsu::UsersConcern
include Course::Assessment::Submission::Koditsu::AnswersConcern
include Course::Assessment::Submission::Koditsu::TestCasesConcern
include Course::Assessment::Submission::Koditsu::SubmissionTimesConcern
def fetch_all_submissions_from_koditsu(assessment, user)
@assessment = assessment
@user = user
submission_service = Course::Assessment::Submission::KoditsuSubmissionService.new(@assessment)
status, response = submission_service.run_fetch_all_submissions
return [status, nil] if status != 200 && status != 207
process_fetch_submissions_response(response)
end
def process_fetch_submissions_response(response)
@all_submissions = response
@questions = @assessment.questions.includes({ actable: :test_cases })
@test_cases_order = test_cases_order_for(@questions)
@cu_submission_hash = course_user_submission_hash(@all_submissions)
process_all_submissions
end
private
def submission_status_hash
{
'inProgress' => 'attempting',
'submitted' => 'submitted'
}
end
def process_all_submissions
create_new_submissions_if_not_existing
@submission_hash = Course::Assessment::Submission.where(assessment: @assessment).to_h do |s|
[s.creator_id, s]
end
@cu_submission_hash.each do |creator, submission|
process_submission(submission, @submission_hash[creator.id])
end
end
def process_submission(submission, cm_submission)
state = submission_status_hash[submission['status']]
submitted_at = calculate_submission_time(state, submission['questions'])
cm_submission.class.transaction do
update_submission(cm_submission, state, submitted_at)
process_submission_answers(submission, cm_submission)
end
end
def create_new_submissions_if_not_existing
existing_submission_user_ids = Course::Assessment::Submission.where(assessment: @assessment).
pluck(:creator_id)
koditsu_submission_user_ids = @cu_submission_hash.keys.map { |creator, _| creator.id }
user_ids_without_submission = koditsu_submission_user_ids - existing_submission_user_ids
return if user_ids_without_submission.empty?
user_info_hash = user_related_hash(user_ids_without_submission)
user_ids_without_submission.each do |user_id|
user, course_user = user_info_hash[user_id]
create_new_submission_for(user, course_user)
end
end
def create_new_submission_for(creator, course_user)
User.with_stamper(creator) do
new_submission = @assessment.submissions.new(creator: creator,
course_user: course_user)
success = @assessment.create_new_submission(new_submission, course_user)
raise ActiveRecord::Rollback unless success
new_submission.create_new_answers
end
end
def update_submission(cm_submission, state, submitted_at)
update_submission_object = { workflow_state: state, submitted_at: submitted_at }
User.with_stamper(@user) do
raise ActiveRecord::Rollback unless cm_submission.update!(update_submission_object)
end
end
def process_submission_answers(submission, cm_submission)
answers = Course::Assessment::Answer.includes(:question).where(submission_id: cm_submission.id)
build_answer_hash(answers)
raise ActiveRecord::Rollback unless destroy_all_existing_autogradings(answers)
raise ActiveRecord::Rollback unless destroy_all_existing_files(answers)
submission_answers = submission['questions'].reject do |submission_answer|
['notStarted', 'error'].include?(submission_answer['status'])
end
process_all_answers(submission_answers)
end
end
================================================
FILE: app/controllers/concerns/course/assessment/submission/koditsu/test_cases_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Submission::Koditsu::TestCasesConcern
extend ActiveSupport::Concern
def test_cases_order_for(questions)
questions.to_h do |question|
test_cases = question.actable.test_cases
[question.id, sort_for_koditsu(test_cases)]
end
end
private
def order_test_cases_type
{
'public' => 0,
'private' => 1,
'evaluation' => 2
}
end
def sort_for_koditsu(test_cases)
return [] if test_cases.empty?
mapped_test_cases = test_cases.map do |tc|
[tc.id, tc.identifier.split('/').last]
end
sorted_test_cases = mapped_test_cases.sort_by do |_, identifier|
parts = identifier.split('_')
[order_test_cases_type[parts[1]], parts[2].to_i]
end
sorted_test_cases.map { |id, _| id }.each_with_index.to_h { |id, index| [index + 1, id] }
end
end
================================================
FILE: app/controllers/concerns/course/assessment/submission/koditsu/users_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Submission::Koditsu::UsersConcern
extend ActiveSupport::Concern
def user_related_hash(user_ids)
user_hash = User.where(id: user_ids).to_h { |u| [u.id, u] }
course_user_hash = CourseUser.where(course_id: @assessment.course.id,
user_id: user_ids).to_h do |cu|
[cu.user_id, cu]
end
user_ids.to_h do |uid|
[uid, [user_hash[uid], course_user_hash[uid]]]
end
end
def course_user_submission_hash(submissions)
es_hash = email_submission_hash(submissions)
ecu_hash = email_course_user_hash(es_hash.keys)
ecu_hash.to_h do |email, user|
[user, es_hash[email]]
end
end
def email_course_user_hash(emails)
user_hash = User.
joins(:emails).
where(user_emails: { email: emails }).to_h do |user|
[user.id, user]
end
CourseUser.where(course_id: @assessment.course.id,
user_id: user_hash.keys).to_h do |cu|
[user_hash[cu.user_id].email, user_hash[cu.user_id]]
end
end
def email_submission_hash(submissions)
attempted_submissions = submissions.reject do |submission|
submission['status'] == 'notStarted' || submission['status'] == 'error'
end
attempted_submissions.to_h { |s| [s['user']['email'], s] }
end
end
================================================
FILE: app/controllers/concerns/course/assessment/submission/monitoring_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Submission::MonitoringConcern
extend ActiveSupport::Concern
included do
before_action :check_blocked_by_monitor, only: [:create, :edit, :update]
after_action :stop_monitoring_session_if_submitted, only: [:update]
end
def should_monitor? # rubocop:disable Metrics/CyclomaticComplexity
monitoring_component_enabled? &&
current_user.id == @submission.creator_id &&
current_course_user&.student? &&
can?(:create, Course::Monitoring::Session.new(creator_id: current_user.id)) &&
@assessment&.monitor&.enabled? &&
@submission.attempting?
end
def monitoring_service
return unless should_monitor? || can_update_monitoring_session?
@monitoring_service ||= Course::Assessment::Submission::MonitoringService.for(@submission, @assessment, session)
end
private
def monitoring_component_enabled?
current_component_host[:course_monitoring_component].present?
end
def can_update_monitoring_session?
can?(:update, Course::Monitoring::Session.new)
end
def stop_monitoring_session_if_submitted
monitoring_service&.stop! if @submission.submitted?
end
def check_blocked_by_monitor
render json: { newSessionUrl: course_assessment_path(current_course, @assessment) } if blocked_by_monitor?
end
def blocked_by_monitor?
should_monitor? && monitoring_service&.should_block?(request)
end
end
================================================
FILE: app/controllers/concerns/course/assessment/submission/submissions_controller_service_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::Submission::SubmissionsControllerServiceConcern
extend ActiveSupport::Concern
private
# Get the service class based on the assessment display mode.
#
# @return [Class] The class of the service.
def service_class
Course::Assessment::Submission::UpdateService
end
# Instantiate a service based on the assessment display mode.
#
# @return [Course::Assessment::Submission::UpdateService] The service instance.
def service
@service ||= service_class.new(self, assessment: @assessment, submission: @submission)
end
# Extract the defined instance variables from the service, so that views can access them.
# Call this method at the end of the action if there are any instance variables defined in the
# action.
# @param [Course::Assessment::UpdateService] service the service instance.
def extract_instance_variables(service)
service.instance_variables.each do |name|
value = service.instance_variable_get(name)
instance_variable_set(name, value)
end
end
module ClassMethods
# Delegate the action to the service and extract the instance variables from the service after
# the action is done.
# @param [Symbol] action the name of the action to delegate.
def delegate_to_service(action)
define_method(action) do
service.public_send(action)
extract_instance_variables(service)
end
end
end
end
================================================
FILE: app/controllers/concerns/course/assessment/submission_concern.rb
================================================
# frozen_string_literal: true
module Course::Assessment::SubmissionConcern
extend ActiveSupport::Concern
private
def authorize_submission!
if @submission.attempting?
authorize!(:update, @submission)
else
authorize!(:read, @submission)
end
end
def check_password
return unless @submission.attempting?
return if !@assessment.session_password_protected? || can?(:manage, @assessment)
return if authentication_service.authenticated?
log_service.log_submission_access(request)
render json: { newSessionUrl: new_session_path }
end
def authentication_service
@authentication_service ||=
Course::Assessment::SessionAuthenticationService.new(@assessment, current_session_id, @submission)
end
def log_service
@log_service ||=
Course::Assessment::SessionLogService.new(@assessment, current_session_id, @submission)
end
def new_session_path
new_course_assessment_session_path(
current_course, @assessment, submission_id: @submission.id
)
end
end
================================================
FILE: app/controllers/concerns/course/assessment_conditional_concern.rb
================================================
# frozen_string_literal: true
module Course::AssessmentConditionalConcern
extend ActiveSupport::Concern
def success_action
render partial: 'course/condition/conditions', locals: { conditional: @conditional }
end
def set_conditional
@conditional = Course::Assessment.find(conditional_params[:assessment_id])
end
private
def conditional_params
params.permit(:assessment_id)
end
end
================================================
FILE: app/controllers/concerns/course/cikgo_chats_concern.rb
================================================
# frozen_string_literal: true
module Course::CikgoChatsConcern
extend ActiveSupport::Concern
def find_or_create_room(course_user)
return unless course_user.present?
user = course_user.user
create_cikgo_user(user) if user.cikgo_user.nil?
Cikgo::ChatsService.find_or_create_room!(course_user)
end
def get_mission_control_url(course_user)
Cikgo::ChatsService.mission_control!(course_user)
end
private
def create_cikgo_user(user)
provider_user_id = current_decoded_token[:sub]
image_url = helpers.user_image(user, url: true)
provided_user_id = Cikgo::UsersService.authenticate!(user, provider_user_id, image_url)
(user.cikgo_user || user.build_cikgo_user).provided_user_id = provided_user_id
user.cikgo_user.save!
end
end
================================================
FILE: app/controllers/concerns/course/cikgo_push_concern.rb
================================================
# frozen_string_literal: true
module Course::CikgoPushConcern
extend ActiveSupport::Concern
include Cikgo::PushableItemConcern
private
def push_lesson_plan_items_to_remote_course
return unless current_course.component_enabled?(Course::StoriesComponent)
Cikgo::ResourcesService.push_repository!(
current_course,
course_url(current_course),
pushable_lesson_plan_items.filter_map do |item|
actable = item.actable
kind = actable.class.name.demodulize
{
id: item.id.to_s,
kind: kind,
name: item.title,
description: item.description,
url: send("course_#{kind.underscore}_url", current_course, actable)
}
end
)
end
def pushable_lesson_plan_items
current_course.lesson_plan_items.published.includes(:actable).
where(actable_type: pushable_lesson_plan_item_types.map(&:name))
end
end
================================================
FILE: app/controllers/concerns/course/discussion/posts_concern.rb
================================================
# frozen_string_literal: true
module Course::Discussion::PostsConcern
extend ActiveSupport::Concern
included do
before_action :set_topic
load_and_authorize_resource :post, through: :discussion_topic,
class: 'Course::Discussion::Post', parent: false
end
protected
# Update pending status of the topic:
# If the student replies to the topic, set to true.
# If the staff replies the post, set to false.
#
# @return [Boolean] Boolean on whether the update is successful.
def update_topic_pending_status
return true if !current_course_user || skip_update_topic_status
if current_course_user.teaching_staff?
@post.topic.unmark_as_pending
else
@post.topic.mark_as_pending
end
end
# Option for controller to skip the topic_status.
def skip_update_topic_status
false
end
# Create topic subscriptions for related users
#
# @return [Boolean] True if all subscriptions are created successfully.
def create_topic_subscription
raise NotImplementedError, 'To be implemented by the concrete topic posts controller.'
end
# The discussion topic record that posts belong to.
# When your model uses 'acts_as :topic', you can write: 'your_instance.topic' in this method.
#
# @return [Course::Discussion::Topic] The discussion topic record.
def discussion_topic
raise NotImplementedError, 'To be implemented by the concrete topic posts controller.'
end
private
def post_params
params.require(:discussion_post).permit(:title, :text, :parent_id, :workflow_state, :is_anonymous,
codaveri_feedback_attributes: [:id, :rating, :status])
end
def set_topic
@discussion_topic ||= discussion_topic
end
end
================================================
FILE: app/controllers/concerns/course/forum/auto_answering_concern.rb
================================================
# frozen_string_literal: true
module Course::Forum::AutoAnsweringConcern
extend ActiveSupport::Concern
def auto_answer_action(query_post, topic, is_regenerated_response: false)
return unless current_course.component_enabled?(Course::RagWiseComponent)
return if response_should_not_be_generated?(is_regenerated_response)
settings = rag_settings
# ensures that when manually generating new reply it will always draft
settings[:response_workflow] = '0' if is_regenerated_response
system ||= User.find(User::SYSTEM_USER_ID)
raise 'No system user. Did you run rake db:seed?' unless system
query_post.rag_auto_answer!(topic, system, nil, settings)
end
def publish_post_action
return false unless current_course.component_enabled?(Course::RagWiseComponent)
@post.publish!
publish_post(@post, @topic, current_user, current_course_user)
end
def last_rag_auto_answering_job
return head(:bad_request) unless current_course.component_enabled?(Course::RagWiseComponent)
job = @post.rag_auto_answering&.job
(job&.status == 'submitted') ? job : nil
end
def rag_settings
rag_component = current_component_host[:course_rag_wise_component]&.settings
{
response_workflow: rag_component&.response_workflow,
roleplay: rag_component&.roleplay
}
end
def publish_post(post, topic, current_author, current_course_author)
# In case of conditional publish, when non course-creator publish AI responses
# The post creator will become the person who pressed the publish button
post.creator = current_author
post.updater = current_author
result = ActiveRecord::Base.transaction do
raise ActiveRecord::Rollback unless post.save && create_topic_subscription(topic, current_author)
raise ActiveRecord::Rollback unless topic.update_column(:latest_post_at, post.updated_at)
true
end
send_created_notification(current_author, current_course_author, post) if result
result
end
def create_topic_subscription(topic, current_user)
if topic.forum.forum_topics_auto_subscribe
topic.ensure_subscribed_by(current_user)
else
true
end
end
def send_created_notification(current_author, current_course_author, post)
return unless current_author
Course::Forum::PostNotifier.post_replied(current_author, current_course_author, post)
end
private
def response_should_not_be_generated?(is_regenerated_response)
!is_regenerated_response && (current_course_user.staff? || rag_settings[:response_workflow] == 'no')
end
end
================================================
FILE: app/controllers/concerns/course/forum/topic_controller_hiding_concern.rb
================================================
# frozen_string_literal: true
module Course::Forum::TopicControllerHidingConcern
extend ActiveSupport::Concern
def set_hidden
if @topic.update(hidden_params)
head :ok
else
render json: { errors: @topic.errors }, status: :bad_request
end
end
private
def hidden_params
params.permit(:hidden)
end
end
================================================
FILE: app/controllers/concerns/course/forum/topic_controller_locking_concern.rb
================================================
# frozen_string_literal: true
module Course::Forum::TopicControllerLockingConcern
extend ActiveSupport::Concern
def set_locked
if @topic.update(locked_params)
head :ok
else
render json: { errors: @topic.errors }, status: :bad_request
end
end
private
def locked_params
params.permit(:locked)
end
end
================================================
FILE: app/controllers/concerns/course/forum/topic_controller_subscription_concern.rb
================================================
# frozen_string_literal: true
module Course::Forum::TopicControllerSubscriptionConcern
extend ActiveSupport::Concern
def subscribe
authorize!(:read, @topic)
if set_subscription_state
head :ok
else
render json: { errors: @topic.errors }, status: :bad_request
end
end
private
def set_subscription_state
if subscribe?
@topic.subscriptions.create(user: current_user)
else
@topic.subscriptions.where(user: current_user).destroy_all
end
end
def subscribe?
params[:subscribe] == true
end
end
================================================
FILE: app/controllers/concerns/course/group/group_manager_concern.rb
================================================
# frozen_string_literal: true
module Course::Group::GroupManagerConcern
extend ActiveSupport::Concern
def manageable_groups
@manageable_groups ||= current_course.groups.accessible_by(current_ability, :manage)
end
def viewable_group_categories
@viewable_group_categories ||= current_course.group_categories.accessible_by(current_ability)
end
end
================================================
FILE: app/controllers/concerns/course/koditsu_workspace_concern.rb
================================================
# frozen_string_literal: true
module Course::KoditsuWorkspaceConcern
extend ActiveSupport::Concern
def setup_koditsu_workspace
workspace_service = Course::KoditsuWorkspaceService.new(current_course)
response = workspace_service.run_create_koditsu_workspace_service
workspace_id = response['id']
current_course.update!(koditsu_workspace_id: workspace_id)
end
end
================================================
FILE: app/controllers/concerns/course/lesson_plan/acts_as_lesson_plan_item_concern.rb
================================================
# frozen_string_literal: true
module Course::LessonPlan::ActsAsLessonPlanItemConcern
extend ActiveSupport::Concern
module ClassMethods
# Use method to build new specific lesson_plan_items
# Refer to app/controllers/course/assessment/question/controller.rb for motivation
def build_and_authorize_new_lesson_plan_item(item_name, options)
before_action only: options[:only], except: options[:except] do
specific_item = options[:class].new
specific_item.lesson_plan_item.course = @course
if action_name != 'new'
item_params = send("#{item_name}_params")
specific_item.assign_attributes(item_params.except(:item))
end
authorize!(action_name.to_sym, specific_item)
instance_variable_set("@#{item_name}", specific_item) unless instance_variable_get("@#{item_name}")
end
end
end
end
================================================
FILE: app/controllers/concerns/course/lesson_plan/learning_rate_concern.rb
================================================
# frozen_string_literal: true
module Course::LessonPlan::LearningRateConcern
extend ActiveSupport::Concern
include Course::LessonPlan::StoriesConcern
# Returns { lesson_plan_item_id => submitted_time or nil }.
# If the lesson plan item is a key in this hash then we consider the item "submitted" regardless of whether we have a
# submission time for it.
#
# @param [CourseUser] course_user The course user to compute the lesson plan items submission time hash for.
# @return [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] A hash of submitted lesson plan items' ID to their
# submitted time, if relevant/available.
def lesson_plan_items_submission_time_hash(course_user)
lesson_plan_items_submission_time_hash = {}
# Extend this if more lesson plan items to personalize are added in the future.
merge_course_assessments(lesson_plan_items_submission_time_hash, course_user)
merge_course_videos(lesson_plan_items_submission_time_hash, course_user)
merge_course_stories(lesson_plan_items_submission_time_hash, course_user)
end
# Computes the learning rate exponential moving average for the given course user.
#
# @param [CourseUser] course_user The course user to compute the learning rate for.
# @param [Array<Course::LessonPlan::Item>] items_affecting_personal_times An array of lesson plan items that affect
# personal times, sorted by the start_at for the given user, i.e. via time_for(course_user).start_at.
# @param [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] submitted_items A hash of submitted lesson plan items' ID to
# their submitted time, if relevant/available.
# @param [Float] alpha Alpha value used in exponential moving average computation.
# @return [Float|nil] Learning rate exponential moving average, if computable.
def compute_learning_rate_ema(course_user, items_affecting_personal_times, submitted_items, alpha = 0.4) # rubocop:disable Metrics/AbcSize
submitted_items_affecting_personal_times = items_affecting_personal_times.
select { |i| i.id.in? submitted_items.keys }.
select { |i| i.time_for(course_user).end_at.present? }
return nil if submitted_items_affecting_personal_times.empty?
learning_rate_ema = 1.0
# Currently, for the item to affect learning rate, it needs to have an end_at timing.
# In the future, we may want to consider other ways of computing how much an item affects learning rate.
submitted_items_affecting_personal_times.each do |item|
times = item.time_for(course_user)
next if times.end_at - times.start_at == 0 || submitted_items[item.id].nil?
learning_rate = (submitted_items[item.id] - times.start_at) / (times.end_at - times.start_at)
learning_rate = [learning_rate, 0].max
learning_rate_ema = (alpha * learning_rate) + ((1 - alpha) * learning_rate_ema)
end
learning_rate_ema
end
# Bounds the learning rate based on a given min and max learning rate.
# Min/max overall learning rate refers to how early/late a student is allowed to complete the course.
#
# E.g. if max_overall_lr = 2 means a student is allowed to complete a 1-month course over 2 months.
# However, if the student somehow managed to complete half of the course within the first day, then we can allow him
# to continue at lr = 4 and still have the student complete the course over 2 months. This method computes the
# effective limits to preserve the overall min/max lr.
#
# NOTE: It is completely possible for negative results (even -infinity), i.e. student needs to go back in time in
# order to have any hope of completing the course within the limits. The algorithm needs to take care of this.
#
# @param [CourseUser] course_user The course user to compute the learning rate for.
# @param [Array<Course::LessonPlan::Item>] items An array of lesson plan items for the course user's course,
# sorted by the start_at for the given user, i.e. via time_for(course_user).start_at.
# @param [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] submitted_items A hash of submitted lesson plan items' ID to
# their submitted time, if relevant/available.
# @param [Float] min_learning_rate The minimum overall learning rate.
# @param [Float] max_learning_rate The maximum overall learning rate.
# @return [Array<Float>] An array pair containing [min learning rate, max learning rate].
def compute_learning_rate_effective_limits(course_user, items, submitted_items, min_learning_rate, max_learning_rate) # rubocop:disable Metrics/AbcSize
course_start = items.first.start_at
course_end = items.last.start_at
last_submitted_item = items.reverse_each.lazy.
# TODO: Look into whether there's a need to filter on affects_personal_times?
select { |item| item.affects_personal_times? && item.id.in?(submitted_items.keys) }.
first
return [min_learning_rate, max_learning_rate] if last_submitted_item.nil?
reference_remaining_time = items.last.start_at - last_submitted_item.reference_time_for(course_user).start_at
reference_remaining_time += 1e-99 # Prevent division by zero.
min_remaining_time = course_start + (min_learning_rate * (course_end - course_start)) -
last_submitted_item.time_for(course_user).start_at
max_remaining_time = course_start + (max_learning_rate * (course_end - course_start)) -
last_submitted_item.time_for(course_user).start_at
[min_remaining_time / reference_remaining_time, max_remaining_time / reference_remaining_time]
end
def lesson_plan_items_with_sorted_times_for(course_user)
course_user.course.lesson_plan_items.published.
with_reference_times_for(course_user).
with_personal_times_for(course_user).
to_a.
concat(stories_for(course_user)).
sort_by { |item| item.time_for(course_user).start_at }
end
private
# Merges course assessment submissions into the given hash, with the following format:
# { lesson_plan_item_id => submitted_time }
#
# @param [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] hash A hash of submitted lesson plan items' ID to their
# submitted time, if relevant/available.
# @param [CourseUser] course_user Course user to retrieve course assessments for.
# @return [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] Data with course assessment submission data merged in.
def merge_course_assessments(hash, course_user)
# Assessments - consider submitted only if submitted_at is present
hash.merge!(
course_user.course.assessments.
with_submissions_by(course_user.user).
select { |x| x.submissions.present? && x.submissions.first.submitted_at.present? }.
to_h { |x| [x.lesson_plan_item.id, x.submissions.first.submitted_at] }
)
end
# Merges course video submissions into the given hash, with the following format:
# { lesson_plan_item_id => nil }
#
# @param [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] hash A hash of submitted lesson plan items' ID to their
# submitted time, if relevant/available.
# @param [CourseUser] course_user Course user to retrieve course videos for.
# @return [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] Data with course video submission data merged in.
def merge_course_videos(hash, course_user)
# Videos - consider submitted as long as submission exists
hash.merge!(
course_user.course.videos.
with_submissions_by(course_user.user).
select { |x| x.submissions.present? }.
to_h { |x| [x.lesson_plan_item.id, nil] }
)
end
def merge_course_stories(hash, course_user)
hash.merge!(stories_for(course_user).filter(&:submitted_at).to_h { |s| [s.id, s.submitted_at] })
end
end
================================================
FILE: app/controllers/concerns/course/lesson_plan/personalization_concern.rb
================================================
# frozen_string_literal: true
module Course::LessonPlan::PersonalizationConcern
extend ActiveSupport::Concern
# Dispatches the call to the correct personalization algorithm strategy.
# If the algorithm takes too long (e.g. voodoo AI magic), it is responsible for scheduling an async job.
#
# Some properties for the algorithms:
# - We don't shift personal dates that have already passed. This is to prevent items becoming locked
# when students are switched between different algos. There are thus quite a few checks for
# > Time.zone.now. The only exception is the backwards-shifting of already-past deadlines, which
# allows students to slow down their learning more effectively.
# - We don't shift closing dates forward when the item has already opened for the student. This is to
# prevent students from being shocked that their deadlines have shifted forward suddenly.
#
# @param [CourseUser] course_user The user to update the personalized timeline for.
# @param [String|nil] timeline_algorithm The timeline algorithm to run. If not provided, the user's timeline algorithm
# is used.
# @param [Set<Number>|nil] items_to_shift A set of lesson plan item IDs to shift. If not in this set, the item won't
# be shifted.
def update_personalized_timeline_for_user(course_user, timeline_algorithm = nil, items_to_shift = nil)
timeline_algorithm ||= course_user.timeline_algorithm
strategy = case timeline_algorithm
when 'otot'
Course::LessonPlan::Strategies::OtotPersonalizationStrategy.new
when 'fomo'
Course::LessonPlan::Strategies::FomoPersonalizationStrategy.new
when 'stragglers'
Course::LessonPlan::Strategies::StragglersPersonalizationStrategy.new
else
# Default to fixed.
Course::LessonPlan::Strategies::FixedPersonalizationStrategy.new
end
precomputed_data = strategy.precompute_data(course_user)
strategy.execute(course_user, precomputed_data, items_to_shift)
return if precomputed_data[:learning_rate_ema].nil?
# Log the information for future usages
learning_rate_record = Course::LearningRateRecord.new(course_user: course_user,
learning_rate: precomputed_data[:learning_rate_ema],
effective_min: precomputed_data[:effective_min],
effective_max: precomputed_data[:effective_max])
learning_rate_record.save!
end
# Updates the personalized timeline for all course users in the course of the given lesson plan item.
# Only the timing for the lesson plan item will be shifted. Generally, you should only call this if the timing of the
# lesson plan item has shifted, or other personalized timeline related changes have been made for a specific item.
def update_personalized_timeline_for_item(lesson_plan_item)
course = Course.includes(:course_users).find(lesson_plan_item.course_id)
course.course_users.each do |course_user|
update_personalized_timeline_for_user(course_user, nil, Set[lesson_plan_item.id])
end
end
end
================================================
FILE: app/controllers/concerns/course/lesson_plan/stories_concern.rb
================================================
# frozen_string_literal: true
module Course::LessonPlan::StoriesConcern
extend ActiveSupport::Concern
def delete_all_future_stories_personal_times(course_user)
future_story_ids = stories_for(course_user).filter_map do |story|
story.id if story.personal_time_for(course_user) && story.submitted_at.blank?
end
return if future_story_ids.blank?
Cikgo::TimelinesService.delete_times!(course_user, future_story_ids)
rescue StandardError => e
Rails.logger.error("Cikgo: Cannot delete personal times for story IDs #{future_story_ids}: #{e}")
raise e unless Rails.env.production?
end
private
def stories_for(course_user)
@stories_for ||= Course::Story.for_course_user!(course_user) || []
rescue StandardError => e
Rails.logger.error("Cannot fetch stories for course user #{course_user.id}: #{e}")
raise e unless Rails.env.production?
[]
end
end
================================================
FILE: app/controllers/concerns/course/lesson_plan/strategies/base_personalization_strategy.rb
================================================
# frozen_string_literal: true
# The BasePersonalizationStrategy declares operations common to all, if not most, personalized timeline algorithms.
# It also defines the interface to use when calling the algorithm defined by the subclasses.
class Course::LessonPlan::Strategies::BasePersonalizationStrategy
include Course::LessonPlan::LearningRateConcern
# To override any of these constants, simply define the same constant in the subclass.
LEARNING_RATE_ALPHA = 0.4
MIN_LEARNING_RATE = 1.0
MAX_LEARNING_RATE = 1.0
HARD_MIN_LEARNING_RATE = 1.0
# How generously we round off. E.g. if `threshold` = 0.5, then a datetime with a time of > 0.5 * 1.day will be
# snapped to the next day.
DATE_ROUNDING_THRESHOLD = 0.5
# Returns precomputed data for the given course user.
# The data returned depends on the strategy requirements, and will need to be of the same format
# that the execute method accepts.
#
# By default, the data returned is a hash containing {
# items: Array<Course::LessonPlan::Item>,
# submitted_items: Hash{Integer=>DateTime or nil},
# learning_rate_ema: Float|nil
# }
# where items is a sorted array of lesson plan items based on the course_user start_at,
# submitted_items is a hash of the user's submitted lesson plan items to the submission time (if available),
# and learning_rate_ema is a learning rate exponential moving average, bounded based on algorithm specifications.
#
# @param [CourseUser] course_user The course user to compute data for.
# @return [Hash] Precomputed data to aid execution.
def precompute_data(course_user) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
submitted_items = lesson_plan_items_submission_time_hash(course_user)
items = lesson_plan_items_with_sorted_times_for(course_user)
items_affecting_personal_times = items.select(&:affects_personal_times?)
learning_rate_ema = compute_learning_rate_ema(
course_user, items_affecting_personal_times, submitted_items, self.class::LEARNING_RATE_ALPHA
)
unless learning_rate_ema.nil?
effective_min, effective_max = compute_learning_rate_effective_limits(course_user, items, submitted_items,
self.class::MIN_LEARNING_RATE,
self.class::MAX_LEARNING_RATE)
effective_min = [effective_min, self.class::HARD_MIN_LEARNING_RATE].max
effective_max = [effective_max, self.class::HARD_MIN_LEARNING_RATE].max
learning_rate_ema = learning_rate_ema.clamp(effective_min, effective_max)
end
{ submitted_items: submitted_items, items: items, learning_rate_ema: learning_rate_ema,
effective_min: effective_min, effective_max: effective_max }
end
# Executes the relevant personalization strategy for the given course user, using the given precomputed
# data.
#
# @param [CourseUser] course_user The course user to execute the strategy on.
# @param [Hash|nil] precomputed_data Data to determine strategy execution.
# @param [Set<Number>|nil] items_to_shift Set of item ids to shift. If provided, only items with ids in this set will
# be shifted.
def execute(_course_user, _precomputed_data, _items_to_shift = nil)
raise NotImplementedError, 'Subclasses must implmement a execute method.'
end
protected
# Round to "nearest" date in course's time zone, NOT user's time zone.
#
# @param [ActiveSupport::TimeWithZone] datetime The datetime object to round.
# @param [String] course_tz The time zone of the course.
# @param [Boolean] to_2359 Whether to round off to 2359. This will set the datetime to be 2359 of the date before the
# rounded date.
def round_to_date(datetime, course_tz, to_2359: false)
prev_day = datetime.in_time_zone(course_tz).to_date.in_time_zone(course_tz).in_time_zone
date = ((datetime - prev_day) < self.class::DATE_ROUNDING_THRESHOLD ? prev_day : prev_day + 1.day)
to_2359 ? date - 1.minute : date
end
end
================================================
FILE: app/controllers/concerns/course/lesson_plan/strategies/fixed_personalization_strategy.rb
================================================
# frozen_string_literal: true
class Course::LessonPlan::Strategies::FixedPersonalizationStrategy <
Course::LessonPlan::Strategies::BasePersonalizationStrategy
# Returns a hash containing lesson plan item ids to submission time.
#
# @param [CourseUser] course_user The course user to compute data for.
# @return [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] A hash of submitted lesson plan items' IDs to their
# submitted time, if relevant/available.
def precompute_data(course_user)
lesson_plan_items_submission_time_hash(course_user)
end
# Deletes all personal times that are not fixed or submitted. This basically causes the course user to follow the
# reference timeline moving forward.
#
# @param [CourseUser] course_user The course user to compute data for.
# @param [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] precompute_data A hash of submitted lesson plan items' ID to
# their submitted time, if relevant/available.
# @param [Set<Number>|nil] items_to_shift Unused and does not affect behaviour.
def execute(course_user, precompute_data, _items_to_shift)
course_user.personal_times.where(fixed: false).
where.not(lesson_plan_item_id: precompute_data.keys).delete_all
delete_all_future_stories_personal_times(course_user)
end
end
================================================
FILE: app/controllers/concerns/course/lesson_plan/strategies/fomo_personalization_strategy.rb
================================================
# frozen_string_literal: true
class Course::LessonPlan::Strategies::FomoPersonalizationStrategy <
Course::LessonPlan::Strategies::BasePersonalizationStrategy
MIN_LEARNING_RATE = 0.67
MAX_LEARNING_RATE = 1.0
HARD_MIN_LEARNING_RATE = 0.5
DATE_ROUNDING_THRESHOLD = 0.8
# Shifts start_at of relevant lesson plan items and resets the bonus_end_at and end_at
# of the same items. The amount shifted is based the learning rate precomputed.
#
# The expected precomputed_data is the default data from precompute_data.
#
# @param [CourseUser] course_user The user to adjust the personalized timeline for.
# @param [Hash] precomputed_data The default data precomputed by precompute_data.
# @param [Set<Number>|nil] items_to_shift Set of item ids to shift. If provided, only items with ids in this set will
# be shifted.
def execute(course_user, precomputed_data, items_to_shift = nil) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
return if precomputed_data[:learning_rate_ema].nil?
@course_tz = course_user.course.time_zone
reference_point = personal_point = precomputed_data[:items].first.reference_time_for(course_user).start_at
course_user.transaction do
precomputed_data[:items].each do |item|
reference_point, personal_point = update_points(course_user, item, precomputed_data[:submitted_items],
reference_point, personal_point)
next if cannot_shift_item(course_user, item, precomputed_data[:submitted_items], items_to_shift)
reference_time = item.reference_time_for(course_user)
personal_time = item.find_or_create_personal_time_for(course_user)
next if item_is_open_and_straggling(personal_time, reference_time)
shift_start_at(personal_time, reference_time, personal_point, reference_point,
precomputed_data[:learning_rate_ema])
reset_bonus_end_at(personal_time, reference_time)
reset_end_at(personal_time, reference_time)
personal_time.save!
end
end
end
private
# Checks if the given item should act as the most recent "anchor point" for the following shifts.
# If the item should act, returns an array [new_reference_point, new_personal_point] computed with that item.
# If the item should not act, then the original reference_point and personal_point will be returned.
#
# @param [CourseUser] course_user The user to update points for.
# @param [Course::LessonPlan::Item] item The item to reference for the update of points.
# @param [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] submitted_items A hash of submitted lesson plan items' ID to
# their submitted time, if relevant/available.
# @param [DateTime] reference_point The current reference_point.
# @param [DateTime] personal_point The current personal_point.
# @return [Array<ActiveSupport::TimeWithZone>] An array containing [new_reference_point, new_personal_point].
def update_points(course_user, item, submitted_items, reference_point, personal_point)
if item.affects_personal_times? && item.id.in?(submitted_items.keys)
return [item.reference_time_for(course_user).start_at, item.time_for(course_user).start_at]
end
[reference_point, personal_point]
end
# Checks if the lesson plan item cannot be shifted. If cannot, the timings for this item will not be adjusted.
# Currently, it checks for the following conditions, for it to be possible to be shifted:
# - Item has personal times
# - Item is not submitted
# - Item's personal time isn't fixed
# - Item isn't currently open with an adjusted end_at from stragglers algorithm
# - Item ID is in the set of items to shift, if provided
#
# @param [CourseUser] course_user The user whose item we are checking.
# @param [Course::LessonPlan::Item] item The item that we are checking.
# @param [Hash{Integer=>ActiveSupport::TimeWithZone|nil}] submitted_items A hash of submitted lesson plan items' ID
# to their submitted time, if relevant/available.
# @param [Set<Number>|nil] items_to_shift Set of item ids to shift. If provided, only items with ids in this set will
# be shifted.
# @return [Boolean] Whether the item cannot be shifted.
def cannot_shift_item(course_user, item, submitted_items, items_to_shift)
!item.has_personal_times? || item.id.in?(submitted_items.keys) || item.personal_time_for(course_user)&.fixed? ||
(!items_to_shift.nil? && !items_to_shift.include?(item.id))
end
def item_is_straggling(personal_time, reference_time)
if reference_time.end_at.present? && personal_time.end_at.present?
return reference_time.end_at < personal_time.end_at
elsif reference_time.end_at.present? && personal_time.end_at.nil?
return true
end
false
end
# Checks if the item is already open with a deadline shifted back by stragglers algorithm.
# If the user was previously on the stragglers algorithm and just switched over, and has already open
# items, we want to keep those items as they are.
#
# @param [Course::PersonalTime] personal_time Personal time that we are checking.
# @param [Course::ReferenceTime] reference_time Reference time that we are referring.
# @return [Boolean] Whether the item is already open with a deadline shifted back by stragglers algorithm
def item_is_open_and_straggling(personal_time, reference_time)
item_is_straggling = item_is_straggling(personal_time, reference_time)
item_is_open = personal_time.start_at < Time.zone.now
item_is_straggling && item_is_open
end
# Shifts the start_at of the personal_time forward based on the learning rate of the user and the most recent
# personal and reference points. This major shift only occurs if the personal_time's current start_at is in the
# future.
#
# In addition, it also handles the case where the reference_time's start_at has shifted forward, as the
# start_at of the personal_time will never be later than the start_at of the reference time.
#
# @param [Course::PersonalTime] personal_time Personal time that we are shifting.
# @param [Course::ReferenceTime] reference_time Reference time that we are referring.
# @param [ActiveSupport::TimeWithZone] personal_point Personal point from the most recent item.
# @param [ActiveSupport::TimeWithZone] reference_point Reference point from the most recent item.
# @param [Float] learning_rate_ema Learning rate to use for computing the shift amount.
def shift_start_at(personal_time, reference_time, personal_point, reference_point, learning_rate_ema)
if personal_time.start_at > Time.zone.now
personal_time.start_at =
round_to_date(
personal_point + ((reference_time.start_at - reference_point) * learning_rate_ema),
@course_tz
)
end
# Hard limits to make sure we don't fail bounds checks
personal_time.start_at = [personal_time.start_at, reference_time.start_at, reference_time.end_at].compact.min
end
# Resets the bonus_end_at of the personal_time to that of the reference_time if the personal_time has bonus_end_at.
# The personal time's current bonus_end_at timing must also be in the future.
#
# @param [Course::PersonalTime] personal_time Personal time that we are resetting.
# @param [Course::ReferenceTime] reference_time Reference time that we are using as reference.
def reset_bonus_end_at(personal_time, reference_time)
return unless personal_time.bonus_end_at && personal_time.bonus_end_at > Time.zone.now
personal_time.bonus_end_at = reference_time.bonus_end_at
end
# Resets the end_at of the personal_time to that of the reference_time if the personal_time has end_at.
# The personal time's current end_at timing must also be in the future.
#
# @param [Course::PersonalTime] personal_time Personal time that we are resetting.
# @param [Course::ReferenceTime] reference_time Reference time that we are using as reference.
def reset_end_at(personal_time, reference_time)
return unless personal_time.end_at && personal_time.end_at > Time.zone.now
personal_time.end_at = reference_time.end_at
end
end
================================================
FILE: app/controllers/concerns/course/lesson_plan/strategies/otot_personalization_strategy.rb
================================================
# frozen_string_literal: true
class Course::LessonPlan::Strategies::OtotPersonalizationStrategy <
Course::LessonPlan::Strategies::BasePersonalizationStrategy
# Returns precomputed data for the given course user.
# This method is identical to that of BasePersonalizationStrategy except for the fact that the effective
# learning rate is constrained based on limits determined by the initial learning rate.
#
# @param [CourseUser] course_user The course user to compute data for.
# @return [Hash] Precomputed data to aid execution.
def precompute_data(course_user) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
submitted_items = lesson_plan_items_submission_time_hash(course_user)
items = lesson_plan_items_with_sorted_times_for(course_user)
items_affecting_personal_times = items.select(&:affects_personal_times?)
learning_rate_ema = compute_learning_rate_ema(
course_user, items_affecting_personal_times, submitted_items, self.class::LEARNING_RATE_ALPHA
)
unless learning_rate_ema.nil?
strategy = if learning_rate_ema < 1
Course::LessonPlan::Strategies::FomoPersonalizationStrategy
else
Course::LessonPlan::Strategies::StragglersPersonalizationStrategy
end
effective_min, effective_max = compute_learning_rate_effective_limits(course_user, items, submitted_items,
strategy::MIN_LEARNING_RATE,
strategy::MAX_LEARNING_RATE)
effective_min = [effective_min, strategy::HARD_MIN_LEARNING_RATE].max
effective_max = [effective_max, strategy::HARD_MIN_LEARNING_RATE].max
bounded_learning_rate_ema = learning_rate_ema.clamp(effective_min, effective_max)
end
{ submitted_items: submitted_items, items: items, learning_rate_ema: bounded_learning_rate_ema,
original_learning_rate_ema: learning_rate_ema, effective_min: effective_min, effective_max: effective_max }
end
# Applies the appropriate algorithm strategy for the student based on the student's learning rate.
#
# The expected precomputed_data is the default data from precompute_data.
#
# @param [CourseUser] course_user The user to adjust the personalized timeline for.
# @param [Hash] precomputed_data The default data precomputed by precompute_data.
# @param [Set<Number>|nil] items_to_shift Set of item ids to shift. If provided, only items with ids in this set will
# be shifted.
def execute(course_user, precomputed_data, items_to_shift = nil)
return if precomputed_data[:learning_rate_ema].nil?
# Apply the appropriate algo depending on student's original learning rate
new_strategy = if precomputed_data[:original_learning_rate_ema] < 1
Course::LessonPlan::Strategies::FomoPersonalizationStrategy.new
else
Course::LessonPlan::Strategies::StragglersPersonalizationStrategy.new
end
new_strategy.execute(course_user, precomputed_data, items_to_shift)
end
end
================================================
FILE: app/controllers/concerns/course/lesson_plan/strategies/stragglers_personalization_strategy.rb
================================================
# frozen_string_literal: true
class Course::LessonPlan::Strategies::StragglersPersonalizationStrategy <
Course::LessonPlan::Strategies::BasePersonalizationStrategy
MIN_LEARNING_RATE = 1.0
MAX_LEARNING_RATE = 2.0
HARD_MIN_LEARNING_RATE = 0.8
DATE_ROUNDING_THRESHOLD = 0.2
STRAGGLERS_FIXES = 1
# Shifts end_at of relevant lesson plan items and resets the bonus_end_at and start_at
# of the same items. The amount shifted is based the learning rate precomputed.
#
# The expected precomputed_data is the default data from precompute_data.
#
# @param [CourseUser] course_user The user to adjust the personalized timeline for.
# @param [Hash] precomputed_data The default data precomputed by precompute_data.
# @param [Set<Number>|nil] items_to_shift Set of item ids to shift. If provided, only items with ids in this set will
# be shifted.
de
Showing preview only (339K chars total). Download the full file or copy to clipboard to get everything.
gitextract_31rkx6m_/ ├── .circleci/ │ └── config.yml ├── .codecov.yml ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── 1-bug-report.yml │ │ ├── 2-feature-request.yml │ │ └── config.yml │ └── dependabot.yml ├── .gitignore ├── .gitmodules ├── .hound.yml ├── .rspec ├── .rubocop.unhound.yml ├── .rubocop.yml ├── .yardopts ├── CONTRIBUTING.md ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── app/ │ ├── README.md │ ├── assets/ │ │ └── config/ │ │ └── manifest.js │ ├── channels/ │ │ ├── application_cable/ │ │ │ ├── channel.rb │ │ │ └── connection.rb │ │ ├── concerns/ │ │ │ ├── application_cable_ability_concern.rb │ │ │ ├── application_cable_authentication_concern.rb │ │ │ ├── application_cable_component_concern.rb │ │ │ ├── application_cable_course_concern.rb │ │ │ └── application_cable_multitenancy_concern.rb │ │ └── course/ │ │ ├── channel.rb │ │ └── monitoring/ │ │ ├── heartbeat_channel.rb │ │ └── live_monitoring_channel.rb │ ├── controllers/ │ │ ├── announcements_controller.rb │ │ ├── application_controller.rb │ │ ├── attachment_references_controller.rb │ │ ├── components/ │ │ │ └── course/ │ │ │ ├── achievements_component.rb │ │ │ ├── announcements_component.rb │ │ │ ├── assessments_component.rb │ │ │ ├── codaveri_component.rb │ │ │ ├── controller_component_host.rb │ │ │ ├── discussion/ │ │ │ │ └── topics_component.rb │ │ │ ├── duplication_component.rb │ │ │ ├── experience_points_component.rb │ │ │ ├── forums_component.rb │ │ │ ├── groups_component.rb │ │ │ ├── koditsu_platform_component.rb │ │ │ ├── leaderboard_component.rb │ │ │ ├── learning_map_component.rb │ │ │ ├── lesson_plan_component.rb │ │ │ ├── levels_component.rb │ │ │ ├── materials_component.rb │ │ │ ├── monitoring_component.rb │ │ │ ├── multiple_reference_timelines_component.rb │ │ │ ├── plagiarism_component.rb │ │ │ ├── rag_wise_component.rb │ │ │ ├── scholaistic_component.rb │ │ │ ├── settings_component.rb │ │ │ ├── statistics_component.rb │ │ │ ├── stories_component.rb │ │ │ ├── survey_component.rb │ │ │ ├── users_component.rb │ │ │ └── videos_component.rb │ │ ├── concerns/ │ │ │ ├── application_ability_concern.rb │ │ │ ├── application_announcements_concern.rb │ │ │ ├── application_authentication_concern.rb │ │ │ ├── application_components_concern.rb │ │ │ ├── application_controller_multitenancy_concern.rb │ │ │ ├── application_instance_user_concern.rb │ │ │ ├── application_internationalization_concern.rb │ │ │ ├── application_multitenancy.rb │ │ │ ├── application_pagination_concern.rb │ │ │ ├── application_user_concern.rb │ │ │ ├── application_user_time_zone_concern.rb │ │ │ ├── codaveri_language_concern.rb │ │ │ ├── course/ │ │ │ │ ├── achievement_conditional_concern.rb │ │ │ │ ├── activity_feeds_concern.rb │ │ │ │ ├── assessment/ │ │ │ │ │ ├── answer/ │ │ │ │ │ │ └── update_answer_concern.rb │ │ │ │ │ ├── koditsu_assessment_concern.rb │ │ │ │ │ ├── koditsu_assessment_invitation_concern.rb │ │ │ │ │ ├── live_feedback/ │ │ │ │ │ │ ├── file_concern.rb │ │ │ │ │ │ ├── message_concern.rb │ │ │ │ │ │ ├── message_file_concern.rb │ │ │ │ │ │ └── thread_concern.rb │ │ │ │ │ ├── monitoring/ │ │ │ │ │ │ └── seb_payload_concern.rb │ │ │ │ │ ├── monitoring_concern.rb │ │ │ │ │ ├── question/ │ │ │ │ │ │ ├── codaveri_question_concern.rb │ │ │ │ │ │ ├── koditsu_question_concern.rb │ │ │ │ │ │ ├── multiple_responses_concern.rb │ │ │ │ │ │ ├── rubric_based_response_controller_concern.rb │ │ │ │ │ │ └── rubric_based_response_question_concern.rb │ │ │ │ │ ├── question_bundle_assignment_concern.rb │ │ │ │ │ ├── submission/ │ │ │ │ │ │ ├── koditsu/ │ │ │ │ │ │ │ ├── answers_concern.rb │ │ │ │ │ │ │ ├── submission_times_concern.rb │ │ │ │ │ │ │ ├── submissions_concern.rb │ │ │ │ │ │ │ ├── test_cases_concern.rb │ │ │ │ │ │ │ └── users_concern.rb │ │ │ │ │ │ ├── monitoring_concern.rb │ │ │ │ │ │ └── submissions_controller_service_concern.rb │ │ │ │ │ └── submission_concern.rb │ │ │ │ ├── assessment_conditional_concern.rb │ │ │ │ ├── cikgo_chats_concern.rb │ │ │ │ ├── cikgo_push_concern.rb │ │ │ │ ├── discussion/ │ │ │ │ │ └── posts_concern.rb │ │ │ │ ├── forum/ │ │ │ │ │ ├── auto_answering_concern.rb │ │ │ │ │ ├── topic_controller_hiding_concern.rb │ │ │ │ │ ├── topic_controller_locking_concern.rb │ │ │ │ │ └── topic_controller_subscription_concern.rb │ │ │ │ ├── group/ │ │ │ │ │ └── group_manager_concern.rb │ │ │ │ ├── koditsu_workspace_concern.rb │ │ │ │ ├── lesson_plan/ │ │ │ │ │ ├── acts_as_lesson_plan_item_concern.rb │ │ │ │ │ ├── learning_rate_concern.rb │ │ │ │ │ ├── personalization_concern.rb │ │ │ │ │ ├── stories_concern.rb │ │ │ │ │ └── strategies/ │ │ │ │ │ ├── base_personalization_strategy.rb │ │ │ │ │ ├── fixed_personalization_strategy.rb │ │ │ │ │ ├── fomo_personalization_strategy.rb │ │ │ │ │ ├── otot_personalization_strategy.rb │ │ │ │ │ └── stragglers_personalization_strategy.rb │ │ │ │ ├── reminder_service_concern.rb │ │ │ │ ├── scholaistic/ │ │ │ │ │ └── concern.rb │ │ │ │ ├── ssid_folder_concern.rb │ │ │ │ ├── statistics/ │ │ │ │ │ ├── counts_concern.rb │ │ │ │ │ ├── grades_concern.rb │ │ │ │ │ ├── reference_times_concern.rb │ │ │ │ │ ├── submissions_concern.rb │ │ │ │ │ ├── times_concern.rb │ │ │ │ │ └── users_concern.rb │ │ │ │ ├── survey/ │ │ │ │ │ └── reordering_concern.rb │ │ │ │ ├── unread_counts_concern.rb │ │ │ │ └── users_controller_management_concern.rb │ │ │ └── signals/ │ │ │ ├── emission_concern.rb │ │ │ └── slices/ │ │ │ ├── announcements.rb │ │ │ ├── assessment_submissions.rb │ │ │ ├── cikgo_mission_control.rb │ │ │ ├── cikgo_open_threads_count.rb │ │ │ ├── comments.rb │ │ │ ├── enrol_requests.rb │ │ │ ├── forums.rb │ │ │ └── videos.rb │ │ ├── course/ │ │ │ ├── achievement/ │ │ │ │ ├── achievements_controller.rb │ │ │ │ ├── condition/ │ │ │ │ │ ├── achievements_controller.rb │ │ │ │ │ ├── assessments_controller.rb │ │ │ │ │ ├── levels_controller.rb │ │ │ │ │ ├── scholaistic_assessments_controller.rb │ │ │ │ │ └── surveys_controller.rb │ │ │ │ └── controller.rb │ │ │ ├── admin/ │ │ │ │ ├── admin_controller.rb │ │ │ │ ├── announcement_settings_controller.rb │ │ │ │ ├── assessment_settings_controller.rb │ │ │ │ ├── assessments/ │ │ │ │ │ ├── categories_controller.rb │ │ │ │ │ └── tabs_controller.rb │ │ │ │ ├── codaveri_settings_controller.rb │ │ │ │ ├── component_settings_controller.rb │ │ │ │ ├── controller.rb │ │ │ │ ├── discussion/ │ │ │ │ │ └── topic_settings_controller.rb │ │ │ │ ├── forum_settings_controller.rb │ │ │ │ ├── leaderboard_settings_controller.rb │ │ │ │ ├── lesson_plan_settings_controller.rb │ │ │ │ ├── material_settings_controller.rb │ │ │ │ ├── notification_settings_controller.rb │ │ │ │ ├── rag_wise_settings_controller.rb │ │ │ │ ├── scholaistic_settings_controller.rb │ │ │ │ ├── sidebar_settings_controller.rb │ │ │ │ ├── stories_settings_controller.rb │ │ │ │ ├── video_settings_controller.rb │ │ │ │ └── videos/ │ │ │ │ └── tabs_controller.rb │ │ │ ├── announcements_controller.rb │ │ │ ├── assessment/ │ │ │ │ ├── assessments_controller.rb │ │ │ │ ├── categories_controller.rb │ │ │ │ ├── component_controller.rb │ │ │ │ ├── condition/ │ │ │ │ │ ├── achievements_controller.rb │ │ │ │ │ ├── assessments_controller.rb │ │ │ │ │ ├── levels_controller.rb │ │ │ │ │ ├── scholaistic_assessments_controller.rb │ │ │ │ │ └── surveys_controller.rb │ │ │ │ ├── controller.rb │ │ │ │ ├── mock_answers_controller.rb │ │ │ │ ├── question/ │ │ │ │ │ ├── controller.rb │ │ │ │ │ ├── forum_post_responses_controller.rb │ │ │ │ │ ├── multiple_responses_controller.rb │ │ │ │ │ ├── programming_controller.rb │ │ │ │ │ ├── rubric_based_responses_controller.rb │ │ │ │ │ ├── scribing_controller.rb │ │ │ │ │ ├── text_responses_controller.rb │ │ │ │ │ └── voice_responses_controller.rb │ │ │ │ ├── question_bundle_assignments_controller.rb │ │ │ │ ├── question_bundle_questions_controller.rb │ │ │ │ ├── question_bundles_controller.rb │ │ │ │ ├── question_groups_controller.rb │ │ │ │ ├── questions_controller.rb │ │ │ │ ├── rubrics_controller.rb │ │ │ │ ├── sessions_controller.rb │ │ │ │ ├── skill_branches_controller.rb │ │ │ │ ├── skills_controller.rb │ │ │ │ ├── submission/ │ │ │ │ │ ├── answer/ │ │ │ │ │ │ ├── answers_controller.rb │ │ │ │ │ │ ├── controller.rb │ │ │ │ │ │ ├── forum_post_response/ │ │ │ │ │ │ │ └── posts_controller.rb │ │ │ │ │ │ ├── programming/ │ │ │ │ │ │ │ ├── annotations_controller.rb │ │ │ │ │ │ │ ├── controller.rb │ │ │ │ │ │ │ └── programming_controller.rb │ │ │ │ │ │ ├── scribing/ │ │ │ │ │ │ │ ├── controller.rb │ │ │ │ │ │ │ └── scribbles_controller.rb │ │ │ │ │ │ └── text_response/ │ │ │ │ │ │ ├── controller.rb │ │ │ │ │ │ └── text_response_controller.rb │ │ │ │ │ ├── controller.rb │ │ │ │ │ ├── live_feedback_controller.rb │ │ │ │ │ ├── logs_controller.rb │ │ │ │ │ └── submissions_controller.rb │ │ │ │ ├── submission_question/ │ │ │ │ │ ├── comments_controller.rb │ │ │ │ │ ├── controller.rb │ │ │ │ │ └── submission_questions_controller.rb │ │ │ │ └── submissions_controller.rb │ │ │ ├── component_controller.rb │ │ │ ├── condition/ │ │ │ │ ├── achievements_controller.rb │ │ │ │ ├── assessments_controller.rb │ │ │ │ ├── levels_controller.rb │ │ │ │ ├── scholaistic_assessments_controller.rb │ │ │ │ └── surveys_controller.rb │ │ │ ├── conditions_controller.rb │ │ │ ├── controller.rb │ │ │ ├── courses_controller.rb │ │ │ ├── discussion/ │ │ │ │ ├── posts_controller.rb │ │ │ │ └── topics_controller.rb │ │ │ ├── duplications_controller.rb │ │ │ ├── enrol_requests_controller.rb │ │ │ ├── experience_points/ │ │ │ │ ├── disbursement_controller.rb │ │ │ │ └── forum_disbursement_controller.rb │ │ │ ├── experience_points_records_controller.rb │ │ │ ├── forum/ │ │ │ │ ├── component_controller.rb │ │ │ │ ├── controller.rb │ │ │ │ ├── forums_controller.rb │ │ │ │ ├── posts_controller.rb │ │ │ │ └── topics_controller.rb │ │ │ ├── group/ │ │ │ │ ├── group_categories_controller.rb │ │ │ │ └── groups_controller.rb │ │ │ ├── leaderboards_controller.rb │ │ │ ├── learning_map_controller.rb │ │ │ ├── lesson_plan/ │ │ │ │ ├── controller.rb │ │ │ │ ├── events_controller.rb │ │ │ │ ├── items_controller.rb │ │ │ │ ├── milestones_controller.rb │ │ │ │ └── todos_controller.rb │ │ │ ├── levels_controller.rb │ │ │ ├── material/ │ │ │ │ ├── controller.rb │ │ │ │ ├── folders_controller.rb │ │ │ │ └── materials_controller.rb │ │ │ ├── object_duplications_controller.rb │ │ │ ├── personal_times_controller.rb │ │ │ ├── plagiarism/ │ │ │ │ ├── assessments_controller.rb │ │ │ │ ├── controller.rb │ │ │ │ └── plagiarism_controller.rb │ │ │ ├── reference_timelines_controller.rb │ │ │ ├── reference_times_controller.rb │ │ │ ├── rubrics_controller.rb │ │ │ ├── scholaistic/ │ │ │ │ ├── assistants_controller.rb │ │ │ │ ├── controller.rb │ │ │ │ ├── scholaistic_assessments_controller.rb │ │ │ │ └── submissions_controller.rb │ │ │ ├── statistics/ │ │ │ │ ├── aggregate_controller.rb │ │ │ │ ├── assessments_controller.rb │ │ │ │ ├── controller.rb │ │ │ │ ├── statistics_controller.rb │ │ │ │ └── users_controller.rb │ │ │ ├── stories/ │ │ │ │ └── stories_controller.rb │ │ │ ├── survey/ │ │ │ │ ├── controller.rb │ │ │ │ ├── questions_controller.rb │ │ │ │ ├── responses_controller.rb │ │ │ │ ├── sections_controller.rb │ │ │ │ └── surveys_controller.rb │ │ │ ├── user_email_subscriptions_controller.rb │ │ │ ├── user_invitations_controller.rb │ │ │ ├── user_notifications_controller.rb │ │ │ ├── user_registrations_controller.rb │ │ │ ├── users_controller.rb │ │ │ ├── video/ │ │ │ │ ├── controller.rb │ │ │ │ ├── submission/ │ │ │ │ │ ├── controller.rb │ │ │ │ │ ├── sessions_controller.rb │ │ │ │ │ └── submissions_controller.rb │ │ │ │ ├── topics_controller.rb │ │ │ │ └── videos_controller.rb │ │ │ └── video_submissions_controller.rb │ │ ├── csrf_token_controller.rb │ │ ├── health_check_controller.rb │ │ ├── instance_user_role_requests_controller.rb │ │ ├── jobs_controller.rb │ │ ├── system/ │ │ │ └── admin/ │ │ │ ├── admin_controller.rb │ │ │ ├── announcements_controller.rb │ │ │ ├── controller.rb │ │ │ ├── courses_controller.rb │ │ │ ├── get_help_controller.rb │ │ │ ├── instance/ │ │ │ │ ├── admin_controller.rb │ │ │ │ ├── announcements_controller.rb │ │ │ │ ├── components_controller.rb │ │ │ │ ├── controller.rb │ │ │ │ ├── courses_controller.rb │ │ │ │ ├── get_help_controller.rb │ │ │ │ ├── user_invitations_controller.rb │ │ │ │ └── users_controller.rb │ │ │ ├── instances_controller.rb │ │ │ └── users_controller.rb │ │ ├── test/ │ │ │ ├── controller.rb │ │ │ ├── factories_controller.rb │ │ │ └── mailer_controller.rb │ │ ├── user/ │ │ │ ├── confirmations_controller.rb │ │ │ ├── emails_controller.rb │ │ │ ├── passwords_controller.rb │ │ │ ├── profiles_controller.rb │ │ │ ├── registrations_controller.rb │ │ │ └── sessions_controller.rb │ │ └── users_controller.rb │ ├── helpers/ │ │ ├── application_formatters_helper.rb │ │ ├── application_helper.rb │ │ ├── application_html_formatters_helper.rb │ │ ├── application_jobs_helper.rb │ │ ├── application_mailer_helper.rb │ │ ├── application_notifications_helper.rb │ │ ├── consolidated_opening_reminder_mailer_helper.rb │ │ ├── course/ │ │ │ ├── achievement/ │ │ │ │ ├── achievements_helper.rb │ │ │ │ └── controller_helper.rb │ │ │ ├── assessment/ │ │ │ │ ├── answer/ │ │ │ │ │ └── programming_test_case_helper.rb │ │ │ │ ├── assessments_helper.rb │ │ │ │ ├── question/ │ │ │ │ │ └── programming_helper.rb │ │ │ │ ├── submission/ │ │ │ │ │ └── submissions_helper.rb │ │ │ │ └── submissions_helper.rb │ │ │ ├── condition/ │ │ │ │ └── conditions_helper.rb │ │ │ ├── controller_helper.rb │ │ │ ├── discussion/ │ │ │ │ └── topics_helper.rb │ │ │ ├── forum/ │ │ │ │ └── controller_helper.rb │ │ │ ├── group/ │ │ │ │ └── group_categories_helper.rb │ │ │ ├── leaderboards_helper.rb │ │ │ ├── material/ │ │ │ │ └── folders_helper.rb │ │ │ ├── object_duplications_helper.rb │ │ │ └── users_helper.rb │ │ ├── route_overrides_helper.rb │ │ └── tmp_cleanup_helper.rb │ ├── jobs/ │ │ ├── application_job.rb │ │ ├── consolidated_item_email_job.rb │ │ ├── course/ │ │ │ ├── announcement/ │ │ │ │ └── opening_reminder_job.rb │ │ │ ├── assessment/ │ │ │ │ ├── answer/ │ │ │ │ │ ├── auto_grading_job.rb │ │ │ │ │ ├── base_auto_grading_job.rb │ │ │ │ │ ├── programming_codaveri_feedback_job.rb │ │ │ │ │ └── reduce_priority_auto_grading_job.rb │ │ │ │ ├── closing_reminder_job.rb │ │ │ │ ├── invite_to_koditsu_job.rb │ │ │ │ ├── plagiarism_check_job.rb │ │ │ │ ├── question/ │ │ │ │ │ ├── answers_evaluation_job.rb │ │ │ │ │ ├── codaveri_import_job.rb │ │ │ │ │ └── programming_import_job.rb │ │ │ │ └── submission/ │ │ │ │ ├── auto_feedback_job.rb │ │ │ │ ├── auto_grading_job.rb │ │ │ │ ├── csv_download_job.rb │ │ │ │ ├── deleting_job.rb │ │ │ │ ├── fetch_submissions_from_koditsu_job.rb │ │ │ │ ├── force_submit_timed_submission_job.rb │ │ │ │ ├── force_submitting_job.rb │ │ │ │ ├── publishing_job.rb │ │ │ │ ├── statistics_download_job.rb │ │ │ │ ├── unsubmitting_job.rb │ │ │ │ └── zip_download_job.rb │ │ │ ├── conditional/ │ │ │ │ ├── conditional_satisfiability_evaluation_job.rb │ │ │ │ └── coursewide_conditional_satisfiability_evaluation_job.rb │ │ │ ├── discussion/ │ │ │ │ └── post/ │ │ │ │ └── codaveri_feedback_rating_job.rb │ │ │ ├── duplication_job.rb │ │ │ ├── experience_points_download_job.rb │ │ │ ├── forum/ │ │ │ │ ├── auto_answering_job.rb │ │ │ │ └── importing_job.rb │ │ │ ├── lesson_plan/ │ │ │ │ └── coursewide_personalized_timeline_update_job.rb │ │ │ ├── material/ │ │ │ │ ├── text_chunk_job.rb │ │ │ │ └── zip_download_job.rb │ │ │ ├── object_duplication_job.rb │ │ │ ├── rubric/ │ │ │ │ └── rubric_evaluation_export_job.rb │ │ │ ├── statistics/ │ │ │ │ └── assessments_score_summary_download_job.rb │ │ │ ├── survey/ │ │ │ │ ├── closing_reminder_job.rb │ │ │ │ └── survey_download_job.rb │ │ │ ├── user_deletion_job.rb │ │ │ └── video/ │ │ │ └── closing_reminder_job.rb │ │ ├── read_marks_clean_up_job.rb │ │ ├── user_email_database_cleanup_job.rb │ │ └── video_statistic_update_job.rb │ ├── mailers/ │ │ ├── activity_mailer.rb │ │ ├── application_mailer.rb │ │ ├── consolidated_opening_reminder_mailer.rb │ │ ├── course/ │ │ │ └── mailer.rb │ │ ├── instance/ │ │ │ └── mailer.rb │ │ └── instance_user_role_request_mailer.rb │ ├── models/ │ │ ├── .rubocop.yml │ │ ├── ability.rb │ │ ├── activity.rb │ │ ├── application_record.rb │ │ ├── attachment.rb │ │ ├── attachment_reference.rb │ │ ├── cikgo_user.rb │ │ ├── components/ │ │ │ ├── ability_host.rb │ │ │ ├── course/ │ │ │ │ ├── achievements_ability_component.rb │ │ │ │ ├── announcements_ability_component.rb │ │ │ │ ├── assessments_ability_component.rb │ │ │ │ ├── conditions_ability_component.rb │ │ │ │ ├── course_ability_component.rb │ │ │ │ ├── course_user_ability_component.rb │ │ │ │ ├── discussions_ability_component.rb │ │ │ │ ├── duplication_ability_component.rb │ │ │ │ ├── experience_points_disbursement_ability_component.rb │ │ │ │ ├── experience_points_records_ability_component.rb │ │ │ │ ├── forums_ability_component.rb │ │ │ │ ├── groups_ability_component.rb │ │ │ │ ├── learning_map_ability_component.rb │ │ │ │ ├── lesson_plan_ability_component.rb │ │ │ │ ├── levels_ability_component.rb │ │ │ │ ├── materials_ability_component.rb │ │ │ │ ├── model_component_host.rb │ │ │ │ ├── monitoring_ability_component.rb │ │ │ │ ├── plagiarism_ability_component.rb │ │ │ │ ├── rag_wise_setting_ability_component.rb │ │ │ │ ├── scholaistic_ability_component.rb │ │ │ │ ├── statistics_ability_component.rb │ │ │ │ ├── stories_ability_component.rb │ │ │ │ ├── surveys_ability_component.rb │ │ │ │ ├── timelines_ability_component.rb │ │ │ │ ├── user_email_unsubscriptions_ability_component.rb │ │ │ │ └── videos_ability_component.rb │ │ │ ├── system/ │ │ │ │ └── admin/ │ │ │ │ ├── instance_admin_ability_component.rb │ │ │ │ ├── instance_announcements_ability_component.rb │ │ │ │ ├── system_admin_ability_component.rb │ │ │ │ └── system_announcements_ability_component.rb │ │ │ ├── user_notifications_ability_component.rb │ │ │ └── users_ability_component.rb │ │ ├── concerns/ │ │ │ ├── announcement_concern.rb │ │ │ ├── application_acts_as_concern.rb │ │ │ ├── application_userstamp_concern.rb │ │ │ ├── cikgo/ │ │ │ │ └── pushable_item_concern.rb │ │ │ ├── component_settings_concern.rb │ │ │ ├── course/ │ │ │ │ ├── assessment/ │ │ │ │ │ ├── new_submission_concern.rb │ │ │ │ │ ├── questions_concern.rb │ │ │ │ │ ├── submission/ │ │ │ │ │ │ ├── answers_concern.rb │ │ │ │ │ │ ├── cikgo_task_completion_concern.rb │ │ │ │ │ │ ├── notification_concern.rb │ │ │ │ │ │ ├── todo_concern.rb │ │ │ │ │ │ └── workflow_event_concern.rb │ │ │ │ │ └── todo_concern.rb │ │ │ │ ├── closing_reminder_concern.rb │ │ │ │ ├── course_components_concern.rb │ │ │ │ ├── course_user_type_concern.rb │ │ │ │ ├── discussion/ │ │ │ │ │ ├── post/ │ │ │ │ │ │ ├── ordering_concern.rb │ │ │ │ │ │ └── retrieval_concern.rb │ │ │ │ │ └── topic/ │ │ │ │ │ └── posts_concern.rb │ │ │ │ ├── duplication_concern.rb │ │ │ │ ├── forum_participation_concern.rb │ │ │ │ ├── lesson_plan/ │ │ │ │ │ ├── item/ │ │ │ │ │ │ └── cikgo_push_concern.rb │ │ │ │ │ └── item_todo_concern.rb │ │ │ │ ├── levels_concern.rb │ │ │ │ ├── material/ │ │ │ │ │ └── folder/ │ │ │ │ │ └── ordering_concern.rb │ │ │ │ ├── material_concern.rb │ │ │ │ ├── opening_reminder_concern.rb │ │ │ │ ├── sanitize_description_concern.rb │ │ │ │ ├── search_concern.rb │ │ │ │ ├── settings/ │ │ │ │ │ └── lesson_plan_settings_concern.rb │ │ │ │ ├── survey/ │ │ │ │ │ └── response/ │ │ │ │ │ ├── cikgo_task_completion_concern.rb │ │ │ │ │ └── todo_concern.rb │ │ │ │ └── video/ │ │ │ │ ├── interval_query_concern.rb │ │ │ │ ├── submission/ │ │ │ │ │ ├── notification_concern.rb │ │ │ │ │ ├── statistic/ │ │ │ │ │ │ └── cikgo_task_completion_concern.rb │ │ │ │ │ └── todo_concern.rb │ │ │ │ ├── url_concern.rb │ │ │ │ └── watch_statistics_concern.rb │ │ │ ├── course_component_query_concern.rb │ │ │ ├── course_user/ │ │ │ │ ├── achievements_concern.rb │ │ │ │ ├── level_progress_concern.rb │ │ │ │ ├── staff_concern.rb │ │ │ │ └── todo_concern.rb │ │ │ ├── duplication_state_tracking_concern.rb │ │ │ ├── generic/ │ │ │ │ └── collection_concern.rb │ │ │ ├── instance/ │ │ │ │ └── course_components_concern.rb │ │ │ ├── instance_user_search_concern.rb │ │ │ ├── safe_mark_as_read_concern.rb │ │ │ ├── time_zone_concern.rb │ │ │ ├── user_authentication_concern.rb │ │ │ ├── user_notifications_concern.rb │ │ │ └── user_search_concern.rb │ │ ├── course/ │ │ │ ├── achievement.rb │ │ │ ├── announcement.rb │ │ │ ├── assessment/ │ │ │ │ ├── answer/ │ │ │ │ │ ├── auto_grading.rb │ │ │ │ │ ├── forum_post.rb │ │ │ │ │ ├── forum_post_response.rb │ │ │ │ │ ├── multiple_response.rb │ │ │ │ │ ├── multiple_response_option.rb │ │ │ │ │ ├── programming.rb │ │ │ │ │ ├── programming_ability.rb │ │ │ │ │ ├── programming_auto_grading.rb │ │ │ │ │ ├── programming_auto_grading_test_result.rb │ │ │ │ │ ├── programming_file.rb │ │ │ │ │ ├── programming_file_annotation.rb │ │ │ │ │ ├── rubric_based_response.rb │ │ │ │ │ ├── rubric_based_response_selection.rb │ │ │ │ │ ├── rubric_playground_answer_adapter.rb │ │ │ │ │ ├── scribing.rb │ │ │ │ │ ├── scribing_scribble.rb │ │ │ │ │ ├── text_response.rb │ │ │ │ │ └── voice_response.rb │ │ │ │ ├── answer.rb │ │ │ │ ├── assessment_ability.rb │ │ │ │ ├── category.rb │ │ │ │ ├── link.rb │ │ │ │ ├── live_feedback/ │ │ │ │ │ ├── file.rb │ │ │ │ │ ├── message.rb │ │ │ │ │ ├── message_file.rb │ │ │ │ │ ├── message_option.rb │ │ │ │ │ ├── option.rb │ │ │ │ │ └── thread.rb │ │ │ │ ├── live_feedback.rb │ │ │ │ ├── live_feedback_code.rb │ │ │ │ ├── live_feedback_comment.rb │ │ │ │ ├── plagiarism_check.rb │ │ │ │ ├── question/ │ │ │ │ │ ├── forum_post_response.rb │ │ │ │ │ ├── mock_answer/ │ │ │ │ │ │ └── answer_adapter.rb │ │ │ │ │ ├── mock_answer.rb │ │ │ │ │ ├── multiple_response.rb │ │ │ │ │ ├── multiple_response_option.rb │ │ │ │ │ ├── programming.rb │ │ │ │ │ ├── programming_template_file.rb │ │ │ │ │ ├── programming_test_case.rb │ │ │ │ │ ├── question_rubric.rb │ │ │ │ │ ├── rubric_based_response.rb │ │ │ │ │ ├── rubric_based_response_category.rb │ │ │ │ │ ├── rubric_based_response_criterion.rb │ │ │ │ │ ├── scribing.rb │ │ │ │ │ ├── text_response.rb │ │ │ │ │ ├── text_response_comprehension_group.rb │ │ │ │ │ ├── text_response_comprehension_point.rb │ │ │ │ │ ├── text_response_comprehension_solution.rb │ │ │ │ │ ├── text_response_solution.rb │ │ │ │ │ └── voice_response.rb │ │ │ │ ├── question.rb │ │ │ │ ├── question_bundle.rb │ │ │ │ ├── question_bundle_assignment.rb │ │ │ │ ├── question_bundle_question.rb │ │ │ │ ├── question_group.rb │ │ │ │ ├── skill.rb │ │ │ │ ├── skill_ability.rb │ │ │ │ ├── skill_branch.rb │ │ │ │ ├── submission/ │ │ │ │ │ └── log.rb │ │ │ │ ├── submission.rb │ │ │ │ ├── submission_question.rb │ │ │ │ └── tab.rb │ │ │ ├── assessment.rb │ │ │ ├── condition/ │ │ │ │ ├── achievement.rb │ │ │ │ ├── assessment.rb │ │ │ │ ├── level.rb │ │ │ │ ├── scholaistic_assessment.rb │ │ │ │ ├── survey.rb │ │ │ │ └── video.rb │ │ │ ├── condition.rb │ │ │ ├── discussion/ │ │ │ │ ├── post/ │ │ │ │ │ ├── codaveri_feedback.rb │ │ │ │ │ └── vote.rb │ │ │ │ ├── post.rb │ │ │ │ ├── topic/ │ │ │ │ │ └── subscription.rb │ │ │ │ └── topic.rb │ │ │ ├── discussion.rb │ │ │ ├── enrol_request.rb │ │ │ ├── experience_points/ │ │ │ │ ├── disbursement.rb │ │ │ │ └── forum_disbursement.rb │ │ │ ├── experience_points_record.rb │ │ │ ├── forum/ │ │ │ │ ├── discussion.rb │ │ │ │ ├── discussion_reference.rb │ │ │ │ ├── import.rb │ │ │ │ ├── rag_auto_answering.rb │ │ │ │ ├── search.rb │ │ │ │ ├── subscription.rb │ │ │ │ ├── topic/ │ │ │ │ │ └── view.rb │ │ │ │ └── topic.rb │ │ │ ├── forum.rb │ │ │ ├── group.rb │ │ │ ├── group_category.rb │ │ │ ├── group_user.rb │ │ │ ├── learning_map.rb │ │ │ ├── learning_rate_record.rb │ │ │ ├── lesson_plan/ │ │ │ │ ├── event.rb │ │ │ │ ├── event_material.rb │ │ │ │ ├── item.rb │ │ │ │ ├── milestone.rb │ │ │ │ └── todo.rb │ │ │ ├── lesson_plan.rb │ │ │ ├── level.rb │ │ │ ├── material/ │ │ │ │ ├── folder.rb │ │ │ │ ├── text_chunk.rb │ │ │ │ ├── text_chunk_reference.rb │ │ │ │ └── text_chunking.rb │ │ │ ├── material.rb │ │ │ ├── monitoring/ │ │ │ │ ├── browser_authorization/ │ │ │ │ │ ├── base.rb │ │ │ │ │ ├── seb_config_key.rb │ │ │ │ │ └── user_agent.rb │ │ │ │ ├── heartbeat.rb │ │ │ │ ├── monitor.rb │ │ │ │ └── session.rb │ │ │ ├── monitoring.rb │ │ │ ├── notification.rb │ │ │ ├── personal_time.rb │ │ │ ├── question_assessment.rb │ │ │ ├── reference_time.rb │ │ │ ├── reference_timeline.rb │ │ │ ├── registration.rb │ │ │ ├── rubric/ │ │ │ │ ├── answer_evaluation/ │ │ │ │ │ └── selection.rb │ │ │ │ ├── answer_evaluation.rb │ │ │ │ ├── category/ │ │ │ │ │ └── criterion.rb │ │ │ │ ├── category.rb │ │ │ │ ├── mock_answer_evaluation/ │ │ │ │ │ └── selection.rb │ │ │ │ ├── mock_answer_evaluation.rb │ │ │ │ └── rubric_adapter.rb │ │ │ ├── rubric.rb │ │ │ ├── scholaistic_assessment.rb │ │ │ ├── scholaistic_submission.rb │ │ │ ├── settings/ │ │ │ │ ├── announcements_component.rb │ │ │ │ ├── assessments_component.rb │ │ │ │ ├── codaveri_component.rb │ │ │ │ ├── component.rb │ │ │ │ ├── components.rb │ │ │ │ ├── email.rb │ │ │ │ ├── forums_component.rb │ │ │ │ ├── leaderboard_component.rb │ │ │ │ ├── learning_map_component.rb │ │ │ │ ├── lesson_plan_component.rb │ │ │ │ ├── lesson_plan_items.rb │ │ │ │ ├── materials_component.rb │ │ │ │ ├── pan_component.rb │ │ │ │ ├── rag_wise_component.rb │ │ │ │ ├── scholaistic_component.rb │ │ │ │ ├── sidebar.rb │ │ │ │ ├── sidebar_item.rb │ │ │ │ ├── stories_component.rb │ │ │ │ ├── survey_component.rb │ │ │ │ ├── topics_component.rb │ │ │ │ ├── users_component.rb │ │ │ │ └── videos_component.rb │ │ │ ├── settings.rb │ │ │ ├── story.rb │ │ │ ├── survey/ │ │ │ │ ├── answer.rb │ │ │ │ ├── answer_option.rb │ │ │ │ ├── question.rb │ │ │ │ ├── question_option.rb │ │ │ │ ├── response.rb │ │ │ │ └── section.rb │ │ │ ├── survey.rb │ │ │ ├── user_achievement.rb │ │ │ ├── user_email_unsubscription.rb │ │ │ ├── user_invitation.rb │ │ │ ├── video/ │ │ │ │ ├── event.rb │ │ │ │ ├── session.rb │ │ │ │ ├── statistic.rb │ │ │ │ ├── submission/ │ │ │ │ │ └── statistic.rb │ │ │ │ ├── submission.rb │ │ │ │ ├── tab.rb │ │ │ │ └── topic.rb │ │ │ └── video.rb │ │ ├── course.rb │ │ ├── course_user.rb │ │ ├── duplication_traceable/ │ │ │ ├── assessment.rb │ │ │ └── course.rb │ │ ├── duplication_traceable.rb │ │ ├── generic_announcement.rb │ │ ├── instance/ │ │ │ ├── announcement.rb │ │ │ ├── settings/ │ │ │ │ └── components.rb │ │ │ ├── settings.rb │ │ │ ├── user_invitation.rb │ │ │ └── user_role_request.rb │ │ ├── instance.rb │ │ ├── instance_user.rb │ │ ├── settings.rb │ │ ├── system/ │ │ │ └── announcement.rb │ │ ├── user/ │ │ │ ├── email.rb │ │ │ └── identity.rb │ │ ├── user.rb │ │ └── user_notification.rb │ ├── notifiers/ │ │ ├── course/ │ │ │ ├── achievement_notifier.rb │ │ │ ├── announcement_notifier.rb │ │ │ ├── assessment/ │ │ │ │ ├── answer/ │ │ │ │ │ └── comment_notifier.rb │ │ │ │ └── submission_question/ │ │ │ │ └── comment_notifier.rb │ │ │ ├── assessment_notifier.rb │ │ │ ├── consolidated_opening_reminder_notifier.rb │ │ │ ├── forum/ │ │ │ │ ├── post_notifier.rb │ │ │ │ └── topic_notifier.rb │ │ │ ├── level_notifier.rb │ │ │ └── video_notifier.rb │ │ └── notifier/ │ │ └── base.rb │ ├── services/ │ │ ├── authentication/ │ │ │ ├── authentication_service.rb │ │ │ ├── jwt_verification_service.rb │ │ │ ├── keycloak_verification_service.rb │ │ │ └── verification_service.rb │ │ ├── cikgo/ │ │ │ ├── chats_service.rb │ │ │ ├── resources_service.rb │ │ │ ├── service.rb │ │ │ ├── timelines_service.rb │ │ │ └── users_service.rb │ │ ├── codaveri_async_api_service.rb │ │ ├── concerns/ │ │ │ ├── cikgo/ │ │ │ │ └── course_concern.rb │ │ │ ├── course/ │ │ │ │ └── user_invitation_service/ │ │ │ │ ├── email_invitation_concern.rb │ │ │ │ ├── parse_invitation_concern.rb │ │ │ │ └── process_invitation_concern.rb │ │ │ └── instance/ │ │ │ └── user_invitation_service/ │ │ │ ├── email_invitation_concern.rb │ │ │ ├── parse_invitation_concern.rb │ │ │ └── process_invitation_concern.rb │ │ ├── course/ │ │ │ ├── announcement/ │ │ │ │ └── reminder_service.rb │ │ │ ├── assessment/ │ │ │ │ ├── achievement_preload_service.rb │ │ │ │ ├── answer/ │ │ │ │ │ ├── ai_generated_post_service.rb │ │ │ │ │ ├── auto_grading_service.rb │ │ │ │ │ ├── live_feedback/ │ │ │ │ │ │ ├── feedback_service.rb │ │ │ │ │ │ └── thread_service.rb │ │ │ │ │ ├── multiple_response_auto_grading_service.rb │ │ │ │ │ ├── programming_auto_grading_service.rb │ │ │ │ │ ├── programming_codaveri_async_feedback_service.rb │ │ │ │ │ ├── programming_codaveri_auto_grading_service.rb │ │ │ │ │ ├── prompts/ │ │ │ │ │ │ ├── rubric_auto_grading_output_format.json │ │ │ │ │ │ ├── rubric_auto_grading_system_prompt.json │ │ │ │ │ │ └── rubric_auto_grading_user_prompt.json │ │ │ │ │ ├── rubric_auto_grading_service.rb │ │ │ │ │ ├── rubric_based_response/ │ │ │ │ │ │ └── answer_adapter.rb │ │ │ │ │ ├── text_response_auto_grading_service.rb │ │ │ │ │ └── text_response_comprehension_auto_grading_service.rb │ │ │ │ ├── authentication_service.rb │ │ │ │ ├── koditsu_assessment_invitation_service.rb │ │ │ │ ├── koditsu_assessment_service.rb │ │ │ │ ├── monitoring_service.rb │ │ │ │ ├── programming_codaveri_evaluation_service.rb │ │ │ │ ├── programming_evaluation_service.rb │ │ │ │ ├── question/ │ │ │ │ │ ├── answers_evaluation_service.rb │ │ │ │ │ ├── codaveri_problem_generation_service.rb │ │ │ │ │ ├── koditsu_question_service.rb │ │ │ │ │ ├── mrq_generation_service.rb │ │ │ │ │ ├── programming/ │ │ │ │ │ │ ├── c_sharp/ │ │ │ │ │ │ │ ├── c_sharp_makefile │ │ │ │ │ │ │ └── c_sharp_package_service.rb │ │ │ │ │ │ ├── cpp/ │ │ │ │ │ │ │ ├── cpp_autograde_include.cc │ │ │ │ │ │ │ ├── cpp_autograde_post.cc │ │ │ │ │ │ │ ├── cpp_autograde_pre.cc │ │ │ │ │ │ │ ├── cpp_makefile │ │ │ │ │ │ │ └── cpp_package_service.rb │ │ │ │ │ │ ├── go/ │ │ │ │ │ │ │ ├── go_makefile │ │ │ │ │ │ │ └── go_package_service.rb │ │ │ │ │ │ ├── java/ │ │ │ │ │ │ │ ├── RunTests.java │ │ │ │ │ │ │ ├── java_autograde_pre.java │ │ │ │ │ │ │ ├── java_build.xml │ │ │ │ │ │ │ ├── java_package_service.rb │ │ │ │ │ │ │ ├── java_simple_makefile │ │ │ │ │ │ │ └── java_standard_makefile │ │ │ │ │ │ ├── java_script/ │ │ │ │ │ │ │ ├── java_script_makefile │ │ │ │ │ │ │ └── java_script_package_service.rb │ │ │ │ │ │ ├── language_package_service.rb │ │ │ │ │ │ ├── programming_package_service.rb │ │ │ │ │ │ ├── python/ │ │ │ │ │ │ │ ├── python_autograde_post.py │ │ │ │ │ │ │ ├── python_autograde_pre.py │ │ │ │ │ │ │ ├── python_makefile │ │ │ │ │ │ │ └── python_package_service.rb │ │ │ │ │ │ ├── r/ │ │ │ │ │ │ │ ├── r_makefile │ │ │ │ │ │ │ └── r_package_service.rb │ │ │ │ │ │ ├── rust/ │ │ │ │ │ │ │ ├── rust_makefile │ │ │ │ │ │ │ └── rust_package_service.rb │ │ │ │ │ │ └── type_script/ │ │ │ │ │ │ ├── type_script_makefile │ │ │ │ │ │ └── type_script_package_service.rb │ │ │ │ │ ├── programming_codaveri/ │ │ │ │ │ │ ├── c_sharp/ │ │ │ │ │ │ │ └── c_sharp_package_service.rb │ │ │ │ │ │ ├── go/ │ │ │ │ │ │ │ └── go_package_service.rb │ │ │ │ │ │ ├── java/ │ │ │ │ │ │ │ └── java_package_service.rb │ │ │ │ │ │ ├── java_script/ │ │ │ │ │ │ │ └── java_script_package_service.rb │ │ │ │ │ │ ├── language_package_service.rb │ │ │ │ │ │ ├── programming_codaveri_package_service.rb │ │ │ │ │ │ ├── python/ │ │ │ │ │ │ │ └── python_package_service.rb │ │ │ │ │ │ ├── r/ │ │ │ │ │ │ │ └── r_package_service.rb │ │ │ │ │ │ ├── rust/ │ │ │ │ │ │ │ └── rust_package_service.rb │ │ │ │ │ │ └── type_script/ │ │ │ │ │ │ └── type_script_package_service.rb │ │ │ │ │ ├── programming_codaveri_service.rb │ │ │ │ │ ├── programming_import_service.rb │ │ │ │ │ ├── prompts/ │ │ │ │ │ │ ├── mcq_generation_system_prompt.json │ │ │ │ │ │ ├── mcq_generation_user_prompt.json │ │ │ │ │ │ ├── mcq_mrq_generation_output_format.json │ │ │ │ │ │ ├── mrq_generation_system_prompt.json │ │ │ │ │ │ └── mrq_generation_user_prompt.json │ │ │ │ │ ├── question_adapter.rb │ │ │ │ │ ├── rubric_based_response/ │ │ │ │ │ │ └── rubric_adapter.rb │ │ │ │ │ ├── scribing_import_service.rb │ │ │ │ │ └── text_response_lemma_service.rb │ │ │ │ ├── reminder_service.rb │ │ │ │ ├── session_authentication_service.rb │ │ │ │ ├── session_log_service.rb │ │ │ │ └── submission/ │ │ │ │ ├── auto_grading_service.rb │ │ │ │ ├── base_zip_download_service.rb │ │ │ │ ├── calculate_exp_service.rb │ │ │ │ ├── csv_download_service.rb │ │ │ │ ├── koditsu_submission_service.rb │ │ │ │ ├── monitoring_service.rb │ │ │ │ ├── ssid_plagiarism_service.rb │ │ │ │ ├── ssid_zip_download_service.rb │ │ │ │ ├── statistics_download_service.rb │ │ │ │ ├── update_service.rb │ │ │ │ └── zip_download_service.rb │ │ │ ├── conditional/ │ │ │ │ ├── conditional_satisfiability_evaluation_service.rb │ │ │ │ └── satisfiability_graph_build_service.rb │ │ │ ├── course_owner_preload_service.rb │ │ │ ├── course_user_preload_service.rb │ │ │ ├── discussion/ │ │ │ │ └── post/ │ │ │ │ └── codaveri_feedback_rating_service.rb │ │ │ ├── duplication/ │ │ │ │ ├── base_service.rb │ │ │ │ ├── course_duplication_service.rb │ │ │ │ └── object_duplication_service.rb │ │ │ ├── experience_points_download_service.rb │ │ │ ├── group_manager_preload_service.rb │ │ │ ├── koditsu_workspace_service.rb │ │ │ ├── material/ │ │ │ │ ├── preload_service.rb │ │ │ │ └── zip_download_service.rb │ │ │ ├── reference_time/ │ │ │ │ └── time_offset_service.rb │ │ │ ├── rubric/ │ │ │ │ ├── llm_service/ │ │ │ │ │ ├── answer_adapter.rb │ │ │ │ │ ├── question_adapter.rb │ │ │ │ │ └── rubric_adapter.rb │ │ │ │ └── llm_service.rb │ │ │ ├── skills_mastery_preload_service.rb │ │ │ ├── ssid_folder_service.rb │ │ │ ├── statistics/ │ │ │ │ └── assessments_score_summary_download_service.rb │ │ │ ├── survey/ │ │ │ │ ├── reminder_service.rb │ │ │ │ └── survey_download_service.rb │ │ │ ├── user_invitation_service.rb │ │ │ ├── user_registration_service.rb │ │ │ └── video/ │ │ │ └── reminder_service.rb │ │ ├── instance/ │ │ │ └── user_invitation_service.rb │ │ ├── koditsu_async_api_service.rb │ │ ├── rag_wise/ │ │ │ ├── chunking_service.rb │ │ │ ├── discussion_extraction_service.rb │ │ │ ├── llm_service.rb │ │ │ ├── prompts/ │ │ │ │ ├── forum_assistant_system_prompt.json │ │ │ │ └── guess_course_material_name_system_prompt_template.json │ │ │ ├── rag_workflow_service.rb │ │ │ ├── response_evaluation_service.rb │ │ │ └── tools/ │ │ │ ├── course_forum_discussions_tool.rb │ │ │ └── course_materials_tool.rb │ │ ├── scholaistic_api_service.rb │ │ ├── sidekiq_api_service.rb │ │ ├── ssid_async_api_service.rb │ │ └── user/ │ │ └── instance_preload_service.rb │ ├── uploaders/ │ │ ├── file_uploader.rb │ │ └── image_uploader.rb │ └── views/ │ ├── announcements/ │ │ ├── _announcement_data.json.jbuilder │ │ ├── _announcement_list_data.json.jbuilder │ │ └── index.json.jbuilder │ ├── application/ │ │ └── index.json.jbuilder │ ├── attachment_references/ │ │ └── create.json.jbuilder │ ├── attachments/ │ │ └── _attachment_reference.json.jbuilder │ ├── course/ │ │ ├── achievement/ │ │ │ └── achievements/ │ │ │ ├── _achievement.json.jbuilder │ │ │ ├── _achievement_conditional.json.jbuilder │ │ │ ├── _achievement_data.json.jbuilder │ │ │ ├── _achievement_list_data.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ └── show.json.jbuilder │ │ ├── admin/ │ │ │ ├── admin/ │ │ │ │ ├── index.json.jbuilder │ │ │ │ └── time_zones.json.jbuilder │ │ │ ├── announcement_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── assessment_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── codaveri_settings/ │ │ │ │ ├── assessment.json.jbuilder │ │ │ │ └── edit.json.jbuilder │ │ │ ├── component_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── discussion/ │ │ │ │ └── topic_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── forum_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── leaderboard_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── lesson_plan_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── material_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── notification_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── rag_wise_settings/ │ │ │ │ ├── courses.json.jbuilder │ │ │ │ ├── edit.json.jbuilder │ │ │ │ ├── folders.json.jbuilder │ │ │ │ ├── forums.json.jbuilder │ │ │ │ └── materials.json.jbuilder │ │ │ ├── scholaistic_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ ├── sidebar_settings/ │ │ │ │ ├── edit.json.jbuilder │ │ │ │ └── show.json.jbuilder │ │ │ ├── stories_settings/ │ │ │ │ └── edit.json.jbuilder │ │ │ └── video_settings/ │ │ │ └── edit.json.jbuilder │ │ ├── announcements/ │ │ │ └── index.json.jbuilder │ │ ├── assessment/ │ │ │ ├── answer/ │ │ │ │ ├── forum_post_responses/ │ │ │ │ │ └── _forum_post_response.json.jbuilder │ │ │ │ ├── multiple_responses/ │ │ │ │ │ └── _multiple_response.json.jbuilder │ │ │ │ ├── programming/ │ │ │ │ │ ├── _annotations.json.jbuilder │ │ │ │ │ └── _programming.json.jbuilder │ │ │ │ ├── rubric_based_responses/ │ │ │ │ │ └── _rubric_based_response.json.jbuilder │ │ │ │ ├── scribing/ │ │ │ │ │ └── _scribing.json.jbuilder │ │ │ │ ├── text_responses/ │ │ │ │ │ └── _text_response.json.jbuilder │ │ │ │ └── voice_responses/ │ │ │ │ └── _voice_response.json.jbuilder │ │ │ ├── answers/ │ │ │ │ └── _answer.json.jbuilder │ │ │ ├── assessments/ │ │ │ │ ├── _achievement_badges.json.jbuilder │ │ │ │ ├── _assessment_actions.json.jbuilder │ │ │ │ ├── _assessment_conditional.json.jbuilder │ │ │ │ ├── _assessment_lesson_plan_item.json.jbuilder │ │ │ │ ├── _assessment_list_data.json.jbuilder │ │ │ │ ├── _assessment_question_bundle_buttons.html.slim │ │ │ │ ├── _monitoring_details.json.jbuilder │ │ │ │ ├── authenticate.json.jbuilder │ │ │ │ ├── blocked_by_monitor.json.jbuilder │ │ │ │ ├── edit.json.jbuilder │ │ │ │ ├── index.json.jbuilder │ │ │ │ ├── monitoring.json.jbuilder │ │ │ │ └── show.json.jbuilder │ │ │ ├── categories/ │ │ │ │ ├── _category.json.jbuilder │ │ │ │ └── index.json.jbuilder │ │ │ ├── mock_answers/ │ │ │ │ └── index.json.jbuilder │ │ │ ├── programming_evaluations/ │ │ │ │ ├── _programming_evaluation.json.jbuilder │ │ │ │ ├── allocate.json.jbuilder │ │ │ │ ├── show.json.jbuilder │ │ │ │ └── update_result.json.jbuilder │ │ │ ├── question/ │ │ │ │ ├── _form.json.jbuilder │ │ │ │ ├── _skills.json.jbuilder │ │ │ │ ├── forum_post_responses/ │ │ │ │ │ ├── _form.json.jbuilder │ │ │ │ │ ├── _forum_post_response.json.jbuilder │ │ │ │ │ ├── edit.json.jbuilder │ │ │ │ │ └── new.json.jbuilder │ │ │ │ ├── multiple_responses/ │ │ │ │ │ ├── _form.json.jbuilder │ │ │ │ │ ├── _multiple_response.json.jbuilder │ │ │ │ │ ├── _multiple_response_details.json.jbuilder │ │ │ │ │ ├── _switch_question_type_button.json.jbuilder │ │ │ │ │ ├── edit.json.jbuilder │ │ │ │ │ └── new.json.jbuilder │ │ │ │ ├── programming/ │ │ │ │ │ ├── _form.json.jbuilder │ │ │ │ │ ├── _import_result.json.jbuilder │ │ │ │ │ ├── _languages.json.jbuilder │ │ │ │ │ ├── _package_ui.json.jbuilder │ │ │ │ │ ├── _programming.json.jbuilder │ │ │ │ │ ├── _question.json.jbuilder │ │ │ │ │ ├── _response.json.jbuilder │ │ │ │ │ ├── _test_cases.json.jbuilder │ │ │ │ │ ├── _test_ui.json.jbuilder │ │ │ │ │ ├── edit.json.jbuilder │ │ │ │ │ ├── import_result.json.jbuilder │ │ │ │ │ ├── metadata/ │ │ │ │ │ │ ├── _c_cpp.json.jbuilder │ │ │ │ │ │ ├── _csharp.json.jbuilder │ │ │ │ │ │ ├── _default.json.jbuilder │ │ │ │ │ │ ├── _golang.json.jbuilder │ │ │ │ │ │ ├── _java.json.jbuilder │ │ │ │ │ │ ├── _javascript.json.jbuilder │ │ │ │ │ │ ├── _python.json.jbuilder │ │ │ │ │ │ ├── _r.json.jbuilder │ │ │ │ │ │ ├── _rust.json.jbuilder │ │ │ │ │ │ ├── _typescript.json.jbuilder │ │ │ │ │ │ └── partials/ │ │ │ │ │ │ ├── _file.json.jbuilder │ │ │ │ │ │ └── _test_cases.json.jbuilder │ │ │ │ │ └── new.json.jbuilder │ │ │ │ ├── rubric_based_responses/ │ │ │ │ │ ├── _category_details.json.jbuilder │ │ │ │ │ ├── _form.json.jbuilder │ │ │ │ │ ├── _grade_details.json.jbuilder │ │ │ │ │ ├── _rubric_based_response.json.jbuilder │ │ │ │ │ ├── edit.json.jbuilder │ │ │ │ │ └── new.json.jbuilder │ │ │ │ ├── scribing/ │ │ │ │ │ ├── _scribing.json.jbuilder │ │ │ │ │ └── _scribing_question.json.jbuilder │ │ │ │ ├── text_responses/ │ │ │ │ │ ├── _form.json.jbuilder │ │ │ │ │ ├── _solution_details.json.jbuilder │ │ │ │ │ ├── _text_response.json.jbuilder │ │ │ │ │ ├── edit.json.jbuilder │ │ │ │ │ └── new.json.jbuilder │ │ │ │ └── voice_responses/ │ │ │ │ ├── _form.json.jbuilder │ │ │ │ ├── _voice_response.json.jbuilder │ │ │ │ ├── edit.json.jbuilder │ │ │ │ └── new.json.jbuilder │ │ │ ├── question_bundle_assignments/ │ │ │ │ ├── _form.html.slim │ │ │ │ ├── _validation_result.html.slim │ │ │ │ ├── edit.html.slim │ │ │ │ └── index.html.slim │ │ │ ├── question_bundle_questions/ │ │ │ │ ├── _form.html.slim │ │ │ │ ├── edit.html.slim │ │ │ │ ├── index.html.slim │ │ │ │ └── new.html.slim │ │ │ ├── question_bundles/ │ │ │ │ ├── _form.html.slim │ │ │ │ ├── edit.html.slim │ │ │ │ ├── index.html.slim │ │ │ │ └── new.html.slim │ │ │ ├── question_groups/ │ │ │ │ ├── _form.html.slim │ │ │ │ ├── edit.html.slim │ │ │ │ ├── index.html.slim │ │ │ │ └── new.html.slim │ │ │ ├── questions/ │ │ │ │ └── show.json.jbuilder │ │ │ ├── rubrics/ │ │ │ │ ├── fetch_answer_evaluations.json.jbuilder │ │ │ │ ├── fetch_mock_answer_evaluations.json.jbuilder │ │ │ │ ├── index.json.jbuilder │ │ │ │ └── rubric_answers.json.jbuilder │ │ │ ├── skill_branches/ │ │ │ │ ├── _skill_branch_list_data.json.jbuilder │ │ │ │ └── _skill_branch_user_list_data.json.jbuilder │ │ │ ├── skills/ │ │ │ │ ├── _options.json.jbuilder │ │ │ │ ├── _skill_list_data.json.jbuilder │ │ │ │ ├── _skill_user_list_data.json.jbuilder │ │ │ │ └── index.json.jbuilder │ │ │ ├── submission/ │ │ │ │ ├── answer/ │ │ │ │ │ ├── answers/ │ │ │ │ │ │ └── show.json.jbuilder │ │ │ │ │ └── forum_post_response/ │ │ │ │ │ └── posts/ │ │ │ │ │ ├── _post_packs.json.jbuilder │ │ │ │ │ └── selected.json.jbuilder │ │ │ │ ├── logs/ │ │ │ │ │ ├── _info.json.jbuilder │ │ │ │ │ ├── _logs.json.jbuilder │ │ │ │ │ └── index.json.jbuilder │ │ │ │ └── submissions/ │ │ │ │ ├── _answers.json.jbuilder │ │ │ │ ├── _history.json.jbuilder │ │ │ │ ├── _question.json.jbuilder │ │ │ │ ├── _questions.json.jbuilder │ │ │ │ ├── _submission.json.jbuilder │ │ │ │ ├── _topics.json.jbuilder │ │ │ │ ├── create_live_feedback_chat.json.jbuilder │ │ │ │ ├── edit.json.jbuilder │ │ │ │ ├── fetch_live_feedback_chat.json.jbuilder │ │ │ │ ├── fetch_live_feedback_status.json.jbuilder │ │ │ │ └── index.json.jbuilder │ │ │ ├── submission_question/ │ │ │ │ └── submission_questions/ │ │ │ │ └── all_answers.json.jbuilder │ │ │ └── submissions/ │ │ │ ├── _filter.json.jbuilder │ │ │ ├── _submissions_list_data.json.jbuilder │ │ │ ├── _tabs.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ └── pending.json.jbuilder │ │ ├── condition/ │ │ │ ├── _condition_data.json.jbuilder │ │ │ ├── _condition_list_data.json.jbuilder │ │ │ ├── _conditions.json.jbuilder │ │ │ ├── _enabled_conditions.json.jbuilder │ │ │ ├── achievements/ │ │ │ │ └── _achievement.json.jbuilder │ │ │ ├── assessments/ │ │ │ │ ├── _assessment.json.jbuilder │ │ │ │ ├── _assessment_condition.json.jbuilder │ │ │ │ └── available_assessments.json.jbuilder │ │ │ ├── levels/ │ │ │ │ └── _level.json.jbuilder │ │ │ ├── scholaistic_assessments/ │ │ │ │ ├── _scholaistic_assessment.json.jbuilder │ │ │ │ └── available_scholaistic_assessments.json.jbuilder │ │ │ └── surveys/ │ │ │ ├── _survey.json.jbuilder │ │ │ └── available_surveys.json.jbuilder │ │ ├── courses/ │ │ │ ├── _course_data.json.jbuilder │ │ │ ├── _course_list_data.json.jbuilder │ │ │ ├── _course_user_progress.json.jbuilder │ │ │ ├── _sidebar_items.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ ├── show.json.jbuilder │ │ │ └── sidebar.json.jbuilder │ │ ├── discussion/ │ │ │ ├── posts/ │ │ │ │ └── _post.json.jbuilder │ │ │ └── topics/ │ │ │ ├── _discussion_topic_programming_file_annotation.jbuilder │ │ │ ├── _discussion_topic_submission_question.json.jbuilder │ │ │ ├── _discussion_topic_video.json.jbuilder │ │ │ ├── _tabs.json.jbuilder │ │ │ ├── _topic.json.jbuilder │ │ │ ├── discussion_topic_list_data.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── enrol_requests/ │ │ │ ├── _enrol_request_list_data.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── experience_points/ │ │ │ ├── disbursement/ │ │ │ │ └── new.json.jbuilder │ │ │ └── forum_disbursement/ │ │ │ └── new.json.jbuilder │ │ ├── experience_points_records/ │ │ │ ├── _experience_points_record.json.jbuilder │ │ │ ├── index.jbuilder │ │ │ └── show.jbuilder │ │ ├── forum/ │ │ │ ├── forums/ │ │ │ │ ├── _forum_list_data.json.jbuilder │ │ │ │ ├── all_posts.json.jbuilder │ │ │ │ ├── index.json.jbuilder │ │ │ │ ├── search.json.jbuilder │ │ │ │ └── show.json.jbuilder │ │ │ ├── posts/ │ │ │ │ ├── _post_creator_data.json.jbuilder │ │ │ │ ├── _post_list_data.json.jbuilder │ │ │ │ ├── _post_publish_data.json.jbuilder │ │ │ │ └── create.json.jbuilder │ │ │ └── topics/ │ │ │ ├── _topic_list_data.json.jbuilder │ │ │ └── show.json.jbuilder │ │ ├── group/ │ │ │ ├── _group.json.jbuilder │ │ │ ├── group_categories/ │ │ │ │ ├── create_groups.json.jbuilder │ │ │ │ ├── index.json.jbuilder │ │ │ │ ├── show_info.json.jbuilder │ │ │ │ └── show_users.json.jbuilder │ │ │ └── groups/ │ │ │ └── update.json.jbuilder │ │ ├── leaderboards/ │ │ │ ├── _leaderboard_achievement_list_data.json.jbuilder │ │ │ ├── _leaderboard_group_list_data.json.jbuilder │ │ │ ├── _leaderboard_list_data.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── learning_map/ │ │ │ └── index.json.jbuilder │ │ ├── lesson_plan/ │ │ │ ├── events/ │ │ │ │ └── _event_lesson_plan_item.json.jbuilder │ │ │ ├── items/ │ │ │ │ ├── _item.json.jbuilder │ │ │ │ ├── _personal_or_ref_time.json.jbuilder │ │ │ │ └── index.json.jbuilder │ │ │ ├── milestones/ │ │ │ │ └── _milestone.json.jbuilder │ │ │ └── todos/ │ │ │ └── _todo.json.jbuilder │ │ ├── levels/ │ │ │ └── index.json.jbuilder │ │ ├── mailer/ │ │ │ ├── assessment_closing_reminder_email.html.slim │ │ │ ├── assessment_closing_reminder_email.text.erb │ │ │ ├── assessment_closing_summary_email.html.slim │ │ │ ├── assessment_closing_summary_email.text.erb │ │ │ ├── course_duplicate_failed_email.html.slim │ │ │ ├── course_duplicate_failed_email.text.erb │ │ │ ├── course_duplicated_email.html.slim │ │ │ ├── course_duplicated_email.text.erb │ │ │ ├── course_user_deletion_failed_email.html.slim │ │ │ ├── course_user_deletion_failed_email.text.erb │ │ │ ├── submission_graded_email.html.slim │ │ │ ├── submission_graded_email.text.erb │ │ │ ├── survey_closing_reminder_email.html.slim │ │ │ ├── survey_closing_reminder_email.text.erb │ │ │ ├── survey_closing_summary_email.html.slim │ │ │ ├── survey_closing_summary_email.text.erb │ │ │ ├── user_added_email.html.slim │ │ │ ├── user_added_email.text.erb │ │ │ ├── user_enrol_request_received_email.html.slim │ │ │ ├── user_enrol_request_received_email.text.erb │ │ │ ├── user_enrol_requested_email.html.slim │ │ │ ├── user_enrol_requested_email.text.erb │ │ │ ├── user_invitation_email.html.slim │ │ │ ├── user_invitation_email.text.erb │ │ │ ├── user_rejected_email.html.slim │ │ │ ├── user_rejected_email.text.erb │ │ │ ├── user_suspended_email.html.slim │ │ │ ├── user_suspended_email.text.erb │ │ │ ├── user_unsuspended_email.html.slim │ │ │ ├── user_unsuspended_email.text.erb │ │ │ ├── video_closing_reminder_email.html.slim │ │ │ └── video_closing_reminder_email.text.erb │ │ ├── material/ │ │ │ ├── _material.json.jbuilder │ │ │ └── folders/ │ │ │ ├── breadcrumbs.json.jbuilder │ │ │ ├── show.json.jbuilder │ │ │ └── upload_materials.json.jbuilder │ │ ├── object_duplications/ │ │ │ ├── _course_duplication_data.json.jbuilder │ │ │ └── new.json.jbuilder │ │ ├── personal_times/ │ │ │ ├── _personal_time_list_data.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── plagiarism/ │ │ │ └── assessments/ │ │ │ ├── _plagiarism_check.json.jbuilder │ │ │ ├── _plagiarism_checks.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ ├── linked_and_unlinked_assessments.json.jbuilder │ │ │ └── plagiarism_data.json.jbuilder │ │ ├── question_assessments/ │ │ │ └── _question_assessment.json.jbuilder │ │ ├── reference_timelines/ │ │ │ ├── _reference_timeline.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── rubrics/ │ │ │ ├── _answer_evaluation.json.jbuilder │ │ │ ├── _mock_answer_evaluation.json.jbuilder │ │ │ ├── _rubric.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── scholaistic/ │ │ │ ├── assistants/ │ │ │ │ ├── index.json.jbuilder │ │ │ │ └── show.json.jbuilder │ │ │ ├── scholaistic_assessments/ │ │ │ │ ├── edit.json.jbuilder │ │ │ │ ├── index.json.jbuilder │ │ │ │ ├── new.json.jbuilder │ │ │ │ └── show.json.jbuilder │ │ │ └── submissions/ │ │ │ ├── index.json.jbuilder │ │ │ └── show.json.jbuilder │ │ ├── statistics/ │ │ │ ├── aggregate/ │ │ │ │ ├── activity_get_help.json.jbuilder │ │ │ │ ├── all_assessments.json.jbuilder │ │ │ │ ├── all_staff.json.jbuilder │ │ │ │ ├── all_students.json.jbuilder │ │ │ │ ├── course_performance.json.jbuilder │ │ │ │ └── course_progression.json.jbuilder │ │ │ ├── assessments/ │ │ │ │ ├── _answer.json.jbuilder │ │ │ │ ├── _assessment.json.jbuilder │ │ │ │ ├── _attempt_status.json.jbuilder │ │ │ │ ├── _course_user.json.jbuilder │ │ │ │ ├── _live_feedback_history_details.json.jbuilder │ │ │ │ ├── _submission.json.jbuilder │ │ │ │ ├── ancestor_info.json.jbuilder │ │ │ │ ├── ancestor_statistics.json.jbuilder │ │ │ │ ├── assessment_statistics.json.jbuilder │ │ │ │ ├── live_feedback_history.json.jbuilder │ │ │ │ ├── live_feedback_statistics.json.jbuilder │ │ │ │ └── submission_statistics.json.jbuilder │ │ │ ├── statistics/ │ │ │ │ └── index.json.jbuilder │ │ │ └── users/ │ │ │ └── learning_rate_records.json.jbuilder │ │ ├── survey/ │ │ │ ├── questions/ │ │ │ │ ├── _option.json.jbuilder │ │ │ │ └── _question.json.jbuilder │ │ │ ├── responses/ │ │ │ │ ├── _response.json.jbuilder │ │ │ │ ├── _see_other.json.jbuilder │ │ │ │ └── index.json.jbuilder │ │ │ ├── sections/ │ │ │ │ └── _section.json.jbuilder │ │ │ └── surveys/ │ │ │ ├── _survey.json.jbuilder │ │ │ ├── _survey_with_questions.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ └── results.json.jbuilder │ │ ├── surveys/ │ │ │ └── _survey_lesson_plan_item.json.jbuilder │ │ ├── user_email_subscriptions/ │ │ │ └── _subscription_setting.json.jbuilder │ │ ├── user_invitations/ │ │ │ ├── _course_user_invitation_list.json.jbuilder │ │ │ ├── _course_user_invitation_list_data.json.jbuilder │ │ │ ├── _invitation_result_data.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ └── new.json.jbuilder │ │ ├── user_registrations/ │ │ │ └── _registration.json.jbuilder │ │ ├── users/ │ │ │ ├── _permissions_data.json.jbuilder │ │ │ ├── _tabs_data.json.jbuilder │ │ │ ├── _upgrade_to_staff_results.json.jbuilder │ │ │ ├── _user.json.jbuilder │ │ │ ├── _user_data.json.jbuilder │ │ │ ├── _user_list_data.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ ├── show.json.jbuilder │ │ │ ├── staff.json.jbuilder │ │ │ └── students.json.jbuilder │ │ ├── video/ │ │ │ ├── sessions/ │ │ │ │ └── _session.json.jbuilder │ │ │ ├── submission/ │ │ │ │ ├── sessions/ │ │ │ │ │ └── create.json.jbuilder │ │ │ │ └── submissions/ │ │ │ │ ├── _watch_next_video_url.json.jbuilder │ │ │ │ ├── edit.json.jbuilder │ │ │ │ ├── index.json.jbuilder │ │ │ │ └── show.json.jbuilder │ │ │ ├── topics/ │ │ │ │ ├── _post.json.jbuilder │ │ │ │ ├── _posts.json.jbuilder │ │ │ │ ├── _topic.json.jbuilder │ │ │ │ ├── _topics.json.jbuilder │ │ │ │ ├── create.json.jbuilder │ │ │ │ ├── index.json.jbuilder │ │ │ │ └── show.json.jbuilder │ │ │ └── videos/ │ │ │ ├── _video.json.jbuilder │ │ │ ├── _video_data.json.jbuilder │ │ │ ├── _video_lesson_plan_item.json.jbuilder │ │ │ ├── _video_list_data.json.jbuilder │ │ │ ├── _video_statistics.json.jbuilder │ │ │ ├── index.json.jbuilder │ │ │ └── show.json.jbuilder │ │ └── video_submissions/ │ │ └── index.json.jbuilder │ ├── instance/ │ │ └── mailer/ │ │ ├── user_added_email.html.slim │ │ ├── user_added_email.text.erb │ │ ├── user_invitation_email.html.slim │ │ └── user_invitation_email.text.erb │ ├── instance_user_role_request_mailer/ │ │ ├── new_role_request.html.slim │ │ ├── new_role_request.text.erb │ │ ├── role_request_approved.html.slim │ │ ├── role_request_approved.text.erb │ │ ├── role_request_rejected.html.slim │ │ └── role_request_rejected.text.erb │ ├── instance_user_role_requests/ │ │ ├── _instance_user_role_request_list_data.json.jbuilder │ │ └── index.json.jbuilder │ ├── jobs/ │ │ ├── _completed.json.jbuilder │ │ ├── _errored.json.jbuilder │ │ ├── _submitted.json.jbuilder │ │ └── show.json.jbuilder │ ├── layouts/ │ │ ├── _manage_email_subscription.html.slim │ │ ├── _manage_email_subscription.text.erb │ │ ├── _materials.json.jbuilder │ │ ├── mailer.html.slim │ │ ├── mailer.text.erb │ │ ├── no_greeting_mailer.html.slim │ │ └── no_greeting_mailer.text.erb │ ├── notifiers/ │ │ └── course/ │ │ ├── achievement_notifier/ │ │ │ └── gained/ │ │ │ ├── course_notifications/ │ │ │ │ └── _feed.json.jbuilder │ │ │ └── user_notifications/ │ │ │ └── popup.json.jbuilder │ │ ├── announcement_notifier/ │ │ │ └── new/ │ │ │ └── course_notifications/ │ │ │ └── email.html.slim │ │ ├── assessment/ │ │ │ ├── answer/ │ │ │ │ └── comment_notifier/ │ │ │ │ └── annotated/ │ │ │ │ └── user_notifications/ │ │ │ │ └── email.html.slim │ │ │ └── submission_question/ │ │ │ └── comment_notifier/ │ │ │ └── replied/ │ │ │ └── user_notifications/ │ │ │ └── email.html.slim │ │ ├── assessment_notifier/ │ │ │ ├── attempted/ │ │ │ │ └── course_notifications/ │ │ │ │ └── _feed.json.jbuilder │ │ │ ├── opening/ │ │ │ │ └── course_notifications/ │ │ │ │ └── email.html.slim │ │ │ └── submitted/ │ │ │ └── user_notifications/ │ │ │ └── email.html.slim │ │ ├── consolidated_opening_reminder_notifier/ │ │ │ └── opening_reminder/ │ │ │ └── course_notifications/ │ │ │ ├── course/ │ │ │ │ ├── _assessment.html.slim │ │ │ │ ├── _survey.html.slim │ │ │ │ └── _video.html.slim │ │ │ └── email.html.slim │ │ ├── forum/ │ │ │ ├── post_notifier/ │ │ │ │ ├── replied/ │ │ │ │ │ ├── course_notifications/ │ │ │ │ │ │ └── _feed.json.jbuilder │ │ │ │ │ └── user_notifications/ │ │ │ │ │ └── email.html.slim │ │ │ │ └── voted/ │ │ │ │ └── course_notifications/ │ │ │ │ └── _feed.json.jbuilder │ │ │ └── topic_notifier/ │ │ │ └── created/ │ │ │ ├── course_notifications/ │ │ │ │ └── _feed.json.jbuilder │ │ │ └── user_notifications/ │ │ │ └── email.html.slim │ │ ├── level_notifier/ │ │ │ └── reached/ │ │ │ ├── course_notifications/ │ │ │ │ └── _feed.json.jbuilder │ │ │ └── user_notifications/ │ │ │ └── popup.json.jbuilder │ │ └── video_notifier/ │ │ ├── attempted/ │ │ │ └── course_notifications/ │ │ │ └── _feed.json.jbuilder │ │ ├── closing/ │ │ │ └── user_notifications/ │ │ │ └── email.html.slim │ │ └── opening/ │ │ └── course_notifications/ │ │ └── email.html.slim │ ├── system/ │ │ └── admin/ │ │ ├── announcements/ │ │ │ └── index.json.jbuilder │ │ ├── courses/ │ │ │ ├── _course_list_data.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── get_help/ │ │ │ └── index.json.jbuilder │ │ ├── instance/ │ │ │ ├── admin/ │ │ │ │ └── index.json.jbuilder │ │ │ ├── announcements/ │ │ │ │ └── index.json.jbuilder │ │ │ ├── components/ │ │ │ │ └── index.json.jbuilder │ │ │ ├── courses/ │ │ │ │ └── index.json.jbuilder │ │ │ ├── get_help/ │ │ │ │ └── index.json.jbuilder │ │ │ ├── user_invitations/ │ │ │ │ ├── _instance_user_invitation_list_data.json.jbuilder │ │ │ │ ├── _invitation_result_data.json.jbuilder │ │ │ │ └── index.json.jbuilder │ │ │ └── users/ │ │ │ ├── _user_list_data.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── instances/ │ │ │ ├── _instance_list_data.json.jbuilder │ │ │ └── index.json.jbuilder │ │ └── users/ │ │ ├── _user_list_data.json.jbuilder │ │ └── index.json.jbuilder │ ├── user/ │ │ ├── emails/ │ │ │ ├── _email_list_data.json.jbuilder │ │ │ └── index.json.jbuilder │ │ ├── profiles/ │ │ │ ├── edit.json.jbuilder │ │ │ └── show.json.jbuilder │ │ └── registrations/ │ │ └── create.json.jbuilder │ └── users/ │ ├── _course_list_data.json.jbuilder │ ├── _instance_list_data.json.jbuilder │ └── show.json.jbuilder ├── authentication/ │ ├── Dockerfile │ ├── README.md │ ├── docker-compose.yml │ ├── env │ ├── import/ │ │ └── coursemology_realm.json │ ├── script/ │ │ └── cm_db_federation.sql │ └── theme/ │ └── coursemology-keycloakify-keycloak-theme-6.1.7.jar ├── bin/ │ ├── bundle │ ├── rails │ ├── rake │ ├── setup │ ├── spring │ └── update ├── client/ │ ├── .babelrc │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .prettierignore │ ├── .prettierrc.js │ ├── .yarn-integrity │ ├── CONTRIBUTING.md │ ├── README.md │ ├── app/ │ │ ├── App.tsx │ │ ├── __test__/ │ │ │ ├── mocks/ │ │ │ │ ├── ResizeObserver.js │ │ │ │ ├── axiosMock.js │ │ │ │ ├── fileMock.js │ │ │ │ ├── matchMedia.js │ │ │ │ ├── requestAnimationFrame.js │ │ │ │ └── svgMock.js │ │ │ ├── setup.js │ │ │ └── utils/ │ │ │ ├── __test__/ │ │ │ │ └── shallowUntil.test.js │ │ │ └── shallowUntil.js │ │ ├── api/ │ │ │ ├── Announcements.ts │ │ │ ├── Attachments.ts │ │ │ ├── Base.ts │ │ │ ├── ErrorHandling.ts │ │ │ ├── Home.ts │ │ │ ├── Jobs.ts │ │ │ ├── Users.ts │ │ │ ├── course/ │ │ │ │ ├── Achievements.ts │ │ │ │ ├── Admin/ │ │ │ │ │ ├── Announcements.ts │ │ │ │ │ ├── Assessments.ts │ │ │ │ │ ├── Base.ts │ │ │ │ │ ├── Codaveri.ts │ │ │ │ │ ├── Comments.ts │ │ │ │ │ ├── Components.ts │ │ │ │ │ ├── Course.ts │ │ │ │ │ ├── Forums.ts │ │ │ │ │ ├── Leaderboard.ts │ │ │ │ │ ├── LessonPlan.ts │ │ │ │ │ ├── Materials.ts │ │ │ │ │ ├── Notifications.ts │ │ │ │ │ ├── RagWise.ts │ │ │ │ │ ├── Scholaistic.ts │ │ │ │ │ ├── Sidebar.ts │ │ │ │ │ ├── Stories.ts │ │ │ │ │ ├── Videos.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── Announcements.ts │ │ │ │ ├── Assessment/ │ │ │ │ │ ├── AllAnswers.ts │ │ │ │ │ ├── Assessments.js │ │ │ │ │ ├── Base.js │ │ │ │ │ ├── Categories.js │ │ │ │ │ ├── Question/ │ │ │ │ │ │ ├── ForumPostResponse.ts │ │ │ │ │ │ ├── McqMrq.ts │ │ │ │ │ │ ├── MockAnswers.ts │ │ │ │ │ │ ├── Programming.ts │ │ │ │ │ │ ├── Questions.ts │ │ │ │ │ │ ├── RubricBasedResponse.ts │ │ │ │ │ │ ├── Rubrics.ts │ │ │ │ │ │ ├── Scribing.js │ │ │ │ │ │ ├── TextResponse.ts │ │ │ │ │ │ ├── VoiceResponse.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── Sessions.ts │ │ │ │ │ ├── Skills.ts │ │ │ │ │ ├── Submission/ │ │ │ │ │ │ ├── Answer/ │ │ │ │ │ │ │ ├── Answer.ts │ │ │ │ │ │ │ ├── ForumPostResponse.js │ │ │ │ │ │ │ ├── Programming.js │ │ │ │ │ │ │ ├── Scribing.js │ │ │ │ │ │ │ ├── TextResponse.ts │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ └── Logs/ │ │ │ │ │ │ └── Logs.ts │ │ │ │ │ ├── SubmissionQuestions.js │ │ │ │ │ ├── Submissions/ │ │ │ │ │ │ └── Submissions.ts │ │ │ │ │ ├── Submissions.js │ │ │ │ │ └── index.ts │ │ │ │ ├── Base.js │ │ │ │ ├── Comments.ts │ │ │ │ ├── Conditions.ts │ │ │ │ ├── Courses.ts │ │ │ │ ├── Disbursement.ts │ │ │ │ ├── Duplication.js │ │ │ │ ├── EnrolRequests.ts │ │ │ │ ├── ExperiencePointsRecord.ts │ │ │ │ ├── Forum/ │ │ │ │ │ ├── Forums.ts │ │ │ │ │ ├── Posts.ts │ │ │ │ │ ├── Topics.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── Groups.js │ │ │ │ ├── Leaderboard.ts │ │ │ │ ├── LearningMap.js │ │ │ │ ├── LessonPlan.js │ │ │ │ ├── Level.ts │ │ │ │ ├── Material/ │ │ │ │ │ └── Folders.ts │ │ │ │ ├── MaterialFolders.js │ │ │ │ ├── Materials.ts │ │ │ │ ├── PersonalTimes.ts │ │ │ │ ├── Plagiarism.ts │ │ │ │ ├── Posts.js │ │ │ │ ├── ReferenceTimelines.ts │ │ │ │ ├── Rubrics.ts │ │ │ │ ├── Scholaistic.ts │ │ │ │ ├── Statistics/ │ │ │ │ │ ├── AnswerStatistics.ts │ │ │ │ │ ├── AssessmentStatistics.ts │ │ │ │ │ ├── CourseStatistics.ts │ │ │ │ │ ├── UserStatistics.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── Stories.ts │ │ │ │ ├── Survey/ │ │ │ │ │ ├── Base.js │ │ │ │ │ ├── Questions.js │ │ │ │ │ ├── Responses.js │ │ │ │ │ ├── Sections.js │ │ │ │ │ ├── Surveys.js │ │ │ │ │ └── index.js │ │ │ │ ├── UserEmailSubscriptions.js │ │ │ │ ├── UserInvitations.ts │ │ │ │ ├── UserNotifications.ts │ │ │ │ ├── Users.ts │ │ │ │ ├── Video/ │ │ │ │ │ ├── Base.js │ │ │ │ │ ├── Sessions.js │ │ │ │ │ ├── Submissions.ts │ │ │ │ │ ├── Topics.js │ │ │ │ │ ├── Videos.ts │ │ │ │ │ └── index.js │ │ │ │ ├── VideoSubmissions.ts │ │ │ │ └── index.js │ │ │ ├── index.ts │ │ │ ├── system/ │ │ │ │ ├── Admin.ts │ │ │ │ ├── Base.ts │ │ │ │ ├── InstanceAdmin.ts │ │ │ │ └── index.js │ │ │ └── types.ts │ │ ├── assets/ │ │ │ └── templates/ │ │ │ └── course-user-invitation-template.csv │ │ ├── bundles/ │ │ │ ├── announcements/ │ │ │ │ ├── GlobalAnnouncementIndex.tsx │ │ │ │ ├── operations.ts │ │ │ │ ├── selectors.ts │ │ │ │ ├── store.ts │ │ │ │ └── types.ts │ │ │ ├── authentication/ │ │ │ │ └── pages/ │ │ │ │ └── AuthenticationRedirection/ │ │ │ │ └── index.tsx │ │ │ ├── common/ │ │ │ │ ├── DashboardPage.tsx │ │ │ │ ├── ErrorPage.tsx │ │ │ │ ├── LandingPage.tsx │ │ │ │ ├── PrivacyPolicyPage/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── privacy-policy.md │ │ │ │ ├── TermsOfServicePage/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── terms-of-service.md │ │ │ │ ├── components/ │ │ │ │ │ └── NewCourseButton.tsx │ │ │ │ └── store.ts │ │ │ ├── course/ │ │ │ │ ├── achievement/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ ├── AchievementManagementButtons.tsx │ │ │ │ │ │ │ └── AwardButton.tsx │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ └── AchievementForm.tsx │ │ │ │ │ │ ├── misc/ │ │ │ │ │ │ │ └── AchievementReordering.tsx │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ └── AchievementTable.tsx │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── AchievementAward/ │ │ │ │ │ │ │ ├── AchievementAwardManager.tsx │ │ │ │ │ │ │ ├── AchievementAwardSummary.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── AchievementEdit/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── AchievementNew/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── AchievementShow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── AchievementsIndex/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── admin/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ └── SettingsNavigation.tsx │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── AnnouncementsSettings/ │ │ │ │ │ │ │ ├── AnnouncementsSettingsForm.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── AssessmentSettings/ │ │ │ │ │ │ │ ├── AssessmentCategoriesManager/ │ │ │ │ │ │ │ │ ├── Category.tsx │ │ │ │ │ │ │ │ ├── MoveAssessmentsMenu.tsx │ │ │ │ │ │ │ │ ├── MoveTabsMenu.tsx │ │ │ │ │ │ │ │ ├── Tab.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ │ ├── AssessmentSettingsContext.ts │ │ │ │ │ │ │ ├── AssessmentSettingsForm.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── CodaveriSettings/ │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── AssessmentCategory.tsx │ │ │ │ │ │ │ │ ├── AssessmentList.tsx │ │ │ │ │ │ │ │ ├── AssessmentListItem.tsx │ │ │ │ │ │ │ │ ├── AssessmentProgrammingQnList.tsx │ │ │ │ │ │ │ │ ├── AssessmentTab.tsx │ │ │ │ │ │ │ │ ├── CodaveriSettingsChip.tsx │ │ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ │ │ ├── CodaveriEvaluatorToggleButton.tsx │ │ │ │ │ │ │ │ │ ├── CodaveriToggleButtons.tsx │ │ │ │ │ │ │ │ │ ├── ExpandAllSwitch.tsx │ │ │ │ │ │ │ │ │ └── LiveFeedbackToggleButton.tsx │ │ │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ │ │ └── CodaveriSettingsForm.tsx │ │ │ │ │ │ │ │ └── lists/ │ │ │ │ │ │ │ │ └── CollapsibleList.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── CommentsSettings/ │ │ │ │ │ │ │ ├── CommentsSettingsForm.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── ComponentSettings/ │ │ │ │ │ │ │ ├── ComponentSettingsForm.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── CourseSettings/ │ │ │ │ │ │ │ ├── CourseSettingsForm.tsx │ │ │ │ │ │ │ ├── DeleteCoursePrompt.tsx │ │ │ │ │ │ │ ├── OffsetTimesPrompt.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ ├── translations.ts │ │ │ │ │ │ │ └── validationSchema.ts │ │ │ │ │ │ ├── ForumsSettings/ │ │ │ │ │ │ │ ├── ForumsSettingsForm.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── LeaderboardSettings/ │ │ │ │ │ │ │ ├── LeaderboardSettingsForm.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── LessonPlanSettings/ │ │ │ │ │ │ │ ├── MilestoneGroupSettings.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ │ ├── index.jsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.intl.js │ │ │ │ │ │ ├── MaterialsSettings/ │ │ │ │ │ │ │ ├── MaterialsSettingsForm.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── NotificationSettings/ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ │ ├── index.jsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.intl.js │ │ │ │ │ │ ├── RagWiseSettings/ │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── CourseTab.tsx │ │ │ │ │ │ │ │ ├── FolderTab.tsx │ │ │ │ │ │ │ │ ├── ForumItem.tsx │ │ │ │ │ │ │ │ ├── ForumList.tsx │ │ │ │ │ │ │ │ ├── MaterialItem.tsx │ │ │ │ │ │ │ │ ├── MaterialList.tsx │ │ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ │ │ ├── ExpandAllSwitch.tsx │ │ │ │ │ │ │ │ │ ├── ForumKnowledgeBaseSwitch.tsx │ │ │ │ │ │ │ │ │ └── MaterialKnowledgeBaseSwitch.tsx │ │ │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ │ │ └── RagWiseSettingsForm.tsx │ │ │ │ │ │ │ │ └── lists/ │ │ │ │ │ │ │ │ └── CollapsibleList.tsx │ │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── ScholaisticSettings/ │ │ │ │ │ │ │ ├── PingResultAlert.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── loader.ts │ │ │ │ │ │ │ └── operations.ts │ │ │ │ │ │ ├── SidebarSettings/ │ │ │ │ │ │ │ ├── SidebarSettingsForm.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ ├── StoriesSettings/ │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ └── Introduction.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── operations.ts │ │ │ │ │ │ └── VideosSettings/ │ │ │ │ │ │ ├── VideosSettingsForm.tsx │ │ │ │ │ │ ├── VideosTabsManager/ │ │ │ │ │ │ │ ├── Tab.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ └── translations.ts │ │ │ │ │ ├── reducers/ │ │ │ │ │ │ ├── codaveriSettings.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── lessonPlanSettings.ts │ │ │ │ │ │ ├── notificationSettings.ts │ │ │ │ │ │ └── ragWiseSettings.ts │ │ │ │ │ └── translations.ts │ │ │ │ ├── announcements/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ └── NewAnnouncementButton.tsx │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ └── AnnouncementForm.tsx │ │ │ │ │ │ └── misc/ │ │ │ │ │ │ ├── AnnouncementCard.tsx │ │ │ │ │ │ └── AnnouncementsDisplay.tsx │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── AnnouncementEdit/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── AnnouncementNew/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── AnnouncementsIndex/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── assessment/ │ │ │ │ │ ├── attemptLoader.ts │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AssessmentForm/ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ ├── translations.ts │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ └── useFormValidation.tsx │ │ │ │ │ │ ├── ConvertMcqMrqButton/ │ │ │ │ │ │ │ ├── ConvertMcqMrqPrompt.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── FileManager/ │ │ │ │ │ │ │ ├── Toolbar.tsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── translations.intl.js │ │ │ │ │ │ ├── Koditsu/ │ │ │ │ │ │ │ ├── KoditsuChip.tsx │ │ │ │ │ │ │ └── KoditsuChipButton.tsx │ │ │ │ │ │ └── monitoring/ │ │ │ │ │ │ ├── BlocksInvalidBrowserFormField.tsx │ │ │ │ │ │ ├── BrowserAuthorizationMethodOptionsFormFields/ │ │ │ │ │ │ │ ├── SebConfigKeyOptionsFormFields.tsx │ │ │ │ │ │ │ ├── UserAgentOptionsFormFields.tsx │ │ │ │ │ │ │ ├── common.ts │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── BrowserAuthorizationOptionsFormFields.tsx │ │ │ │ │ │ ├── EnableMonitoringFormField.tsx │ │ │ │ │ │ ├── MonitoringIntervalsFormFields.tsx │ │ │ │ │ │ ├── MonitoringOptionsFormFields.tsx │ │ │ │ │ │ └── translations.ts │ │ │ │ │ ├── constants.js │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── operations/ │ │ │ │ │ │ ├── assessments.ts │ │ │ │ │ │ ├── history.ts │ │ │ │ │ │ ├── liveFeedback.ts │ │ │ │ │ │ ├── monitoring.ts │ │ │ │ │ │ ├── plagiarism.ts │ │ │ │ │ │ ├── questions.ts │ │ │ │ │ │ └── statistics.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── AssessmentAuthenticate/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── AssessmentBlockedByMonitorPage.tsx │ │ │ │ │ │ ├── AssessmentEdit/ │ │ │ │ │ │ │ ├── AssessmentEditPage.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── AssessmentGenerate/ │ │ │ │ │ │ │ ├── GenerateTabs.tsx │ │ │ │ │ │ │ ├── LockableSection.tsx │ │ │ │ │ │ │ ├── MultipleResponse/ │ │ │ │ │ │ │ │ ├── GenerateMcqMrqConversation.tsx │ │ │ │ │ │ │ │ ├── GenerateMcqMrqExportDialog.tsx │ │ │ │ │ │ │ │ ├── GenerateMcqMrqPrototypeForm.tsx │ │ │ │ │ │ │ │ └── GenerateMcqMrqQuestionPage.tsx │ │ │ │ │ │ │ ├── Programming/ │ │ │ │ │ │ │ │ ├── GenerateProgrammingConversation.tsx │ │ │ │ │ │ │ │ ├── GenerateProgrammingExportDialog.tsx │ │ │ │ │ │ │ │ ├── GenerateProgrammingPrototypeForm.tsx │ │ │ │ │ │ │ │ ├── GenerateProgrammingQuestionPage.tsx │ │ │ │ │ │ │ │ └── TestCasesManager.tsx │ │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── AssessmentMonitoring/ │ │ │ │ │ │ │ ├── PulseGrid.tsx │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── ActiveSessionBlob.tsx │ │ │ │ │ │ │ │ ├── ActivityCenter.tsx │ │ │ │ │ │ │ │ ├── ConnectionStatus.tsx │ │ │ │ │ │ │ │ ├── FilterAutocomplete.tsx │ │ │ │ │ │ │ │ ├── HeartbeatDetailCard.tsx │ │ │ │ │ │ │ │ ├── HeartbeatsTimeline.tsx │ │ │ │ │ │ │ │ ├── HeartbeatsTimelineChart.tsx │ │ │ │ │ │ │ │ ├── SebPayloadDetail.tsx │ │ │ │ │ │ │ │ ├── Session.tsx │ │ │ │ │ │ │ │ ├── SessionBlob.tsx │ │ │ │ │ │ │ │ ├── SessionBlobLegend.tsx │ │ │ │ │ │ │ │ ├── SessionDetailsPopup.tsx │ │ │ │ │ │ │ │ ├── SessionsGrid.tsx │ │ │ │ │ │ │ │ ├── UserAgentDetail.tsx │ │ │ │ │ │ │ │ └── ValidChip.tsx │ │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ │ ├── liveMonitoringChannel.ts │ │ │ │ │ │ │ │ ├── useLiveMonitoringChannel.ts │ │ │ │ │ │ │ │ ├── useMonitoring.ts │ │ │ │ │ │ │ │ └── usePresence.ts │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── AssessmentPlagiarism/ │ │ │ │ │ │ │ ├── AssessmentPlagiarismPage.tsx │ │ │ │ │ │ │ ├── PlagiarismCheckStatus.tsx │ │ │ │ │ │ │ ├── PlagiarismResultsTable.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── selectors.ts │ │ │ │ │ │ ├── AssessmentShow/ │ │ │ │ │ │ │ ├── AssessmentDetails.tsx │ │ │ │ │ │ │ ├── AssessmentShowHeader.tsx │ │ │ │ │ │ │ ├── AssessmentShowPage.tsx │ │ │ │ │ │ │ ├── GenerateQuestionMenu.tsx │ │ │ │ │ │ │ ├── McqWidget.tsx │ │ │ │ │ │ │ ├── NewQuestionMenu.tsx │ │ │ │ │ │ │ ├── Question.tsx │ │ │ │ │ │ │ ├── QuestionsManager.tsx │ │ │ │ │ │ │ ├── UnavailableAlert.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── prompts/ │ │ │ │ │ │ │ ├── DeleteQuestionButtonPrompt.tsx │ │ │ │ │ │ │ └── DuplicationPrompt.tsx │ │ │ │ │ │ ├── AssessmentStatistics/ │ │ │ │ │ │ │ ├── AncestorOptions.tsx │ │ │ │ │ │ │ ├── AncestorStatistics.tsx │ │ │ │ │ │ │ ├── AnswerDisplay/ │ │ │ │ │ │ │ │ └── LastAttempt.tsx │ │ │ │ │ │ │ ├── AssessmentStatisticsPage.tsx │ │ │ │ │ │ │ ├── DuplicationHistoryStatistics.tsx │ │ │ │ │ │ │ ├── GradeDistribution/ │ │ │ │ │ │ │ │ ├── AncestorGradesChart.tsx │ │ │ │ │ │ │ │ ├── GradesChart.tsx │ │ │ │ │ │ │ │ └── MainGradesChart.tsx │ │ │ │ │ │ │ ├── LiveFeedbackHistory/ │ │ │ │ │ │ │ │ ├── GetHelpSlider.tsx │ │ │ │ │ │ │ │ ├── LiveFeedbackConversation.tsx │ │ │ │ │ │ │ │ ├── LiveFeedbackDetails.tsx │ │ │ │ │ │ │ │ ├── LiveFeedbackFiles.tsx │ │ │ │ │ │ │ │ ├── LiveFeedbackHistoryTimelineView.tsx │ │ │ │ │ │ │ │ ├── LiveFeedbackMessageHistory.tsx │ │ │ │ │ │ │ │ ├── LiveFeedbackMessageOptionHistory.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── LiveFeedbackStatistics.tsx │ │ │ │ │ │ │ ├── LiveFeedbackStatisticsTable.tsx │ │ │ │ │ │ │ ├── StatisticsCharts.tsx │ │ │ │ │ │ │ ├── StudentAttemptCountTable.tsx │ │ │ │ │ │ │ ├── StudentGradesPerQuestionTable.tsx │ │ │ │ │ │ │ ├── SubmissionStatus/ │ │ │ │ │ │ │ │ ├── AncestorSubmissionChart.tsx │ │ │ │ │ │ │ │ ├── MainSubmissionChart.tsx │ │ │ │ │ │ │ │ └── SubmissionStatusChart.tsx │ │ │ │ │ │ │ ├── SubmissionTimeAndGradeStatistics/ │ │ │ │ │ │ │ │ ├── AncestorSubmissionTimeAndGradeStatistics.tsx │ │ │ │ │ │ │ │ ├── MainSubmissionTimeAndGradeStatistics.tsx │ │ │ │ │ │ │ │ └── SubmissionTimeAndGradeChart.tsx │ │ │ │ │ │ │ ├── classNameUtils.ts │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ └── LiveFeedbackMetricsSelector.tsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ │ ├── translations.ts │ │ │ │ │ │ │ └── utils.js │ │ │ │ │ │ └── AssessmentsIndex/ │ │ │ │ │ │ ├── ActionButtons.tsx │ │ │ │ │ │ ├── AssessmentsTable.tsx │ │ │ │ │ │ ├── NewAssessmentFormButton.jsx │ │ │ │ │ │ ├── StatusBadges.tsx │ │ │ │ │ │ ├── UnavailableMessage.tsx │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── question/ │ │ │ │ │ │ ├── commons/ │ │ │ │ │ │ │ ├── useDirty.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── AIGradingPlaygroundAlert.tsx │ │ │ │ │ │ │ ├── CommonQuestionFields.tsx │ │ │ │ │ │ │ ├── QuestionFormOutlet.tsx │ │ │ │ │ │ │ └── SkillsAutocomplete.tsx │ │ │ │ │ │ ├── forum-post-responses/ │ │ │ │ │ │ │ ├── EditForumPostResponsePage.tsx │ │ │ │ │ │ │ ├── NewForumPostResponsePage.tsx │ │ │ │ │ │ │ ├── commons/ │ │ │ │ │ │ │ │ └── validations.ts │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ └── ForumPostResponseForm.tsx │ │ │ │ │ │ │ └── operation.ts │ │ │ │ │ │ ├── multiple-responses/ │ │ │ │ │ │ │ ├── EditMcqMrqPage.tsx │ │ │ │ │ │ │ ├── NewMcqMrqPage.tsx │ │ │ │ │ │ │ ├── commons/ │ │ │ │ │ │ │ │ ├── translationAdapter.tsx │ │ │ │ │ │ │ │ └── validations.ts │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── AdaptedForm.tsx │ │ │ │ │ │ │ │ ├── ConvertMcqMrqIllustration/ │ │ │ │ │ │ │ │ │ ├── McqIllustration.tsx │ │ │ │ │ │ │ │ │ ├── MrqIllustration.tsx │ │ │ │ │ │ │ │ │ ├── OptionSkeleton.tsx │ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ │ ├── McqMrqForm.tsx │ │ │ │ │ │ │ │ ├── Option.tsx │ │ │ │ │ │ │ │ └── OptionsManager.tsx │ │ │ │ │ │ │ └── operations.ts │ │ │ │ │ │ ├── programming/ │ │ │ │ │ │ │ ├── EditProgrammingQuestionPage.tsx │ │ │ │ │ │ │ ├── NewProgrammingQuestionPage.tsx │ │ │ │ │ │ │ ├── ProgrammingForm.tsx │ │ │ │ │ │ │ ├── commons/ │ │ │ │ │ │ │ │ ├── builder.ts │ │ │ │ │ │ │ │ └── validation.ts │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── ReorderableTestCasesManager.tsx │ │ │ │ │ │ │ │ ├── common/ │ │ │ │ │ │ │ │ │ ├── ControlledEditor.tsx │ │ │ │ │ │ │ │ │ ├── DataFileRow.tsx │ │ │ │ │ │ │ │ │ ├── DataFilesAccordion.tsx │ │ │ │ │ │ │ │ │ ├── DataFilesManager.tsx │ │ │ │ │ │ │ │ │ ├── EditorAccordion.tsx │ │ │ │ │ │ │ │ │ ├── ExpressionField.tsx │ │ │ │ │ │ │ │ │ ├── ImportResult.tsx │ │ │ │ │ │ │ │ │ ├── InstalledDependenciesPrompt.tsx │ │ │ │ │ │ │ │ │ ├── InstalledDependenciesTable.tsx │ │ │ │ │ │ │ │ │ ├── PackageInfo.tsx │ │ │ │ │ │ │ │ │ ├── PackageUploader.tsx │ │ │ │ │ │ │ │ │ ├── ReorderableJavaTestCase.tsx │ │ │ │ │ │ │ │ │ ├── ReorderableTestCase.tsx │ │ │ │ │ │ │ │ │ ├── ReorderableTestCases.tsx │ │ │ │ │ │ │ │ │ ├── StaticTestCase.tsx │ │ │ │ │ │ │ │ │ ├── StaticTestCases.tsx │ │ │ │ │ │ │ │ │ ├── StaticTestCasesTable.tsx │ │ │ │ │ │ │ │ │ ├── TestCaseCell.tsx │ │ │ │ │ │ │ │ │ └── TestCaseRow.tsx │ │ │ │ │ │ │ │ ├── package/ │ │ │ │ │ │ │ │ │ ├── BasicPackageEditor.tsx │ │ │ │ │ │ │ │ │ ├── CppPackageEditor.tsx │ │ │ │ │ │ │ │ │ ├── CsharpPackageEditor.tsx │ │ │ │ │ │ │ │ │ ├── GoPackageEditor.tsx │ │ │ │ │ │ │ │ │ ├── JavaPackageEditor.tsx │ │ │ │ │ │ │ │ │ ├── JavascriptPackageEditor.tsx │ │ │ │ │ │ │ │ │ ├── PackageDetails.tsx │ │ │ │ │ │ │ │ │ ├── PackageEditor.tsx │ │ │ │ │ │ │ │ │ ├── PolyglotEditor.tsx │ │ │ │ │ │ │ │ │ ├── PythonPackageEditor.tsx │ │ │ │ │ │ │ │ │ ├── RPackageEditor.tsx │ │ │ │ │ │ │ │ │ ├── RustPackageEditor.tsx │ │ │ │ │ │ │ │ │ └── TypescriptPackageEditor.tsx │ │ │ │ │ │ │ │ └── sections/ │ │ │ │ │ │ │ │ ├── BuildLog.tsx │ │ │ │ │ │ │ │ ├── EvaluatorFields.tsx │ │ │ │ │ │ │ │ ├── FeedbackFields.tsx │ │ │ │ │ │ │ │ ├── LanguageFields.tsx │ │ │ │ │ │ │ │ ├── PackageFields.tsx │ │ │ │ │ │ │ │ ├── QuestionFields.tsx │ │ │ │ │ │ │ │ └── SubmitWarningDialog.tsx │ │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ │ ├── ProgrammingFormDataContext.tsx │ │ │ │ │ │ │ │ └── useLanguageMode.tsx │ │ │ │ │ │ │ └── operations.ts │ │ │ │ │ │ ├── reducers/ │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ └── rubrics.ts │ │ │ │ │ │ ├── rubric-based-responses/ │ │ │ │ │ │ │ ├── EditRubricBasedResponsePage.tsx │ │ │ │ │ │ │ ├── NewRubricBasedResponsePage.tsx │ │ │ │ │ │ │ ├── commons/ │ │ │ │ │ │ │ │ └── validation.ts │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── AIGradingFields.tsx │ │ │ │ │ │ │ │ ├── CategoryManager.tsx │ │ │ │ │ │ │ │ ├── QuestionFields.tsx │ │ │ │ │ │ │ │ └── RubricBasedResponseForm.tsx │ │ │ │ │ │ │ ├── hooks/ │ │ │ │ │ │ │ │ └── RubricBasedResponseFormDataContext.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── rubric-playground/ │ │ │ │ │ │ │ ├── AddAnswersPrompt.tsx │ │ │ │ │ │ │ ├── AnswerEvaluationsTable/ │ │ │ │ │ │ │ │ ├── CategoryGradeCell.tsx │ │ │ │ │ │ │ │ ├── PopoverContentCell.tsx │ │ │ │ │ │ │ │ ├── TotalGradeCell.tsx │ │ │ │ │ │ │ │ ├── UnevaluatedCell.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ │ ├── AnswerEvaluationsTableHeader.tsx │ │ │ │ │ │ │ ├── RubricEditForm/ │ │ │ │ │ │ │ │ ├── PlaygroundCategoryManager.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── RubricHeader/ │ │ │ │ │ │ │ │ ├── HeaderButton.tsx │ │ │ │ │ │ │ │ ├── VersionSlider.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── RubricPlaygroundPage.tsx │ │ │ │ │ │ │ ├── operations/ │ │ │ │ │ │ │ │ ├── answers.ts │ │ │ │ │ │ │ │ ├── mockAnswers.ts │ │ │ │ │ │ │ │ ├── rowEvaluation.ts │ │ │ │ │ │ │ │ └── rubric.ts │ │ │ │ │ │ │ ├── translations.ts │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ ├── scribing/ │ │ │ │ │ │ │ ├── ScribingQuestion.tsx │ │ │ │ │ │ │ ├── ScribingQuestionForm/ │ │ │ │ │ │ │ │ ├── ScribingQuestionForm.scss │ │ │ │ │ │ │ │ ├── index.jsx │ │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ ├── index.test.tsx │ │ │ │ │ │ │ │ └── responses.test.ts │ │ │ │ │ │ │ ├── constants.js │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ ├── propTypes.js │ │ │ │ │ │ │ ├── store.ts │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ └── utils.js │ │ │ │ │ │ ├── selectors/ │ │ │ │ │ │ │ └── rubrics.ts │ │ │ │ │ │ ├── text-responses/ │ │ │ │ │ │ │ ├── EditTextResponsePage.tsx │ │ │ │ │ │ │ ├── NewTextResponsePage.tsx │ │ │ │ │ │ │ ├── commons/ │ │ │ │ │ │ │ │ └── validations.ts │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── FileUploadManager.tsx │ │ │ │ │ │ │ │ ├── Solution.tsx │ │ │ │ │ │ │ │ ├── SolutionsManager.tsx │ │ │ │ │ │ │ │ └── TextResponseForm.tsx │ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ └── voice-responses/ │ │ │ │ │ │ ├── EditVoicePage.tsx │ │ │ │ │ │ ├── NewVoicePage.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ └── VoiceForm.tsx │ │ │ │ │ │ └── operations.ts │ │ │ │ │ ├── reducers/ │ │ │ │ │ │ ├── editPage.js │ │ │ │ │ │ ├── formDialog.js │ │ │ │ │ │ ├── generation.ts │ │ │ │ │ │ ├── liveFeedback.ts │ │ │ │ │ │ ├── monitoring.ts │ │ │ │ │ │ ├── plagiarism.ts │ │ │ │ │ │ └── statistics.ts │ │ │ │ │ ├── sessions/ │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ └── pages/ │ │ │ │ │ │ └── AssessmentSessionNew/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── skills/ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ │ └── SkillManagementButtons.tsx │ │ │ │ │ │ │ ├── dialogs/ │ │ │ │ │ │ │ │ └── SkillDialog.tsx │ │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ │ └── SkillForm.tsx │ │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ │ └── SkillsTable.tsx │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ ├── pages/ │ │ │ │ │ │ │ └── SkillsIndex/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ ├── store.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── submission/ │ │ │ │ │ │ ├── actions/ │ │ │ │ │ │ │ ├── annotations.js │ │ │ │ │ │ │ ├── answers/ │ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ │ └── scribing.test.ts │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ ├── programming.js │ │ │ │ │ │ │ │ ├── scribing.ts │ │ │ │ │ │ │ │ ├── textResponse.js │ │ │ │ │ │ │ │ └── voiceResponse.js │ │ │ │ │ │ │ ├── comments.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── live_feedback.ts │ │ │ │ │ │ │ ├── logs.ts │ │ │ │ │ │ │ ├── submissions.js │ │ │ │ │ │ │ └── utils.js │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── AllAttempts/ │ │ │ │ │ │ │ │ ├── AllAttemptsQuestion.tsx │ │ │ │ │ │ │ │ ├── AllAttemptsSequenceView.tsx │ │ │ │ │ │ │ │ ├── AllAttemptsTimelineView.tsx │ │ │ │ │ │ │ │ ├── Comment.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── AnswerDetails/ │ │ │ │ │ │ │ │ ├── AnswerDetails.tsx │ │ │ │ │ │ │ │ ├── AttachmentDetails.tsx │ │ │ │ │ │ │ │ ├── FileUploadDetails.tsx │ │ │ │ │ │ │ │ ├── ForumPostResponseComponent/ │ │ │ │ │ │ │ │ │ ├── ParentPostPack.tsx │ │ │ │ │ │ │ │ │ ├── PostContent.tsx │ │ │ │ │ │ │ │ │ └── PostPack.tsx │ │ │ │ │ │ │ │ ├── ForumPostResponseDetails.tsx │ │ │ │ │ │ │ │ ├── MultipleChoiceDetails.tsx │ │ │ │ │ │ │ │ ├── MultipleResponseDetails.tsx │ │ │ │ │ │ │ │ ├── ProgrammingAnswerDetails.tsx │ │ │ │ │ │ │ │ ├── ProgrammingComponent/ │ │ │ │ │ │ │ │ │ ├── CodaveriFeedbackStatus.tsx │ │ │ │ │ │ │ │ │ ├── FileContent.tsx │ │ │ │ │ │ │ │ │ ├── TestCaseRow.tsx │ │ │ │ │ │ │ │ │ └── TestCases.tsx │ │ │ │ │ │ │ │ ├── RubricBasedResponseDetails.tsx │ │ │ │ │ │ │ │ └── TextResponseDetails.tsx │ │ │ │ │ │ │ ├── DropzoneErrorComponent.tsx │ │ │ │ │ │ │ ├── Editor.jsx │ │ │ │ │ │ │ ├── EvaluatorErrorPanel.tsx │ │ │ │ │ │ │ ├── FileInput.jsx │ │ │ │ │ │ │ ├── GetHelpChatPage/ │ │ │ │ │ │ │ │ ├── ChatInputArea.tsx │ │ │ │ │ │ │ │ ├── ChipButton.tsx │ │ │ │ │ │ │ │ ├── ConversationArea.tsx │ │ │ │ │ │ │ │ ├── Header.tsx │ │ │ │ │ │ │ │ ├── SuggestionChips.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── utils.ts │ │ │ │ │ │ │ ├── MarkdownText.tsx │ │ │ │ │ │ │ ├── ProgressPanel.tsx │ │ │ │ │ │ │ ├── ReadOnlyEditor/ │ │ │ │ │ │ │ │ ├── AddCommentIcon.jsx │ │ │ │ │ │ │ │ ├── Checkbox.jsx │ │ │ │ │ │ │ │ ├── NarrowEditor.jsx │ │ │ │ │ │ │ │ ├── WideComments.jsx │ │ │ │ │ │ │ │ ├── WideEditor.jsx │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ ├── ScribingView/ │ │ │ │ │ │ │ │ ├── LayersComponent.tsx │ │ │ │ │ │ │ │ ├── ScribingCanvas.tsx │ │ │ │ │ │ │ │ ├── ScribingToolbar.tsx │ │ │ │ │ │ │ │ ├── ScribingView.scss │ │ │ │ │ │ │ │ ├── ToolDropdown.jsx │ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ │ ├── ScribingToolbar.test.tsx │ │ │ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ │ │ │ ├── fields/ │ │ │ │ │ │ │ │ │ ├── ColorPickerField.jsx │ │ │ │ │ │ │ │ │ ├── FontFamilyField.jsx │ │ │ │ │ │ │ │ │ ├── FontSizeField.jsx │ │ │ │ │ │ │ │ │ ├── LineStyleField.jsx │ │ │ │ │ │ │ │ │ ├── LineThicknessField.jsx │ │ │ │ │ │ │ │ │ ├── ShapeField.tsx │ │ │ │ │ │ │ │ │ └── __test__/ │ │ │ │ │ │ │ │ │ └── ColorPickerField.test.js │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── popovers/ │ │ │ │ │ │ │ │ ├── DrawPopover.jsx │ │ │ │ │ │ │ │ ├── LinePopover.jsx │ │ │ │ │ │ │ │ ├── ShapePopover.jsx │ │ │ │ │ │ │ │ └── TypePopover.jsx │ │ │ │ │ │ │ ├── SubmissionWorkflowState.tsx │ │ │ │ │ │ │ ├── TextResponseSolutions.jsx │ │ │ │ │ │ │ ├── WarningDialog.tsx │ │ │ │ │ │ │ ├── answers/ │ │ │ │ │ │ │ │ ├── Answer.tsx │ │ │ │ │ │ │ │ ├── AnswerHeader.tsx │ │ │ │ │ │ │ │ ├── AnswerNotImplemented.tsx │ │ │ │ │ │ │ │ ├── FileUpload/ │ │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ │ ├── ForumPostResponse/ │ │ │ │ │ │ │ │ │ ├── CardTitle.jsx │ │ │ │ │ │ │ │ │ ├── Error.jsx │ │ │ │ │ │ │ │ │ ├── ForumCard.jsx │ │ │ │ │ │ │ │ │ ├── ForumPost.jsx │ │ │ │ │ │ │ │ │ ├── ForumPostOption.jsx │ │ │ │ │ │ │ │ │ ├── ForumPostSelect.jsx │ │ │ │ │ │ │ │ │ ├── ForumPostSelectDialog.jsx │ │ │ │ │ │ │ │ │ ├── Labels.jsx │ │ │ │ │ │ │ │ │ ├── ParentPost.jsx │ │ │ │ │ │ │ │ │ ├── SelectedPostCard.jsx │ │ │ │ │ │ │ │ │ ├── TopicCard.jsx │ │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ │ ├── MultipleChoice/ │ │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ │ ├── MultipleResponse/ │ │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ │ ├── Programming/ │ │ │ │ │ │ │ │ │ ├── ProgrammingFile.tsx │ │ │ │ │ │ │ │ │ ├── ProgrammingFileDownloadChip.tsx │ │ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ │ │ └── ProgrammingFile.test.tsx │ │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ │ ├── RubricBasedResponse/ │ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ │ ├── TextResponse/ │ │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ │ ├── adapters/ │ │ │ │ │ │ │ │ │ ├── FileUploadAdapter.tsx │ │ │ │ │ │ │ │ │ ├── ForumPostResponseAdapter.tsx │ │ │ │ │ │ │ │ │ ├── MultipleChoiceAdapter.tsx │ │ │ │ │ │ │ │ │ ├── MultipleResponseAdapter.tsx │ │ │ │ │ │ │ │ │ ├── ProgrammingAdapter.tsx │ │ │ │ │ │ │ │ │ ├── RubricBasedResponseAdapter.tsx │ │ │ │ │ │ │ │ │ ├── ScribingAdapter.tsx │ │ │ │ │ │ │ │ │ ├── TextResponseAdapter.tsx │ │ │ │ │ │ │ │ │ └── VoiceResponseAdapter.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ │ │ └── utils.tsx │ │ │ │ │ │ │ └── comment/ │ │ │ │ │ │ │ ├── CodaveriCommentCard.jsx │ │ │ │ │ │ │ ├── CommentCard.jsx │ │ │ │ │ │ │ └── CommentField.jsx │ │ │ │ │ │ ├── constants.ts │ │ │ │ │ │ ├── containers/ │ │ │ │ │ │ │ ├── Annotations.jsx │ │ │ │ │ │ │ ├── CodaveriFeedbackStatus.jsx │ │ │ │ │ │ │ ├── Comments.jsx │ │ │ │ │ │ │ ├── GradingPanel.jsx │ │ │ │ │ │ │ ├── PostPreview.tsx │ │ │ │ │ │ │ ├── ProgrammingImport/ │ │ │ │ │ │ │ │ ├── ImportedFileView.jsx │ │ │ │ │ │ │ │ ├── ProgrammingImportEditor.jsx │ │ │ │ │ │ │ │ └── ProgrammingImportHistoryView.jsx │ │ │ │ │ │ │ ├── QuestionGrade.tsx │ │ │ │ │ │ │ ├── ReadOnlyEditor.jsx │ │ │ │ │ │ │ ├── RubricExplanation.tsx │ │ │ │ │ │ │ ├── RubricGrade.tsx │ │ │ │ │ │ │ ├── RubricPanel.tsx │ │ │ │ │ │ │ ├── RubricPanelRow.tsx │ │ │ │ │ │ │ ├── ScribingView.jsx │ │ │ │ │ │ │ ├── TestCaseView/ │ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ │ └── index.test.js │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ ├── UploadedFileView.jsx │ │ │ │ │ │ │ └── VoiceResponseAnswer.jsx │ │ │ │ │ │ ├── localStorage/ │ │ │ │ │ │ │ └── liveFeedbackChat/ │ │ │ │ │ │ │ └── operations.ts │ │ │ │ │ │ ├── pages/ │ │ │ │ │ │ │ ├── LogsIndex/ │ │ │ │ │ │ │ │ ├── LogsContent.tsx │ │ │ │ │ │ │ │ ├── LogsHead.tsx │ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ │ └── translations.ts │ │ │ │ │ │ │ ├── SubmissionEditIndex/ │ │ │ │ │ │ │ │ ├── BlockedSubmission.tsx │ │ │ │ │ │ │ │ ├── ErrorHelper.tsx │ │ │ │ │ │ │ │ ├── SubmissionEmptyForm.tsx │ │ │ │ │ │ │ │ ├── SubmissionForm.tsx │ │ │ │ │ │ │ │ ├── TimeLimitBanner.tsx │ │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ │ ├── ActionButtonsRow.tsx │ │ │ │ │ │ │ │ │ ├── AutogradingErrorPanel.tsx │ │ │ │ │ │ │ │ │ ├── ErrorMessages.tsx │ │ │ │ │ │ │ │ │ ├── ExplanationPanel.tsx │ │ │ │ │ │ │ │ │ ├── QuestionContent.tsx │ │ │ │ │ │ │ │ │ ├── SinglePageQuestions.tsx │ │ │ │ │ │ │ │ │ ├── TabbedViewQuestions.tsx │ │ │ │ │ │ │ │ │ └── button/ │ │ │ │ │ │ │ │ │ ├── AutogradeSubmissionButton.tsx │ │ │ │ │ │ │ │ │ ├── ContinueButton.tsx │ │ │ │ │ │ │ │ │ ├── FinaliseButton.tsx │ │ │ │ │ │ │ │ │ ├── LiveFeedbackButton.tsx │ │ │ │ │ │ │ │ │ ├── MarkButton.tsx │ │ │ │ │ │ │ │ │ ├── PublishButton.tsx │ │ │ │ │ │ │ │ │ ├── ReevaluateButton.tsx │ │ │ │ │ │ │ │ │ ├── ResetAnswerButton.tsx │ │ │ │ │ │ │ │ │ ├── SaveDraftButton.tsx │ │ │ │ │ │ │ │ │ ├── SaveGradeButton.tsx │ │ │ │ │ │ │ │ │ ├── StepperButton.tsx │ │ │ │ │ │ │ │ │ ├── SubmitButton.tsx │ │ │ │ │ │ │ │ │ ├── SubmitEmptyFormButton.tsx │ │ │ │ │ │ │ │ │ ├── UnmarkButton.tsx │ │ │ │ │ │ │ │ │ └── UnsubmitButton.tsx │ │ │ │ │ │ │ │ ├── index.jsx │ │ │ │ │ │ │ │ ├── useErrorTranslation.ts │ │ │ │ │ │ │ │ └── validations/ │ │ │ │ │ │ │ │ ├── AllValidation.tsx │ │ │ │ │ │ │ │ ├── AttachmentValidation.tsx │ │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ │ └── SubmissionsIndex/ │ │ │ │ │ │ │ ├── SubmissionsTable.jsx │ │ │ │ │ │ │ ├── SubmissionsTableRow.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── submissionsTable.test.jsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── translations.js │ │ │ │ │ │ ├── propTypes.js │ │ │ │ │ │ ├── reducers/ │ │ │ │ │ │ │ ├── annotations.js │ │ │ │ │ │ │ ├── answerFlags/ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── answers.js │ │ │ │ │ │ │ ├── assessment.js │ │ │ │ │ │ │ ├── attachments.js │ │ │ │ │ │ │ ├── codaveriFeedbackStatus.js │ │ │ │ │ │ │ ├── commentForms.js │ │ │ │ │ │ │ ├── explanations.js │ │ │ │ │ │ │ ├── grading/ │ │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ │ ├── history/ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── liveFeedbackChats/ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── posts.js │ │ │ │ │ │ │ ├── questions.js │ │ │ │ │ │ │ ├── questionsFlags.js │ │ │ │ │ │ │ ├── recorder.js │ │ │ │ │ │ │ ├── scribing/ │ │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ │ ├── submission.js │ │ │ │ │ │ │ ├── submissionFlags.js │ │ │ │ │ │ │ ├── submissions.js │ │ │ │ │ │ │ ├── testCases.js │ │ │ │ │ │ │ └── topics.js │ │ │ │ │ │ ├── selectors/ │ │ │ │ │ │ │ ├── answerFlags.ts │ │ │ │ │ │ │ ├── answers.ts │ │ │ │ │ │ │ ├── assessments.ts │ │ │ │ │ │ │ ├── attachments.ts │ │ │ │ │ │ │ ├── codaveriFeedbackStatus.ts │ │ │ │ │ │ │ ├── comments.ts │ │ │ │ │ │ │ ├── explanations.ts │ │ │ │ │ │ │ ├── grading.ts │ │ │ │ │ │ │ ├── history.ts │ │ │ │ │ │ │ ├── liveFeedbackChats.ts │ │ │ │ │ │ │ ├── questionFlags.ts │ │ │ │ │ │ │ ├── questions.ts │ │ │ │ │ │ │ ├── submissionFlags.ts │ │ │ │ │ │ │ ├── submissions.ts │ │ │ │ │ │ │ └── topics.ts │ │ │ │ │ │ ├── suggestionTranslations.ts │ │ │ │ │ │ ├── translations.ts │ │ │ │ │ │ ├── types.ts │ │ │ │ │ │ └── utils/ │ │ │ │ │ │ ├── answers.ts │ │ │ │ │ │ ├── rubrics.ts │ │ │ │ │ │ └── timer.ts │ │ │ │ │ ├── submissions/ │ │ │ │ │ │ ├── SubmissionsIndex.tsx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ │ └── SubmissionsTableButton.tsx │ │ │ │ │ │ │ ├── misc/ │ │ │ │ │ │ │ │ ├── SubmissionFilter.tsx │ │ │ │ │ │ │ │ └── SubmissionTabs.tsx │ │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ │ └── SubmissionsTable.tsx │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ ├── store.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── translations.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ └── index.test.js │ │ │ │ │ ├── index.js │ │ │ │ │ └── recorderHelper.js │ │ │ │ ├── container/ │ │ │ │ │ ├── Breadcrumbs/ │ │ │ │ │ │ ├── Breadcrumbs.tsx │ │ │ │ │ │ ├── Crumb.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── sliders.tsx │ │ │ │ │ ├── CourseContainer.tsx │ │ │ │ │ ├── CourseLoader.ts │ │ │ │ │ ├── Sidebar/ │ │ │ │ │ │ ├── CourseItem.tsx │ │ │ │ │ │ ├── CourseUserItem.tsx │ │ │ │ │ │ ├── CourseUserProgress.tsx │ │ │ │ │ │ ├── LevelRing.tsx │ │ │ │ │ │ ├── PinSidebarButton.tsx │ │ │ │ │ │ ├── Sidebar.tsx │ │ │ │ │ │ ├── SidebarAccordion.tsx │ │ │ │ │ │ ├── SidebarContainer.tsx │ │ │ │ │ │ ├── SidebarItem.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── unread.ts │ │ │ │ ├── courses/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ ├── TodoAccessButton.tsx │ │ │ │ │ │ │ └── TodoIgnoreButton.tsx │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ ├── CourseInvitationCodeForm.tsx │ │ │ │ │ │ │ └── NewCourseForm.tsx │ │ │ │ │ │ ├── misc/ │ │ │ │ │ │ │ ├── CourseAnnouncements.tsx │ │ │ │ │ │ │ ├── CourseDisplay.tsx │ │ │ │ │ │ │ ├── CourseEnrolOptions.tsx │ │ │ │ │ │ │ ├── CourseInfoBox.tsx │ │ │ │ │ │ │ ├── CourseNotifications.tsx │ │ │ │ │ │ │ ├── CourseSuspendedAlert.tsx │ │ │ │ │ │ │ └── NotificationCard.tsx │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ └── PendingTodosTable.tsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── CourseShow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── CoursesIndex/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── CoursesNew/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── discussion/ │ │ │ │ │ └── topics/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── cards/ │ │ │ │ │ │ │ ├── CodaveriCommentCard.tsx │ │ │ │ │ │ │ ├── CommentCard.tsx │ │ │ │ │ │ │ └── TopicCard.tsx │ │ │ │ │ │ ├── fields/ │ │ │ │ │ │ │ └── CommentField.tsx │ │ │ │ │ │ └── lists/ │ │ │ │ │ │ └── TopicList.tsx │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ └── CommentIndex/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── duplication/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── BulkSelectors.jsx │ │ │ │ │ │ ├── CourseDropdownMenu.jsx │ │ │ │ │ │ ├── IndentedCheckbox.jsx │ │ │ │ │ │ ├── TypeBadge/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ └── UnpublishedIcon.jsx │ │ │ │ │ ├── constants.js │ │ │ │ │ ├── operations.js │ │ │ │ │ ├── pages/ │ │ │ │ │ │ └── Duplication/ │ │ │ │ │ │ ├── DestinationCourseSelector/ │ │ │ │ │ │ │ ├── InstanceDropdown.tsx │ │ │ │ │ │ │ ├── NewCourseForm.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── DuplicateAllButton.jsx │ │ │ │ │ │ ├── DuplicateButton.jsx │ │ │ │ │ │ ├── DuplicateItemsConfirmation/ │ │ │ │ │ │ │ ├── AchievementsListing.jsx │ │ │ │ │ │ │ ├── AssessmentsListing.jsx │ │ │ │ │ │ │ ├── MaterialsListing.jsx │ │ │ │ │ │ │ ├── SurveyListing.jsx │ │ │ │ │ │ │ ├── VideosListing.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── ItemsSelector/ │ │ │ │ │ │ │ ├── AchievementsSelector.jsx │ │ │ │ │ │ │ ├── AssessmentsSelector.jsx │ │ │ │ │ │ │ ├── MaterialsSelector.jsx │ │ │ │ │ │ │ ├── SurveysSelector.jsx │ │ │ │ │ │ │ ├── VideosSelector.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── ItemsSelectorMenu/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ ├── DuplicateButton.test.tsx │ │ │ │ │ │ │ └── ObjectDuplication.test.jsx │ │ │ │ │ │ └── index.jsx │ │ │ │ │ ├── propTypes.js │ │ │ │ │ ├── selectors/ │ │ │ │ │ │ ├── destinationCourse.js │ │ │ │ │ │ └── destinationInstance.ts │ │ │ │ │ ├── store.js │ │ │ │ │ └── utils.js │ │ │ │ ├── enrol-requests/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ └── PendingEnrolRequestsButtons.tsx │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ └── EnrolRequestsTable.tsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ └── UserRequests/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── experience-points/ │ │ │ │ │ ├── ExperiencePointsDetails.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── ExperiencePointsDownload.tsx │ │ │ │ │ │ ├── ExperiencePointsFiltering.tsx │ │ │ │ │ │ ├── ExperiencePointsNumberField.tsx │ │ │ │ │ │ ├── ExperiencePointsReasonField.tsx │ │ │ │ │ │ ├── ExperiencePointsTable.tsx │ │ │ │ │ │ └── ExperiencePointsTableRow.tsx │ │ │ │ │ ├── disbursement/ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ │ ├── DuplicateButton.tsx │ │ │ │ │ │ │ │ └── RemoveAllButton.tsx │ │ │ │ │ │ │ ├── fields/ │ │ │ │ │ │ │ │ └── PointField.tsx │ │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ │ ├── DisbursementForm.tsx │ │ │ │ │ │ │ │ ├── FilterForm.tsx │ │ │ │ │ │ │ │ └── ForumDisbursementForm.tsx │ │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ │ ├── DisbursementTable.tsx │ │ │ │ │ │ │ ├── ForumDisbursementTable.tsx │ │ │ │ │ │ │ └── ForumPostTable.tsx │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ ├── pages/ │ │ │ │ │ │ │ ├── ForumDisbursement/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── GeneralDisbursement/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ ├── store.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── selectors.ts │ │ │ │ │ └── store.ts │ │ │ │ ├── forum/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ ├── ForumManagementButtons.tsx │ │ │ │ │ │ │ ├── ForumTopicManagementButtons.tsx │ │ │ │ │ │ │ ├── ForumTopicPostEditActionButtons.tsx │ │ │ │ │ │ │ ├── ForumTopicPostManagementButtons.tsx │ │ │ │ │ │ │ ├── GenerateReplyButton.tsx │ │ │ │ │ │ │ ├── HideButton.tsx │ │ │ │ │ │ │ ├── LockButton.tsx │ │ │ │ │ │ │ ├── MarkAllAsReadButton.tsx │ │ │ │ │ │ │ ├── MarkAnswerAndPublishButton.tsx │ │ │ │ │ │ │ ├── MarkAnswerButton.tsx │ │ │ │ │ │ │ ├── NextUnreadButton.tsx │ │ │ │ │ │ │ ├── ReplyButton.tsx │ │ │ │ │ │ │ ├── SubscribeButton.tsx │ │ │ │ │ │ │ └── VotePostButton.tsx │ │ │ │ │ │ ├── cards/ │ │ │ │ │ │ │ ├── PostCard.tsx │ │ │ │ │ │ │ └── ReplyCard.tsx │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ ├── ForumForm.tsx │ │ │ │ │ │ │ ├── ForumTopicForm.tsx │ │ │ │ │ │ │ └── ForumTopicPostForm.tsx │ │ │ │ │ │ ├── misc/ │ │ │ │ │ │ │ └── PostCreatorObject.tsx │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ ├── ForumTable.tsx │ │ │ │ │ │ └── ForumTopicTable.tsx │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── ForumEdit/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ForumNew/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ForumShow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ForumTopicEdit/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ForumTopicNew/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ForumTopicPostNew/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ForumTopicShow/ │ │ │ │ │ │ │ ├── TopicPostTrees.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── ForumsIndex/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── translations.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── group/ │ │ │ │ │ ├── actions/ │ │ │ │ │ │ ├── categories.js │ │ │ │ │ │ ├── general.js │ │ │ │ │ │ ├── groups.js │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── GroupCard.tsx │ │ │ │ │ │ └── GroupRoleChip.tsx │ │ │ │ │ ├── constants.js │ │ │ │ │ ├── forms/ │ │ │ │ │ │ ├── GroupCreationForm.jsx │ │ │ │ │ │ ├── GroupFormDialog.jsx │ │ │ │ │ │ └── NameDescriptionForm.jsx │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── GroupIndex/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── GroupNew/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ └── GroupShow/ │ │ │ │ │ │ ├── CategoryCard.tsx │ │ │ │ │ │ ├── GroupManager/ │ │ │ │ │ │ │ ├── ChangeSummaryTable.jsx │ │ │ │ │ │ │ ├── GroupManager.jsx │ │ │ │ │ │ │ ├── GroupUserManager.jsx │ │ │ │ │ │ │ ├── GroupUserManagerList.jsx │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ ├── GroupTableCard.tsx │ │ │ │ │ │ └── index.jsx │ │ │ │ │ ├── propTypes.js │ │ │ │ │ ├── reducers/ │ │ │ │ │ │ ├── groupsDialog.js │ │ │ │ │ │ ├── groupsFetch.js │ │ │ │ │ │ └── groupsManage.js │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── groups.js │ │ │ │ │ └── sort.js │ │ │ │ ├── helper/ │ │ │ │ │ ├── achievements.ts │ │ │ │ │ └── index.ts │ │ │ │ ├── leaderboard/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ └── LeaderboardTable.tsx │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ └── LeaderboardIndex/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── learning-map/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── ConnectionPoint/ │ │ │ │ │ │ │ ├── ConnectionPoint.scss │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── Gate/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── Node/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── NodeMenu/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── UnlockRateDisplay/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ └── ZoomActionElements/ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ ├── constants.js │ │ │ │ │ ├── containers/ │ │ │ │ │ │ ├── ArrowOverlay/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── Canvas/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── Dashboard/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── GateToNodeArrows/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── LearningMap/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── Levels/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ └── NodeToGateArrows/ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── propTypes.js │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── translations.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── lesson-plan/ │ │ │ │ │ ├── constants.js │ │ │ │ │ ├── containers/ │ │ │ │ │ │ ├── ColumnVisibilityDropdown/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── EventFormDialog/ │ │ │ │ │ │ │ ├── EventForm.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── LessonPlanFilter/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── LessonPlanLayout/ │ │ │ │ │ │ │ ├── EnterEditModeButton.jsx │ │ │ │ │ │ │ ├── NewEventButton.jsx │ │ │ │ │ │ │ ├── NewMilestoneButton.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ ├── NewEventButton.test.jsx │ │ │ │ │ │ │ │ ├── NewMilestoneButton.test.jsx │ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── LessonPlanNav/ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── MilestoneFormDialog/ │ │ │ │ │ │ │ ├── MilestoneForm.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ └── TranslatedItemType.tsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── LessonPlanEdit/ │ │ │ │ │ │ │ ├── ItemRow/ │ │ │ │ │ │ │ │ ├── DateCell.jsx │ │ │ │ │ │ │ │ ├── PublishedCell.jsx │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ ├── MilestoneRow.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ ├── ItemRow.test.jsx │ │ │ │ │ │ │ │ ├── MilestoneRow.test.jsx │ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ └── LessonPlanShow/ │ │ │ │ │ │ ├── LessonPlanGroup.jsx │ │ │ │ │ │ ├── LessonPlanItem/ │ │ │ │ │ │ │ ├── AdminTools.jsx │ │ │ │ │ │ │ ├── Details/ │ │ │ │ │ │ │ │ ├── Chips.jsx │ │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ │ ├── Material.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── AdminTools.test.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── MilestoneAdminTools.jsx │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ ├── LessonPlanShow.test.jsx │ │ │ │ │ │ │ └── MilestoneAdminTools.test.jsx │ │ │ │ │ │ └── index.jsx │ │ │ │ │ ├── reducers/ │ │ │ │ │ │ ├── eventForm.js │ │ │ │ │ │ ├── flags.js │ │ │ │ │ │ ├── lessonPlan.js │ │ │ │ │ │ ├── milestoneForm.js │ │ │ │ │ │ └── utils.js │ │ │ │ │ ├── store.ts │ │ │ │ │ └── translations.ts │ │ │ │ ├── level/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── LevelsTable.tsx │ │ │ │ │ │ └── LevelsTableRow.tsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ └── LevelsIndex/ │ │ │ │ │ │ ├── LevelsManager.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selector.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── material/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ └── MaterialStatusPage.tsx │ │ │ │ │ ├── files/ │ │ │ │ │ │ ├── DownloadingFilePage.tsx │ │ │ │ │ │ └── ErrorRetrievingFilePage.tsx │ │ │ │ │ ├── folders/ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ │ ├── DownloadFolderButton.tsx │ │ │ │ │ │ │ │ ├── KnowledgeBaseSwitch.tsx │ │ │ │ │ │ │ │ ├── NewSubfolderButton.tsx │ │ │ │ │ │ │ │ ├── UploadFilesButton.tsx │ │ │ │ │ │ │ │ └── WorkbinTableButtons.tsx │ │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ │ ├── FolderForm.tsx │ │ │ │ │ │ │ │ ├── MaterialForm.tsx │ │ │ │ │ │ │ │ └── MaterialUploadForm.tsx │ │ │ │ │ │ │ ├── misc/ │ │ │ │ │ │ │ │ ├── MaterialEdit.tsx │ │ │ │ │ │ │ │ ├── MaterialUpload.tsx │ │ │ │ │ │ │ │ └── MultipleFileInput.tsx │ │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ │ ├── TableMaterialRow.tsx │ │ │ │ │ │ │ ├── TableSubfolderRow.tsx │ │ │ │ │ │ │ └── WorkbinTable.tsx │ │ │ │ │ │ ├── handles.ts │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ ├── pages/ │ │ │ │ │ │ │ ├── ErrorRetrievingFolderPage.tsx │ │ │ │ │ │ │ ├── FolderEdit/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── FolderNew/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── FolderShow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── selectors.ts │ │ │ │ │ │ ├── store.ts │ │ │ │ │ │ └── types.ts │ │ │ │ │ └── materialLoader.ts │ │ │ │ ├── plagiarism/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AssessmentLinkDialog.tsx │ │ │ │ │ │ └── AssessmentLinkList.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ └── PlagiarismIndex/ │ │ │ │ │ │ ├── assessments/ │ │ │ │ │ │ │ └── AssessmentsPlagiarismTable.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── reducers/ │ │ │ │ │ │ └── assessments.ts │ │ │ │ │ ├── selectors.ts │ │ │ │ │ └── store.ts │ │ │ │ ├── reference-timelines/ │ │ │ │ │ ├── TimelineDesigner.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── CreateRenameTimelinePrompt.tsx │ │ │ │ │ │ ├── DayCalendar/ │ │ │ │ │ │ │ ├── DayCalendar.tsx │ │ │ │ │ │ │ ├── DayColumn.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── DeleteTimelinePrompt.tsx │ │ │ │ │ │ ├── HorizontallyDraggable.tsx │ │ │ │ │ │ ├── HorizontallyResizable.tsx │ │ │ │ │ │ ├── SeriouslyAnchoredPopup.tsx │ │ │ │ │ │ ├── SubmitIndicator.tsx │ │ │ │ │ │ ├── TimeBar/ │ │ │ │ │ │ │ ├── DurationBar.tsx │ │ │ │ │ │ │ ├── TimeBar.tsx │ │ │ │ │ │ │ ├── TimeBarHandle.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── TimePopup/ │ │ │ │ │ │ │ ├── TimePopup.tsx │ │ │ │ │ │ │ ├── TimePopupForm.tsx │ │ │ │ │ │ │ ├── TimePopupTopBar.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ ├── TimelinesOverview/ │ │ │ │ │ │ │ ├── TimelinesOverview.tsx │ │ │ │ │ │ │ ├── TimelinesOverviewItem.tsx │ │ │ │ │ │ │ └── index.ts │ │ │ │ │ │ └── TimelinesStack/ │ │ │ │ │ │ ├── AssignableTimeline.tsx │ │ │ │ │ │ ├── AssignedTimeline.tsx │ │ │ │ │ │ ├── Timeline.tsx │ │ │ │ │ │ ├── TimelinesStack.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── contexts/ │ │ │ │ │ │ ├── LastSavedContext.tsx │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── translations.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── utils.ts │ │ │ │ │ └── views/ │ │ │ │ │ └── DayView/ │ │ │ │ │ ├── DayView.tsx │ │ │ │ │ ├── ItemsSidebar.tsx │ │ │ │ │ ├── TimelineSidebarItem.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── scholaistic/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── ScholaisticAsyncContainer.tsx │ │ │ │ │ │ ├── ScholaisticErrorPage.tsx │ │ │ │ │ │ └── ScholaisticFramePage.tsx │ │ │ │ │ ├── handles.ts │ │ │ │ │ └── pages/ │ │ │ │ │ ├── ScholaisticAssessmentEdit/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── loader.ts │ │ │ │ │ │ └── operations.ts │ │ │ │ │ ├── ScholaisticAssessmentNew/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── loader.ts │ │ │ │ │ ├── ScholaisticAssessmentSubmissionEdit/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── loader.ts │ │ │ │ │ ├── ScholaisticAssessmentSubmissionsIndex/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── loader.ts │ │ │ │ │ ├── ScholaisticAssessmentView/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── loader.ts │ │ │ │ │ ├── ScholaisticAssessmentsIndex/ │ │ │ │ │ │ ├── ActionButtons.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── loader.ts │ │ │ │ │ ├── ScholaisticAssistantEdit/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── loader.ts │ │ │ │ │ └── ScholaisticAssistantsIndex/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── loader.ts │ │ │ │ ├── statistics/ │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ └── StatisticsIndex/ │ │ │ │ │ │ ├── assessments/ │ │ │ │ │ │ │ ├── AssessmentsScoreSummaryDownload.tsx │ │ │ │ │ │ │ ├── AssessmentsStatistics.tsx │ │ │ │ │ │ │ └── AssessmentsStatisticsTable.tsx │ │ │ │ │ │ ├── course/ │ │ │ │ │ │ │ ├── CourseStatistics.tsx │ │ │ │ │ │ │ ├── StudentPerformanceTable.tsx │ │ │ │ │ │ │ ├── StudentProgressionChart.tsx │ │ │ │ │ │ │ └── utils.js │ │ │ │ │ │ ├── get_help/ │ │ │ │ │ │ │ ├── CourseGetHelpFilter.tsx │ │ │ │ │ │ │ ├── CourseGetHelpStatistics.tsx │ │ │ │ │ │ │ └── CourseGetHelpStatisticsTable.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── staff/ │ │ │ │ │ │ │ ├── StaffStatistics.tsx │ │ │ │ │ │ │ └── StaffStatisticsTable.tsx │ │ │ │ │ │ └── students/ │ │ │ │ │ │ ├── StudentStatisticsTable.tsx │ │ │ │ │ │ └── StudentsStatistics.tsx │ │ │ │ │ ├── types.ts │ │ │ │ │ └── utils/ │ │ │ │ │ ├── parseCourseResponse.js │ │ │ │ │ ├── parseStaffResponse.js │ │ │ │ │ └── parseStudentsResponse.js │ │ │ │ ├── stories/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── CikgoChatsPage.tsx │ │ │ │ │ │ ├── CikgoErrorPage.tsx │ │ │ │ │ │ ├── CikgoFramePage.tsx │ │ │ │ │ │ ├── CikgoSidebarItems.tsx │ │ │ │ │ │ └── LearnRedirect.tsx │ │ │ │ │ └── pages/ │ │ │ │ │ ├── LearnPage.tsx │ │ │ │ │ └── MissionControlPage.tsx │ │ │ │ ├── survey/ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ └── index.test.tsx │ │ │ │ │ ├── actions/ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ └── responses.test.ts │ │ │ │ │ │ ├── questions.js │ │ │ │ │ │ ├── responses.js │ │ │ │ │ │ ├── sections.js │ │ │ │ │ │ └── surveys.js │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── Dialogs.jsx │ │ │ │ │ │ └── OptionsListItem.jsx │ │ │ │ │ ├── constants.js │ │ │ │ │ ├── containers/ │ │ │ │ │ │ ├── QuestionFormDialogue/ │ │ │ │ │ │ │ ├── QuestionForm.jsx │ │ │ │ │ │ │ ├── QuestionFormDeletedOptions.jsx │ │ │ │ │ │ │ ├── QuestionFormOption.jsx │ │ │ │ │ │ │ ├── QuestionFormOptions.jsx │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ └── ImageField.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── RespondButton/ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── ResponseForm/ │ │ │ │ │ │ │ ├── ResponseAnswer.jsx │ │ │ │ │ │ │ ├── ResponseSection.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ │ ├── MultipleChoiceOptionsField.jsx │ │ │ │ │ │ │ │ └── MultipleResponseOptionsField.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── SectionFormDialogue/ │ │ │ │ │ │ │ ├── SectionForm.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── SurveyFormDialogue/ │ │ │ │ │ │ │ ├── SurveyForm.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── SurveyLayout/ │ │ │ │ │ │ │ ├── AdminMenu.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ ├── AdminMenu.test.jsx │ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ └── UnsubmitButton.jsx │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── ResponseEdit/ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── ResponseIndex/ │ │ │ │ │ │ │ ├── RemindButton.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ ├── RemindButton.test.tsx │ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── translations.js │ │ │ │ │ │ ├── ResponseShow/ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── SurveyIndex/ │ │ │ │ │ │ │ ├── NewSurveyButton.jsx │ │ │ │ │ │ │ ├── SurveyBadges.jsx │ │ │ │ │ │ │ ├── SurveysTable.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── NewSurveyButton.test.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── SurveyResults/ │ │ │ │ │ │ │ ├── OptionsQuestionResults.jsx │ │ │ │ │ │ │ ├── ResultsQuestion.jsx │ │ │ │ │ │ │ ├── ResultsSection.jsx │ │ │ │ │ │ │ ├── TextResponseResults.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ ├── ResultsQuestion.test.tsx │ │ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── SurveyShow/ │ │ │ │ │ │ ├── DownloadResponsesButton.jsx │ │ │ │ │ │ ├── NewSectionButton.jsx │ │ │ │ │ │ ├── Section/ │ │ │ │ │ │ │ ├── DeleteSectionButton.jsx │ │ │ │ │ │ │ ├── EditSectionButton.jsx │ │ │ │ │ │ │ ├── MoveDownButton.jsx │ │ │ │ │ │ │ ├── MoveUpButton.jsx │ │ │ │ │ │ │ ├── NewQuestionButton.jsx │ │ │ │ │ │ │ ├── Question.jsx │ │ │ │ │ │ │ ├── QuestionCard.jsx │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ ├── DeleteSectionButton.test.tsx │ │ │ │ │ │ │ │ ├── EditSectionButton.test.jsx │ │ │ │ │ │ │ │ ├── MoveDownButton.test.tsx │ │ │ │ │ │ │ │ ├── MoveUpButton.test.jsx │ │ │ │ │ │ │ │ └── NewQuestionButton.test.jsx │ │ │ │ │ │ │ └── index.jsx │ │ │ │ │ │ ├── SurveyDetails.jsx │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ ├── DownloadResponsesButton.test.tsx │ │ │ │ │ │ │ └── NewSectionButton.test.jsx │ │ │ │ │ │ └── index.jsx │ │ │ │ │ ├── propTypes.js │ │ │ │ │ ├── reducers/ │ │ │ │ │ │ ├── questionForm.js │ │ │ │ │ │ ├── responseForm.js │ │ │ │ │ │ ├── responses.js │ │ │ │ │ │ ├── results.js │ │ │ │ │ │ ├── section.js │ │ │ │ │ │ ├── sectionForm.js │ │ │ │ │ │ ├── survey.js │ │ │ │ │ │ ├── surveyForm.js │ │ │ │ │ │ ├── surveys.js │ │ │ │ │ │ └── surveysFlags.js │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── translations.js │ │ │ │ │ └── utils/ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ └── index.test.js │ │ │ │ │ └── index.js │ │ │ │ ├── translations.ts │ │ │ │ ├── user-email-subscriptions/ │ │ │ │ │ ├── UserEmailSubscriptions.tsx │ │ │ │ │ ├── UserEmailSubscriptionsTable.jsx │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ └── index.test.jsx │ │ │ │ │ ├── constants.js │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── translations.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── user-invitations/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ ├── InvitationActionButtons.tsx │ │ │ │ │ │ │ ├── RegistrationCodeButton.tsx │ │ │ │ │ │ │ ├── ResendAllInvitationsButton.tsx │ │ │ │ │ │ │ └── UploadFileButton.tsx │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ ├── IndividualInvitation.tsx │ │ │ │ │ │ │ ├── IndividualInvitations.tsx │ │ │ │ │ │ │ ├── IndividualInviteForm.tsx │ │ │ │ │ │ │ └── InviteUsersFileUploadForm.tsx │ │ │ │ │ │ ├── misc/ │ │ │ │ │ │ │ ├── InvitationResultDialog.tsx │ │ │ │ │ │ │ └── InvitationsBarChart.tsx │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ ├── InvitationResultInvitationsTable.tsx │ │ │ │ │ │ ├── InvitationResultUsersTable.tsx │ │ │ │ │ │ └── UserInvitationsTable.tsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── InvitationsIndex/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── InviteUsers/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── InviteUsersFileUpload/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── InviteUsersRegistrationCode/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── translations.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── user-notification/ │ │ │ │ │ ├── PopupNotifier.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── AchievementGainedPopup.tsx │ │ │ │ │ │ ├── LevelReachedPopup.tsx │ │ │ │ │ │ ├── PopupDialog.tsx │ │ │ │ │ │ └── __test__/ │ │ │ │ │ │ └── LevelReachedPopup.test.tsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ └── translations.ts │ │ │ │ ├── users/ │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ ├── PointManagementButtons.tsx │ │ │ │ │ │ │ └── UserManagementButtons.tsx │ │ │ │ │ │ ├── misc/ │ │ │ │ │ │ │ ├── PersonalTimeEditor.tsx │ │ │ │ │ │ │ ├── SelectCourseUser.tsx │ │ │ │ │ │ │ ├── UpgradeToStaff.tsx │ │ │ │ │ │ │ ├── UserProfileAchievements.tsx │ │ │ │ │ │ │ ├── UserProfileCard.scss │ │ │ │ │ │ │ ├── UserProfileCard.tsx │ │ │ │ │ │ │ ├── UserProfileCardStats.tsx │ │ │ │ │ │ │ ├── UserProfileSkills.tsx │ │ │ │ │ │ │ └── __test__/ │ │ │ │ │ │ │ └── UserProfileCard.test.tsx │ │ │ │ │ │ ├── navigation/ │ │ │ │ │ │ │ └── UserManagementTabs.tsx │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ ├── ManageUsersTable/ │ │ │ │ │ │ │ ├── ActiveTableToolbar.tsx │ │ │ │ │ │ │ ├── AlgorithmMenu.tsx │ │ │ │ │ │ │ ├── BulkActionsButton.tsx │ │ │ │ │ │ │ ├── BulkAssignTimelineMenu.tsx │ │ │ │ │ │ │ ├── PhantomSwitch.tsx │ │ │ │ │ │ │ ├── RoleMenu.tsx │ │ │ │ │ │ │ ├── TimelineMenu.tsx │ │ │ │ │ │ │ ├── UserNameField.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── PersonalTimesTable.tsx │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── ExperiencePointsRecords/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ManageStaff/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ManageStudents/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── PersonalTimes/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── PersonalTimesShow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── UserShow/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── UserStatistics/ │ │ │ │ │ │ │ ├── LearningRateRecords/ │ │ │ │ │ │ │ │ ├── LearningRateRecordsChart.tsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── UsersIndex/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── translations.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── video/ │ │ │ │ │ ├── attemptLoader.ts │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ ├── VideoManagementButtons.tsx │ │ │ │ │ │ │ └── WatchVideoButton.tsx │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ └── VideoForm.tsx │ │ │ │ │ │ ├── misc/ │ │ │ │ │ │ │ ├── VideoBadges.tsx │ │ │ │ │ │ │ └── VideoTabs.tsx │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ └── VideoTable.tsx │ │ │ │ │ ├── handles.ts │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── VideoEdit/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── VideoNew/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── VideoShow/ │ │ │ │ │ │ │ ├── VideoDetails.tsx │ │ │ │ │ │ │ ├── VideoPlayerWithStore.jsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── VideosIndex/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ ├── submission/ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ └── store.test.js │ │ │ │ │ │ ├── actions/ │ │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ │ └── video.test.js │ │ │ │ │ │ │ ├── discussion.js │ │ │ │ │ │ │ └── video.js │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ │ └── VideoSubmissionsTable.tsx │ │ │ │ │ │ ├── containers/ │ │ │ │ │ │ │ ├── Charts/ │ │ │ │ │ │ │ │ ├── HeatMap.jsx │ │ │ │ │ │ │ │ └── ProgressGraph.jsx │ │ │ │ │ │ │ ├── Discussion.jsx │ │ │ │ │ │ │ ├── Discussion.scss │ │ │ │ │ │ │ ├── DiscussionElements/ │ │ │ │ │ │ │ │ ├── Controls.jsx │ │ │ │ │ │ │ │ ├── EditPostContainer.jsx │ │ │ │ │ │ │ │ ├── Editor.jsx │ │ │ │ │ │ │ │ ├── NewPostContainer.jsx │ │ │ │ │ │ │ │ ├── NewReplyContainer.jsx │ │ │ │ │ │ │ │ ├── PostContainer.jsx │ │ │ │ │ │ │ │ ├── PostMenu.jsx │ │ │ │ │ │ │ │ ├── PostPresentation.jsx │ │ │ │ │ │ │ │ ├── Reply.jsx │ │ │ │ │ │ │ │ └── Topic.jsx │ │ │ │ │ │ │ ├── Statistics.jsx │ │ │ │ │ │ │ ├── Statistics.scss │ │ │ │ │ │ │ ├── Submission.jsx │ │ │ │ │ │ │ ├── VideoControls/ │ │ │ │ │ │ │ │ ├── CaptionsButton.jsx │ │ │ │ │ │ │ │ ├── NextVideoButton.jsx │ │ │ │ │ │ │ │ ├── PlayBackRateSelector.jsx │ │ │ │ │ │ │ │ ├── PlayButton.jsx │ │ │ │ │ │ │ │ ├── VideoPlayerSlider.jsx │ │ │ │ │ │ │ │ ├── VideoTimestamp.jsx │ │ │ │ │ │ │ │ ├── VolumeButton.jsx │ │ │ │ │ │ │ │ ├── VolumeSlider.jsx │ │ │ │ │ │ │ │ └── index.js │ │ │ │ │ │ │ ├── VideoPlayer.jsx │ │ │ │ │ │ │ └── VideoPlayer.scss │ │ │ │ │ │ ├── pages/ │ │ │ │ │ │ │ ├── VideoSubmissionEdit/ │ │ │ │ │ │ │ │ ├── SubmissionEditWithStore.jsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ ├── VideoSubmissionShow/ │ │ │ │ │ │ │ │ ├── StatisticsWithStore.jsx │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── VideoSubmissionsIndex/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── reducers/ │ │ │ │ │ │ │ ├── discussion.js │ │ │ │ │ │ │ ├── index.js │ │ │ │ │ │ │ ├── oldSessions.js │ │ │ │ │ │ │ └── video.js │ │ │ │ │ │ ├── selectors/ │ │ │ │ │ │ │ └── discussion.js │ │ │ │ │ │ ├── store.js │ │ │ │ │ │ └── translations.js │ │ │ │ │ └── types.ts │ │ │ │ └── video-submissions/ │ │ │ │ ├── components/ │ │ │ │ │ └── tables/ │ │ │ │ │ └── UserVideoSubmissionTable.tsx │ │ │ │ ├── operations.ts │ │ │ │ └── pages/ │ │ │ │ └── UserVideoSubmissionsIndex/ │ │ │ │ └── index.tsx │ │ │ ├── system/ │ │ │ │ └── admin/ │ │ │ │ ├── admin/ │ │ │ │ │ ├── AdminNavigator.tsx │ │ │ │ │ ├── components/ │ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ │ ├── CoursesButtons.tsx │ │ │ │ │ │ │ ├── InstancesButtons.tsx │ │ │ │ │ │ │ └── UsersButtons.tsx │ │ │ │ │ │ ├── forms/ │ │ │ │ │ │ │ └── InstanceForm.tsx │ │ │ │ │ │ ├── misc/ │ │ │ │ │ │ │ └── SystemGetHelpFilter.tsx │ │ │ │ │ │ └── tables/ │ │ │ │ │ │ ├── CoursesTable.tsx │ │ │ │ │ │ ├── InstancesTable/ │ │ │ │ │ │ │ ├── InstanceField.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── SystemGetHelpActivityTable.tsx │ │ │ │ │ │ └── UsersTable.tsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── pages/ │ │ │ │ │ │ ├── AnnouncementsIndex.tsx │ │ │ │ │ │ ├── CoursesIndex.tsx │ │ │ │ │ │ ├── InstanceNew.tsx │ │ │ │ │ │ ├── InstancesIndex.tsx │ │ │ │ │ │ ├── SystemGetHelpActivityIndex.tsx │ │ │ │ │ │ └── UsersIndex.tsx │ │ │ │ │ ├── selectors.ts │ │ │ │ │ ├── store.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── components/ │ │ │ │ │ └── AdminNavigablePage.tsx │ │ │ │ └── instance/ │ │ │ │ └── instance/ │ │ │ │ ├── InstanceAdminNavigator.tsx │ │ │ │ ├── components/ │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ ├── InvitationActionButtons.tsx │ │ │ │ │ │ ├── PendingRoleRequestsButtons.tsx │ │ │ │ │ │ ├── ResendAllInvitationsButton.tsx │ │ │ │ │ │ └── UsersButtons.tsx │ │ │ │ │ ├── forms/ │ │ │ │ │ │ ├── IndividualInvitation.tsx │ │ │ │ │ │ ├── IndividualInvitations.tsx │ │ │ │ │ │ ├── IndividualInviteForm.tsx │ │ │ │ │ │ ├── InstanceUserRoleRequestForm.tsx │ │ │ │ │ │ └── RejectWithMessageForm.tsx │ │ │ │ │ ├── misc/ │ │ │ │ │ │ ├── InstanceGetHelpFilter.tsx │ │ │ │ │ │ └── InvitationResultDialog.tsx │ │ │ │ │ ├── navigation/ │ │ │ │ │ │ └── InstanceUsersTabs.tsx │ │ │ │ │ └── tables/ │ │ │ │ │ ├── InstanceGetHelpActivityTable.tsx │ │ │ │ │ ├── InstanceUserRoleRequestsTable.tsx │ │ │ │ │ ├── InvitationResultInvitationsTable.tsx │ │ │ │ │ ├── InvitationResultUsersTable.tsx │ │ │ │ │ ├── UserInvitationsTable.tsx │ │ │ │ │ ├── UsersTable.tsx │ │ │ │ │ └── __test__/ │ │ │ │ │ └── InstanceUserRoleRequestsTable.test.tsx │ │ │ │ ├── operations.ts │ │ │ │ ├── pages/ │ │ │ │ │ ├── InstanceAnnouncementsIndex.tsx │ │ │ │ │ ├── InstanceComponentsIndex.tsx │ │ │ │ │ ├── InstanceCoursesIndex.tsx │ │ │ │ │ ├── InstanceGetHelpActivityIndex.tsx │ │ │ │ │ ├── InstanceUserRoleRequestsIndex.tsx │ │ │ │ │ ├── InstanceUsersIndex.tsx │ │ │ │ │ ├── InstanceUsersInvitations.tsx │ │ │ │ │ └── InstanceUsersInvite.tsx │ │ │ │ ├── selectors.ts │ │ │ │ ├── store.ts │ │ │ │ └── types.ts │ │ │ ├── user/ │ │ │ │ ├── AccountSettings/ │ │ │ │ │ ├── AccountSettingsForm.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── components/ │ │ │ │ │ ├── AddEmailSubsection.tsx │ │ │ │ │ └── EmailsList.tsx │ │ │ │ ├── operations.ts │ │ │ │ └── translations.ts │ │ │ └── users/ │ │ │ ├── components/ │ │ │ │ ├── Widget.tsx │ │ │ │ └── tables/ │ │ │ │ ├── CoursesTable.tsx │ │ │ │ ├── InstancesTable.tsx │ │ │ │ └── __test__/ │ │ │ │ └── InstancesTable.test.tsx │ │ │ ├── operations.ts │ │ │ ├── pages/ │ │ │ │ ├── ConfirmEmailPage.tsx │ │ │ │ ├── ForgotPasswordLandingPage.tsx │ │ │ │ ├── ForgotPasswordPage.tsx │ │ │ │ ├── ResendConfirmationEmailLandingPage.tsx │ │ │ │ ├── ResendConfirmationEmailPage.tsx │ │ │ │ ├── ResetPasswordPage.tsx │ │ │ │ ├── SignUpLandingPage.tsx │ │ │ │ ├── SignUpPage.tsx │ │ │ │ ├── UserShow.tsx │ │ │ │ └── __test__/ │ │ │ │ └── UserShow.test.tsx │ │ │ ├── selectors.ts │ │ │ ├── store.ts │ │ │ ├── translations.ts │ │ │ ├── types.ts │ │ │ └── validations.ts │ │ ├── declaration.d.ts │ │ ├── index.tsx │ │ ├── lib/ │ │ │ ├── actions/ │ │ │ │ └── index.js │ │ │ ├── components/ │ │ │ │ ├── core/ │ │ │ │ │ ├── AvatarSelector.tsx │ │ │ │ │ ├── AvatarWithLabel.tsx │ │ │ │ │ ├── BarChart.jsx │ │ │ │ │ ├── BetaChip.tsx │ │ │ │ │ ├── CourseUserTypeFragment.tsx │ │ │ │ │ ├── CourseUserTypeTabs.tsx │ │ │ │ │ ├── CustomTooltip.tsx │ │ │ │ │ ├── DescriptionCard.tsx │ │ │ │ │ ├── ErrorText.jsx │ │ │ │ │ ├── Expandable.tsx │ │ │ │ │ ├── ExpandableCode.tsx │ │ │ │ │ ├── ExperimentalChip.tsx │ │ │ │ │ ├── Hint.tsx │ │ │ │ │ ├── ImageCropper/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── utils.ts │ │ │ │ │ ├── InfoLabel.tsx │ │ │ │ │ ├── LinearProgressWithLabel.tsx │ │ │ │ │ ├── Link.tsx │ │ │ │ │ ├── LoadingEllipsis.tsx │ │ │ │ │ ├── LoadingIndicator.tsx │ │ │ │ │ ├── LoadingOverlay.tsx │ │ │ │ │ ├── Note.tsx │ │ │ │ │ ├── NotificationBar.jsx │ │ │ │ │ ├── PopupMenu.tsx │ │ │ │ │ ├── Thumbnail.jsx │ │ │ │ │ ├── UserHTMLText.tsx │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ ├── ErrorText.test.tsx │ │ │ │ │ │ ├── LoadingIndicator.test.tsx │ │ │ │ │ │ └── __snapshots__/ │ │ │ │ │ │ ├── ErrorText.test.tsx.snap │ │ │ │ │ │ └── LoadingIndicator.test.tsx.snap │ │ │ │ │ ├── buttons/ │ │ │ │ │ │ ├── AcceptButton.tsx │ │ │ │ │ │ ├── AddButton.tsx │ │ │ │ │ │ ├── Checkbox.tsx │ │ │ │ │ │ ├── DeleteButton.tsx │ │ │ │ │ │ ├── DownloadButton.tsx │ │ │ │ │ │ ├── EditButton.tsx │ │ │ │ │ │ ├── EmailButton.tsx │ │ │ │ │ │ ├── IconRadio.tsx │ │ │ │ │ │ ├── RadioButton.tsx │ │ │ │ │ │ ├── SaveButton.tsx │ │ │ │ │ │ └── __test__/ │ │ │ │ │ │ ├── DeleteButton.test.tsx │ │ │ │ │ │ ├── EditButton.test.tsx │ │ │ │ │ │ └── __snapshots__/ │ │ │ │ │ │ ├── DeleteButton.test.tsx.snap │ │ │ │ │ │ └── EditButton.test.tsx.snap │ │ │ │ │ ├── charts/ │ │ │ │ │ │ ├── GeneralChart.tsx │ │ │ │ │ │ ├── LineChart.tsx │ │ │ │ │ │ └── emptyChartPlugin.ts │ │ │ │ │ ├── dialogs/ │ │ │ │ │ │ ├── ConfirmationDialog.jsx │ │ │ │ │ │ ├── ImageCropDialog.tsx │ │ │ │ │ │ ├── Prompt.tsx │ │ │ │ │ │ └── RailsConfirmationDialog.jsx │ │ │ │ │ ├── fields/ │ │ │ │ │ │ ├── AceEditor.css │ │ │ │ │ │ ├── CAPTCHAField.tsx │ │ │ │ │ │ ├── CKEditor.css │ │ │ │ │ │ ├── CKEditorField.tsx │ │ │ │ │ │ ├── CKEditorRichText.tsx │ │ │ │ │ │ ├── DateTimePicker.jsx │ │ │ │ │ │ ├── EditorField.tsx │ │ │ │ │ │ ├── NumberTextField.tsx │ │ │ │ │ │ ├── PasswordTextField.tsx │ │ │ │ │ │ ├── SearchField.tsx │ │ │ │ │ │ ├── SwitchableTextField.tsx │ │ │ │ │ │ └── TextField.tsx │ │ │ │ │ ├── indicators/ │ │ │ │ │ │ └── SavingIndicator/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── layouts/ │ │ │ │ │ ├── Accordion.tsx │ │ │ │ │ ├── BackendPagination.tsx │ │ │ │ │ ├── Banner.tsx │ │ │ │ │ ├── ContactableErrorAlert.tsx │ │ │ │ │ ├── ContextualErrorPage.tsx │ │ │ │ │ ├── DataTable.jsx │ │ │ │ │ ├── Footer.tsx │ │ │ │ │ ├── MarkdownPage.tsx │ │ │ │ │ ├── Page.tsx │ │ │ │ │ ├── Pagination.tsx │ │ │ │ │ ├── Section.tsx │ │ │ │ │ ├── Subsection.tsx │ │ │ │ │ ├── SummaryCard.tsx │ │ │ │ │ ├── TableContainer.tsx │ │ │ │ │ └── layout.scss │ │ │ │ ├── extensions/ │ │ │ │ │ ├── CustomBadge.tsx │ │ │ │ │ ├── CustomSlider.tsx │ │ │ │ │ ├── PersonalStartEndTime.tsx │ │ │ │ │ ├── PersonalTimeBooleanIcon.tsx │ │ │ │ │ ├── StackedBadges.tsx │ │ │ │ │ └── conditions/ │ │ │ │ │ ├── AnyCondition.ts │ │ │ │ │ ├── ConditionRow.tsx │ │ │ │ │ ├── ConditionsManager.tsx │ │ │ │ │ ├── conditions/ │ │ │ │ │ │ ├── AchievementCondition.tsx │ │ │ │ │ │ ├── AssessmentCondition.tsx │ │ │ │ │ │ ├── LevelCondition.tsx │ │ │ │ │ │ ├── ScholaisticAssessmentCondition.tsx │ │ │ │ │ │ └── SurveyCondition.tsx │ │ │ │ │ ├── operations.ts │ │ │ │ │ ├── specifiers.ts │ │ │ │ │ └── translations.ts │ │ │ │ ├── form/ │ │ │ │ │ ├── Form.tsx │ │ │ │ │ ├── FormDialogue.jsx │ │ │ │ │ ├── dialog/ │ │ │ │ │ │ └── FormDialog.tsx │ │ │ │ │ └── fields/ │ │ │ │ │ ├── AutoCompleteField.jsx │ │ │ │ │ ├── CheckboxField.tsx │ │ │ │ │ ├── DataTableInlineEditable/ │ │ │ │ │ │ └── TextField.tsx │ │ │ │ │ ├── DateTimePickerField.jsx │ │ │ │ │ ├── EditorField.jsx │ │ │ │ │ ├── MultiSelectField.jsx │ │ │ │ │ ├── RichTextField.jsx │ │ │ │ │ ├── SelectField.jsx │ │ │ │ │ ├── SingleFileInput/ │ │ │ │ │ │ ├── BadgePreview.jsx │ │ │ │ │ │ ├── DeleteButton.jsx │ │ │ │ │ │ ├── FilePreview.jsx │ │ │ │ │ │ ├── ImagePreview.jsx │ │ │ │ │ │ ├── __test__/ │ │ │ │ │ │ │ ├── BadgePreview.test.js │ │ │ │ │ │ │ ├── ImagePreview.test.js │ │ │ │ │ │ │ └── index.test.js │ │ │ │ │ │ ├── index.jsx │ │ │ │ │ │ └── translations.js │ │ │ │ │ ├── TextField.tsx │ │ │ │ │ ├── ToggleField.jsx │ │ │ │ │ └── utils/ │ │ │ │ │ ├── mapError.js │ │ │ │ │ └── propsAreEqual.js │ │ │ │ ├── icons/ │ │ │ │ │ ├── GhostIcon.tsx │ │ │ │ │ └── PointerIcon.tsx │ │ │ │ ├── navigation/ │ │ │ │ │ ├── AdminPopupMenuList.tsx │ │ │ │ │ ├── BrandingHead.tsx │ │ │ │ │ ├── CourseSwitcherPopupMenu.tsx │ │ │ │ │ ├── UserPopupMenuList.tsx │ │ │ │ │ └── withRouter.jsx │ │ │ │ ├── table/ │ │ │ │ │ ├── MuiTableAdapter/ │ │ │ │ │ │ ├── MuiFilterMenu.tsx │ │ │ │ │ │ ├── MuiFilterMenuItem.tsx │ │ │ │ │ │ ├── MuiTable.tsx │ │ │ │ │ │ ├── MuiTableBody.tsx │ │ │ │ │ │ ├── MuiTableHeader.tsx │ │ │ │ │ │ ├── MuiTablePagination.tsx │ │ │ │ │ │ ├── MuiTableRow.tsx │ │ │ │ │ │ ├── MuiTableRowSelector.tsx │ │ │ │ │ │ ├── MuiTableToolbar.tsx │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── translations.ts │ │ │ │ │ ├── Table.tsx │ │ │ │ │ ├── TanStackTableBuilder/ │ │ │ │ │ │ ├── columnsBuilder.ts │ │ │ │ │ │ ├── csvGenerator.ts │ │ │ │ │ │ ├── customFlexRender.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── useTanStackTableBuilder.tsx │ │ │ │ │ ├── adapters/ │ │ │ │ │ │ ├── Body.ts │ │ │ │ │ │ ├── Filter.ts │ │ │ │ │ │ ├── Handlers.ts │ │ │ │ │ │ ├── Header.ts │ │ │ │ │ │ ├── Pagination.ts │ │ │ │ │ │ ├── RowSelector.ts │ │ │ │ │ │ ├── Sort.ts │ │ │ │ │ │ ├── Table.ts │ │ │ │ │ │ ├── Toolbar.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── builder/ │ │ │ │ │ │ ├── ColumnTemplate.ts │ │ │ │ │ │ ├── TableTemplate.ts │ │ │ │ │ │ ├── buildColumns.ts │ │ │ │ │ │ ├── featureTemplates.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── utils.ts │ │ │ │ └── wrappers/ │ │ │ │ ├── AttributionsProvider.tsx │ │ │ │ ├── AuthProvider.tsx │ │ │ │ ├── ErrorBoundary.tsx │ │ │ │ ├── FooterProvider.tsx │ │ │ │ ├── I18nProvider.tsx │ │ │ │ ├── Preload.tsx │ │ │ │ ├── Providers.tsx │ │ │ │ ├── RollbarWrapper.tsx │ │ │ │ ├── StoreProvider.tsx │ │ │ │ ├── ThemeProvider.tsx │ │ │ │ └── ToastProvider.tsx │ │ │ ├── constants/ │ │ │ │ ├── icons.ts │ │ │ │ ├── index.js │ │ │ │ ├── sharedConstants.ts │ │ │ │ └── videoConstants.js │ │ │ ├── containers/ │ │ │ │ ├── AppContainer/ │ │ │ │ │ ├── AppContainer.tsx │ │ │ │ │ ├── AppLoader.ts │ │ │ │ │ ├── GlobalAnnouncements.tsx │ │ │ │ │ ├── ServerUnreachableBanner.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── AuthPagesContainer.tsx │ │ │ │ ├── CourselessContainer.tsx │ │ │ │ ├── DeleteConfirmation/ │ │ │ │ │ └── index.jsx │ │ │ │ ├── NotificationPopup/ │ │ │ │ │ └── index.jsx │ │ │ │ └── TableLegends.tsx │ │ │ ├── helpers/ │ │ │ │ ├── __test__/ │ │ │ │ │ └── htmlFormatHelpers.test.js │ │ │ │ ├── htmlFormatHelpers.js │ │ │ │ ├── jobHelpers.ts │ │ │ │ ├── mui-datatables-helpers.ts │ │ │ │ ├── react-hook-form-helper.js │ │ │ │ ├── reducer-helpers.js │ │ │ │ ├── url-builders.js │ │ │ │ ├── url-helpers.ts │ │ │ │ └── videoHelpers.js │ │ │ ├── history.js │ │ │ ├── hooks/ │ │ │ │ ├── items/ │ │ │ │ │ ├── useItems.ts │ │ │ │ │ ├── usePaginate.ts │ │ │ │ │ ├── useSearch.ts │ │ │ │ │ └── useSort.ts │ │ │ │ ├── router/ │ │ │ │ │ ├── dynamicNest.ts │ │ │ │ │ ├── redirect.tsx │ │ │ │ │ └── usePrompt.tsx │ │ │ │ ├── session.ts │ │ │ │ ├── store.ts │ │ │ │ ├── toast/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── loadingToast.ts │ │ │ │ │ └── toast.tsx │ │ │ │ ├── unread.ts │ │ │ │ ├── useDebounce.ts │ │ │ │ ├── useEffectOnce.ts │ │ │ │ ├── useMedia.ts │ │ │ │ └── useTranslation.ts │ │ │ ├── moment.ts │ │ │ ├── reducers/ │ │ │ │ ├── deleteConfirmation.js │ │ │ │ └── notificationPopup.js │ │ │ ├── translations/ │ │ │ │ ├── course/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── users/ │ │ │ │ │ ├── index.ts │ │ │ │ │ └── roles.ts │ │ │ │ ├── form.ts │ │ │ │ ├── getHelp.ts │ │ │ │ ├── index.ts │ │ │ │ ├── messages.ts │ │ │ │ └── table.ts │ │ │ └── types.js │ │ ├── routers/ │ │ │ ├── AuthenticatableApp.tsx │ │ │ ├── AuthenticatedApp.tsx │ │ │ ├── UnauthenticatedApp.tsx │ │ │ ├── course/ │ │ │ │ ├── achievements.tsx │ │ │ │ ├── admin.tsx │ │ │ │ ├── assessments/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── questions.tsx │ │ │ │ │ └── submissions.tsx │ │ │ │ ├── forums.tsx │ │ │ │ ├── groups.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── lessonPlan.tsx │ │ │ │ ├── materials.tsx │ │ │ │ ├── plagiarism.tsx │ │ │ │ ├── scholaistic.tsx │ │ │ │ ├── statistics.tsx │ │ │ │ ├── surveys.tsx │ │ │ │ ├── users.tsx │ │ │ │ └── videos.tsx │ │ │ ├── courseless/ │ │ │ │ ├── index.tsx │ │ │ │ ├── instanceAdmin.tsx │ │ │ │ ├── systemAdmin.tsx │ │ │ │ └── users.tsx │ │ │ ├── index.ts │ │ │ ├── redirects.tsx │ │ │ └── router.tsx │ │ ├── store.ts │ │ ├── theme/ │ │ │ ├── bouncing-dot.css │ │ │ ├── colors.js │ │ │ ├── github.css │ │ │ ├── index.css │ │ │ ├── mui-style.ts │ │ │ ├── palette.js │ │ │ ├── sidebar.css │ │ │ └── syntax-highlighting.css │ │ ├── types/ │ │ │ ├── channels/ │ │ │ │ ├── heartbeat.ts │ │ │ │ └── liveMonitoring.ts │ │ │ ├── components/ │ │ │ │ └── DataTable.ts │ │ │ ├── course/ │ │ │ │ ├── achievements.ts │ │ │ │ ├── admin/ │ │ │ │ │ ├── announcements.ts │ │ │ │ │ ├── assessments.ts │ │ │ │ │ ├── codaveri.ts │ │ │ │ │ ├── comments.ts │ │ │ │ │ ├── components.ts │ │ │ │ │ ├── course.ts │ │ │ │ │ ├── forums.ts │ │ │ │ │ ├── leaderboard.ts │ │ │ │ │ ├── lessonPlan.ts │ │ │ │ │ ├── materials.ts │ │ │ │ │ ├── notifications.ts │ │ │ │ │ ├── ragWise.ts │ │ │ │ │ ├── scholaistic.ts │ │ │ │ │ ├── sidebar.ts │ │ │ │ │ ├── stories.ts │ │ │ │ │ └── videos.ts │ │ │ │ ├── announcements.ts │ │ │ │ ├── assessment/ │ │ │ │ │ ├── assessments.ts │ │ │ │ │ ├── monitoring.ts │ │ │ │ │ ├── question/ │ │ │ │ │ │ ├── forum-post-responses.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── multiple-responses.ts │ │ │ │ │ │ ├── programming.ts │ │ │ │ │ │ ├── rubric-based-responses.ts │ │ │ │ │ │ ├── scribing.ts │ │ │ │ │ │ ├── text-responses.ts │ │ │ │ │ │ └── voice-responses.ts │ │ │ │ │ ├── question-generation.ts │ │ │ │ │ ├── questions.ts │ │ │ │ │ ├── sessions.ts │ │ │ │ │ ├── skills/ │ │ │ │ │ │ ├── skills.ts │ │ │ │ │ │ └── userSkills.ts │ │ │ │ │ ├── submission/ │ │ │ │ │ │ ├── annotations.ts │ │ │ │ │ │ ├── answer/ │ │ │ │ │ │ │ ├── answer.ts │ │ │ │ │ │ │ ├── forumPostResponse.ts │ │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ │ ├── multipleResponse.ts │ │ │ │ │ │ │ ├── programming.ts │ │ │ │ │ │ │ ├── rubricBasedResponse.ts │ │ │ │ │ │ │ ├── scribing.ts │ │ │ │ │ │ │ ├── textResponse.ts │ │ │ │ │ │ │ └── voiceResponse.ts │ │ │ │ │ │ ├── liveFeedback.ts │ │ │ │ │ │ ├── logs.ts │ │ │ │ │ │ ├── question/ │ │ │ │ │ │ │ └── types.ts │ │ │ │ │ │ ├── submission-question.ts │ │ │ │ │ │ └── submission.ts │ │ │ │ │ └── submissions.ts │ │ │ │ ├── comments.ts │ │ │ │ ├── conditions.ts │ │ │ │ ├── courseUsers.ts │ │ │ │ ├── courses.ts │ │ │ │ ├── disbursement.ts │ │ │ │ ├── duplication.ts │ │ │ │ ├── enrolRequests.ts │ │ │ │ ├── experiencePointsRecords.ts │ │ │ │ ├── forums.ts │ │ │ │ ├── leaderboard.ts │ │ │ │ ├── learn.ts │ │ │ │ ├── lesson-plan/ │ │ │ │ │ └── todos.ts │ │ │ │ ├── material/ │ │ │ │ │ ├── files.ts │ │ │ │ │ └── folders.ts │ │ │ │ ├── notifications.ts │ │ │ │ ├── personalTimes.ts │ │ │ │ ├── plagiarism.ts │ │ │ │ ├── referenceTimelines.ts │ │ │ │ ├── rubrics.ts │ │ │ │ ├── scholaistic.ts │ │ │ │ ├── statistics/ │ │ │ │ │ ├── answer.ts │ │ │ │ │ └── assessmentStatistics.ts │ │ │ │ ├── subscriptions.ts │ │ │ │ ├── userInvitations.ts │ │ │ │ ├── userNotifications.ts │ │ │ │ ├── video/ │ │ │ │ │ └── submissions.ts │ │ │ │ ├── videoSubmissions.ts │ │ │ │ └── videos.ts │ │ │ ├── home.ts │ │ │ ├── index.ts │ │ │ ├── jobs.ts │ │ │ ├── store.ts │ │ │ ├── system/ │ │ │ │ ├── courses.ts │ │ │ │ ├── instance/ │ │ │ │ │ ├── components.ts │ │ │ │ │ ├── invitations.ts │ │ │ │ │ ├── roleRequests.ts │ │ │ │ │ └── users.ts │ │ │ │ └── instances.ts │ │ │ └── users.ts │ │ ├── utilities/ │ │ │ ├── ResizeObserver.ts │ │ │ ├── TestApp.tsx │ │ │ ├── array.ts │ │ │ ├── authentication.ts │ │ │ ├── downloadFile.ts │ │ │ ├── index.ts │ │ │ ├── mirrorCreator.ts │ │ │ ├── socket.ts │ │ │ ├── store.ts │ │ │ └── test-utils.tsx │ │ └── workers/ │ │ ├── constructors.ts │ │ ├── heartbeat.sharedworker.ts │ │ ├── heartbeat.worker.ts │ │ ├── heartbeatChannel.ts │ │ ├── listeners.ts │ │ ├── monitoringDatabase.ts │ │ ├── types.ts │ │ └── withHeartbeatWorker.tsx │ ├── css-includes.json │ ├── env │ ├── env.test │ ├── jest.config.js │ ├── locales/ │ │ ├── en.json │ │ ├── ko.json │ │ └── zh.json │ ├── package.json │ ├── postcss.config.js │ ├── public/ │ │ └── index.html │ ├── tailwind.config.ts │ ├── tsconfig.eslint.json │ ├── tsconfig.json │ ├── webpack.common.js │ ├── webpack.dev.js │ ├── webpack.prod.js │ └── webpack.profile.js ├── config/ │ ├── application.rb │ ├── boot.rb │ ├── cable.yml │ ├── credentials/ │ │ ├── README.md │ │ ├── test.key │ │ └── test.yml.enc │ ├── database.yml │ ├── environment.rb │ ├── environments/ │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── i18n-js.yml │ ├── i18n-tasks.yml │ ├── image_optim.yml │ ├── initializers/ │ │ ├── action_cable_acts_as_tenant.rb │ │ ├── acts_as_tenant.rb │ │ ├── application_controller_renderer.rb │ │ ├── argument_deserializer.rb │ │ ├── aws.rb │ │ ├── backtrace_silencers.rb │ │ ├── bullet.rb │ │ ├── carrier_wave.rb │ │ ├── content_security_policy.rb │ │ ├── cookies_serializer.rb │ │ ├── coverage.rb │ │ ├── devise.rb │ │ ├── extensions.rb │ │ ├── filter_parameter_logging.rb │ │ ├── formats_filter.rb │ │ ├── inflections.rb │ │ ├── keycloak.rb │ │ ├── llm_langchain.rb │ │ ├── locale.rb │ │ ├── lograge.rb │ │ ├── mail_delivery_job.rb │ │ ├── mime_types.rb │ │ ├── oembed.rb │ │ ├── rack_mini_profiler.rb │ │ ├── recaptcha.rb │ │ ├── redis.rb │ │ ├── send_file.rb │ │ ├── session_store.rb │ │ ├── sidekiq.rb │ │ ├── userstamp.rb │ │ ├── worker_http_listener.rb │ │ └── wrap_parameters.rb │ ├── locales/ │ │ ├── en/ │ │ │ ├── activemodel/ │ │ │ │ └── course/ │ │ │ │ └── experience_points/ │ │ │ │ └── forum_disbursement.yml │ │ │ ├── activerecord/ │ │ │ │ ├── attributes.yml │ │ │ │ └── errors.yml │ │ │ ├── course/ │ │ │ │ └── assessment/ │ │ │ │ ├── answer/ │ │ │ │ │ └── text_response_comprehension_auto_grading.yml │ │ │ │ ├── assessments.yml │ │ │ │ ├── question/ │ │ │ │ │ ├── forum_post_response.yml │ │ │ │ │ ├── multiple_responses.yml │ │ │ │ │ ├── programming.yml │ │ │ │ │ ├── scribing.yml │ │ │ │ │ └── voice_responses.yml │ │ │ │ └── question_bundle_assignments.yml │ │ │ ├── csv.yml │ │ │ ├── devise.yml │ │ │ ├── errors.yml │ │ │ ├── jobs.yml │ │ │ ├── mailers.yml │ │ │ └── time.yml │ │ ├── ko/ │ │ │ ├── activemodel/ │ │ │ │ └── course/ │ │ │ │ └── experience_points/ │ │ │ │ └── forum_disbursement.yml │ │ │ ├── activerecord/ │ │ │ │ ├── attributes.yml │ │ │ │ └── errors.yml │ │ │ ├── course/ │ │ │ │ └── assessment/ │ │ │ │ ├── answer/ │ │ │ │ │ └── text_response_comprehension_auto_grading.yml │ │ │ │ ├── assessments.yml │ │ │ │ ├── question/ │ │ │ │ │ ├── forum_post_response.yml │ │ │ │ │ ├── multiple_responses.yml │ │ │ │ │ ├── programming.yml │ │ │ │ │ ├── scribing.yml │ │ │ │ │ └── voice_responses.yml │ │ │ │ └── question_bundle_assignments.yml │ │ │ ├── csv.yml │ │ │ ├── devise.yml │ │ │ ├── errors.yml │ │ │ ├── instance_user_role_request_mailer.yml │ │ │ ├── jobs.yml │ │ │ ├── mailers.yml │ │ │ └── time.yml │ │ └── zh/ │ │ ├── activemodel/ │ │ │ └── course/ │ │ │ └── experience_points/ │ │ │ └── forum_disbursement.yml │ │ ├── activerecord/ │ │ │ ├── attributes.yml │ │ │ └── errors.yml │ │ ├── course/ │ │ │ └── assessment/ │ │ │ ├── answer/ │ │ │ │ └── text_response_comprehension_auto_grading.yml │ │ │ ├── assessments.yml │ │ │ ├── question/ │ │ │ │ ├── forum_post_response.yml │ │ │ │ ├── multiple_responses.yml │ │ │ │ ├── programming.yml │ │ │ │ ├── scribing.yml │ │ │ │ └── voice_responses.yml │ │ │ └── question_bundle_assignments.yml │ │ ├── csv.yml │ │ ├── devise.yml │ │ ├── errors.yml │ │ ├── instance_user_role_request_mailer.yml │ │ ├── jobs.yml │ │ ├── mailers.yml │ │ └── time.yml │ ├── puma.rb │ ├── routes.rb │ ├── schedule.yml │ ├── spring.rb │ └── storage.yml ├── config.ru ├── db/ │ ├── migrate/ │ │ ├── .rubocop.yml │ │ ├── 20141203044211_create_instances.rb │ │ ├── 20141204122534_devise_create_users.rb │ │ ├── 20141204122851_create_user_emails.rb │ │ ├── 20141205065248_create_instance_users.rb │ │ ├── 20141210044557_add_role_to_users_and_instance_users.rb │ │ ├── 20141210105742_create_courses.rb │ │ ├── 20141210133147_create_course_users.rb │ │ ├── 20141222074908_add_userstamps_to_courses.rb │ │ ├── 20150106073750_add_name_to_instances.rb │ │ ├── 20150114024350_create_course_announcements.rb │ │ ├── 20150114025131_create_instance_announcements.rb │ │ ├── 20150116102204_add_name_to_users.rb │ │ ├── 20150126080047_add_sticky_to_course_announcements.rb │ │ ├── 20150129040648_create_system_announcements.rb │ │ ├── 20150204075501_create_course_achievements.rb │ │ ├── 20150206020132_create_course_levels.rb │ │ ├── 20150309030221_create_attachments.rb │ │ ├── 20150314025251_add_logo_to_courses.rb │ │ ├── 20150316080645_unread_migration.rb │ │ ├── 20150411065243_create_course_lesson_plan_items.rb │ │ ├── 20150413043822_add_settings_to_instances_and_courses.rb │ │ ├── 20150415033008_create_course_experience_points_records.rb │ │ ├── 20150422152756_create_course_condition_levels.rb │ │ ├── 20150425030128_set_timestamps_nullity.rb │ │ ├── 20150426062119_create_course_conditions.rb │ │ ├── 20150426062133_create_course_conditions_achievements.rb │ │ ├── 20150512014731_add_workflow_state_to_course_users.rb │ │ ├── 20150512015621_add_userstamps_to_course_users.rb │ │ ├── 20150513110737_create_course_groups.rb │ │ ├── 20150513111716_create_course_group_users.rb │ │ ├── 20150614024340_combine_instance_system_announcements.rb │ │ ├── 20150615014716_create_course_invitations.rb │ │ ├── 20150615073135_add_fields_to_course_lesson_plan_item.rb │ │ ├── 20150615075515_create_course_events.rb │ │ ├── 20150616120237_create_activities_and_notifications.rb │ │ ├── 20150617021911_create_course_lesson_plan_milestones.rb │ │ ├── 20150624230355_add_course_registration_key_to_course.rb │ │ ├── 20150702122955_instance_users_change_user_id_unique.rb │ │ ├── 20150713125423_create_assessments.rb │ │ ├── 20150721051322_add_course_assessment_logic.rb │ │ ├── 20150721055754_change_experience_points_record_points_null.rb │ │ ├── 20150721070705_create_user_identities.rb │ │ ├── 20150726062900_create_course_assessment_question_multiple_response.rb │ │ ├── 20150726130555_set_achievement_condition_nullity.rb │ │ ├── 20150726130922_set_conditional_nullity.rb │ │ ├── 20150728020832_add_schema_nullity.rb │ │ ├── 20150728022835_rename_published_to_draft.rb │ │ ├── 20150729133128_rename_course_events_to_course_lesson_plan_events.rb │ │ ├── 20150730074301_rename_start_end_time_to_start_end_at.rb │ │ ├── 20150731010032_rename_valid_from_to_start_end_at.rb │ │ ├── 20150803065430_change_multiple_response_question_option_option_explanation_column_type.rb │ │ ├── 20150803065716_create_materials.rb │ │ ├── 20150803080715_add_assessment_answer_workflow_state.rb │ │ ├── 20150812024950_add_fields_to_course_material_folders.rb │ │ ├── 20151011151130_create_course_user_achievements.rb │ │ ├── 20151016094007_create_discussions_and_forums.rb │ │ ├── 20151016094008_create_forums.rb │ │ ├── 20151016151834_add_root_folder_to_courses.rb │ │ ├── 20151018122902_add_grade_to_course_assessment_answer.rb │ │ ├── 20151021014315_create_course_assessment_question_text_response.rb │ │ ├── 20151022105653_add_unique_index_to_forum_and_topic.rb │ │ ├── 20151027050627_add_submission_grading_statistics.rb │ │ ├── 20151028151258_add_unique_index_to_materials.rb │ │ ├── 20151030063045_add_unique_index_to_course_material_folders.rb │ │ ├── 20151031044810_add_course_assessment_answer_auto_grading.rb │ │ ├── 20151101050627_create_folder_for_categories_and_assessments.rb │ │ ├── 20151114043545_create_jobs.rb │ │ ├── 20151114093538_link_course_assessment_answer_auto_grading_to_jobs.rb │ │ ├── 20151117141053_unread_polymorphic_reader_migration.rb │ │ ├── 20151119020459_create_course_assessment_programming_questions.rb │ │ ├── 20151121070719_create_polyglot_languages.rb │ │ ├── 20151121082432_integrate_assessments_with_polyglot_framework.rb │ │ ├── 20151122011709_create_course_assessment_programming_evaluations.rb │ │ ├── 20151202030421_add_profile_photo_to_users.rb │ │ ├── 20151210055839_create_course_condition_assessments.rb │ │ ├── 20151212091754_normalise_programming_question_file_names.rb │ │ ├── 20151212232827_add_token_authentication_to_user.rb │ │ ├── 20151214080700_add_package_to_programming_evaluation.rb │ │ ├── 20151214081508_add_unique_index_to_course_levels.rb │ │ ├── 20151224034135_add_display_mode_to_assessments.rb │ │ ├── 20151228030006_add_weight_to_questions.rb │ │ ├── 20160119055307_add_correct_to_assessment_answers.rb │ │ ├── 20160124054745_add_exit_code_to_programming_evaluation.rb │ │ ├── 20160126094510_add_badge_to_course_achievements.rb │ │ ├── 20160220081731_rename_assessment_tags_to_skills.rb │ │ ├── 20160220092350_add_course_to_skill_and_skill_branch.rb │ │ ├── 20160226013208_create_course_assessment_answer_programming_file_annotations.rb │ │ ├── 20160229082515_create_attachment_references.rb │ │ ├── 20160330031839_create_course_discussion_post_votes.rb │ │ ├── 20160420005403_change_course_groups_from_user_to_course_user.rb │ │ ├── 20160429135101_add_attributes_to_course_discussion_topics.rb │ │ ├── 20160523093423_add_field_to_course_discussion_topics.rb │ │ ├── 20160628052136_add_staff_only_comments_to_questions.rb │ │ ├── 20160714053644_add_timestamps_to_course_assessment_answers.rb │ │ ├── 20160716091234_add_autograded_to_course_assessments.rb │ │ ├── 20160722020938_add_time_zone_to_users.rb │ │ ├── 20160729022656_add_fields_to_course_assessment_question_programming_test_cases.rb │ │ ├── 20160730044448_chang_attachment_references.rb │ │ ├── 20160801084814_rename_question_type_to_grading_scheme.rb │ │ ├── 20160808023535_change_course_assessment_questions_title_nullity.rb │ │ ├── 20160811064336_change_test_cases_expected_type.rb │ │ ├── 20160815141617_prevent_duplicate_submissions.rb │ │ ├── 20160822092000_add_publisher_to_submissions.rb │ │ ├── 20160823091240_add_unique_index_to_read_marks.rb │ │ ├── 20160823094126_add_unique_index_to_multiple_response_answer_options.rb │ │ ├── 20160830023835_alter_grade_type.rb │ │ ├── 20160906091734_add_fields_to_course_assessment_answer_text_responses.rb │ │ ├── 20160908100211_rename_programming_auto_grading_test_result_messages.rb │ │ ├── 20160916101014_change_discussion_posts_title.rb │ │ ├── 20160920101847_add_hide_text_to_course_assessment_question_text_responses.rb │ │ ├── 20161003094742_create_lesson_plan_todos.rb │ │ ├── 20161006063146_rename_assessments_display_mode.rb │ │ ├── 20161007061116_add_fields_to_assessments.rb │ │ ├── 20161013115452_migrate_graded_submissions_to_published.rb │ │ ├── 20161020020353_add_todos_for_existing_lesson_plan_items.rb │ │ ├── 20161027020646_add_package_type_to_course_assessment_question_programming.rb │ │ ├── 20161027074807_add_session_id_to_submissions.rb │ │ ├── 20161102022455_add_stdout_stderr_to_course_assessment_answer_programming_auto_grading.rb │ │ ├── 20161107023238_add_attempt_limit_to_programming_questions.rb │ │ ├── 20161108030759_add_gamified_to_courses.rb │ │ ├── 20161116075305_add_tabbed_view_to_course_assessments.rb │ │ ├── 20161202071856_add_skippable_to_assessments.rb │ │ ├── 20161206101644_remove_mode_and_invert_draft.rb │ │ ├── 20161207013914_create_course_survey_tables.rb │ │ ├── 20161214050848_add_sent_at_to_course_user_invitations.rb │ │ ├── 20161219105620_change_course_user_invitations.rb │ │ ├── 20161223123359_create_course_enrol_requests.rb │ │ ├── 20161227125455_remove_workflow_state_from_course_users.rb │ │ ├── 20170102053335_create_course_video_tables.rb │ │ ├── 20170103104020_create_course_lectures.rb │ │ ├── 20170110022335_remove_extra_bonus_exp_from_lesson_plan.rb │ │ ├── 20170115105609_add_delayed_grade_publication_to_course_assessments.rb │ │ ├── 20170116103602_add_tokens_to_course_lesson_plan_items.rb │ │ ├── 20170117145558_add_fields_to_courses.rb │ │ ├── 20170117164747_add_awarded_at_and_draft_exp_to_course_experience_points_records.rb │ │ ├── 20170120063357_change_default_value_of_assessment_questions_weight.rb │ │ ├── 20170128041649_change_survey_tables.rb │ │ ├── 20170203020915_add_weight_to_course_assessment_question_multiple_response_options.rb │ │ ├── 20170210073247_add_selected_to_survey_answer_options.rb │ │ ├── 20170214062036_add_index_for_survey_response_user.rb │ │ ├── 20170217041431_add_survey_booleans.rb │ │ ├── 20170220123952_remove_image_from_survey_question_option.rb │ │ ├── 20170222101701_remove_default_from_groups.rb │ │ ├── 20170302054635_add_submitted_at_to_submissions.rb │ │ ├── 20170306051518_rename_lectures_to_virtual_classrooms.rb │ │ ├── 20170307043218_add_instructor_id_to_virtual_classrooms.rb │ │ ├── 20170307080839_add_timestamp_to_trackable_jobs.rb │ │ ├── 20170307090147_add_time_limit_to_existing_programming_questions.rb │ │ ├── 20170308044737_add_recorded_videos_to_virtual_classrooms.rb │ │ ├── 20170308073855_create_course_assessment_submission_logs.rb │ │ ├── 20170308074359_add_course_assessment_submission_question.rb │ │ ├── 20170309094211_add_section_id_to_survey_questions.rb │ │ ├── 20170407083553_add_reminded_at_and_allow_responsee_to_surveys.rb │ │ ├── 20170420063829_remove_length_limit_of_expression.rb │ │ ├── 20170426024809_remove_constraint_in_skills.rb │ │ ├── 20170506010828_create_course_assessment_question_scribings.rb │ │ ├── 20170510233359_remove_selected_from_survey_answer_options.rb │ │ ├── 20170515061739_add_more_options_to_course_assessments.rb │ │ ├── 20170522104534_regroup_course_settings.rb │ │ ├── 20170528035408_create_course_assessment_question_voice_responses.rb │ │ ├── 20170529035430_create_course_assessment_answer_voice_responses.rb │ │ ├── 2017
Showing preview only (965K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (10175 symbols across 2444 files)
FILE: app/channels/application_cable/channel.rb
class ApplicationCable::Channel (line 2) | class ApplicationCable::Channel < ActionCable::Channel::Base
method request (line 7) | def request
method session (line 11) | def session
method ip_address_and_user_agent (line 15) | def ip_address_and_user_agent
FILE: app/channels/application_cable/connection.rb
class ApplicationCable::Connection (line 2) | class ApplicationCable::Connection < ActionCable::Connection::Base
method connect (line 7) | def connect
FILE: app/channels/concerns/application_cable_ability_concern.rb
type ApplicationCableAbilityConcern (line 2) | module ApplicationCableAbilityConcern
function current_ability (line 9) | def current_ability
function can? (line 13) | def can?(*args)
function cannot? (line 17) | def cannot?(*args)
FILE: app/channels/concerns/application_cable_authentication_concern.rb
type ApplicationCableAuthenticationConcern (line 2) | module ApplicationCableAuthenticationConcern
function current_user_from_token (line 3) | def current_user_from_token
function retrieve_current_session_id (line 8) | def retrieve_current_session_id
function current_decoded_token (line 12) | def current_decoded_token
function authenticate_token (line 18) | def authenticate_token
function token_from_request (line 28) | def token_from_request
FILE: app/channels/concerns/application_cable_component_concern.rb
type ApplicationCableComponentConcern (line 2) | module ApplicationCableComponentConcern
function current_component_host (line 10) | def current_component_host
function component (line 18) | def component
function check_component (line 23) | def check_component
FILE: app/channels/concerns/application_cable_course_concern.rb
type ApplicationCableCourseConcern (line 2) | module ApplicationCableCourseConcern
function find_course (line 9) | def find_course
function current_course (line 14) | def current_course
function current_course_user (line 18) | def current_course_user
FILE: app/channels/concerns/application_cable_multitenancy_concern.rb
type ApplicationCableMultitenancyConcern (line 2) | module ApplicationCableMultitenancyConcern
FILE: app/channels/course/channel.rb
class Course::Channel (line 17) | class Course::Channel < ApplicationCable::Channel
FILE: app/channels/course/monitoring/heartbeat_channel.rb
class Course::Monitoring::HeartbeatChannel (line 2) | class Course::Monitoring::HeartbeatChannel < Course::Channel
method subscribed (line 5) | def subscribed
method pulse (line 14) | def pulse(data)
method flush (line 42) | def flush(data)
method broadcast_terminate (line 63) | def broadcast_terminate(session)
method listening? (line 70) | def listening?
method filter_and_sort_heartbeats (line 74) | def filter_and_sort_heartbeats(heartbeats)
method time_from (line 81) | def time_from(milliseconds)
method broadcast_pulse_to_live_monitoring (line 85) | def broadcast_pulse_to_live_monitoring(heartbeat)
method broadcast_terminate_to_live_monitoring (line 95) | def broadcast_terminate_to_live_monitoring
method broadcast_terminate (line 99) | def broadcast_terminate
method broadcast_flushed (line 103) | def broadcast_flushed(first_timestamp, last_timestamp)
method broadcast_next (line 111) | def broadcast_next(received_timestamp, next_timeout)
method component (line 119) | def component
method can_pulse? (line 123) | def can_pulse?
method assessment_id (line 127) | def assessment_id
method valid_heartbeat? (line 131) | def valid_heartbeat?(heartbeat)
FILE: app/channels/course/monitoring/live_monitoring_channel.rb
class Course::Monitoring::LiveMonitoringChannel (line 2) | class Course::Monitoring::LiveMonitoringChannel < Course::Channel
method subscribed (line 8) | def subscribed
method broadcast_pulse_to (line 17) | def broadcast_pulse_to(monitor, session, snapshot)
method broadcast_terminate (line 21) | def broadcast_terminate(monitor, session)
method broadcast_from (line 25) | def broadcast_from(monitor, action, payload)
method watch (line 30) | def watch
method view (line 42) | def view(data)
method active_sessions_snapshots (line 62) | def active_sessions_snapshots
method groups (line 86) | def groups
method broadcast (line 97) | def broadcast(action, payload)
method broadcast_watch (line 101) | def broadcast_watch(users, snapshots, groups)
method broadcast_viewed (line 115) | def broadcast_viewed(recent_heartbeats)
method component (line 119) | def component
method course_users_hash (line 123) | def course_users_hash
method submission_ids_hash (line 127) | def submission_ids_hash
FILE: app/controllers/announcements_controller.rb
class AnnouncementsController (line 2) | class AnnouncementsController < ApplicationController
method index (line 5) | def index
method mark_as_read (line 14) | def mark_as_read
method publicly_accessible? (line 25) | def publicly_accessible?
method requesting_unread? (line 31) | def requesting_unread?
FILE: app/controllers/application_controller.rb
class ApplicationController (line 3) | class ApplicationController < ActionController::Base
method index (line 22) | def index
method without_bullet (line 32) | def without_bullet
method handle_illegal_state_error (line 42) | def handle_illegal_state_error(exception)
method handle_csrf_error (line 47) | def handle_csrf_error(exception)
method handle_authentication_error (line 52) | def handle_authentication_error(exception)
method append_info_to_payload (line 59) | def append_info_to_payload(payload)
FILE: app/controllers/attachment_references_controller.rb
class AttachmentReferencesController (line 2) | class AttachmentReferencesController < ApplicationController
method create (line 5) | def create
method show (line 12) | def show
method file_params (line 30) | def file_params
FILE: app/controllers/components/course/achievements_component.rb
class Course::AchievementsComponent (line 2) | class Course::AchievementsComponent < SimpleDelegator
method gamified? (line 5) | def self.gamified?
method sidebar_items (line 9) | def sidebar_items
FILE: app/controllers/components/course/announcements_component.rb
class Course::AnnouncementsComponent (line 2) | class Course::AnnouncementsComponent < SimpleDelegator
method sidebar_items (line 6) | def sidebar_items
method main_sidebar_items (line 12) | def main_sidebar_items
method settings_sidebar_items (line 25) | def settings_sidebar_items
FILE: app/controllers/components/course/assessments_component.rb
class Course::AssessmentsComponent (line 2) | class Course::AssessmentsComponent < SimpleDelegator
method lesson_plan_item_actable_names (line 6) | def self.lesson_plan_item_actable_names
method sidebar_items (line 10) | def sidebar_items
method main_sidebar_items (line 16) | def main_sidebar_items
method assessment_categories (line 20) | def assessment_categories
method assessment_submissions (line 32) | def assessment_submissions
method admin_sidebar_items (line 44) | def admin_sidebar_items
method admin_settings_items (line 58) | def admin_settings_items
FILE: app/controllers/components/course/codaveri_component.rb
class Course::CodaveriComponent (line 2) | class Course::CodaveriComponent < SimpleDelegator
method sidebar_items (line 5) | def sidebar_items
method settings_sidebar_items (line 11) | def settings_sidebar_items
FILE: app/controllers/components/course/controller_component_host.rb
class Course::ControllerComponentHost (line 26) | class Course::ControllerComponentHost
type Sidebar (line 29) | module Sidebar
function sidebar_items (line 36) | def sidebar_items
type Settings (line 41) | module Settings
type ClassMethods (line 48) | module ClassMethods
function enabled_by_default? (line 50) | def enabled_by_default?
function key (line 57) | def key
function display_name (line 65) | def display_name
function gamified? (line 71) | def gamified?
function can_be_disabled_for_course? (line 77) | def can_be_disabled_for_course?
function settings_class (line 92) | def settings_class
function lesson_plan_item_actable_names (line 101) | def lesson_plan_item_actable_names
function settings (line 110) | def settings
method initialize (line 129) | def initialize(context)
method enabled_components (line 135) | def enabled_components
method components (line 142) | def components
method [] (line 151) | def [](component_key)
method sidebar_items (line 176) | def sidebar_items
method validate_component_key! (line 183) | def validate_component_key!(key)
method component_key_set (line 187) | def component_key_set
FILE: app/controllers/components/course/discussion/topics_component.rb
class Course::Discussion::TopicsComponent (line 2) | class Course::Discussion::TopicsComponent < SimpleDelegator
method sidebar_items (line 6) | def sidebar_items
method main_sidebar_items (line 12) | def main_sidebar_items
method settings_sidebar_items (line 25) | def settings_sidebar_items
FILE: app/controllers/components/course/duplication_component.rb
class Course::DuplicationComponent (line 2) | class Course::DuplicationComponent < SimpleDelegator
method sidebar_items (line 5) | def sidebar_items
FILE: app/controllers/components/course/experience_points_component.rb
class Course::ExperiencePointsComponent (line 2) | class Course::ExperiencePointsComponent < SimpleDelegator
method gamified? (line 5) | def self.gamified?
method sidebar_items (line 9) | def sidebar_items
method can_create_experience_points_record? (line 25) | def can_create_experience_points_record?
FILE: app/controllers/components/course/forums_component.rb
class Course::ForumsComponent (line 2) | class Course::ForumsComponent < SimpleDelegator
method sidebar_items (line 6) | def sidebar_items
method main_sidebar_items (line 12) | def main_sidebar_items
method settings_sidebar_items (line 25) | def settings_sidebar_items
FILE: app/controllers/components/course/groups_component.rb
class Course::GroupsComponent (line 2) | class Course::GroupsComponent < SimpleDelegator
method sidebar_items (line 6) | def sidebar_items
method group_category_url (line 22) | def group_category_url
method show_group_sidebar_item? (line 31) | def show_group_sidebar_item?
FILE: app/controllers/components/course/koditsu_platform_component.rb
class Course::KoditsuPlatformComponent (line 2) | class Course::KoditsuPlatformComponent < SimpleDelegator
method enabled_by_default? (line 5) | def self.enabled_by_default?
FILE: app/controllers/components/course/leaderboard_component.rb
class Course::LeaderboardComponent (line 2) | class Course::LeaderboardComponent < SimpleDelegator
method gamified? (line 5) | def self.gamified?
method sidebar_items (line 9) | def sidebar_items
method main_sidebar_items (line 15) | def main_sidebar_items
method settings_sidebar_items (line 27) | def settings_sidebar_items
FILE: app/controllers/components/course/learning_map_component.rb
class Course::LearningMapComponent (line 2) | class Course::LearningMapComponent < SimpleDelegator
method enabled_by_default? (line 5) | def self.enabled_by_default?
method sidebar_items (line 9) | def sidebar_items
FILE: app/controllers/components/course/lesson_plan_component.rb
class Course::LessonPlanComponent (line 2) | class Course::LessonPlanComponent < SimpleDelegator
method lesson_plan_item_actable_names (line 5) | def self.lesson_plan_item_actable_names
method sidebar_items (line 9) | def sidebar_items
method main_sidebar_items (line 15) | def main_sidebar_items
method settings_sidebar_items (line 26) | def settings_sidebar_items
FILE: app/controllers/components/course/levels_component.rb
class Course::LevelsComponent (line 2) | class Course::LevelsComponent < SimpleDelegator
method gamified? (line 5) | def self.gamified?
method sidebar_items (line 9) | def sidebar_items
FILE: app/controllers/components/course/materials_component.rb
class Course::MaterialsComponent (line 2) | class Course::MaterialsComponent < SimpleDelegator
method sidebar_items (line 5) | def sidebar_items
method main_sidebar_items (line 11) | def main_sidebar_items
method settings_sidebar_items (line 23) | def settings_sidebar_items
FILE: app/controllers/components/course/monitoring_component.rb
class Course::MonitoringComponent (line 2) | class Course::MonitoringComponent < SimpleDelegator
method enabled_by_default? (line 5) | def self.enabled_by_default?
FILE: app/controllers/components/course/multiple_reference_timelines_component.rb
class Course::MultipleReferenceTimelinesComponent (line 2) | class Course::MultipleReferenceTimelinesComponent < SimpleDelegator
method enabled_by_default? (line 5) | def self.enabled_by_default?
method sidebar_items (line 9) | def sidebar_items
FILE: app/controllers/components/course/plagiarism_component.rb
class Course::PlagiarismComponent (line 2) | class Course::PlagiarismComponent < SimpleDelegator
method enabled_by_default? (line 5) | def self.enabled_by_default?
method sidebar_items (line 9) | def sidebar_items
FILE: app/controllers/components/course/rag_wise_component.rb
class Course::RagWiseComponent (line 2) | class Course::RagWiseComponent < SimpleDelegator
method enabled_by_default? (line 5) | def self.enabled_by_default?
method sidebar_items (line 9) | def sidebar_items
method settings_sidebar_items (line 15) | def settings_sidebar_items
FILE: app/controllers/components/course/scholaistic_component.rb
class Course::ScholaisticComponent (line 2) | class Course::ScholaisticComponent < SimpleDelegator
method enabled_by_default? (line 6) | def self.enabled_by_default?
method sidebar_items (line 10) | def sidebar_items
method main_sidebar_items (line 16) | def main_sidebar_items
method student_sidebar_items (line 22) | def student_sidebar_items
method assistant_sidebar_items (line 34) | def assistant_sidebar_items
method admin_sidebar_items (line 51) | def admin_sidebar_items
method settings_sidebar_items (line 66) | def settings_sidebar_items
FILE: app/controllers/components/course/settings_component.rb
class Course::SettingsComponent (line 2) | class Course::SettingsComponent < SimpleDelegator
method can_be_disabled_for_course? (line 6) | def self.can_be_disabled_for_course?
method sidebar_items (line 10) | def sidebar_items
method admin_sidebar_items (line 16) | def admin_sidebar_items
method settings_sidebar_items (line 30) | def settings_sidebar_items
method settings_index_item (line 39) | def settings_index_item
method settings_components_item (line 48) | def settings_components_item
method settings_sidebar_item (line 57) | def settings_sidebar_item
method settings_notifications (line 66) | def settings_notifications
FILE: app/controllers/components/course/statistics_component.rb
class Course::StatisticsComponent (line 2) | class Course::StatisticsComponent < SimpleDelegator
method sidebar_items (line 5) | def sidebar_items
FILE: app/controllers/components/course/stories_component.rb
class Course::StoriesComponent (line 2) | class Course::StoriesComponent < SimpleDelegator
method enabled_by_default? (line 5) | def self.enabled_by_default?
method sidebar_items (line 9) | def sidebar_items
method main_sidebar_items (line 15) | def main_sidebar_items
method student_sidebar_items (line 24) | def student_sidebar_items
method staff_sidebar_items (line 36) | def staff_sidebar_items
method settings_sidebar_items (line 50) | def settings_sidebar_items
FILE: app/controllers/components/course/survey_component.rb
class Course::SurveyComponent (line 2) | class Course::SurveyComponent < SimpleDelegator
method lesson_plan_item_actable_names (line 5) | def self.lesson_plan_item_actable_names
method sidebar_items (line 9) | def sidebar_items
FILE: app/controllers/components/course/users_component.rb
class Course::UsersComponent (line 2) | class Course::UsersComponent < SimpleDelegator
method can_be_disabled_for_course? (line 6) | def self.can_be_disabled_for_course?
method sidebar_items (line 11) | def sidebar_items
method main_sidebar_items (line 17) | def main_sidebar_items
method admin_sidebar_items (line 30) | def admin_sidebar_items
FILE: app/controllers/components/course/videos_component.rb
class Course::VideosComponent (line 2) | class Course::VideosComponent < SimpleDelegator
method lesson_plan_item_actable_names (line 6) | def self.lesson_plan_item_actable_names
method sidebar_items (line 10) | def sidebar_items
method main_sidebar_items (line 16) | def main_sidebar_items
method settings_sidebar_items (line 29) | def settings_sidebar_items
FILE: app/controllers/concerns/application_ability_concern.rb
type ApplicationAbilityConcern (line 2) | module ApplicationAbilityConcern
function current_ability (line 4) | def current_ability
FILE: app/controllers/concerns/application_announcements_concern.rb
type ApplicationAnnouncementsConcern (line 2) | module ApplicationAnnouncementsConcern
function unread_global_announcements (line 8) | def unread_global_announcements
function global_announcements (line 15) | def global_announcements
FILE: app/controllers/concerns/application_authentication_concern.rb
type ApplicationAuthenticationConcern (line 2) | module ApplicationAuthenticationConcern
function current_user_from_token (line 15) | def current_user_from_token
function current_session_id (line 20) | def current_session_id
function token_from_request (line 24) | def token_from_request
function current_decoded_token (line 28) | def current_decoded_token
function authenticate_token (line 34) | def authenticate_token
function get_token_from_bearer (line 49) | def get_token_from_bearer
function get_token_from_cookies (line 68) | def get_token_from_cookies
FILE: app/controllers/concerns/application_components_concern.rb
type ApplicationComponentsConcern (line 2) | module ApplicationComponentsConcern
function handle_component_not_found (line 11) | def handle_component_not_found(exception)
FILE: app/controllers/concerns/application_controller_multitenancy_concern.rb
type ApplicationControllerMultitenancyConcern (line 2) | module ApplicationControllerMultitenancyConcern
FILE: app/controllers/concerns/application_instance_user_concern.rb
type ApplicationInstanceUserConcern (line 2) | module ApplicationInstanceUserConcern
function current_instance_user (line 9) | def current_instance_user
function track_instance_user (line 17) | def track_instance_user
FILE: app/controllers/concerns/application_internationalization_concern.rb
type ApplicationInternationalizationConcern (line 2) | module ApplicationInternationalizationConcern
function set_locale (line 10) | def set_locale
FILE: app/controllers/concerns/application_multitenancy.rb
type ApplicationMultitenancy (line 2) | module ApplicationMultitenancy
function deduce_and_set_current_tenant (line 5) | def deduce_and_set_current_tenant
function deduce_tenant (line 14) | def deduce_tenant
function deduce_tenant_host (line 27) | def deduce_tenant_host
type ClassMethods (line 43) | module ClassMethods
function set_current_tenant_through_filter (line 44) | def set_current_tenant_through_filter
FILE: app/controllers/concerns/application_pagination_concern.rb
type ApplicationPaginationConcern (line 2) | module ApplicationPaginationConcern
function page_param (line 9) | def page_param
FILE: app/controllers/concerns/application_user_concern.rb
type ApplicationUserConcern (line 2) | module ApplicationUserConcern
function url_to_user_or_course_user (line 16) | def url_to_user_or_course_user(course, user)
function current_user (line 23) | def current_user
function publicly_accessible? (line 29) | def publicly_accessible?
function handle_access_denied (line 33) | def handle_access_denied(exception)
function authenticate! (line 39) | def authenticate!
function add_token_to_cookie (line 46) | def add_token_to_cookie
function update_user_tracked_fields (line 51) | def update_user_tracked_fields
function update_tracked_fields (line 57) | def update_tracked_fields
FILE: app/controllers/concerns/application_user_time_zone_concern.rb
type ApplicationUserTimeZoneConcern (line 2) | module ApplicationUserTimeZoneConcern
function set_time_zone (line 12) | def set_time_zone(&block) # rubocop:disable Naming/AccessorMethodName
FILE: app/controllers/concerns/codaveri_language_concern.rb
type CodaveriLanguageConcern (line 2) | module CodaveriLanguageConcern
function codaveri_language (line 3) | def codaveri_language
function codaveri_version (line 7) | def codaveri_version
function programming_language_map (line 15) | def programming_language_map
FILE: app/controllers/concerns/course/achievement_conditional_concern.rb
type Course::AchievementConditionalConcern (line 2) | module Course::AchievementConditionalConcern
function success_action (line 5) | def success_action
function set_conditional (line 9) | def set_conditional
FILE: app/controllers/concerns/course/activity_feeds_concern.rb
type Course::ActivityFeedsConcern (line 2) | module Course::ActivityFeedsConcern
function recent_activity_feeds (line 8) | def recent_activity_feeds
FILE: app/controllers/concerns/course/assessment/answer/update_answer_concern.rb
type Course::Assessment::Answer::UpdateAnswerConcern (line 2) | module Course::Assessment::Answer::UpdateAnswerConcern
function update_answer (line 7) | def update_answer(answer, answer_params)
function update_answer_params (line 21) | def update_answer_params(answer, update_params)
function additional_answer_params (line 27) | def additional_answer_params(answer)
function update_specific_answer_type_params (line 34) | def update_specific_answer_type_params(answer) # rubocop:disable Metri...
function update_multiple_response_params (line 59) | def update_multiple_response_params(array_params)
function update_programming_params (line 63) | def update_programming_params(array_params)
function update_text_response_params (line 67) | def update_text_response_params(scalar_params)
function update_voice_response_params (line 72) | def update_voice_response_params(scalar_params)
function update_rubric_based_response_params (line 76) | def update_rubric_based_response_params(scalar_params, array_params, a...
function update_forum_post_response_params (line 83) | def update_forum_post_response_params(scalar_params, array_params)
FILE: app/controllers/concerns/course/assessment/koditsu_assessment_concern.rb
type Course::Assessment::KoditsuAssessmentConcern (line 2) | module Course::Assessment::KoditsuAssessmentConcern
function create_assessment_in_koditsu (line 5) | def create_assessment_in_koditsu
function adjust_assessment_from_koditsu_response (line 17) | def adjust_assessment_from_koditsu_response(status, response)
function update_assessment_in_koditsu (line 28) | def update_assessment_in_koditsu
function create_or_update_assessment_in_koditsu (line 43) | def create_or_update_assessment_in_koditsu
function flag_assessment_not_synced_with_koditsu (line 51) | def flag_assessment_not_synced_with_koditsu
function remove_question_from_assessment_in_koditsu (line 55) | def remove_question_from_assessment_in_koditsu(question_id)
function questions_in_koditsu (line 72) | def questions_in_koditsu(koditsu_assessment_id)
function monitoring_configuration (line 83) | def monitoring_configuration
function edit_koditsu_assessment (line 105) | def edit_koditsu_assessment(assessment, questions, course, monitoring_...
FILE: app/controllers/concerns/course/assessment/koditsu_assessment_invitation_concern.rb
type Course::Assessment::KoditsuAssessmentInvitationConcern (line 2) | module Course::Assessment::KoditsuAssessmentInvitationConcern
function send_invitation_for_koditsu_assessment (line 5) | def send_invitation_for_koditsu_assessment(assessment)
function all_invitation_successful? (line 21) | def all_invitation_successful?(invitation_response)
FILE: app/controllers/concerns/course/assessment/live_feedback/file_concern.rb
type Course::Assessment::LiveFeedback::FileConcern (line 2) | module Course::Assessment::LiveFeedback::FileConcern
function snapshot_files_hash (line 5) | def snapshot_files_hash(file_ids)
function answer_files_hash (line 11) | def answer_files_hash
function fetch_all_unchanged_files (line 17) | def fetch_all_unchanged_files(file_hash, current_answer_file_hash)
function fetch_all_modified_files (line 25) | def fetch_all_modified_files(file_hash, current_answer_file_hash)
function fetch_all_files_to_be_associated (line 34) | def fetch_all_files_to_be_associated(file_ids)
FILE: app/controllers/concerns/course/assessment/live_feedback/message_concern.rb
type Course::Assessment::LiveFeedback::MessageConcern (line 2) | module Course::Assessment::LiveFeedback::MessageConcern
function handle_save_user_message (line 6) | def handle_save_user_message
function create_new_message (line 26) | def create_new_message
FILE: app/controllers/concerns/course/assessment/live_feedback/message_file_concern.rb
type Course::Assessment::LiveFeedback::MessageFileConcern (line 2) | module Course::Assessment::LiveFeedback::MessageFileConcern
function associate_new_message_with_new_or_existing_files (line 6) | def associate_new_message_with_new_or_existing_files(new_message)
function associated_file_ids_with_last_message (line 17) | def associated_file_ids_with_last_message(new_message)
function save_message_file_association (line 27) | def save_message_file_association(new_message, associated_file_ids)
FILE: app/controllers/concerns/course/assessment/live_feedback/thread_concern.rb
type Course::Assessment::LiveFeedback::ThreadConcern (line 2) | module Course::Assessment::LiveFeedback::ThreadConcern
function safe_create_and_save_thread_info (line 5) | def safe_create_and_save_thread_info
function existing_thread_status (line 20) | def existing_thread_status(thread)
function create_and_save_thread_if_empty (line 29) | def create_and_save_thread_if_empty(submission_question)
function save_thread_info (line 37) | def save_thread_info(thread_info, submission_question_id)
FILE: app/controllers/concerns/course/assessment/monitoring/seb_payload_concern.rb
type Course::Assessment::Monitoring::SebPayloadConcern (line 2) | module Course::Assessment::Monitoring::SebPayloadConcern
function seb_payload_from_request (line 7) | def seb_payload_from_request(request)
function stub_heartbeat_from_request (line 16) | def stub_heartbeat_from_request(request)
FILE: app/controllers/concerns/course/assessment/monitoring_concern.rb
type Course::Assessment::MonitoringConcern (line 2) | module Course::Assessment::MonitoringConcern
function monitoring (line 20) | def monitoring
function seb_payload (line 26) | def seb_payload
function unblock_monitor (line 33) | def unblock_monitor
function upsert_monitoring! (line 43) | def upsert_monitoring!
function monitoring_params (line 52) | def monitoring_params
function unblock_monitor_params (line 56) | def unblock_monitor_params
function raise_if_no_monitor (line 60) | def raise_if_no_monitor
function check_blocked_by_monitor (line 64) | def check_blocked_by_monitor
function blocked_by_monitor? (line 68) | def blocked_by_monitor?
function monitoring_service (line 72) | def monitoring_service
function monitoring_component_enabled? (line 78) | def monitoring_component_enabled?
function can_manage_monitor? (line 82) | def can_manage_monitor?
function monitor (line 86) | def monitor
function should_disable_block? (line 90) | def should_disable_block?
function submitted_assessment? (line 94) | def submitted_assessment?
FILE: app/controllers/concerns/course/assessment/question/codaveri_question_concern.rb
type Course::Assessment::Question::CodaveriQuestionConcern (line 2) | module Course::Assessment::Question::CodaveriQuestionConcern
function safe_create_or_update_codaveri_question (line 5) | def safe_create_or_update_codaveri_question(question)
function extract_pathname_from_java_file (line 19) | def extract_pathname_from_java_file(file_content)
FILE: app/controllers/concerns/course/assessment/question/koditsu_question_concern.rb
type Course::Assessment::Question::KoditsuQuestionConcern (line 3) | module Course::Assessment::Question::KoditsuQuestionConcern
function create_koditsu_question (line 7) | def create_koditsu_question
function adjust_question_from_koditsu_response (line 17) | def adjust_question_from_koditsu_response(status, response)
function arrange_questions_in_assessment_in_koditsu (line 31) | def arrange_questions_in_assessment_in_koditsu
function edit_koditsu_question (line 50) | def edit_koditsu_question
function delete_koditsu_question (line 60) | def delete_koditsu_question(id)
function create_or_edit_question_in_koditsu (line 67) | def create_or_edit_question_in_koditsu
function extract_programming_question_metadata (line 77) | def extract_programming_question_metadata
function programming_package_service (line 83) | def programming_package_service
function koditsu_programming_language_map (line 89) | def koditsu_programming_language_map
FILE: app/controllers/concerns/course/assessment/question/multiple_responses_concern.rb
type Course::Assessment::Question::MultipleResponsesConcern (line 2) | module Course::Assessment::Question::MultipleResponsesConcern
function switch_mcq_mrq_type (line 5) | def switch_mcq_mrq_type(is_mcq, unsubmit)
function unsubmit_submissions (line 18) | def unsubmit_submissions
FILE: app/controllers/concerns/course/assessment/question/rubric_based_response_controller_concern.rb
type Course::Assessment::Question::RubricBasedResponseControllerConcern (line 2) | module Course::Assessment::Question::RubricBasedResponseControllerConcern
function create_new_category_grade_instances (line 6) | def create_new_category_grade_instances(new_category_ids)
function update_all_submission_answer_grades (line 28) | def update_all_submission_answer_grades
function preload_criterions_per_category (line 43) | def preload_criterions_per_category
FILE: app/controllers/concerns/course/assessment/question/rubric_based_response_question_concern.rb
type Course::Assessment::Question::RubricBasedResponseQuestionConcern (line 2) | module Course::Assessment::Question::RubricBasedResponseQuestionConcern
function construct_answer_score_array (line 5) | def construct_answer_score_array
function total_grade_for (line 14) | def total_grade_for(selections, maximum_grade)
function grade_value (line 20) | def grade_value(selection)
function answer_object (line 24) | def answer_object(answer, total_grade)
FILE: app/controllers/concerns/course/assessment/question_bundle_assignment_concern.rb
type Course::Assessment::QuestionBundleAssignmentConcern (line 2) | module Course::Assessment::QuestionBundleAssignmentConcern
class AssignmentSet (line 26) | class AssignmentSet
method initialize (line 29) | def initialize(students, group_bundles)
method add_assignment (line 37) | def add_assignment(student, bundle)
class AssignmentRandomizer (line 48) | class AssignmentRandomizer
method initialize (line 51) | def initialize(assessment)
method load (line 64) | def load
method save (line 72) | def save(assignment_set)
method randomize (line 90) | def randomize
method validate (line 101) | def validate(assignment_set)
method validate_no_overlapping_questions (line 112) | def validate_no_overlapping_questions
method validate_no_empty_groups (line 129) | def validate_no_empty_groups
method validate_one_bundle_assigned (line 143) | def validate_one_bundle_assigned(assignment_set)
method validate_no_repeat_bundles (line 170) | def validate_no_repeat_bundles(assignment_set)
method t_scoped (line 204) | def t_scoped(key, *args, **kwargs)
FILE: app/controllers/concerns/course/assessment/submission/koditsu/answers_concern.rb
type Course::Assessment::Submission::Koditsu::AnswersConcern (line 2) | module Course::Assessment::Submission::Koditsu::AnswersConcern
function build_answer_hash (line 5) | def build_answer_hash(answers)
function destroy_all_existing_autogradings (line 13) | def destroy_all_existing_autogradings(answers)
function destroy_all_existing_files (line 17) | def destroy_all_existing_files(answers)
function update_all_submission_files (line 23) | def update_all_submission_files(submission_answers)
function process_all_answers (line 40) | def process_all_answers(submission_answers)
function process_all_test_case_results (line 46) | def process_all_test_case_results(submission_answers)
function update_all_answer_status (line 63) | def update_all_answer_status(submission_answers)
function build_answer_object (line 74) | def build_answer_object(question, answer, submitted_answer)
function save_all_test_case_results (line 86) | def save_all_test_case_results(submission_answers)
function new_autograding_id (line 106) | def new_autograding_id(answer)
FILE: app/controllers/concerns/course/assessment/submission/koditsu/submission_times_concern.rb
type Course::Assessment::Submission::Koditsu::SubmissionTimesConcern (line 2) | module Course::Assessment::Submission::Koditsu::SubmissionTimesConcern
function calculate_submission_time (line 5) | def calculate_submission_time(state, questions)
function final_submission_time (line 17) | def final_submission_time(attempted_questions)
FILE: app/controllers/concerns/course/assessment/submission/koditsu/submissions_concern.rb
type Course::Assessment::Submission::Koditsu::SubmissionsConcern (line 2) | module Course::Assessment::Submission::Koditsu::SubmissionsConcern
function fetch_all_submissions_from_koditsu (line 10) | def fetch_all_submissions_from_koditsu(assessment, user)
function process_fetch_submissions_response (line 21) | def process_fetch_submissions_response(response)
function submission_status_hash (line 32) | def submission_status_hash
function process_all_submissions (line 39) | def process_all_submissions
function process_submission (line 51) | def process_submission(submission, cm_submission)
function create_new_submissions_if_not_existing (line 61) | def create_new_submissions_if_not_existing
function create_new_submission_for (line 78) | def create_new_submission_for(creator, course_user)
function update_submission (line 90) | def update_submission(cm_submission, state, submitted_at)
function process_submission_answers (line 98) | def process_submission_answers(submission, cm_submission)
FILE: app/controllers/concerns/course/assessment/submission/koditsu/test_cases_concern.rb
type Course::Assessment::Submission::Koditsu::TestCasesConcern (line 2) | module Course::Assessment::Submission::Koditsu::TestCasesConcern
function test_cases_order_for (line 5) | def test_cases_order_for(questions)
function order_test_cases_type (line 14) | def order_test_cases_type
function sort_for_koditsu (line 22) | def sort_for_koditsu(test_cases)
FILE: app/controllers/concerns/course/assessment/submission/koditsu/users_concern.rb
type Course::Assessment::Submission::Koditsu::UsersConcern (line 2) | module Course::Assessment::Submission::Koditsu::UsersConcern
function user_related_hash (line 5) | def user_related_hash(user_ids)
function course_user_submission_hash (line 17) | def course_user_submission_hash(submissions)
function email_course_user_hash (line 26) | def email_course_user_hash(emails)
function email_submission_hash (line 39) | def email_submission_hash(submissions)
FILE: app/controllers/concerns/course/assessment/submission/monitoring_concern.rb
type Course::Assessment::Submission::MonitoringConcern (line 2) | module Course::Assessment::Submission::MonitoringConcern
function should_monitor? (line 11) | def should_monitor? # rubocop:disable Metrics/CyclomaticComplexity
function monitoring_service (line 20) | def monitoring_service
function monitoring_component_enabled? (line 28) | def monitoring_component_enabled?
function can_update_monitoring_session? (line 32) | def can_update_monitoring_session?
function stop_monitoring_session_if_submitted (line 36) | def stop_monitoring_session_if_submitted
function check_blocked_by_monitor (line 40) | def check_blocked_by_monitor
function blocked_by_monitor? (line 44) | def blocked_by_monitor?
FILE: app/controllers/concerns/course/assessment/submission/submissions_controller_service_concern.rb
type Course::Assessment::Submission::SubmissionsControllerServiceConcern (line 2) | module Course::Assessment::Submission::SubmissionsControllerServiceConcern
function service_class (line 10) | def service_class
function service (line 17) | def service
function extract_instance_variables (line 25) | def extract_instance_variables(service)
type ClassMethods (line 32) | module ClassMethods
function delegate_to_service (line 36) | def delegate_to_service(action)
FILE: app/controllers/concerns/course/assessment/submission_concern.rb
type Course::Assessment::SubmissionConcern (line 2) | module Course::Assessment::SubmissionConcern
function authorize_submission! (line 7) | def authorize_submission!
function check_password (line 15) | def check_password
function authentication_service (line 25) | def authentication_service
function log_service (line 30) | def log_service
function new_session_path (line 35) | def new_session_path
FILE: app/controllers/concerns/course/assessment_conditional_concern.rb
type Course::AssessmentConditionalConcern (line 2) | module Course::AssessmentConditionalConcern
function success_action (line 5) | def success_action
function set_conditional (line 9) | def set_conditional
function conditional_params (line 15) | def conditional_params
FILE: app/controllers/concerns/course/cikgo_chats_concern.rb
type Course::CikgoChatsConcern (line 2) | module Course::CikgoChatsConcern
function find_or_create_room (line 5) | def find_or_create_room(course_user)
function get_mission_control_url (line 13) | def get_mission_control_url(course_user)
function create_cikgo_user (line 19) | def create_cikgo_user(user)
FILE: app/controllers/concerns/course/cikgo_push_concern.rb
type Course::CikgoPushConcern (line 2) | module Course::CikgoPushConcern
function push_lesson_plan_items_to_remote_course (line 8) | def push_lesson_plan_items_to_remote_course
function pushable_lesson_plan_items (line 29) | def pushable_lesson_plan_items
FILE: app/controllers/concerns/course/discussion/posts_concern.rb
type Course::Discussion::PostsConcern (line 2) | module Course::Discussion::PostsConcern
function update_topic_pending_status (line 18) | def update_topic_pending_status
function skip_update_topic_status (line 29) | def skip_update_topic_status
function create_topic_subscription (line 36) | def create_topic_subscription
function discussion_topic (line 44) | def discussion_topic
function post_params (line 50) | def post_params
function set_topic (line 55) | def set_topic
FILE: app/controllers/concerns/course/forum/auto_answering_concern.rb
type Course::Forum::AutoAnsweringConcern (line 2) | module Course::Forum::AutoAnsweringConcern
function auto_answer_action (line 5) | def auto_answer_action(query_post, topic, is_regenerated_response: false)
function publish_post_action (line 20) | def publish_post_action
function last_rag_auto_answering_job (line 27) | def last_rag_auto_answering_job
function rag_settings (line 34) | def rag_settings
function publish_post (line 42) | def publish_post(post, topic, current_author, current_course_author)
function create_topic_subscription (line 59) | def create_topic_subscription(topic, current_user)
function send_created_notification (line 67) | def send_created_notification(current_author, current_course_author, p...
function response_should_not_be_generated? (line 75) | def response_should_not_be_generated?(is_regenerated_response)
FILE: app/controllers/concerns/course/forum/topic_controller_hiding_concern.rb
type Course::Forum::TopicControllerHidingConcern (line 2) | module Course::Forum::TopicControllerHidingConcern
function set_hidden (line 5) | def set_hidden
function hidden_params (line 15) | def hidden_params
FILE: app/controllers/concerns/course/forum/topic_controller_locking_concern.rb
type Course::Forum::TopicControllerLockingConcern (line 2) | module Course::Forum::TopicControllerLockingConcern
function set_locked (line 5) | def set_locked
function locked_params (line 15) | def locked_params
FILE: app/controllers/concerns/course/forum/topic_controller_subscription_concern.rb
type Course::Forum::TopicControllerSubscriptionConcern (line 2) | module Course::Forum::TopicControllerSubscriptionConcern
function subscribe (line 5) | def subscribe
function set_subscription_state (line 16) | def set_subscription_state
function subscribe? (line 24) | def subscribe?
FILE: app/controllers/concerns/course/group/group_manager_concern.rb
type Course::Group::GroupManagerConcern (line 2) | module Course::Group::GroupManagerConcern
function manageable_groups (line 4) | def manageable_groups
function viewable_group_categories (line 8) | def viewable_group_categories
FILE: app/controllers/concerns/course/koditsu_workspace_concern.rb
type Course::KoditsuWorkspaceConcern (line 2) | module Course::KoditsuWorkspaceConcern
function setup_koditsu_workspace (line 5) | def setup_koditsu_workspace
FILE: app/controllers/concerns/course/lesson_plan/acts_as_lesson_plan_item_concern.rb
type Course::LessonPlan::ActsAsLessonPlanItemConcern (line 2) | module Course::LessonPlan::ActsAsLessonPlanItemConcern
type ClassMethods (line 5) | module ClassMethods
function build_and_authorize_new_lesson_plan_item (line 8) | def build_and_authorize_new_lesson_plan_item(item_name, options)
FILE: app/controllers/concerns/course/lesson_plan/learning_rate_concern.rb
type Course::LessonPlan::LearningRateConcern (line 2) | module Course::LessonPlan::LearningRateConcern
function lesson_plan_items_submission_time_hash (line 14) | def lesson_plan_items_submission_time_hash(course_user)
function compute_learning_rate_ema (line 31) | def compute_learning_rate_ema(course_user, items_affecting_personal_ti...
function compute_learning_rate_effective_limits (line 70) | def compute_learning_rate_effective_limits(course_user, items, submitt...
function lesson_plan_items_with_sorted_times_for (line 90) | def lesson_plan_items_with_sorted_times_for(course_user)
function merge_course_assessments (line 108) | def merge_course_assessments(hash, course_user)
function merge_course_videos (line 125) | def merge_course_videos(hash, course_user)
function merge_course_stories (line 135) | def merge_course_stories(hash, course_user)
FILE: app/controllers/concerns/course/lesson_plan/personalization_concern.rb
type Course::LessonPlan::PersonalizationConcern (line 2) | module Course::LessonPlan::PersonalizationConcern
function update_personalized_timeline_for_user (line 21) | def update_personalized_timeline_for_user(course_user, timeline_algori...
function update_personalized_timeline_for_item (line 51) | def update_personalized_timeline_for_item(lesson_plan_item)
FILE: app/controllers/concerns/course/lesson_plan/stories_concern.rb
type Course::LessonPlan::StoriesConcern (line 2) | module Course::LessonPlan::StoriesConcern
function delete_all_future_stories_personal_times (line 5) | def delete_all_future_stories_personal_times(course_user)
function stories_for (line 20) | def stories_for(course_user)
FILE: app/controllers/concerns/course/lesson_plan/strategies/base_personalization_strategy.rb
class Course::LessonPlan::Strategies::BasePersonalizationStrategy (line 4) | class Course::LessonPlan::Strategies::BasePersonalizationStrategy
method precompute_data (line 30) | def precompute_data(course_user) # rubocop:disable Metrics/AbcSize, Me...
method execute (line 58) | def execute(_course_user, _precomputed_data, _items_to_shift = nil)
method round_to_date (line 70) | def round_to_date(datetime, course_tz, to_2359: false)
FILE: app/controllers/concerns/course/lesson_plan/strategies/fixed_personalization_strategy.rb
class Course::LessonPlan::Strategies::FixedPersonalizationStrategy (line 2) | class Course::LessonPlan::Strategies::FixedPersonalizationStrategy <
method precompute_data (line 9) | def precompute_data(course_user)
method execute (line 20) | def execute(course_user, precompute_data, _items_to_shift)
FILE: app/controllers/concerns/course/lesson_plan/strategies/fomo_personalization_strategy.rb
class Course::LessonPlan::Strategies::FomoPersonalizationStrategy (line 2) | class Course::LessonPlan::Strategies::FomoPersonalizationStrategy <
method execute (line 18) | def execute(course_user, precomputed_data, items_to_shift = nil) # rub...
method update_points (line 55) | def update_points(course_user, item, submitted_items, reference_point,...
method cannot_shift_item (line 78) | def cannot_shift_item(course_user, item, submitted_items, items_to_shift)
method item_is_straggling (line 83) | def item_is_straggling(personal_time, reference_time)
method item_is_open_and_straggling (line 100) | def item_is_open_and_straggling(personal_time, reference_time)
method shift_start_at (line 118) | def shift_start_at(personal_time, reference_time, personal_point, refe...
method reset_bonus_end_at (line 135) | def reset_bonus_end_at(personal_time, reference_time)
method reset_end_at (line 146) | def reset_end_at(personal_time, reference_time)
FILE: app/controllers/concerns/course/lesson_plan/strategies/otot_personalization_strategy.rb
class Course::LessonPlan::Strategies::OtotPersonalizationStrategy (line 2) | class Course::LessonPlan::Strategies::OtotPersonalizationStrategy <
method precompute_data (line 10) | def precompute_data(course_user) # rubocop:disable Metrics/AbcSize, Me...
method execute (line 43) | def execute(course_user, precomputed_data, items_to_shift = nil)
FILE: app/controllers/concerns/course/lesson_plan/strategies/stragglers_personalization_strategy.rb
class Course::LessonPlan::Strategies::StragglersPersonalizationStrategy (line 2) | class Course::LessonPlan::Strategies::StragglersPersonalizationStrategy <
method execute (line 19) | def execute(course_user, precomputed_data, items_to_shift = nil) # rub...
method update_points (line 60) | def update_points(course_user, item, submitted_items, reference_point,...
method cannot_shift_item (line 85) | def cannot_shift_item(course_user, item, submitted_items, reference_po...
method reset_start_at (line 96) | def reset_start_at(personal_time, reference_time)
method reset_bonus_end_at (line 107) | def reset_bonus_end_at(personal_time, reference_time)
method shift_end_at (line 125) | def shift_end_at(personal_time, reference_time, personal_point, refere...
method fix_items (line 154) | def fix_items(course_user, items, submitted_items)
FILE: app/controllers/concerns/course/reminder_service_concern.rb
type Course::ReminderServiceConcern (line 2) | module Course::ReminderServiceConcern
function name_list (line 10) | def name_list(course_users)
FILE: app/controllers/concerns/course/scholaistic/concern.rb
type Course::Scholaistic::Concern (line 2) | module Course::Scholaistic::Concern
function scholaistic_course_linked? (line 9) | def scholaistic_course_linked?
function can_attempt_scholaistic_assessment? (line 14) | def can_attempt_scholaistic_assessment?(assessment)
function sync_all_scholaistic_submissions! (line 20) | def sync_all_scholaistic_submissions!
function primary_email_to_user_id (line 81) | def primary_email_to_user_id
function build_assessments_hash_and_submission_ids_set (line 88) | def build_assessments_hash_and_submission_ids_set
function user_id_to_course_user (line 110) | def user_id_to_course_user
FILE: app/controllers/concerns/course/ssid_folder_concern.rb
type Course::SsidFolderConcern (line 2) | module Course::SsidFolderConcern
function sync_course_ssid_folder (line 5) | def sync_course_ssid_folder(course)
function sync_assessment_ssid_folder (line 12) | def sync_assessment_ssid_folder(course, assessment)
function create_ssid_folder (line 24) | def create_ssid_folder(folder_name, parent_folder_id = nil)
FILE: app/controllers/concerns/course/statistics/counts_concern.rb
type Course::Statistics::CountsConcern (line 2) | module Course::Statistics::CountsConcern
function num_attempted_students_hash (line 7) | def num_attempted_students_hash
function num_submitted_students_hash (line 23) | def num_submitted_students_hash
function num_late_students_hash (line 40) | def num_late_students_hash
function latest_submission_time_hash (line 61) | def latest_submission_time_hash
function not_late_hash (line 79) | def not_late_hash(submissions)
function not_late_count (line 96) | def not_late_count(submissions)
function not_late_submission_hash (line 103) | def not_late_submission_hash(assessments, not_late_count)
FILE: app/controllers/concerns/course/statistics/grades_concern.rb
type Course::Statistics::GradesConcern (line 2) | module Course::Statistics::GradesConcern
function grade_statistics_hash (line 5) | def grade_statistics_hash
function max_grade_statistics_hash (line 25) | def max_grade_statistics_hash
FILE: app/controllers/concerns/course/statistics/reference_times_concern.rb
type Course::Statistics::ReferenceTimesConcern (line 2) | module Course::Statistics::ReferenceTimesConcern
function personal_end_at_hash (line 5) | def personal_end_at_hash(assessment_id_array, course_id)
function reference_times_hash (line 68) | def reference_times_hash(assessment_id_array, course_id)
FILE: app/controllers/concerns/course/statistics/submissions_concern.rb
type Course::Statistics::SubmissionsConcern (line 2) | module Course::Statistics::SubmissionsConcern
function initialize_student_hash (line 7) | def initialize_student_hash(students)
function fetch_hash_for_main_assessment (line 11) | def fetch_hash_for_main_assessment(submissions, students)
function fetch_hash_for_ancestor_assessment (line 18) | def fetch_hash_for_ancestor_assessment(submissions, students)
function answer_statistics_hash (line 25) | def answer_statistics_hash
function populate_hash_including_answers (line 88) | def populate_hash_including_answers(student_hash, submissions)
function populate_hash_without_answers (line 104) | def populate_hash_without_answers(student_hash, submissions)
function fetch_personal_and_reference_timeline_hash (line 118) | def fetch_personal_and_reference_timeline_hash
FILE: app/controllers/concerns/course/statistics/times_concern.rb
type Course::Statistics::TimesConcern (line 2) | module Course::Statistics::TimesConcern
function duration_statistics_hash (line 5) | def duration_statistics_hash
FILE: app/controllers/concerns/course/statistics/users_concern.rb
type Course::Statistics::UsersConcern (line 2) | module Course::Statistics::UsersConcern
function group_names_hash (line 5) | def group_names_hash
FILE: app/controllers/concerns/course/survey/reordering_concern.rb
type Course::Survey::ReorderingConcern (line 2) | module Course::Survey::ReorderingConcern
function reorder_sections (line 5) | def reorder_sections
function reorder_questions (line 14) | def reorder_questions
function ordered_section_ids (line 25) | def ordered_section_ids
function reorder_params (line 32) | def reorder_params
function valid_section_ordering? (line 40) | def valid_section_ordering?(proposed_ordering)
function valid_question_ordering? (line 51) | def valid_question_ordering?(proposed_ordering)
function valid_section_ids? (line 63) | def valid_section_ids?(section_ids, require_all: false)
function valid_question_ids? (line 75) | def valid_question_ids?(question_ids)
function update_sections_ordering (line 83) | def update_sections_ordering(ordering)
function update_questions_ordering (line 97) | def update_questions_ordering(ordering)
function update_question_ordering (line 114) | def update_question_ordering(question, weight, section_id)
FILE: app/controllers/concerns/course/unread_counts_concern.rb
type Course::UnreadCountsConcern (line 2) | module Course::UnreadCountsConcern
function unread_announcements_count (line 7) | def unread_announcements_count
function unread_forum_topics_count (line 13) | def unread_forum_topics_count
function unwatched_videos_count (line 19) | def unwatched_videos_count
function pending_enrol_requests_count (line 25) | def pending_enrol_requests_count
function pending_assessment_submissions_count (line 35) | def pending_assessment_submissions_count
function unread_comments_count (line 47) | def unread_comments_count # rubocop:disable Metrics/PerceivedComplexit...
FILE: app/controllers/concerns/course/users_controller_management_concern.rb
type Course::UsersControllerManagementConcern (line 2) | module Course::UsersControllerManagementConcern
function update (line 15) | def update
function destroy (line 27) | def destroy
function students (line 35) | def students
function staff (line 43) | def staff
function upgrade_to_staff (line 52) | def upgrade_to_staff
function assign_timeline (line 61) | def assign_timeline
function suspend (line 84) | def suspend
function unsuspend (line 101) | def unsuspend
function should_update_personalized_timeline (line 120) | def should_update_personalized_timeline
function course_user_params (line 124) | def course_user_params
function upgrade_to_staff_params (line 130) | def upgrade_to_staff_params
function assign_timeline_params (line 135) | def assign_timeline_params
function suspend_params (line 139) | def suspend_params
function unsuspend_params (line 143) | def unsuspend_params
function load_resource (line 147) | def load_resource
function upgrade_students_to_staff (line 159) | def upgrade_students_to_staff
function authorize_show! (line 173) | def authorize_show!
function authorize_edit! (line 178) | def authorize_edit!
function update_request_origin (line 183) | def update_request_origin
function delete_redirect_path (line 193) | def delete_redirect_path
function upgrade_to_staff_success (line 201) | def upgrade_to_staff_success
function upgrade_to_staff_failure (line 211) | def upgrade_to_staff_failure
function update_user_success (line 217) | def update_user_success
function update_user_failure (line 230) | def update_user_failure
function destroy_user_success (line 236) | def destroy_user_success
function destroy_user_failure (line 242) | def destroy_user_failure
FILE: app/controllers/concerns/signals/emission_concern.rb
type Signals::EmissionConcern (line 2) | module Signals::EmissionConcern
type ClassMethods (line 9) | module ClassMethods
function signals (line 12) | def signals(slice_name, options = {})
function slice_class_name (line 28) | def slice_class_name(slice_name)
function slice_class (line 32) | def slice_class(slice_name)
function generate_sync_method_name (line 36) | def generate_sync_method_name(slice_name)
FILE: app/controllers/concerns/signals/slices/announcements.rb
type Signals::Slices::Announcements (line 2) | module Signals::Slices::Announcements
function generate_sync_for_announcements (line 5) | def generate_sync_for_announcements
FILE: app/controllers/concerns/signals/slices/assessment_submissions.rb
type Signals::Slices::AssessmentSubmissions (line 2) | module Signals::Slices::AssessmentSubmissions
function generate_sync_for_assessment_submissions (line 5) | def generate_sync_for_assessment_submissions
FILE: app/controllers/concerns/signals/slices/cikgo_mission_control.rb
type Signals::Slices::CikgoMissionControl (line 2) | module Signals::Slices::CikgoMissionControl
function generate_sync_for_cikgo_mission_control (line 3) | def generate_sync_for_cikgo_mission_control
FILE: app/controllers/concerns/signals/slices/cikgo_open_threads_count.rb
type Signals::Slices::CikgoOpenThreadsCount (line 2) | module Signals::Slices::CikgoOpenThreadsCount
function generate_sync_for_cikgo_open_threads_count (line 3) | def generate_sync_for_cikgo_open_threads_count
FILE: app/controllers/concerns/signals/slices/comments.rb
type Signals::Slices::Comments (line 2) | module Signals::Slices::Comments
function generate_sync_for_comments (line 5) | def generate_sync_for_comments
FILE: app/controllers/concerns/signals/slices/enrol_requests.rb
type Signals::Slices::EnrolRequests (line 2) | module Signals::Slices::EnrolRequests
function generate_sync_for_enrol_requests (line 5) | def generate_sync_for_enrol_requests
FILE: app/controllers/concerns/signals/slices/forums.rb
type Signals::Slices::Forums (line 2) | module Signals::Slices::Forums
function generate_sync_for_forums (line 5) | def generate_sync_for_forums
FILE: app/controllers/concerns/signals/slices/videos.rb
type Signals::Slices::Videos (line 2) | module Signals::Slices::Videos
function generate_sync_for_videos (line 5) | def generate_sync_for_videos
FILE: app/controllers/course/achievement/achievements_controller.rb
class Course::Achievement::AchievementsController (line 2) | class Course::Achievement::AchievementsController < Course::Achievement:...
method index (line 5) | def index
method show (line 9) | def show
method create (line 16) | def create
method update (line 26) | def update
method destroy (line 39) | def destroy
method reorder (line 47) | def reorder
method achievement_course_users (line 59) | def achievement_course_users
method achievement_params (line 77) | def achievement_params
method achievement_order_params (line 85) | def achievement_order_params
method authorize_achievement! (line 90) | def authorize_achievement!
method achievements_hash (line 97) | def achievements_hash
method valid_ordering? (line 107) | def valid_ordering?(proposed_ordering)
FILE: app/controllers/course/achievement/condition/achievements_controller.rb
class Course::Achievement::Condition::AchievementsController (line 2) | class Course::Achievement::Condition::AchievementsController <
FILE: app/controllers/course/achievement/condition/assessments_controller.rb
class Course::Achievement::Condition::AssessmentsController (line 2) | class Course::Achievement::Condition::AssessmentsController <
FILE: app/controllers/course/achievement/condition/levels_controller.rb
class Course::Achievement::Condition::LevelsController (line 2) | class Course::Achievement::Condition::LevelsController < Course::Conditi...
FILE: app/controllers/course/achievement/condition/scholaistic_assessments_controller.rb
class Course::Achievement::Condition::ScholaisticAssessmentsController (line 2) | class Course::Achievement::Condition::ScholaisticAssessmentsController <
FILE: app/controllers/course/achievement/condition/surveys_controller.rb
class Course::Achievement::Condition::SurveysController (line 2) | class Course::Achievement::Condition::SurveysController < Course::Condit...
FILE: app/controllers/course/achievement/controller.rb
class Course::Achievement::Controller (line 2) | class Course::Achievement::Controller < Course::ComponentController
method component (line 11) | def component
FILE: app/controllers/course/admin/admin_controller.rb
class Course::Admin::AdminController (line 2) | class Course::Admin::AdminController < Course::Admin::Controller
method index (line 3) | def index
method update (line 9) | def update
method destroy (line 24) | def destroy
method suspend (line 33) | def suspend
method unsuspend (line 39) | def unsuspend
method course_setting_params (line 47) | def course_setting_params
method destroy_success (line 58) | def destroy_success
method destroy_failure (line 62) | def destroy_failure
method shift_all_items (line 66) | def shift_all_items
method time_offset_params (line 78) | def time_offset_params
FILE: app/controllers/course/admin/announcement_settings_controller.rb
class Course::Admin::AnnouncementSettingsController (line 2) | class Course::Admin::AnnouncementSettingsController < Course::Admin::Con...
method edit (line 3) | def edit
method update (line 9) | def update
method announcement_settings_params (line 19) | def announcement_settings_params
method component (line 23) | def component
FILE: app/controllers/course/admin/assessment_settings_controller.rb
class Course::Admin::AssessmentSettingsController (line 2) | class Course::Admin::AssessmentSettingsController < Course::Admin::Contr...
method edit (line 3) | def edit
method update (line 9) | def update
method move_assessments (line 17) | def move_assessments
method move_tabs (line 36) | def move_tabs
method move_assessments_params (line 56) | def move_assessments_params
method move_tabs_params (line 60) | def move_tabs_params
method category_params (line 64) | def category_params
method component (line 88) | def component
FILE: app/controllers/course/admin/assessments/categories_controller.rb
class Course::Admin::Assessments::CategoriesController (line 2) | class Course::Admin::Assessments::CategoriesController < Course::Admin::...
method new (line 8) | def new
method create (line 11) | def create
method destroy (line 19) | def destroy
method category_params (line 34) | def category_params
method component (line 40) | def component
FILE: app/controllers/course/admin/assessments/tabs_controller.rb
class Course::Admin::Assessments::TabsController (line 2) | class Course::Admin::Assessments::TabsController < Course::Admin::Contro...
method new (line 11) | def new
method create (line 14) | def create
method destroy (line 22) | def destroy
method tab_params (line 34) | def tab_params
method component (line 40) | def component
FILE: app/controllers/course/admin/codaveri_settings_controller.rb
class Course::Admin::CodaveriSettingsController (line 2) | class Course::Admin::CodaveriSettingsController < Course::Admin::Controller
method edit (line 3) | def edit
method assessment (line 7) | def assessment
method update (line 12) | def update
method update_evaluator (line 24) | def update_evaluator
method update_live_feedback_enabled (line 31) | def update_live_feedback_enabled
method assessment_params (line 40) | def assessment_params
method codaveri_settings_params (line 44) | def codaveri_settings_params
method update_evaluator_params (line 51) | def update_evaluator_params
method update_live_feedback_enabled_params (line 55) | def update_live_feedback_enabled_params
method component (line 59) | def component
method load_course_assessments_data (line 63) | def load_course_assessments_data
FILE: app/controllers/course/admin/component_settings_controller.rb
class Course::Admin::ComponentSettingsController (line 2) | class Course::Admin::ComponentSettingsController < Course::Admin::Contro...
method edit (line 7) | def edit
method update (line 13) | def update # rubocop:disable Metrics/AbcSize
method settings_components_params (line 31) | def settings_components_params
method load_settings (line 36) | def load_settings
FILE: app/controllers/course/admin/controller.rb
class Course::Admin::Controller (line 2) | class Course::Admin::Controller < Course::ComponentController
method authorize_admin (line 7) | def authorize_admin
method component (line 13) | def component
FILE: app/controllers/course/admin/discussion/topic_settings_controller.rb
class Course::Admin::Discussion::TopicSettingsController (line 2) | class Course::Admin::Discussion::TopicSettingsController < Course::Admin...
method edit (line 3) | def edit
method update (line 9) | def update
method topic_settings_params (line 19) | def topic_settings_params
method component (line 23) | def component
FILE: app/controllers/course/admin/forum_settings_controller.rb
class Course::Admin::ForumSettingsController (line 2) | class Course::Admin::ForumSettingsController < Course::Admin::Controller
method edit (line 3) | def edit
method update (line 9) | def update
method forum_settings_params (line 19) | def forum_settings_params
method component (line 24) | def component
FILE: app/controllers/course/admin/leaderboard_settings_controller.rb
class Course::Admin::LeaderboardSettingsController (line 2) | class Course::Admin::LeaderboardSettingsController < Course::Admin::Cont...
method edit (line 3) | def edit
method update (line 9) | def update
method leaderboard_settings_params (line 19) | def leaderboard_settings_params
method component (line 24) | def component
FILE: app/controllers/course/admin/lesson_plan_settings_controller.rb
class Course::Admin::LessonPlanSettingsController (line 2) | class Course::Admin::LessonPlanSettingsController < Course::Admin::Contr...
method edit (line 5) | def edit
method update (line 11) | def update
method update_lesson_plan_items_settings (line 23) | def update_lesson_plan_items_settings
method update_lesson_plan_component_settings (line 28) | def update_lesson_plan_component_settings
method lesson_plan_item_settings_params (line 33) | def lesson_plan_item_settings_params
method load_item_settings (line 40) | def load_item_settings
method page_data (line 44) | def page_data
method component (line 51) | def component
FILE: app/controllers/course/admin/material_settings_controller.rb
class Course::Admin::MaterialSettingsController (line 2) | class Course::Admin::MaterialSettingsController < Course::Admin::Controller
method edit (line 3) | def edit
method update (line 9) | def update
method material_settings_params (line 19) | def material_settings_params
method component (line 23) | def component
FILE: app/controllers/course/admin/notification_settings_controller.rb
class Course::Admin::NotificationSettingsController (line 2) | class Course::Admin::NotificationSettingsController < Course::Admin::Con...
method edit (line 3) | def edit
method update (line 9) | def update
method page_data (line 19) | def page_data
method notification_settings_params (line 23) | def notification_settings_params
method notification_enabled_params (line 27) | def notification_enabled_params
FILE: app/controllers/course/admin/rag_wise_settings_controller.rb
class Course::Admin::RagWiseSettingsController (line 2) | class Course::Admin::RagWiseSettingsController < Course::Admin::Controller
method edit (line 5) | def edit
method update (line 11) | def update
method materials (line 19) | def materials
method folders (line 24) | def folders
method courses (line 28) | def courses
method forums (line 42) | def forums
method import_course_forums (line 54) | def import_course_forums
method destroy_imported_discussions (line 73) | def destroy_imported_discussions
method authorize_import_forums (line 84) | def authorize_import_forums
method set_parent_courses (line 89) | def set_parent_courses
method rag_wise_settings_params (line 104) | def rag_wise_settings_params
method import_course_forum_params (line 108) | def import_course_forum_params
method component (line 112) | def component
method last_forum_importing_job (line 116) | def last_forum_importing_job
FILE: app/controllers/course/admin/scholaistic_settings_controller.rb
class Course::Admin::ScholaisticSettingsController (line 2) | class Course::Admin::ScholaisticSettingsController < Course::Admin::Cont...
method edit (line 6) | def edit
method update (line 10) | def update
method confirm_link_course (line 18) | def confirm_link_course
method link_course (line 25) | def link_course
method unlink_course (line 37) | def unlink_course
method publicly_accessible? (line 56) | def publicly_accessible?
method scholaistic_settings_params (line 62) | def scholaistic_settings_params
method component (line 66) | def component
method render_settings (line 70) | def render_settings
FILE: app/controllers/course/admin/sidebar_settings_controller.rb
class Course::Admin::SidebarSettingsController (line 2) | class Course::Admin::SidebarSettingsController < Course::Admin::Controller
method edit (line 5) | def edit
method update (line 11) | def update
method settings_sidebar_params (line 21) | def settings_sidebar_params
method load_settings (line 26) | def load_settings
FILE: app/controllers/course/admin/stories_settings_controller.rb
class Course::Admin::StoriesSettingsController (line 2) | class Course::Admin::StoriesSettingsController < Course::Admin::Controller
method edit (line 8) | def edit
method update (line 11) | def update
method ping_remote_course (line 24) | def ping_remote_course
method stories_settings_params (line 33) | def stories_settings_params
method component (line 37) | def component
FILE: app/controllers/course/admin/video_settings_controller.rb
class Course::Admin::VideoSettingsController (line 2) | class Course::Admin::VideoSettingsController < Course::Admin::Controller
method edit (line 3) | def edit
method update (line 9) | def update
method video_settings_params (line 21) | def video_settings_params
method video_tabs_params (line 25) | def video_tabs_params
method component (line 32) | def component
FILE: app/controllers/course/admin/videos/tabs_controller.rb
class Course::Admin::Videos::TabsController (line 2) | class Course::Admin::Videos::TabsController < Course::Admin::Controller
method new (line 8) | def new
method create (line 11) | def create
method destroy (line 19) | def destroy
method tab_params (line 29) | def tab_params
method component (line 35) | def component
FILE: app/controllers/course/announcements_controller.rb
class Course::AnnouncementsController (line 2) | class Course::AnnouncementsController < Course::ComponentController
method index (line 12) | def index
method create (line 21) | def create
method update (line 30) | def update
method destroy (line 40) | def destroy
method announcement_params (line 50) | def announcement_params
method component (line 56) | def component
method mark_announcements_as_read (line 60) | def mark_announcements_as_read
FILE: app/controllers/course/assessment/assessments_controller.rb
class Course::Assessment::AssessmentsController (line 2) | class Course::Assessment::AssessmentsController < Course::Assessment::Co...
method index (line 18) | def index
method show (line 35) | def show
method new (line 51) | def new
method create (line 54) | def create
method edit (line 70) | def edit
method update (line 79) | def update
method destroy (line 97) | def destroy
method sync_with_koditsu (line 109) | def sync_with_koditsu
method invite_to_koditsu (line 148) | def invite_to_koditsu
method reorder (line 167) | def reorder
method authenticate (line 185) | def authenticate
method remind (line 194) | def remind
method auto_feedback_count (line 206) | def auto_feedback_count
method publish_auto_feedback (line 215) | def publish_auto_feedback
method requirements (line 232) | def requirements
method statistics (line 241) | def statistics
method plagiarism (line 246) | def plagiarism
method load_assessment_options (line 252) | def load_assessment_options
method load_assessment_submission_counts (line 260) | def load_assessment_submission_counts
method question_order_ids (line 265) | def question_order_ids
method assessment_params (line 272) | def assessment_params
method auto_feedback_count_params (line 286) | def auto_feedback_count_params
method publish_auto_feedback_params (line 290) | def publish_auto_feedback_params
method autograded_params (line 294) | def autograded_params
method autograded? (line 304) | def autograded?
method tab_params (line 316) | def tab_params
method skip_tab_filter? (line 325) | def skip_tab_filter?
method tab (line 329) | def tab
method category (line 340) | def category
method load_question_duplication_data (line 351) | def load_question_duplication_data
method question_assessments_hash (line 358) | def question_assessments_hash
method valid_ordering? (line 368) | def valid_ordering?(proposed_ordering)
method create_koditsu_invitation_job (line 372) | def create_koditsu_invitation_job
method execute_koditsu_invitation_job_later (line 387) | def execute_koditsu_invitation_job_later
method create_fetch_koditsu_submissions_job (line 393) | def create_fetch_koditsu_submissions_job
method compound_tab_titles (line 410) | def compound_tab_titles
method ordered_assessments_by_tab (line 428) | def ordered_assessments_by_tab
method student_course_users (line 443) | def student_course_users
method can_access_assessment? (line 447) | def can_access_assessment?
method authentication_service (line 453) | def authentication_service
method submissions (line 457) | def submissions
method draft_file_annotation_posts (line 467) | def draft_file_annotation_posts(course_users)
FILE: app/controllers/course/assessment/categories_controller.rb
class Course::Assessment::CategoriesController (line 2) | class Course::Assessment::CategoriesController < Course::ComponentContro...
method index (line 11) | def index; end
method component (line 20) | def component
FILE: app/controllers/course/assessment/component_controller.rb
class Course::Assessment::ComponentController (line 2) | class Course::Assessment::ComponentController < Course::Assessment::Cont...
FILE: app/controllers/course/assessment/condition/achievements_controller.rb
class Course::Assessment::Condition::AchievementsController (line 2) | class Course::Assessment::Condition::AchievementsController <
FILE: app/controllers/course/assessment/condition/assessments_controller.rb
class Course::Assessment::Condition::AssessmentsController (line 2) | class Course::Assessment::Condition::AssessmentsController <
FILE: app/controllers/course/assessment/condition/levels_controller.rb
class Course::Assessment::Condition::LevelsController (line 2) | class Course::Assessment::Condition::LevelsController < Course::Conditio...
FILE: app/controllers/course/assessment/condition/scholaistic_assessments_controller.rb
class Course::Assessment::Condition::ScholaisticAssessmentsController (line 2) | class Course::Assessment::Condition::ScholaisticAssessmentsController <
FILE: app/controllers/course/assessment/condition/surveys_controller.rb
class Course::Assessment::Condition::SurveysController (line 2) | class Course::Assessment::Condition::SurveysController < Course::Conditi...
FILE: app/controllers/course/assessment/controller.rb
class Course::Assessment::Controller (line 2) | class Course::Assessment::Controller < Course::ComponentController
method load_assessment_options (line 10) | def load_assessment_options
method category (line 14) | def category
method tab (line 18) | def tab
method load_category_and_tab (line 24) | def load_category_and_tab
method load_and_authorize_assessment (line 29) | def load_and_authorize_assessment
method component (line 37) | def component
FILE: app/controllers/course/assessment/mock_answers_controller.rb
class Course::Assessment::MockAnswersController (line 2) | class Course::Assessment::MockAnswersController < Course::Assessment::Qu...
method create (line 5) | def create
method mock_answer_params (line 16) | def mock_answer_params
FILE: app/controllers/course/assessment/question/controller.rb
class Course::Assessment::Question::Controller (line 2) | class Course::Assessment::Question::Controller < Course::Assessment::Com...
method build_and_authorize_new_question (line 14) | def self.build_and_authorize_new_question(question_name, options)
method authorize_create_question_in_koditsu (line 28) | def authorize_create_question_in_koditsu
method flag_not_synced_with_koditsu (line 35) | def flag_not_synced_with_koditsu
method load_question_assessment_for (line 43) | def load_question_assessment_for(question)
method update_skill_ids_if_params_present (line 47) | def update_skill_ids_if_params_present(question_assessment_params)
method destroy (line 52) | def destroy
method authorize_assessment (line 58) | def authorize_assessment
FILE: app/controllers/course/assessment/question/forum_post_responses_controller.rb
class Course::Assessment::Question::ForumPostResponsesController (line 2) | class Course::Assessment::Question::ForumPostResponsesController < Cours...
method create (line 10) | def create
method edit (line 18) | def edit
method update (line 25) | def update
method destroy (line 35) | def destroy
method update_forum_post_response_question (line 48) | def update_forum_post_response_question
method forum_post_response_question_params (line 52) | def forum_post_response_question_params
method load_question_assessment (line 60) | def load_question_assessment
FILE: app/controllers/course/assessment/question/multiple_responses_controller.rb
class Course::Assessment::Question::MultipleResponsesController (line 2) | class Course::Assessment::Question::MultipleResponsesController < Course...
method new (line 11) | def new
method create (line 15) | def create
method edit (line 28) | def edit
method update (line 31) | def update
method destroy (line 51) | def destroy
method generate (line 62) | def generate
method respond_to_switch_mcq_mrq_type (line 88) | def respond_to_switch_mcq_mrq_type
method update_multiple_response_question (line 104) | def update_multiple_response_question
method multiple_response_question_params (line 110) | def multiple_response_question_params
method load_question_assessment (line 119) | def load_question_assessment
method parse_generation_params (line 123) | def parse_generation_params
method parse_source_question_data (line 132) | def parse_source_question_data
method validate_generation_params (line 140) | def validate_generation_params(params)
method format_generation_response (line 146) | def format_generation_response(questions)
method format_options (line 159) | def format_options(options)
method format_question (line 173) | def format_question(question)
FILE: app/controllers/course/assessment/question/programming_controller.rb
class Course::Assessment::Question::ProgrammingController (line 2) | class Course::Assessment::Question::ProgrammingController < Course::Asse...
method new (line 14) | def new
method create (line 20) | def create
method edit (line 33) | def edit
method update (line 42) | def update
method import_result (line 63) | def import_result
method codaveri_languages (line 67) | def codaveri_languages
method generate (line 75) | def generate
method update_question_setting (line 96) | def update_question_setting
method destroy (line 105) | def destroy
method format_test_cases (line 118) | def format_test_cases
method set_attributes_for_programming_question (line 130) | def set_attributes_for_programming_question
method programming_question_params (line 134) | def programming_question_params
method programming_question_setting_params (line 144) | def programming_question_setting_params
method render_success_json (line 148) | def render_success_json(redirect_to_edit)
method render_failure_json (line 152) | def render_failure_json
method process_package (line 156) | def process_package
method programming_package_service (line 164) | def programming_package_service(params = nil)
method load_question_assessment (line 170) | def load_question_assessment
FILE: app/controllers/course/assessment/question/rubric_based_responses_controller.rb
class Course::Assessment::Question::RubricBasedResponsesController (line 2) | class Course::Assessment::Question::RubricBasedResponsesController < Cou...
method create (line 16) | def create
method edit (line 31) | def edit
method update (line 43) | def update
method destroy (line 54) | def destroy
method migrate_rubric (line 65) | def migrate_rubric
method add_bonus_category_to_rubric_based_question (line 73) | def add_bonus_category_to_rubric_based_question
method update_rubric_based_response_question (line 92) | def update_rubric_based_response_question
method rubric_based_response_question_params (line 105) | def rubric_based_response_question_params
method load_question_assessment (line 117) | def load_question_assessment
FILE: app/controllers/course/assessment/question/scribing_controller.rb
class Course::Assessment::Question::ScribingController (line 2) | class Course::Assessment::Question::ScribingController < Course::Assessm...
method new (line 10) | def new
method show (line 16) | def show
method create (line 22) | def create # rubocop:disable Metrics/MethodLength
method edit (line 42) | def edit
method update (line 50) | def update
method destroy (line 61) | def destroy
method scribing_question_params (line 74) | def scribing_question_params
method render_scribing_question_json (line 81) | def render_scribing_question_json
method render_success_json (line 86) | def render_success_json(message)
method render_failure_json (line 90) | def render_failure_json(message)
method file_is_pdf? (line 95) | def file_is_pdf?
method pdf_import_service (line 99) | def pdf_import_service
method load_question_assessment (line 103) | def load_question_assessment
FILE: app/controllers/course/assessment/question/text_responses_controller.rb
class Course::Assessment::Question::TextResponsesController (line 2) | class Course::Assessment::Question::TextResponsesController < Course::As...
method new (line 10) | def new
method create (line 20) | def create
method edit (line 28) | def edit
method update (line 37) | def update
method destroy (line 47) | def destroy
method update_text_response_question (line 60) | def update_text_response_question
method text_response_question_params (line 66) | def text_response_question_params
method load_question_assessment (line 97) | def load_question_assessment
FILE: app/controllers/course/assessment/question/voice_responses_controller.rb
class Course::Assessment::Question::VoiceResponsesController (line 2) | class Course::Assessment::Question::VoiceResponsesController < Course::A...
method create (line 10) | def create
method new (line 18) | def new
method update (line 21) | def update
method edit (line 31) | def edit
method destroy (line 34) | def destroy
method update_voice_response_question (line 47) | def update_voice_response_question
method voice_response_question_params (line 51) | def voice_response_question_params
method load_question_assessment (line 59) | def load_question_assessment
FILE: app/controllers/course/assessment/question_bundle_assignments_controller.rb
class Course::Assessment::QuestionBundleAssignmentsController (line 2) | class Course::Assessment::QuestionBundleAssignmentsController < Course::...
method index (line 7) | def index
method create (line 26) | def create
method edit (line 46) | def edit
method update (line 49) | def update
method destroy (line 57) | def destroy
method recompute (line 66) | def recompute
method past_assignments_hash (line 81) | def past_assignments_hash
FILE: app/controllers/course/assessment/question_bundle_questions_controller.rb
class Course::Assessment::QuestionBundleQuestionsController (line 2) | class Course::Assessment::QuestionBundleQuestionsController < Course::As...
method index (line 7) | def index
method new (line 16) | def new
method create (line 20) | def create
method edit (line 29) | def edit
method update (line 32) | def update
method destroy (line 40) | def destroy
method question_bundle_question_params (line 51) | def question_bundle_question_params
FILE: app/controllers/course/assessment/question_bundles_controller.rb
class Course::Assessment::QuestionBundlesController (line 2) | class Course::Assessment::QuestionBundlesController < Course::Assessment...
method index (line 5) | def index
method new (line 8) | def new
method create (line 11) | def create
method edit (line 19) | def edit
method update (line 22) | def update
method destroy (line 30) | def destroy
method question_bundle_params (line 42) | def question_bundle_params
FILE: app/controllers/course/assessment/question_groups_controller.rb
class Course::Assessment::QuestionGroupsController (line 2) | class Course::Assessment::QuestionGroupsController < Course::Assessment:...
method index (line 5) | def index
method new (line 9) | def new
method create (line 12) | def create
method edit (line 20) | def edit
method update (line 23) | def update
method destroy (line 31) | def destroy
method question_group_params (line 42) | def question_group_params
FILE: app/controllers/course/assessment/questions_controller.rb
class Course::Assessment::QuestionsController (line 2) | class Course::Assessment::QuestionsController < Course::Assessment::Cont...
method duplicate (line 10) | def duplicate
method show (line 20) | def show
method load_and_authorize_assessments (line 26) | def load_and_authorize_assessments
method duplicated_question (line 37) | def duplicated_question
method duplicate_question_and_skills (line 42) | def duplicate_question_and_skills
FILE: app/controllers/course/assessment/rubrics_controller.rb
class Course::Assessment::RubricsController (line 2) | class Course::Assessment::RubricsController < Course::Assessment::Questi...
method index (line 5) | def index
method show (line 16) | def show
method create (line 20) | def create
method destroy (line 30) | def destroy
method rubric_answers (line 34) | def rubric_answers
method fetch_answer_evaluations (line 40) | def fetch_answer_evaluations
method fetch_mock_answer_evaluations (line 44) | def fetch_mock_answer_evaluations
method initialize_answer_evaluations (line 48) | def initialize_answer_evaluations
method initialize_mock_answer_evaluations (line 63) | def initialize_mock_answer_evaluations
method evaluate_mock_answer (line 80) | def evaluate_mock_answer
method evaluate_answer (line 99) | def evaluate_answer # rubocop:disable Metrics/AbcSize
method delete_answer_evaluations (line 120) | def delete_answer_evaluations
method delete_mock_answer_evaluations (line 125) | def delete_mock_answer_evaluations
method export_evaluations (line 135) | def export_evaluations
method create_params (line 144) | def create_params
method initialize_mock_answer_evaluations_params (line 154) | def initialize_mock_answer_evaluations_params
FILE: app/controllers/course/assessment/sessions_controller.rb
class Course::Assessment::SessionsController (line 2) | class Course::Assessment::SessionsController < Course::Assessment::Contr...
method new (line 5) | def new
method create (line 8) | def create
method load_and_authorize_submission (line 18) | def load_and_authorize_submission
method load_submission (line 23) | def load_submission
method redirect_or_create_submission (line 33) | def redirect_or_create_submission
method create_params (line 43) | def create_params
method authentication_service (line 47) | def authentication_service
method log_service (line 52) | def log_service
FILE: app/controllers/course/assessment/skill_branches_controller.rb
class Course::Assessment::SkillBranchesController (line 2) | class Course::Assessment::SkillBranchesController < Course::ComponentCon...
method create (line 7) | def create
method update (line 15) | def update
method destroy (line 23) | def destroy
method skill_branch_params (line 33) | def skill_branch_params
method component (line 39) | def component
FILE: app/controllers/course/assessment/skills_controller.rb
class Course::Assessment::SkillsController (line 2) | class Course::Assessment::SkillsController < Course::ComponentController
method index (line 7) | def index
method create (line 14) | def create
method update (line 22) | def update
method destroy (line 30) | def destroy
method options (line 38) | def options
method skill_params (line 46) | def skill_params
method load_skill_branches (line 50) | def load_skill_branches
method component (line 57) | def component
FILE: app/controllers/course/assessment/submission/answer/answers_controller.rb
class Course::Assessment::Submission::Answer::AnswersController (line 3) | class Course::Assessment::Submission::Answer::AnswersController <
method show (line 11) | def show
method update (line 15) | def update
method submit_answer (line 25) | def submit_answer
method answer_params (line 41) | def answer_params
method should_auto_grade_on_submit (line 45) | def should_auto_grade_on_submit(answer)
method auto_grade (line 54) | def auto_grade(answer)
method valid_for_grading? (line 67) | def valid_for_grading?(answer)
method last_attempt_answer_submitted_job (line 74) | def last_attempt_answer_submitted_job(answer)
method reattempt_and_grade_answer (line 83) | def reattempt_and_grade_answer(answer)
method reattempt_answer (line 98) | def reattempt_answer(answer, finalise: true)
FILE: app/controllers/course/assessment/submission/answer/controller.rb
class Course::Assessment::Submission::Answer::Controller (line 2) | class Course::Assessment::Submission::Answer::Controller < \
FILE: app/controllers/course/assessment/submission/answer/forum_post_response/posts_controller.rb
class Course::Assessment::Submission::Answer::ForumPostResponse::PostsController (line 2) | class Course::Assessment::Submission::Answer::ForumPostResponse::PostsCo...
method selected (line 4) | def selected
method post_params (line 10) | def post_params
FILE: app/controllers/course/assessment/submission/answer/programming/annotations_controller.rb
class Course::Assessment::Submission::Answer::Programming::AnnotationsController (line 2) | class Course::Assessment::Submission::Answer::Programming::AnnotationsCo...
method create (line 19) | def create
method annotation_params (line 39) | def annotation_params
method load_existing_annotation (line 43) | def load_existing_annotation
method line_param (line 52) | def line_param
method discussion_topic (line 58) | def discussion_topic
method create_topic_subscription (line 62) | def create_topic_subscription
method send_created_notification (line 75) | def send_created_notification(post)
method render_create_response (line 81) | def render_create_response
FILE: app/controllers/course/assessment/submission/answer/programming/controller.rb
class Course::Assessment::Submission::Answer::Programming::Controller (line 2) | class Course::Assessment::Submission::Answer::Programming::Controller < \
method set_programming_answer (line 6) | def set_programming_answer
FILE: app/controllers/course/assessment/submission/answer/programming/programming_controller.rb
class Course::Assessment::Submission::Answer::Programming::ProgrammingController (line 2) | class Course::Assessment::Submission::Answer::Programming::ProgrammingCo...
method create_programming_files (line 8) | def create_programming_files
method destroy_programming_file (line 18) | def destroy_programming_file
method create_programming_files_params (line 31) | def create_programming_files_params
method delete_programming_file_params (line 35) | def delete_programming_file_params
method update_answer_files_attributes (line 39) | def update_answer_files_attributes(answer_params)
method delete_programming_file (line 43) | def delete_programming_file(file_id)
FILE: app/controllers/course/assessment/submission/answer/scribing/controller.rb
class Course::Assessment::Submission::Answer::Scribing::Controller (line 2) | class Course::Assessment::Submission::Answer::Scribing::Controller < \
method set_scribing_answer (line 10) | def set_scribing_answer
FILE: app/controllers/course/assessment/submission/answer/scribing/scribbles_controller.rb
class Course::Assessment::Submission::Answer::Scribing::ScribblesController (line 2) | class Course::Assessment::Submission::Answer::Scribing::ScribblesControl...
method create (line 6) | def create
method scribble_params (line 21) | def scribble_params
method load_scribble (line 25) | def load_scribble
FILE: app/controllers/course/assessment/submission/answer/text_response/controller.rb
class Course::Assessment::Submission::Answer::TextResponse::Controller (line 2) | class Course::Assessment::Submission::Answer::TextResponse::Controller < \
method set_text_response_answer (line 6) | def set_text_response_answer
FILE: app/controllers/course/assessment/submission/answer/text_response/text_response_controller.rb
class Course::Assessment::Submission::Answer::TextResponse::TextResponseController (line 2) | class Course::Assessment::Submission::Answer::TextResponse::TextResponse...
method create_files (line 8) | def create_files
method delete_file (line 20) | def delete_file
method create_files_params (line 34) | def create_files_params
method delete_file_params (line 38) | def delete_file_params
FILE: app/controllers/course/assessment/submission/controller.rb
class Course::Assessment::Submission::Controller (line 2) | class Course::Assessment::Submission::Controller < Course::Assessment::C...
FILE: app/controllers/course/assessment/submission/live_feedback_controller.rb
class Course::Assessment::Submission::LiveFeedbackController (line 3) | class Course::Assessment::Submission::LiveFeedbackController <
method save_live_feedback (line 5) | def save_live_feedback
method save_new_feedback (line 20) | def save_new_feedback(content, is_error)
method associate_new_message_with_existing_files (line 35) | def associate_new_message_with_existing_files
FILE: app/controllers/course/assessment/submission/logs_controller.rb
class Course::Assessment::Submission::LogsController (line 2) | class Course::Assessment::Submission::LogsController < \
method index (line 5) | def index
FILE: app/controllers/course/assessment/submission/submissions_controller.rb
class Course::Assessment::Submission::SubmissionsController (line 2) | class Course::Assessment::Submission::SubmissionsController < # rubocop:...
method index (line 30) | def index
method create (line 39) | def create # rubocop:disable Metrics/AbcSize
method edit (line 61) | def edit
method auto_grade (line 69) | def auto_grade
method reevaluate_answer (line 76) | def reevaluate_answer
method generate_feedback (line 85) | def generate_feedback
method generate_live_feedback (line 94) | def generate_live_feedback
method fetch_live_feedback_chat (line 126) | def fetch_live_feedback_chat
method create_live_feedback_chat (line 140) | def create_live_feedback_chat
method fetch_live_feedback_status (line 152) | def fetch_live_feedback_status
method reload_answer (line 170) | def reload_answer
method publish_all (line 186) | def publish_all
method force_submit_all (line 200) | def force_submit_all
method fetch_submissions_from_koditsu (line 214) | def fetch_submissions_from_koditsu
method download_all (line 232) | def download_all
method download_statistics (line 241) | def download_statistics
method unsubmit (line 256) | def unsubmit
method unsubmit_all (line 274) | def unsubmit_all
method delete (line 285) | def delete
method reset_question_bundle_assignments (line 301) | def reset_question_bundle_assignments
method delete_all (line 306) | def delete_all
method create_params (line 319) | def create_params
method live_feedback_params (line 323) | def live_feedback_params
method create_success_response (line 327) | def create_success_response(submission)
method authorize_assessment! (line 342) | def authorize_assessment!
method reload_answer_params (line 346) | def reload_answer_params
method answer_params (line 350) | def answer_params
method thread_params (line 354) | def thread_params
method not_downloadable (line 358) | def not_downloadable
method download_job (line 364) | def download_job
method check_zombie_jobs (line 376) | def check_zombie_jobs # rubocop:disable Metrics/AbcSize, Metrics/Perce...
method course_user_ids (line 396) | def course_user_ids
method user_ids_without_submission (line 401) | def user_ids_without_submission
FILE: app/controllers/course/assessment/submission_question/comments_controller.rb
class Course::Assessment::SubmissionQuestion::CommentsController (line 2) | class Course::Assessment::SubmissionQuestion::CommentsController < Cours...
method create (line 8) | def create
method create_topic_subscription (line 30) | def create_topic_subscription
method send_created_notification (line 43) | def send_created_notification(post)
method last_post_from (line 50) | def last_post_from(submission_question)
method discussion_topic (line 55) | def discussion_topic
method render_create_response (line 59) | def render_create_response
FILE: app/controllers/course/assessment/submission_question/controller.rb
class Course::Assessment::SubmissionQuestion::Controller (line 2) | class Course::Assessment::SubmissionQuestion::Controller < Course::Asses...
FILE: app/controllers/course/assessment/submission_question/submission_questions_controller.rb
class Course::Assessment::SubmissionQuestion::SubmissionQuestionsController (line 2) | class Course::Assessment::SubmissionQuestion::SubmissionQuestionsControl...
method all_answers (line 5) | def all_answers
method all_answers_params (line 27) | def all_answers_params
FILE: app/controllers/course/assessment/submissions_controller.rb
class Course::Assessment::SubmissionsController (line 2) | class Course::Assessment::SubmissionsController < Course::ComponentContr...
method index (line 11) | def index
method pending (line 23) | def pending
method submission_params (line 36) | def submission_params
method pending_submission_params (line 40) | def pending_submission_params
method filter_params (line 44) | def filter_params
method category_param (line 50) | def category_param
method category (line 55) | def category
method load_submissions (line 67) | def load_submissions
method pending_submissions (line 81) | def pending_submissions
method load_group_managers (line 91) | def load_group_managers
method load_assessments (line 97) | def load_assessments
method component (line 107) | def component
FILE: app/controllers/course/component_controller.rb
class Course::ComponentController (line 2) | class Course::ComponentController < Course::Controller
method load_current_component_host (line 11) | def load_current_component_host
method check_component (line 19) | def check_component
method load_settings (line 24) | def load_settings
method component (line 33) | def component
FILE: app/controllers/course/condition/achievements_controller.rb
class Course::Condition::AchievementsController (line 2) | class Course::Condition::AchievementsController < Course::ConditionsCont...
method index (line 9) | def index
method show (line 13) | def show
method create (line 17) | def create
method update (line 25) | def update
method destroy (line 29) | def destroy
method render_available_achievements (line 35) | def render_available_achievements
method try_to_perform (line 51) | def try_to_perform(operation_succeeded)
method achievement_condition_params (line 59) | def achievement_condition_params
method set_course (line 63) | def set_course
method component (line 71) | def component
FILE: app/controllers/course/condition/assessments_controller.rb
class Course::Condition::AssessmentsController (line 2) | class Course::Condition::AssessmentsController < Course::ConditionsContr...
method index (line 7) | def index
method show (line 11) | def show
method create (line 15) | def create
method update (line 19) | def update
method destroy (line 23) | def destroy
method render_available_assessments (line 29) | def render_available_assessments
method try_to_perform (line 36) | def try_to_perform(operation_succeeded)
method assessment_condition_params (line 44) | def assessment_condition_params
method set_course_and_conditional (line 48) | def set_course_and_conditional
method component (line 57) | def component
FILE: app/controllers/course/condition/levels_controller.rb
class Course::Condition::LevelsController (line 2) | class Course::Condition::LevelsController < Course::ConditionsController
method create (line 7) | def create
method update (line 12) | def update
method destroy (line 16) | def destroy
method try_to_perform (line 22) | def try_to_perform(operation_succeeded)
method level_condition_params (line 30) | def level_condition_params
method set_course (line 34) | def set_course
method component (line 42) | def component
FILE: app/controllers/course/condition/scholaistic_assessments_controller.rb
class Course::Condition::ScholaisticAssessmentsController (line 2) | class Course::Condition::ScholaisticAssessmentsController < Course::Cond...
method index (line 7) | def index
method show (line 11) | def show
method create (line 15) | def create
method update (line 19) | def update
method destroy (line 23) | def destroy
method render_available_scholaistic_assessments (line 29) | def render_available_scholaistic_assessments
method try_to_perform (line 36) | def try_to_perform(operation_succeeded)
method scholaistic_assessment_condition_params (line 44) | def scholaistic_assessment_condition_params
method set_course_and_conditional (line 48) | def set_course_and_conditional
method component (line 53) | def component
FILE: app/controllers/course/condition/surveys_controller.rb
class Course::Condition::SurveysController (line 2) | class Course::Condition::SurveysController < Course::ConditionsController
method index (line 7) | def index
method show (line 11) | def show
method create (line 15) | def create
method update (line 19) | def update
method destroy (line 23) | def destroy
method render_available_surveys (line 29) | def render_available_surveys
method try_to_perform (line 36) | def try_to_perform(operation_succeeded)
method survey_condition_params (line 44) | def survey_condition_params
method set_course_and_conditional (line 48) | def set_course_and_conditional
method component (line 57) | def component
FILE: app/controllers/course/conditions_controller.rb
class Course::ConditionsController (line 2) | class Course::ConditionsController < Course::ComponentController
method success_action (line 6) | def success_action
method set_conditional (line 18) | def set_conditional
method authorize_conditional (line 23) | def authorize_conditional
method load_and_authorize_conditional (line 27) | def load_and_authorize_conditional
FILE: app/controllers/course/controller.rb
class Course::Controller (line 2) | class Course::Controller < ApplicationController
method sidebar_items (line 12) | def sidebar_items(type: nil)
method current_course (line 25) | def current_course
method current_course_user (line 34) | def current_course_user
method current_component_host (line 46) | def current_component_host
method current_ability (line 52) | def current_ability
method handle_access_denied (line 59) | def handle_access_denied(exception)
method sidebar_items_of_type (line 70) | def sidebar_items_of_type(type)
method sidebar_items_weights (line 80) | def sidebar_items_weights(type: nil)
method set_last_active_at (line 91) | def set_last_active_at
FILE: app/controllers/course/courses_controller.rb
class Course::CoursesController (line 2) | class Course::CoursesController < Course::Controller
method index (line 6) | def index
method show (line 10) | def show
method create (line 28) | def create
method destroy (line 36) | def destroy
method sidebar (line 39) | def sidebar
method publicly_accessible? (line 52) | def publicly_accessible?
method course_params (line 58) | def course_params
method load_todos (line 63) | def load_todos # rubocop:disable Metrics/AbcSize
method load_items_with_timeline (line 91) | def load_items_with_timeline # rubocop:disable Metrics/CyclomaticCompl...
method load_activity_course_users (line 105) | def load_activity_course_users
FILE: app/controllers/course/discussion/posts_controller.rb
class Course::Discussion::PostsController (line 2) | class Course::Discussion::PostsController < Course::ComponentController
method create (line 13) | def create
method update (line 33) | def update
method destroy (line 50) | def destroy
method discussion_topic (line 61) | def discussion_topic
method create_topic_subscription (line 65) | def create_topic_subscription
method topic_id_param (line 71) | def topic_id_param
method codaveri_rating_param (line 75) | def codaveri_rating_param
method load_topic (line 79) | def load_topic
method send_created_notification (line 84) | def send_created_notification(post)
method handle_codaveri_feedback (line 91) | def handle_codaveri_feedback(rating)
method component (line 99) | def component
FILE: app/controllers/course/discussion/topics_controller.rb
class Course::Discussion::TopicsController (line 2) | class Course::Discussion::TopicsController < Course::ComponentController
method index (line 13) | def index
method all (line 16) | def all
method pending (line 27) | def pending
method my_students (line 37) | def my_students
method my_students_pending (line 42) | def my_students_pending
method toggle_pending (line 47) | def toggle_pending
method mark_as_read (line 60) | def mark_as_read
method pagination_page_param (line 71) | def pagination_page_param
method unread_topics_for_student (line 75) | def unread_topics_for_student
method all_topics (line 79) | def all_topics
method my_students_topics (line 90) | def my_students_topics
method component (line 109) | def component
method mark_as_pending? (line 113) | def mark_as_pending?
method render_topics_list_data (line 117) | def render_topics_list_data
FILE: app/controllers/course/duplications_controller.rb
class Course::DuplicationsController (line 2) | class Course::DuplicationsController < Course::ComponentController
method show (line 5) | def show; end
method create (line 7) | def create
method authorize_duplication (line 18) | def authorize_duplication
method create_duplication_params (line 30) | def create_duplication_params
method instance_params (line 34) | def instance_params
method duplication_job_options (line 42) | def duplication_job_options
method component (line 48) | def component
FILE: app/controllers/course/enrol_requests_controller.rb
class Course::EnrolRequestsController (line 2) | class Course::EnrolRequestsController < Course::ComponentController
method index (line 10) | def index
method create (line 14) | def create
method destroy (line 26) | def destroy
method approve (line 35) | def approve
method reject (line 48) | def reject
method course_user_params (line 61) | def course_user_params
method component (line 67) | def component
method approve_success (line 71) | def approve_success
method approve_failure (line 77) | def approve_failure(course_user)
method reject_success (line 83) | def reject_success
method reject_failure (line 89) | def reject_failure
FILE: app/controllers/course/experience_points/disbursement_controller.rb
class Course::ExperiencePoints::DisbursementController (line 2) | class Course::ExperiencePoints::DisbursementController < Course::Compone...
method new (line 6) | def new
method create (line 12) | def create
method load_resource (line 22) | def load_resource
method disbursement_params (line 26) | def disbursement_params
method authorize_resource (line 41) | def authorize_resource
method recipient_count (line 48) | def recipient_count
method component (line 54) | def component
FILE: app/controllers/course/experience_points/forum_disbursement_controller.rb
class Course::ExperiencePoints::ForumDisbursementController (line 2) | class Course::ExperiencePoints::ForumDisbursementController <
method create (line 4) | def create
method load_resource (line 14) | def load_resource
method disbursement_params (line 18) | def disbursement_params
method new_disbursement_params (line 27) | def new_disbursement_params
method create_disbursement_params (line 36) | def create_disbursement_params
FILE: app/controllers/course/experience_points_records_controller.rb
class Course::ExperiencePointsRecordsController (line 2) | class Course::ExperiencePointsRecordsController < Course::ComponentContr...
method index (line 8) | def index
method show (line 15) | def show
method download (line 20) | def download
method update (line 28) | def update
method destroy (line 44) | def destroy
method load_active_experience_points_records (line 54) | def load_active_experience_points_records
method experience_points_record_params (line 59) | def experience_points_record_params
method filter_and_paginate_params (line 63) | def filter_and_paginate_params
method filter_download_params (line 69) | def filter_download_params
method paginate_and_preload_experience_points (line 75) | def paginate_and_preload_experience_points
method preload_exp_points_updater (line 82) | def preload_exp_points_updater
method component (line 89) | def component
FILE: app/controllers/course/forum/component_controller.rb
class Course::Forum::ComponentController (line 2) | class Course::Forum::ComponentController < Course::Forum::Controller
FILE: app/controllers/course/forum/controller.rb
class Course::Forum::Controller (line 2) | class Course::Forum::Controller < Course::ComponentController
method load_forum (line 9) | def load_forum
method component (line 15) | def component
method skip_load_forum? (line 19) | def skip_load_forum?
FILE: app/controllers/course/forum/forums_controller.rb
class Course::Forum::ForumsController (line 2) | class Course::Forum::ForumsController < Course::Forum::Controller
method index (line 10) | def index
method show (line 19) | def show
method create (line 32) | def create
method update (line 42) | def update
method destroy (line 53) | def destroy
method subscribe (line 61) | def subscribe
method unsubscribe (line 69) | def unsubscribe
method all_posts (line 77) | def all_posts
method search (line 91) | def search
method mark_all_as_read (line 95) | def mark_all_as_read
method mark_as_read (line 103) | def mark_as_read
method search_params (line 112) | def search_params
method forum_params (line 120) | def forum_params
method skip_load_forum? (line 124) | def skip_load_forum?
method forum_with_statistics (line 128) | def forum_with_statistics
method preload_topic_subscriptons (line 137) | def preload_topic_subscriptons
FILE: app/controllers/course/forum/posts_controller.rb
class Course::Forum::PostsController (line 2) | class Course::Forum::PostsController < Course::Forum::ComponentController
method create (line 11) | def create
method update (line 29) | def update
method vote (line 37) | def vote
method toggle_answer (line 43) | def toggle_answer
method mark_answer_and_publish (line 54) | def mark_answer_and_publish
method destroy (line 63) | def destroy
method publish (line 77) | def publish
method generate_reply (line 86) | def generate_reply
method discussion_topic (line 99) | def discussion_topic
method skip_update_topic_status (line 103) | def skip_update_topic_status
method topic_id_param (line 109) | def topic_id_param
method load_topic (line 113) | def load_topic
method post_vote_param (line 117) | def post_vote_param
method authorize_locked_topic (line 121) | def authorize_locked_topic
method creator_json (line 125) | def creator_json
FILE: app/controllers/course/forum/topics_controller.rb
class Course::Forum::TopicsController (line 2) | class Course::Forum::TopicsController < Course::Forum::ComponentController
method show (line 17) | def show
method create (line 28) | def create
method update (line 41) | def update
method destroy (line 52) | def destroy
method update_topic_params (line 62) | def update_topic_params
method topic_params (line 66) | def topic_params
method load_topic (line 70) | def load_topic
method mark_posts_read (line 74) | def mark_posts_read
method authorize_topic_type! (line 78) | def authorize_topic_type!(type)
method send_created_notification (line 87) | def send_created_notification(topic)
FILE: app/controllers/course/group/group_categories_controller.rb
class Course::Group::GroupCategoriesController (line 2) | class Course::Group::GroupCategoriesController < Course::ComponentContro...
method index (line 7) | def index
method show (line 13) | def show
method show_info (line 16) | def show_info
method show_users (line 22) | def show_users
method create (line 26) | def create
method create_groups (line 35) | def create_groups
method update (line 48) | def update
method update_group_members (line 56) | def update_group_members
method destroy (line 70) | def destroy
method partition_new_users (line 80) | def partition_new_users(new_users, existing_users)
method add_new_members (line 87) | def add_new_members(members_to_add, group)
method update_members (line 94) | def update_members(members_to_update, existing_users)
method destroy_members (line 101) | def destroy_members(members_to_destroy)
method group_category_params (line 107) | def group_category_params
method groups_params (line 111) | def groups_params
method update_groups_params (line 118) | def update_groups_params
method component (line 127) | def component
FILE: app/controllers/course/group/groups_controller.rb
class Course::Group::GroupsController (line 2) | class Course::Group::GroupsController < Course::ComponentController
method update (line 5) | def update
method destroy (line 13) | def destroy
method group_params (line 23) | def group_params
method component (line 29) | def component
FILE: app/controllers/course/leaderboards_controller.rb
class Course::LeaderboardsController (line 2) | class Course::LeaderboardsController < Course::ComponentController
method index (line 8) | def index
method check_component_settings (line 21) | def check_component_settings
method preload_course_levels (line 29) | def preload_course_levels
method component (line 35) | def component
method fetch_course_users (line 40) | def fetch_course_users
method fetch_users_list (line 45) | def fetch_users_list(achievements_enabled)
method fetch_groups_list (line 52) | def fetch_groups_list(achievements_enabled)
FILE: app/controllers/course/learning_map_controller.rb
class Course::LearningMapController (line 2) | class Course::LearningMapController < Course::ComponentController
method index (line 9) | def index
method add_parent_node (line 17) | def add_parent_node
method remove_parent_node (line 29) | def remove_parent_node
method toggle_satisfiability_type (line 41) | def toggle_satisfiability_type
method authorize_learning_map (line 60) | def authorize_learning_map
method authorize_update (line 64) | def authorize_update
method component (line 70) | def component
method error_response (line 74) | def error_response(errors)
method prepare_response_data (line 82) | def prepare_response_data
method map_conditionals_to_nodes (line 88) | def map_conditionals_to_nodes
method generate_all_node_relations (line 94) | def generate_all_node_relations # rubocop:disable Metrics/AbcSize, Met...
method init_all_node_relations (line 120) | def init_all_node_relations
method map_condition_to_parent (line 126) | def map_condition_to_parent(condition)
method generate_nodes_from_conditionals (line 134) | def generate_nodes_from_conditionals(all_node_relations) # rubocop:dis...
method generate_node_depths (line 159) | def generate_node_depths(nodes)
method init_depths (line 175) | def init_depths(nodes)
method toposort (line 179) | def toposort(nodes)
method dfs (line 191) | def dfs(node, node_ids_to_nodes, visited_node_ids, post_order_nodes)
method parent_and_node_id_pair_params (line 202) | def parent_and_node_id_pair_params
method node_params (line 206) | def node_params
method get_node_id (line 210) | def get_node_id(conditional)
method create_condition (line 214) | def create_condition(node_id, conditional)
method get_conditional (line 226) | def get_conditional(node_id)
method get_condition (line 231) | def get_condition(parent_node_id, node_id)
FILE: app/controllers/course/lesson_plan/controller.rb
class Course::LessonPlan::Controller (line 2) | class Course::LessonPlan::Controller < Course::ComponentController
method component (line 11) | def component
FILE: app/controllers/course/lesson_plan/events_controller.rb
class Course::LessonPlan::EventsController (line 2) | class Course::LessonPlan::EventsController < Course::LessonPlan::Controller
method create (line 10) | def create
method update (line 18) | def update
method destroy (line 26) | def destroy
method event_params (line 36) | def event_params
FILE: app/controllers/course/lesson_plan/items_controller.rb
class Course::LessonPlan::ItemsController (line 2) | class Course::LessonPlan::ItemsController < Course::LessonPlan::Controller
method index (line 13) | def index
method update (line 19) | def update
method item_params (line 29) | def item_params
method render_json_response (line 33) | def render_json_response
method visibility_hash (line 56) | def visibility_hash
method assessment_tabs_visibility_hash (line 66) | def assessment_tabs_visibility_hash
method component_visibility_hash (line 75) | def component_visibility_hash
method assessment_tabs_titles_hash (line 86) | def assessment_tabs_titles_hash
method tab_title_array (line 100) | def tab_title_array(tab)
method assessment_item_settings (line 108) | def assessment_item_settings
method component_item_settings (line 118) | def component_item_settings
method load_item_settings (line 126) | def load_item_settings
FILE: app/controllers/course/lesson_plan/milestones_controller.rb
class Course::LessonPlan::MilestonesController (line 2) | class Course::LessonPlan::MilestonesController < Course::LessonPlan::Con...
method create (line 12) | def create
method update (line 20) | def update
method destroy (line 28) | def destroy
method milestone_params (line 38) | def milestone_params
FILE: app/controllers/course/lesson_plan/todos_controller.rb
class Course::LessonPlan::TodosController (line 2) | class Course::LessonPlan::TodosController < Course::LessonPlan::Controller
method ignore (line 6) | def ignore
FILE: app/controllers/course/levels_controller.rb
class Course::LevelsController (line 2) | class Course::LevelsController < Course::ComponentController
method index (line 5) | def index
method create (line 8) | def create
method component (line 22) | def component
FILE: app/controllers/course/material/controller.rb
class Course::Material::Controller (line 2) | class Course::Material::Controller < Course::ComponentController
method create_text_chunks (line 6) | def create_text_chunks
method destroy_text_chunks (line 22) | def destroy_text_chunks
method material_chunking_params (line 32) | def material_chunking_params
method last_text_chunking_job (line 36) | def last_text_chunking_job
method component (line 43) | def component
method root_folder_name (line 48) | def root_folder_name
FILE: app/controllers/course/material/folders_controller.rb
class Course::Material::FoldersController (line 2) | class Course::Material::FoldersController < Course::Material::Controller
method index (line 7) | def index
method show (line 12) | def show
method update (line 16) | def update
method destroy (line 26) | def destroy
method create_subfolder (line 34) | def create_subfolder
method upload_materials (line 45) | def upload_materials
method download (line 57) | def download
method breadcrumbs (line 65) | def breadcrumbs
method authorize_read_owner! (line 71) | def authorize_read_owner!
method folder_params (line 75) | def folder_params
method files_params (line 80) | def files_params
method load_subfolders (line 84) | def load_subfolders
method load_root_folder_with_subfolders (line 91) | def load_root_folder_with_subfolders
method handle_not_found (line 98) | def handle_not_found
FILE: app/controllers/course/material/materials_controller.rb
class Course::Material::MaterialsController (line 2) | class Course::Material::MaterialsController < Course::Material::Controller
method show (line 5) | def show
method update (line 11) | def update
method destroy (line 30) | def destroy
method material_params (line 40) | def material_params
method create_submission (line 44) | def create_submission
method authentication_service (line 62) | def authentication_service
method log_service (line 67) | def log_service
method delete_material_text_chunks (line 72) | def delete_material_text_chunks
FILE: app/controllers/course/object_duplications_controller.rb
class Course::ObjectDuplicationsController (line 2) | class Course::ObjectDuplicationsController < Course::ComponentController
method new (line 6) | def new
method create (line 12) | def create
method authorize_duplication (line 21) | def authorize_duplication
method load_destination_courses_data (line 27) | def load_destination_courses_data
method load_items_data (line 41) | def load_items_data
method load_assessments_component_data (line 49) | def load_assessments_component_data
method load_survey_component_data (line 53) | def load_survey_component_data
method load_achievements_component_data (line 57) | def load_achievements_component_data
method load_materials_component_data (line 61) | def load_materials_component_data
method load_videos_component_data (line 65) | def load_videos_component_data
method load_destination_instances_data (line 69) | def load_destination_instances_data
method create_duplication_params (line 84) | def create_duplication_params
method authorized_destination_course (line 91) | def authorized_destination_course
method course_item_finders (line 101) | def course_item_finders
method objects_to_duplicate (line 115) | def objects_to_duplicate
method component (line 123) | def component
FILE: app/controllers/course/personal_times_controller.rb
class Course::PersonalTimesController (line 2) | class Course::PersonalTimesController < Course::ComponentController
method index (line 8) | def index
method create (line 27) | def create
method destroy (line 38) | def destroy
method recompute (line 48) | def recompute
method component (line 56) | def component
method authorize_personal_times! (line 60) | def authorize_personal_times!
method personal_time_params (line 64) | def personal_time_params
FILE: app/controllers/course/plagiarism/assessments_controller.rb
class Course::Plagiarism::AssessmentsController (line 2) | class Course::Plagiarism::AssessmentsController < Course::Plagiarism::Co...
method index (line 9) | def index
method plagiarism_data (line 22) | def plagiarism_data
method plagiarism_check (line 46) | def plagiarism_check
method plagiarism_checks (line 59) | def plagiarism_checks
method fetch_plagiarism_checks (line 77) | def fetch_plagiarism_checks
method download_submission_pair_result (line 92) | def download_submission_pair_result
method share_submission_pair_result (line 99) | def share_submission_pair_result
method share_assessment_result (line 106) | def share_assessment_result
method linked_and_unlinked_assessments (line 112) | def linked_and_unlinked_assessments
method update_assessment_links (line 142) | def update_assessment_links
method plagiarism_data_params (line 153) | def plagiarism_data_params
method should_timeout_plagiarism_check? (line 157) | def should_timeout_plagiarism_check?(assessment)
method should_query_plagiarism_check? (line 164) | def should_query_plagiarism_check?(assessment)
method timeout_plagiarism_check (line 171) | def timeout_plagiarism_check(assessment)
method query_and_update_plagiarism_check (line 175) | def query_and_update_plagiarism_check(assessment)
method fetch_plagiarism_data_submissions (line 190) | def fetch_plagiarism_data_submissions(submission_ids)
method fetch_all_assessment_related_statistics_hash (line 217) | def fetch_all_assessment_related_statistics_hash
method fetch_can_manage_rows_hash (line 223) | def fetch_can_manage_rows_hash(rows)
method viewer_is_administrator? (line 240) | def viewer_is_administrator?
method num_plagiarism_checkable_questions_hash (line 245) | def num_plagiarism_checkable_questions_hash
FILE: app/controllers/course/plagiarism/controller.rb
class Course::Plagiarism::Controller (line 2) | class Course::Plagiarism::Controller < Course::ComponentController
method authorize_manage_plagiarism! (line 7) | def authorize_manage_plagiarism!
method component (line 13) | def component
FILE: app/controllers/course/plagiarism/plagiarism_controller.rb
class Course::Plagiarism::PlagiarismController (line 2) | class Course::Plagiarism::PlagiarismController < Course::Plagiarism::Con...
method index (line 5) | def index
FILE: app/controllers/course/reference_timelines_controller.rb
class Course::ReferenceTimelinesController (line 2) | class Course::ReferenceTimelinesController < Course::ComponentController
method index (line 5) | def index
method create (line 15) | def create
method update (line 23) | def update
method destroy (line 31) | def destroy
method reference_timeline_params (line 52) | def reference_timeline_params
method revert_course_users_to_alternative_timeline (line 56) | def revert_course_users_to_alternative_timeline
method destroy_params (line 65) | def destroy_params
method component (line 69) | def component
FILE: app/controllers/course/reference_times_controller.rb
class Course::ReferenceTimesController (line 2) | class Course::ReferenceTimesController < Course::ReferenceTimelinesContr...
method create (line 5) | def create
method update (line 13) | def update
method destroy (line 21) | def destroy
method create_params (line 31) | def create_params
method update_params (line 35) | def update_params
FILE: app/controllers/course/rubrics_controller.rb
class Course::RubricsController (line 2) | class Course::RubricsController < Course::Controller
method index (line 5) | def index
method destroy (line 9) | def destroy
FILE: app/controllers/course/scholaistic/assistants_controller.rb
class Course::Scholaistic::AssistantsController (line 2) | class Course::Scholaistic::AssistantsController < Course::Scholaistic::C...
method index (line 3) | def index
method show (line 13) | def show
FILE: app/controllers/course/scholaistic/controller.rb
class Course::Scholaistic::Controller (line 2) | class Course::Scholaistic::Controller < Course::ComponentController
method component (line 9) | def component
method not_found_if_scholaistic_course_not_linked (line 13) | def not_found_if_scholaistic_course_not_linked
FILE: app/controllers/course/scholaistic/scholaistic_assessments_controller.rb
class Course::Scholaistic::ScholaisticAssessmentsController (line 2) | class Course::Scholaistic::ScholaisticAssessmentsController < Course::Sc...
method index (line 8) | def index
method new (line 34) | def new
method show (line 42) | def show
method edit (line 57) | def edit
method update (line 65) | def update
method update_params (line 75) | def update_params
method sync_scholaistic_assessments! (line 79) | def sync_scholaistic_assessments!
FILE: app/controllers/course/scholaistic/submissions_controller.rb
class Course::Scholaistic::SubmissionsController (line 2) | class Course::Scholaistic::SubmissionsController < Course::Scholaistic::...
method index (line 7) | def index
method show (line 15) | def show
method submission (line 35) | def submission
method load_and_authorize_scholaistic_assessment (line 49) | def load_and_authorize_scholaistic_assessment
method sync_scholaistic_submission! (line 54) | def sync_scholaistic_submission!
method submission_id (line 78) | def submission_id
FILE: app/controllers/course/statistics/aggregate_controller.rb
class Course::Statistics::AggregateController (line 3) | class Course::Statistics::AggregateController < Course::Statistics::Cont...
method course_progression (line 9) | def course_progression
method course_performance (line 14) | def course_performance
method all_staff (line 20) | def all_staff
method all_students (line 25) | def all_students
method all_assessments (line 30) | def all_assessments
method activity_get_help (line 38) | def activity_get_help
method download_score_summary (line 50) | def download_score_summary
method sanitize_date_range (line 59) | def sanitize_date_range(start_at_param, end_at_param)
method valid_date_range? (line 65) | def valid_date_range?(start_date, end_date)
method fetch_course_get_help_data (line 71) | def fetch_course_get_help_data(start_date, end_date)
method load_assessment_question_hash (line 96) | def load_assessment_question_hash
method assessment_info_array (line 111) | def assessment_info_array
method user_submission_array (line 119) | def user_submission_array # rubocop:disable Metrics/AbcSize
method correctness_hash (line 140) | def correctness_hash
method fetch_all_assessment_related_statistics_hash (line 182) | def fetch_all_assessment_related_statistics_hash
method course_users (line 191) | def course_users
method group_manager_preload_service (line 195) | def group_manager_preload_service
method preload_levels (line 201) | def preload_levels
FILE: app/controllers/course/statistics/assessments_controller.rb
class Course::Statistics::AssessmentsController (line 2) | class Course::Statistics::AssessmentsController < Course::Statistics::Co...
method assessment_statistics (line 7) | def assessment_statistics
method submission_statistics (line 19) | def submission_statistics
method ancestor_statistics (line 36) | def ancestor_statistics
method live_feedback_statistics (line 52) | def live_feedback_statistics
method live_feedback_history (line 65) | def live_feedback_history
method ancestor_info (line 85) | def ancestor_info
method load_ordered_questions (line 91) | def load_ordered_questions
method assessment_params (line 95) | def assessment_params
method load_course_user_students_info (line 99) | def load_course_user_students_info
method fetch_all_ancestor_assessments (line 104) | def fetch_all_ancestor_assessments
method create_question_related_hash (line 121) | def create_question_related_hash
method create_student_live_feedback_hash (line 128) | def create_student_live_feedback_hash
method fetch_message_grade_hash (line 173) | def fetch_message_grade_hash
method build_message_grade_sql (line 191) | def build_message_grade_sql(student_ids, submission_question_ids)
method feedback_messages_cte (line 217) | def feedback_messages_cte(student_ids, submission_question_ids)
method feedback_answers_cte (line 238) | def feedback_answers_cte
method grades_before_cte (line 256) | def grades_before_cte
method grades_after_cte (line 268) | def grades_after_cte
method build_live_feedback_data (line 284) | def build_live_feedback_data(submission, final_grade_hash, message_gra...
method calculate_prompt_hash (line 308) | def calculate_prompt_hash(message_hash)
method fetch_messages_for_question (line 318) | def fetch_messages_for_question(submission_question_id)
method create_question_order_hash (line 325) | def create_question_order_hash
method create_submission_question_id_hash (line 331) | def create_submission_question_id_hash(questions)
FILE: app/controllers/course/statistics/controller.rb
class Course::Statistics::Controller (line 2) | class Course::Statistics::Controller < Course::ComponentController
method authorize_read_statistics! (line 7) | def authorize_read_statistics!
method component (line 13) | def component
FILE: app/controllers/course/statistics/statistics_controller.rb
class Course::Statistics::StatisticsController (line 2) | class Course::Statistics::StatisticsController < Course::Statistics::Con...
method index (line 5) | def index
FILE: app/controllers/course/statistics/users_controller.rb
class Course::Statistics::UsersController (line 2) | class Course::Statistics::UsersController < Course::Statistics::Controller
method learning_rate_records (line 3) | def learning_rate_records
FILE: app/controllers/course/stories/stories_controller.rb
class Course::Stories::StoriesController (line 2) | class Course::Stories::StoriesController < Course::ComponentController
method learn (line 12) | def learn
method learn_settings (line 18) | def learn_settings
method mission_control (line 24) | def mission_control
method check_course_user_and_push_key (line 33) | def check_course_user_and_push_key
method push_key (line 37) | def push_key
method component (line 41) | def component
FILE: app/controllers/course/survey/controller.rb
class Course::Survey::Controller (line 2) | class Course::Survey::Controller < Course::ComponentController
method component (line 13) | def component
method load_sections (line 17) | def load_sections
FILE: app/controllers/course/survey/questions_controller.rb
class Course::Survey::QuestionsController (line 2) | class Course::Survey::QuestionsController < Course::Survey::Controller
method create (line 5) | def create
method update (line 15) | def update
method destroy (line 23) | def destroy
method load_question_options (line 33) | def load_question_options
method render_question_json (line 37) | def render_question_json
method question_params (line 42) | def question_params
FILE: app/controllers/course/survey/responses_controller.rb
class Course::Survey::ResponsesController (line 2) | class Course::Survey::ResponsesController < Course::Survey::Controller
method index (line 5) | def index
method create (line 11) | def create
method show (line 23) | def show
method edit (line 28) | def edit
method update (line 39) | def update
method unsubmit (line 56) | def unsubmit
method handle_create_error (line 67) | def handle_create_error(error)
method build_response (line 77) | def build_response
method load_answers (line 82) | def load_answers
method render_response_json (line 86) | def render_response_json
method response_update_params (line 96) | def response_update_params
FILE: app/controllers/course/survey/sections_controller.rb
class Course::Survey::SectionsController (line 2) | class Course::Survey::SectionsController < Course::Survey::Controller
method create (line 5) | def create
method update (line 15) | def update
method destroy (line 23) | def destroy
method load_questions (line 33) | def load_questions
method render_section_json (line 37) | def render_section_json
method section_params (line 42) | def section_params
FILE: app/controllers/course/survey/surveys_controller.rb
class Course::Survey::SurveysController (line 2) | class Course::Survey::SurveysController < Course::Survey::Controller
method index (line 8) | def index
method create (line 13) | def create
method show (line 21) | def show
method update (line 25) | def update
method destroy (line 33) | def destroy
method results (line 41) | def results
method remind (line 46) | def remind
method download (line 59) | def download
method student_course_users (line 70) | def student_course_users
method render_survey_with_questions_json (line 74) | def render_survey_with_questions_json
method preload_questions_results (line 82) | def preload_questions_results
method survey_params (line 91) | def survey_params
method preload_student_submitted_responses_counts (line 100) | def preload_student_submitted_responses_counts
FILE: app/controllers/course/user_email_subscriptions_controller.rb
class Course::UserEmailSubscriptionsController (line 2) | class Course::UserEmailSubscriptionsController < Course::ComponentContro...
method edit (line 5) | def edit
method update (line 13) | def update
method email_setting_params (line 22) | def email_setting_params
method subscription_params (line 26) | def subscription_params
method email_setting_filter_params (line 30) | def email_setting_filter_params
method update_subscription_setting (line 34) | def update_subscription_setting
method load_subscription_settings (line 43) | def load_subscription_settings
method load_email_settings (line 51) | def load_email_settings
method filter_subscription_settings (line 62) | def filter_subscription_settings
method unsubscribe (line 75) | def unsubscribe
method component (line 84) | def component
FILE: app/controllers/course/user_invitations_controller.rb
class Course::UserInvitationsController (line 2) | class Course::UserInvitationsController < Course::ComponentController
method index (line 7) | def index
method create (line 16) | def create
method destroy (line 26) | def destroy
method resend_invitation (line 34) | def resend_invitation
method resend_invitations (line 44) | def resend_invitations
method toggle_registration (line 52) | def toggle_registration
method course_user_invitation_params (line 58) | def course_user_invitation_params
method invitation_params (line 70) | def invitation_params
method registration_params (line 78) | def registration_params
method resend_invitation_params (line 85) | def resend_invitation_params
method load_invitations (line 93) | def load_invitations
method authorize_invitation! (line 106) | def authorize_invitation!
method invite_by_file? (line 113) | def invite_by_file?
method invite (line 120) | def invite
method invitation_service (line 130) | def invitation_service
method propagate_errors (line 137) | def propagate_errors
method propagate_errors_to_file (line 144) | def propagate_errors_to_file
method aggregate_errors (line 152) | def aggregate_errors
method invalid_course_user_errors (line 159) | def invalid_course_user_errors
method invalid_course_users (line 169) | def invalid_course_users
method invalid_invitation_email_errors (line 176) | def invalid_invitation_email_errors
method invalid_invitations (line 186) | def invalid_invitations
method parse_invitation_result (line 191) | def parse_invitation_result(new_invitations, existing_invitations, new...
method enable_registration_code (line 204) | def enable_registration_code(enable)
method component (line 217) | def component
method resend_invitation_success (line 221) | def resend_invitation_success
method resend_invitation_failure (line 229) | def resend_invitation_failure
method resend_invitations_success (line 235) | def resend_invitations_success
method resend_invitations_failure (line 243) | def resend_invitations_failure
method destroy_invitation_success (line 249) | def destroy_invitation_success
method destroy_invitation_failure (line 255) | def destroy_invitation_failure
method create_invitation_success (line 261) | def create_invitation_success(result)
FILE: app/controllers/course/user_notifications_controller.rb
class Course::UserNotificationsController (line 2) | class Course::UserNotificationsController < Course::Controller
method fetch (line 6) | def fetch
method mark_as_read (line 10) | def mark_as_read
method publicly_accessible? (line 17) | def publicly_accessible?
method next_popup_notification (line 28) | def next_popup_notification
FILE: app/controllers/course/user_registrations_controller.rb
class Course::UserRegistrationsController (line 2) | class Course::UserRegistrationsController < Course::ComponentController
method create (line 7) | def create
method registration_params (line 19) | def registration_params
method ensure_unregistered_user (line 23) | def ensure_unregistered_user
method load_registration (line 32) | def load_registration
method registration_service (line 39) | def registration_service
method component (line 45) | def component
FILE: app/controllers/course/users_controller.rb
class Course::UsersController (line 2) | class Course::UsersController < Course::ComponentController
method index (line 8) | def index
method destroy (line 11) | def destroy
method show (line 20) | def show
method load_resource (line 30) | def load_resource
method component (line 52) | def component
FILE: app/controllers/course/video/controller.rb
class Course::Video::Controller (line 2) | class Course::Video::Controller < Course::ComponentController
method current_tab (line 9) | def current_tab
method component (line 15) | def component
FILE: app/controllers/course/video/submission/controller.rb
class Course::Video::Submission::Controller (line 2) | class Course::Video::Submission::Controller < Course::Video::Controller
FILE: app/controllers/course/video/submission/sessions_controller.rb
class Course::Video::Submission::SessionsController (line 2) | class Course::Video::Submission::SessionsController < Course::Video::Sub...
method create (line 5) | def create
method update (line 9) | def update
method current_tab (line 37) | def current_tab
method update_params (line 41) | def update_params
method video_params (line 47) | def video_params
FILE: app/controllers/course/video/submission/submissions_controller.rb
class Course::Video::Submission::SubmissionsController (line 2) | class Course::Video::Submission::SubmissionsController < Course::Video::...
method index (line 11) | def index
method show (line 21) | def show
method create (line 29) | def create
method edit (line 39) | def edit
method create_params (line 57) | def create_params
method scroll_topic_params (line 61) | def scroll_topic_params
method seek_time_params (line 65) | def seek_time_params
method authorize_attempt_video! (line 69) | def authorize_attempt_video!
method authorize_analyze_video! (line 73) | def authorize_analyze_video!
method set_seek_and_scroll (line 77) | def set_seek_and_scroll
method set_monitoring (line 83) | def set_monitoring
method current_tab (line 88) | def current_tab
FILE: app/controllers/course/video/topics_controller.rb
class Course::Video::TopicsController (line 2) | class Course::Video::TopicsController < Course::Video::Controller
method index (line 8) | def index
method create (line 14) | def create
method show (line 25) | def show
method topic_params (line 30) | def topic_params
method discussion_topic (line 34) | def discussion_topic
method create_topic_subscription (line 38) | def create_topic_subscription
method current_tab (line 42) | def current_tab
FILE: app/controllers/course/video/videos_controller.rb
class Course::Video::VideosController (line 2) | class Course::Video::VideosController < Course::Video::Controller
method index (line 7) | def index
method show (line 25) | def show
method create (line 31) | def create
method update (line 41) | def update
method destroy (line 53) | def destroy
method can_for_videos_in_current_course? (line 63) | def can_for_videos_in_current_course?(ability)
method video_params (line 67) | def video_params
method current_tab (line 73) | def current_tab
method load_video_tabs (line 83) | def load_video_tabs
method preload_video_item (line 87) | def preload_video_item
method preload_student_submission_count (line 98) | def preload_student_submission_count
FILE: app/controllers/course/video_submissions_controller.rb
class Course::VideoSubmissionsController (line 2) | class Course::VideoSubmissionsController < Course::ComponentController
method index (line 7) | def index
method component (line 18) | def component
method load_video_submissions (line 23) | def load_video_submissions
method authorize_analyze_video! (line 27) | def authorize_analyze_video!
FILE: app/controllers/csrf_token_controller.rb
class CsrfTokenController (line 2) | class CsrfTokenController < ApplicationController
method csrf_token (line 3) | def csrf_token
method publicly_accessible? (line 9) | def publicly_accessible?
FILE: app/controllers/health_check_controller.rb
class HealthCheckController (line 3) | class HealthCheckController < ActionController::Base
method show (line 6) | def show
FILE: app/controllers/instance_user_role_requests_controller.rb
class InstanceUserRoleRequestsController (line 2) | class InstanceUserRoleRequestsController < ApplicationController
method index (line 5) | def index
method create (line 13) | def create
method update (line 23) | def update
method approve (line 31) | def approve
method reject (line 43) | def reject
method user_role_request_params (line 54) | def user_role_request_params
method user_role_request_rejection_params (line 58) | def user_role_request_rejection_params
method send_rejection_email (line 62) | def send_rejection_email
FILE: app/controllers/jobs_controller.rb
class JobsController (line 2) | class JobsController < ApplicationController
method show (line 5) | def show
method publicly_accessible? (line 17) | def publicly_accessible?
method load_job (line 23) | def load_job
method show_completed_job (line 27) | def show_completed_job
method show_errored_job (line 33) | def show_errored_job
method show_submitted_job (line 39) | def show_submitted_job
FILE: app/controllers/system/admin/admin_controller.rb
class System::Admin::AdminController (line 2) | class System::Admin::AdminController < System::Admin::Controller
method index (line 3) | def index
method deployment_info (line 6) | def deployment_info
FILE: app/controllers/system/admin/announcements_controller.rb
class System::Admin::AnnouncementsController (line 2) | class System::Admin::AnnouncementsController < System::Admin::Controller
method index (line 5) | def index
method create (line 13) | def create
method update (line 23) | def update
method destroy (line 33) | def destroy
method announcement_params (line 43) | def announcement_params
FILE: app/controllers/system/admin/controller.rb
class System::Admin::Controller (line 2) | class System::Admin::Controller < ApplicationController
method authorize_admin (line 7) | def authorize_admin
FILE: app/controllers/system/admin/courses_controller.rb
class System::Admin::CoursesController (line 2) | class System::Admin::CoursesController < System::Admin::Controller
method index (line 5) | def index
method destroy (line 13) | def destroy
method search_param (line 25) | def search_param
method unscope_resources (line 29) | def unscope_resources(&block)
method preload_courses (line 33) | def preload_courses
FILE: app/controllers/system/admin/get_help_controller.rb
class System::Admin::GetHelpController (line 2) | class System::Admin::GetHelpController < System::Admin::Controller
method index (line 3) | def index
method sanitize_date_range (line 24) | def sanitize_date_range(start_at_param, end_at_param)
method valid_date_range? (line 30) | def valid_date_range?(start_date, end_date)
method load_course_user_hash (line 36) | def load_course_user_hash(user_ids)
method fetch_system_get_help_data (line 43) | def fetch_system_get_help_data(start_date, end_date)
method load_assessment_and_course_hash (line 64) | def load_assessment_and_course_hash(assessment_ids)
method load_course_instance_hash (line 79) | def load_course_instance_hash
method build_question_hash (line 93) | def build_question_hash(assessment, question_assessment, course, quest...
FILE: app/controllers/system/admin/instance/admin_controller.rb
class System::Admin::Instance::AdminController (line 2) | class System::Admin::Instance::AdminController < System::Admin::Instance...
method index (line 3) | def index
FILE: app/controllers/system/admin/instance/announcements_controller.rb
class System::Admin::Instance::AnnouncementsController (line 2) | class System::Admin::Instance::AnnouncementsController < System::Admin::...
method index (line 6) | def index
method create (line 14) | def create
method update (line 24) | def update
method destroy (line 34) | def destroy
method announcement_params (line 44) | def announcement_params
FILE: app/controllers/system/admin/instance/components_controller.rb
class System::Admin::Instance::ComponentsController (line 2) | class System::Admin::Instance::ComponentsController < System::Admin::Ins...
method index (line 5) | def index
method update (line 11) | def update
method settings_components_params (line 21) | def settings_components_params
method settings (line 26) | def settings
FILE: app/controllers/system/admin/instance/controller.rb
class System::Admin::Instance::Controller (line 2) | class System::Admin::Instance::Controller < ApplicationController
method load_instance (line 8) | def load_instance
method authorize_instance_admin (line 12) | def authorize_instance_admin
FILE: app/controllers/system/admin/instance/courses_controller.rb
class System::Admin::Instance::CoursesController (line 2) | class System::Admin::Instance::CoursesController < System::Admin::Instan...
method index (line 5) | def index
method destroy (line 13) | def destroy
method search_param (line 23) | def search_param
method preload_courses (line 27) | def preload_courses # rubocop:disable Metrics/AbcSize
FILE: app/controllers/system/admin/instance/get_help_controller.rb
class System::Admin::Instance::GetHelpController (line 2) | class System::Admin::Instance::GetHelpController < System::Admin::Instan...
method index (line 3) | def index
method sanitize_date_range (line 21) | def sanitize_date_range(start_at_param, end_at_param)
method valid_date_range? (line 27) | def valid_date_range?(start_date, end_date)
method load_course_user_hash (line 33) | def load_course_user_hash(user_ids)
method fetch_instance_get_help_data (line 41) | def fetch_instance_get_help_data(start_date, end_date)
method load_assessment_and_course_hash (line 67) | def load_assessment_and_course_hash(assessment_ids)
method build_question_hash (line 82) | def build_question_hash(assessment, question_assessment, course, quest...
FILE: app/controllers/system/admin/instance/user_invitations_controller.rb
class System::Admin::Instance::UserInvitationsController (line 2) | class System::Admin::Instance::UserInvitationsController < System::Admin...
method index (line 7) | def index
method new (line 14) | def new
method create (line 18) | def create
method destroy (line 30) | def destroy
method resend_invitation (line 39) | def resend_invitation
method resend_invitations (line 49) | def resend_invitations
method instance_user_invitation_params (line 60) | def instance_user_invitation_params
method invitation_params (line 67) | def invitation_params
method resend_invitation_params (line 71) | def resend_invitation_params
method invite (line 79) | def invite
method invitation_service (line 83) | def invitation_service
method invitations (line 87) | def invitations
method parse_invitation_result (line 100) | def parse_invitation_result(new_invitations, existing_invitations, new...
FILE: app/controllers/system/admin/instance/users_controller.rb
class System::Admin::Instance::UsersController (line 2) | class System::Admin::Instance::UsersController < System::Admin::Instance...
method index (line 6) | def index
method update (line 15) | def update
method destroy (line 25) | def destroy
method load_instance_users (line 35) | def load_instance_users
method load_counts (line 49) | def load_counts
method instance_user_params (line 56) | def instance_user_params
method search_param (line 60) | def search_param
FILE: app/controllers/system/admin/instances_controller.rb
class System::Admin::InstancesController (line 2) | class System::Admin::InstancesController < System::Admin::Controller
method index (line 5) | def index
method create (line 13) | def create
method update (line 22) | def update
method destroy (line 32) | def destroy
method instance_params (line 42) | def instance_params
method preload_instances (line 46) | def preload_instances
FILE: app/controllers/system/admin/users_controller.rb
class System::Admin::UsersController (line 2) | class System::Admin::UsersController < System::Admin::Controller
method index (line 5) | def index
method update (line 17) | def update
method destroy (line 28) | def destroy
method get_user_course_hash (line 47) | def get_user_course_hash(user_ids)
method user_params (line 53) | def user_params
method search_param (line 57) | def search_param
method load_users (line 61) | def load_users
method load_counts (line 69) | def load_counts
FILE: app/controllers/test/controller.rb
class Test::Controller (line 2) | class Test::Controller < ActionController::Base
method restrict_to_test (line 7) | def restrict_to_test
FILE: app/controllers/test/factories_controller.rb
class Test::FactoriesController (line 2) | class Test::FactoriesController < Test::Controller
method create (line 5) | def create
method create_params (line 24) | def create_params
method set_user_stamper (line 28) | def set_user_stamper
method traits_from (line 32) | def traits_from(attributes)
FILE: app/controllers/test/mailer_controller.rb
class Test::MailerController (line 2) | class Test::MailerController < Test::Controller
method last_sent (line 3) | def last_sent
method clear (line 7) | def clear
FILE: app/controllers/user/confirmations_controller.rb
class User::ConfirmationsController (line 2) | class User::ConfirmationsController < Devise::ConfirmationsController
method show (line 5) | def show
FILE: app/controllers/user/emails_controller.rb
class User::EmailsController (line 2) | class User::EmailsController < ApplicationController
method index (line 5) | def index
method create (line 8) | def create
method destroy (line 16) | def destroy
method set_primary (line 25) | def set_primary
method send_confirmation (line 34) | def send_confirmation
method render_emails (line 45) | def render_emails
method email_params (line 50) | def email_params
FILE: app/controllers/user/passwords_controller.rb
class User::PasswordsController (line 2) | class User::PasswordsController < Devise::PasswordsController
method edit (line 5) | def edit
method hash_reset_password_token (line 17) | def hash_reset_password_token(token)
FILE: app/controllers/user/profiles_controller.rb
class User::ProfilesController (line 2) | class User::ProfilesController < ApplicationController
method show (line 3) | def show
method edit (line 6) | def edit
method update (line 9) | def update
method time_zones (line 18) | def time_zones
method profile_params (line 24) | def profile_params
FILE: app/controllers/user/registrations_controller.rb
class User::RegistrationsController (line 2) | class User::RegistrationsController < Devise::RegistrationsController
method new (line 8) | def new
method create (line 38) | def create
method configure_sign_up_params (line 96) | def configure_sign_up_params
method build_resource (line 117) | def build_resource(*)
method load_invitation (line 122) | def load_invitation
method invitation_params (line 134) | def invitation_params
method authenticate_scope! (line 138) | def authenticate_scope!
FILE: app/controllers/user/sessions_controller.rb
class User::SessionsController (line 2) | class User::SessionsController < Devise::SessionsController
FILE: app/controllers/users_controller.rb
class UsersController (line 2) | class UsersController < ApplicationController
method show (line 5) | def show
FILE: app/helpers/application_formatters_helper.rb
type ApplicationFormattersHelper (line 5) | module ApplicationFormattersHelper
function format_inline_text (line 12) | def format_inline_text(text)
function display_user (line 21) | def display_user(user)
function user_image (line 30) | def user_image(user, url: false)
function link_to_user (line 43) | def link_to_user(user, options = {})
function format_datetime (line 69) | def format_datetime(date, format = :long, user: nil)
function format_duration (line 81) | def format_duration(total_seconds)
function clean_html_text (line 96) | def clean_html_text(text)
function clean_html_text_blank? (line 109) | def clean_html_text_blank?(text)
FILE: app/helpers/application_helper.rb
type ApplicationHelper (line 3) | module ApplicationHelper
function user_time_zone (line 10) | def user_time_zone
function url_to_course_logo (line 14) | def url_to_course_logo(course)
FILE: app/helpers/application_html_formatters_helper.rb
type ApplicationHtmlFormattersHelper (line 3) | module ApplicationHtmlFormattersHelper
function sanitize (line 9) | def sanitize(text, _options = {})
function format_html (line 19) | def format_html(text)
function format_ckeditor_rich_text (line 23) | def format_ckeditor_rich_text(text)
function sanitize_ckeditor_rich_text (line 27) | def sanitize_ckeditor_rich_text(text)
function format_code_block (line 41) | def format_code_block(code, language = nil, start_line = 1)
function highlight_code_block (line 59) | def highlight_code_block(code, language = nil)
function build_html_pipeline (line 75) | def self.build_html_pipeline(custom_options)
function code_size_exceeds_limit? (line 226) | def code_size_exceeds_limit?(code)
function sanitize_and_format_code (line 230) | def sanitize_and_format_code(code, language, start_line)
function process_ckeditor_rich_text_with_pipeline (line 242) | def process_ckeditor_rich_text_with_pipeline(pipeline, text)
function format_with_pipeline (line 255) | def format_with_pipeline(pipeline, text)
function default_code_pipeline (line 263) | def default_code_pipeline(starting_line_number = 1)
function remove_internal_adjacent_code_tags (line 278) | def remove_internal_adjacent_code_tags(text)
FILE: app/helpers/application_jobs_helper.rb
type ApplicationJobsHelper (line 3) | module ApplicationJobsHelper
function job_error_message (line 4) | def job_error_message(error)
FILE: app/helpers/application_mailer_helper.rb
type ApplicationMailerHelper (line 3) | module ApplicationMailerHelper
function plain_link_to (line 8) | def plain_link_to(text, url)
FILE: app/helpers/application_notifications_helper.rb
type ApplicationNotificationsHelper (line 2) | module ApplicationNotificationsHelper
function notification_view_path (line 7) | def notification_view_path(notification)
function notification_directory_path (line 15) | def notification_directory_path(notification)
FILE: app/helpers/consolidated_opening_reminder_mailer_helper.rb
type ConsolidatedOpeningReminderMailerHelper (line 2) | module ConsolidatedOpeningReminderMailerHelper
function actable_type_partial_path (line 10) | def actable_type_partial_path(notification, actable_type)
FILE: app/helpers/course/achievement/achievements_helper.rb
type Course::Achievement::AchievementsHelper (line 2) | module Course::Achievement::AchievementsHelper
function achievement_badge_path (line 8) | def achievement_badge_path(achievement = nil)
FILE: app/helpers/course/achievement/controller_helper.rb
type Course::Achievement::ControllerHelper (line 2) | module Course::Achievement::ControllerHelper
function achievement_status_class (line 13) | def achievement_status_class(achievement, current_course_user)
FILE: app/helpers/course/assessment/answer/programming_test_case_helper.rb
type Course::Assessment::Answer::ProgrammingTestCaseHelper (line 2) | module Course::Assessment::Answer::ProgrammingTestCaseHelper
function get_hint (line 9) | def get_hint(test_case, test_case_result)
function get_output (line 21) | def get_output(test_case_result)
function get_failed_test_cases_by_type (line 35) | def get_failed_test_cases_by_type(test_cases_and_results)
function get_test_cases_and_results (line 54) | def get_test_cases_and_results(test_cases_by_type, auto_grading)
function get_first_failed_test (line 69) | def get_first_failed_test(test_cases_and_results_of_type)
FILE: app/helpers/course/assessment/assessments_helper.rb
type Course::Assessment::AssessmentsHelper (line 2) | module Course::Assessment::AssessmentsHelper
function condition_not_satisfied (line 6) | def condition_not_satisfied(can_attempt, assessment, assessment_time)
function assessment_not_started (line 12) | def assessment_not_started(assessment_time)
function show_bonus_attributes? (line 16) | def show_bonus_attributes?
function show_end_at? (line 26) | def show_end_at?
function display_graded_test_types (line 32) | def display_graded_test_types(assessment)
FILE: app/helpers/course/assessment/question/programming_helper.rb
type Course::Assessment::Question::ProgrammingHelper (line 2) | module Course::Assessment::Question::ProgrammingHelper
function import_result_error (line 7) | def import_result_error
function import_errored? (line 20) | def import_errored?
function display_build_log? (line 27) | def display_build_log?
function validation_errors (line 33) | def validation_errors
function check_import_job? (line 39) | def check_import_job?
function can_switch_package_type? (line 43) | def can_switch_package_type?
function can_edit_online? (line 47) | def can_edit_online?
function import_job_error_map (line 55) | def import_job_error_map
FILE: app/helpers/course/assessment/submission/submissions_helper.rb
type Course::Assessment::Submission::SubmissionsHelper (line 2) | module Course::Assessment::Submission::SubmissionsHelper
function last_attempt (line 14) | def last_attempt(answer)
FILE: app/helpers/course/assessment/submissions_helper.rb
type Course::Assessment::SubmissionsHelper (line 2) | module Course::Assessment::SubmissionsHelper
function pending_submissions_count (line 6) | def pending_submissions_count
function my_students_pending_submissions_count (line 16) | def my_students_pending_submissions_count
function pending_submission_count_for (line 29) | def pending_submission_count_for(student_ids)
FILE: app/helpers/course/condition/conditions_helper.rb
type Course::Condition::ConditionsHelper (line 2) | module Course::Condition::ConditionsHelper
function component_enabled? (line 8) | def component_enabled?(class_name)
function conditions_component_hash (line 17) | def conditions_component_hash
FILE: app/helpers/course/controller_helper.rb
type Course::ControllerHelper (line 2) | module Course::ControllerHelper
function display_course_user (line 10) | def display_course_user(user)
function display_user (line 20) | def display_user(user)
function link_to_course_user (line 41) | def link_to_course_user(user, options = {})
function link_to_user (line 55) | def link_to_user(user, options = {}, &block)
function url_to_material (line 66) | def url_to_material(course, folder, material)
FILE: app/helpers/course/discussion/topics_helper.rb
type Course::Discussion::TopicsHelper (line 2) | module Course::Discussion::TopicsHelper
function display_code_lines (line 9) | def display_code_lines(file, line_start, line_end)
function all_staff_unread_count (line 20) | def all_staff_unread_count
function my_students_unread_count (line 25) | def my_students_unread_count
function from_user (line 39) | def from_user(topic, my_student_ids) # rubocop:disable Metrics/Perceiv...
function all_student_unread_count (line 53) | def all_student_unread_count
FILE: app/helpers/course/forum/controller_helper.rb
type Course::Forum::ControllerHelper (line 2) | module Course::Forum::ControllerHelper
function next_unread_topic_link (line 7) | def next_unread_topic_link(forum = nil)
function email_setting_enabled (line 18) | def email_setting_enabled(component, setting)
function email_setting_enabled_current_course_user (line 22) | def email_setting_enabled_current_course_user(component, setting)
function email_subscription_enabled_current_course_user (line 28) | def email_subscription_enabled_current_course_user(component, setting)
function topic_type_keys (line 34) | def topic_type_keys(topic)
function post_anonymous? (line 41) | def post_anonymous?(post)
FILE: app/helpers/course/group/group_categories_helper.rb
type Course::Group::GroupCategoriesHelper (line 2) | module Course::Group::GroupCategoriesHelper
FILE: app/helpers/course/leaderboards_helper.rb
type Course::LeaderboardsHelper (line 2) | module Course::LeaderboardsHelper
function display_user_count (line 6) | def display_user_count
function leaderboard_position (line 17) | def leaderboard_position(course, course_user, display_user_count)
FILE: app/helpers/course/material/folders_helper.rb
type Course::Material::FoldersHelper (line 2) | module Course::Material::FoldersHelper
function show_sdl_warning? (line 8) | def show_sdl_warning?(folder)
FILE: app/helpers/course/object_duplications_helper.rb
type Course::ObjectDuplicationsHelper (line 2) | module Course::ObjectDuplicationsHelper
function cherrypickable_components_hash (line 4) | def cherrypickable_components_hash
function cherrypickable_items_hash (line 15) | def cherrypickable_items_hash
function map_components_to_frontend_tokens (line 31) | def map_components_to_frontend_tokens(components)
FILE: app/helpers/course/users_helper.rb
type Course::UsersHelper (line 2) | module Course::UsersHelper
function preload_course_users_hash (line 7) | def preload_course_users_hash(course)
FILE: app/helpers/route_overrides_helper.rb
type RouteOverridesHelper (line 2) | module RouteOverridesHelper
function mapping_for (line 6) | def mapping_for(from, to)
function map_route_helpers_with (line 13) | def map_route_helpers_with(mapping)
function map_route (line 30) | def map_route(from, to:)
FILE: app/helpers/tmp_cleanup_helper.rb
type TmpCleanupHelper (line 2) | module TmpCleanupHelper
function cleanup (line 5) | def cleanup
FILE: app/jobs/application_job.rb
class ApplicationJob (line 2) | class ApplicationJob < ActiveJob::Base
FILE: app/jobs/consolidated_item_email_job.rb
class ConsolidatedItemEmailJob (line 2) | class ConsolidatedItemEmailJob < ApplicationJob
method perform (line 4) | def perform
FILE: app/jobs/course/announcement/opening_reminder_job.rb
class Course::Announcement::OpeningReminderJob (line 2) | class Course::Announcement::OpeningReminderJob < ApplicationJob
method perform (line 7) | def perform(user, announcement, token)
FILE: app/jobs/course/assessment/answer/auto_grading_job.rb
class Course::Assessment::Answer::AutoGradingJob (line 2) | class Course::Assessment::Answer::AutoGradingJob < Course::Assessment::A...
method default_queue_name (line 23) | def default_queue_name
method delayed_queue_name (line 27) | def delayed_queue_name
FILE: app/jobs/course/assessment/answer/base_auto_grading_job.rb
class Course::Assessment::Answer::BaseAutoGradingJob (line 2) | class Course::Assessment::Answer::BaseAutoGradingJob < ApplicationJob
class PriorityShouldBeLoweredError (line 7) | class PriorityShouldBeLoweredError < StandardError
method initialize (line 8) | def initialize(message = nil)
method default_queue_name (line 24) | def default_queue_name
method delayed_queue_name (line 28) | def delayed_queue_name
method perform_tracked (line 38) | def perform_tracked(answer, redirect_to_path = nil)
method update_exp? (line 54) | def update_exp?(submission)
method downgrade_if_timeout (line 59) | def downgrade_if_timeout(question, &block)
FILE: app/jobs/course/assessment/answer/programming_codaveri_feedback_job.rb
class Course::Assessment::Answer::ProgrammingCodaveriFeedbackJob (line 2) | class Course::Assessment::Answer::ProgrammingCodaveriFeedbackJob < Appli...
method perform_tracked (line 10) | def perform_tracked(assessment, question, answer)
FILE: app/jobs/course/assessment/answer/reduce_priority_auto_grading_job.rb
class Course::Assessment::Answer::ReducePriorityAutoGradingJob (line 2) | class Course::Assessment::Answer::ReducePriorityAutoGradingJob < Course:...
method default_queue_name (line 18) | def default_queue_name
method delayed_queue_name (line 22) | def delayed_queue_name
FILE: app/jobs/course/assessment/closing_reminder_job.rb
class Course::Assessment::ClosingReminderJob (line 2) | class Course::Assessment::ClosingReminderJob < ApplicationJob
method perform (line 7) | def perform(assessment, token)
FILE: app/jobs/course/assessment/invite_to_koditsu_job.rb
class Course::Assessment::InviteToKoditsuJob (line 2) | class Course::Assessment::InviteToKoditsuJob < ApplicationJob
method perform_tracked (line 9) | def perform_tracked(assessment_id, updated_at)
FILE: app/jobs/course/assessment/plagiarism_check_job.rb
class Course::Assessment::PlagiarismCheckJob (line 2) | class Course::Assessment::PlagiarismCheckJob < ApplicationJob
method perform_tracked (line 7) | def perform_tracked(course, assessment)
FILE: app/jobs/course/assessment/question/answers_evaluation_job.rb
class Course::Assessment::Question::AnswersEvaluationJob (line 2) | class Course::Assessment::Question::AnswersEvaluationJob < ApplicationJob
method perform (line 3) | def perform(question)
FILE: app/jobs/course/assessment/question/codaveri_import_job.rb
class Course::Assessment::Question::CodaveriImportJob (line 2) | class Course::Assessment::Question::CodaveriImportJob < ApplicationJob
method perform_tracked (line 13) | def perform_tracked(question, attachment)
method perform_import (line 24) | def perform_import(question, attachment)
FILE: app/jobs/course/assessment/question/programming_import_job.rb
class Course::Assessment::Question::ProgrammingImportJob (line 2) | class Course::Assessment::Question::ProgrammingImportJob < ApplicationJob
method perform_tracked (line 13) | def perform_tracked(question, attachment, max_time_limit)
method perform_import (line 25) | def perform_import(question, attachment)
FILE: app/jobs/course/assessment/submission/auto_feedback_job.rb
class Course::Assessment::Submission::AutoFeedbackJob (line 2) | class Course::Assessment::Submission::AutoFeedbackJob < ApplicationJob
method perform_tracked (line 12) | def perform_tracked(submission)
FILE: app/jobs/course/assessment/submission/auto_grading_job.rb
class Course::Assessment::Submission::AutoGradingJob (line 2) | class Course::Assessment::Submission::AutoGradingJob < ApplicationJob
method perform_tracked (line 35) | def perform_tracked(submission, only_ungraded = false) # rubocop:disab...
FILE: app/jobs/course/assessment/submission/csv_download_job.rb
class Course::Assessment::Submission::CsvDownloadJob (line 2) | class Course::Assessment::Submission::CsvDownloadJob < ApplicationJob
method perform_tracked (line 14) | def perform_tracked(current_course_user, assessment, course_users = nil)
FILE: app/jobs/course/assessment/submission/deleting_job.rb
class Course::Assessment::Submission::DeletingJob (line 2) | class Course::Assessment::Submission::DeletingJob < ApplicationJob
method perform_tracked (line 8) | def perform_tracked(deleter, submission_ids, assessment)
method delete_submission (line 23) | def delete_submission(assessment, submissions, deleter)
method reset_question_bundle_assignments (line 43) | def reset_question_bundle_assignments(assessment, submissions)
FILE: app/jobs/course/assessment/submission/fetch_submissions_from_koditsu_job.rb
class Course::Assessment::Submission::FetchSubmissionsFromKoditsuJob (line 2) | class Course::Assessment::Submission::FetchSubmissionsFromKoditsuJob <
method perform_tracked (line 10) | def perform_tracked(assessment_id, updated_at, user)
FILE: app/jobs/course/assessment/submission/force_submit_timed_submission_job.rb
class Course::Assessment::Submission::ForceSubmitTimedSubmissionJob (line 3) | class Course::Assessment::Submission::ForceSubmitTimedSubmissionJob < Ap...
method perform_tracked (line 9) | def perform_tracked(assessment, submission_id, submitter)
method force_submit (line 22) | def force_submit(submission, submitter)
FILE: app/jobs/course/assessment/submission/force_submitting_job.rb
class Course::Assessment::Submission::ForceSubmittingJob (line 4) | class Course::Assessment::Submission::ForceSubmittingJob < ApplicationJob
method perform_tracked (line 16) | def perform_tracked(assessment, user_ids, user_ids_without_submission,...
method force_create_and_submit_submissions (line 32) | def force_create_and_submit_submissions(assessment, user_ids, user_ids...
method create_submission (line 52) | def create_submission(assessment, course_user)
method grade_submission (line 68) | def grade_submission(assessment, submission)
method grade_answers (line 89) | def grade_answers(submission)
FILE: app/jobs/course/assessment/submission/publishing_job.rb
class Course::Assessment::Submission::PublishingJob (line 2) | class Course::Assessment::Submission::PublishingJob < ApplicationJob
method perform_tracked (line 8) | def perform_tracked(graded_submission_ids, assessment, publisher)
method publish_submissions (line 23) | def publish_submissions(submissions, publisher)
FILE: app/jobs/course/assessment/submission/statistics_download_job.rb
class Course::Assessment::Submission::StatisticsDownloadJob (line 2) | class Course::Assessment::Submission::StatisticsDownloadJob < Applicatio...
method perform_tracked (line 14) | def perform_tracked(current_course, current_user, submission_ids)
FILE: app/jobs/course/assessment/submission/unsubmitting_job.rb
class Course::Assessment::Submission::UnsubmittingJob (line 5) | class Course::Assessment::Submission::UnsubmittingJob < ApplicationJob
method perform_tracked (line 19) | def perform_tracked(unsubmitter, submission_ids, assessment, question ...
method unsubmit_submission (line 36) | def unsubmit_submission(assessment, submissions, question, unsubmitter)
FILE: app/jobs/course/assessment/submission/zip_download_job.rb
class Course::Assessment::Submission::ZipDownloadJob (line 2) | class Course::Assessment::Submission::ZipDownloadJob < ApplicationJob
method perform_tracked (line 14) | def perform_tracked(course_user, assessment, course_users = nil)
FILE: app/jobs/course/conditional/conditional_satisfiability_evaluation_job.rb
class Course::Conditional::ConditionalSatisfiabilityEvaluationJob (line 2) | class Course::Conditional::ConditionalSatisfiabilityEvaluationJob < Appl...
method perform_tracked (line 13) | def perform_tracked(course_user, redirect_to_path = nil)
FILE: app/jobs/course/conditional/coursewide_conditional_satisfiability_evaluation_job.rb
class Course::Conditional::CoursewideConditionalSatisfiabilityEvaluationJob (line 2) | class Course::Conditional::CoursewideConditionalSatisfiabilityEvaluation...
method perform_tracked (line 16) | def perform_tracked(course, latest_update_time, redirect_to_path = nil)
FILE: app/jobs/course/discussion/post/codaveri_feedback_rating_job.rb
class Course::Discussion::Post::CodaveriFeedbackRatingJob (line 2) | class Course::Discussion::Post::CodaveriFeedbackRatingJob < ApplicationJob
method perform_tracked (line 10) | def perform_tracked(codaveri_feedback)
FILE: app/jobs/course/duplication_job.rb
class Course::DuplicationJob (line 2) | class Course::DuplicationJob < ApplicationJob
method perform_tracked (line 13) | def perform_tracked(source_course, options = {})
FILE: app/jobs/course/experience_points_download_job.rb
class Course::ExperiencePointsDownloadJob (line 2) | class Course::ExperiencePointsDownloadJob < ApplicationJob
method perform_tracked (line 9) | def perform_tracked(course, course_user_id)
FILE: app/jobs/course/forum/auto_answering_job.rb
class Course::Forum::AutoAnsweringJob (line 2) | class Course::Forum::AutoAnsweringJob < ApplicationJob
method perform_tracked (line 10) | def perform_tracked(post, topic, current_author, current_course_author...
method create_response_post (line 27) | def create_response_post(post, response, current_author, evaluation)
method publish_if_needed (line 41) | def publish_if_needed(post, topic, current_author, current_course_author)
method answering! (line 47) | def answering!(post)
method cancel_answering! (line 52) | def cancel_answering!(post)
FILE: app/jobs/course/forum/importing_job.rb
class Course::Forum::ImportingJob (line 2) | class Course::Forum::ImportingJob < ApplicationJob
method perform_tracked (line 8) | def perform_tracked(forum_import_ids, current_user)
FILE: app/jobs/course/lesson_plan/coursewide_personalized_timeline_update_job.rb
class Course::LessonPlan::CoursewidePersonalizedTimelineUpdateJob (line 2) | class Course::LessonPlan::CoursewidePersonalizedTimelineUpdateJob < Appl...
method perform (line 6) | def perform(lesson_plan_item)
FILE: app/jobs/course/material/text_chunk_job.rb
class Course::Material::TextChunkJob (line 2) | class Course::Material::TextChunkJob < ApplicationJob
method perform_tracked (line 8) | def perform_tracked(material_ids, current_user)
FILE: app/jobs/course/material/zip_download_job.rb
class Course::Material::ZipDownloadJob (line 2) | class Course::Material::ZipDownloadJob < ApplicationJob
method perform_tracked (line 16) | def perform_tracked(folder, materials, filename = folder.name)
FILE: app/jobs/course/object_duplication_job.rb
class Course::ObjectDuplicationJob (line 2) | class Course::ObjectDuplicationJob < ApplicationJob
method perform_tracked (line 15) | def perform_tracked(source_course, destination_course, objects, option...
FILE: app/jobs/course/rubric/rubric_evaluation_export_job.rb
class Course::Rubric::RubricEvaluationExportJob (line 2) | class Course::Rubric::RubricEvaluationExportJob < ApplicationJob # ruboc...
method perform_tracked (line 6) | def perform_tracked(course, rubric_id, question_id)
method load_answers_and_evaluations (line 22) | def load_answers_and_evaluations(rubric, question)
method evaluate_answer (line 38) | def evaluate_answer(answer, rubric)
method export_rubric_to_rubric_based_response_question (line 56) | def export_rubric_to_rubric_based_response_question(rubric, rubric_bas...
method build_exported_rubric_hashes (line 83) | def build_exported_rubric_hashes(rubric, rubric_based_response_question)
method update_answer_grade_and_feedback (line 100) | def update_answer_grade_and_feedback(answer, answer_evaluation)
method build_answer_v1_selections (line 109) | def build_answer_v1_selections(answer_evaluation, exported_categories_...
method export_answer_rubric_grading_data (line 119) | def export_answer_rubric_grading_data(rubric, answers_to_export, expor...
FILE: app/jobs/course/statistics/assessments_score_summary_download_job.rb
class Course::Statistics::AssessmentsScoreSummaryDownloadJob (line 2) | class Course::Statistics::AssessmentsScoreSummaryDownloadJob < Applicati...
method perform_tracked (line 9) | def perform_tracked(course, assessment_ids)
FILE: app/jobs/course/survey/closing_reminder_job.rb
class Course::Survey::ClosingReminderJob (line 2) | class Course::Survey::ClosingReminderJob < ApplicationJob
method perform (line 7) | def perform(survey, token)
FILE: app/jobs/course/survey/survey_download_job.rb
class Course::Survey::SurveyDownloadJob (line 2) | class Course::Survey::SurveyDownloadJob < ApplicationJob
method perform_tracked (line 12) | def perform_tracked(survey)
FILE: app/jobs/course/user_deletion_job.rb
class Course::UserDeletionJob (line 2) | class Course::UserDeletionJob < ApplicationJob
method perform (line 3) | def perform(course, course_user, current_user)
FILE: app/jobs/course/video/closing_reminder_job.rb
class Course::Video::ClosingReminderJob (line 2) | class Course::Video::ClosingReminderJob < ApplicationJob
method perform (line 7) | def perform(video, token)
FILE: app/jobs/read_marks_clean_up_job.rb
class ReadMarksCleanUpJob (line 2) | class ReadMarksCleanUpJob < ApplicationJob
method perform (line 3) | def perform
FILE: app/jobs/user_email_database_cleanup_job.rb
class UserEmailDatabaseCleanupJob (line 2) | class UserEmailDatabaseCleanupJob < ApplicationJob
method perform (line 3) | def perform
method cleanup_unconfirmed_users (line 15) | def cleanup_unconfirmed_users
method cleanup_unconfirmed_secondary_emails (line 35) | def cleanup_unconfirmed_secondary_emails
FILE: app/jobs/video_statistic_update_job.rb
class VideoStatisticUpdateJob (line 2) | class VideoStatisticUpdateJob < ApplicationJob
method perform (line 10) | def perform
FILE: app/mailers/activity_mailer.rb
class ActivityMailer (line 5) | class ActivityMailer < ApplicationMailer
method email (line 20) | def email(recipient:, notification:, view_path:, layout_path: nil)
method mail (line 40) | def mail(options)
FILE: app/mailers/application_mailer.rb
class ApplicationMailer (line 2) | class ApplicationMailer < ActionMailer::Base
FILE: app/mailers/consolidated_opening_reminder_mailer.rb
class ConsolidatedOpeningReminderMailer (line 5) | class ConsolidatedOpeningReminderMailer < ActivityMailer
method email (line 17) | def email(recipient:, notification:, view_path:, layout_path: nil)
FILE: app/mailers/course/mailer.rb
class Course::Mailer (line 3) | class Course::Mailer < ApplicationMailer
method user_invitation_email (line 7) | def user_invitation_email(invitation)
method user_enrol_request_received_email (line 24) | def user_enrol_request_received_email(course, user, requires_confirmat...
method user_added_email (line 39) | def user_added_email(user, requires_confirmation: false)
method user_rejected_email (line 55) | def user_rejected_email(course, user)
method user_enrol_requested_email (line 69) | def user_enrol_requested_email(enrol_request)
method course_duplicated_email (line 102) | def course_duplicated_email(original_course, new_course, user)
method course_duplicate_failed_email (line 118) | def course_duplicate_failed_email(original_course, user)
method user_suspended_email (line 132) | def user_suspended_email(course_user)
method user_unsuspended_email (line 147) | def user_unsuspended_email(course_user)
method course_user_deletion_failed_email (line 158) | def course_user_deletion_failed_email(course, course_user, user)
method assessment_closing_reminder_email (line 174) | def assessment_closing_reminder_email(assessment, user)
method assessment_closing_summary_email (line 193) | def assessment_closing_summary_email(recipient, assessment, users)
method submission_graded_email (line 210) | def submission_graded_email(submission)
method video_closing_reminder_email (line 228) | def video_closing_reminder_email(recipient, video)
method survey_closing_reminder_email (line 245) | def survey_closing_reminder_email(recipient, survey)
method survey_closing_summary_email (line 264) | def survey_closing_summary_email(recipient, survey, student_list)
FILE: app/mailers/instance/mailer.rb
class Instance::Mailer (line 2) | class Instance::Mailer < ApplicationMailer
method user_invitation_email (line 7) | def user_invitation_email(invitation)
method user_added_email (line 19) | def user_added_email(user)
FILE: app/mailers/instance_user_role_request_mailer.rb
class InstanceUserRoleRequestMailer (line 3) | class InstanceUserRoleRequestMailer < ApplicationMailer
method new_role_request (line 10) | def new_role_request(request, recipient)
method role_request_approved (line 22) | def role_request_approved(instance_user)
method role_request_rejected (line 40) | def role_request_rejected(instance_user, message)
FILE: app/models/ability.rb
class Ability (line 2) | class Ability
method initialize (line 17) | def initialize(user, course = nil, course_user = nil, instance_user = ...
method define_permissions (line 36) | def define_permissions
FILE: app/models/activity.rb
class Activity (line 6) | class Activity < ApplicationRecord
method notify (line 25) | def notify(recipient, type)
method from_course? (line 41) | def from_course?(course)
method notify_course (line 48) | def notify_course(course, type)
method notify_user (line 55) | def notify_user(user, type)
FILE: app/models/application_record.rb
class ApplicationRecord (line 2) | class ApplicationRecord < ActiveRecord::Base
FILE: app/models/attachment.rb
class Attachment (line 2) | class Attachment < ApplicationRecord
method find_or_initialize_by (line 30) | def find_or_initialize_by(attributes, &block)
method find_or_create_by (line 43) | def find_or_create_by(attributes, &block)
method file_digest (line 55) | def file_digest(file)
method open (line 73) | def open(opt = {}, &block)
method open_with_block (line 85) | def open_with_block(opt, block)
method open_without_block (line 98) | def open_without_block(opt)
method contents (line 111) | def contents
FILE: app/models/attachment_reference.rb
class AttachmentReference (line 2) | class AttachmentReference < ApplicationRecord
method file= (line 23) | def file=(file)
method record_userstamp (line 29) | def record_userstamp
method initialize_duplicate (line 33) | def initialize_duplicate(duplicator, other)
method generate_public_url (line 40) | def generate_public_url
method filename (line 50) | def filename(file)
method update_expires_at (line 60) | def update_expires_at
FILE: app/models/cikgo_user.rb
class CikgoUser (line 2) | class CikgoUser < ApplicationRecord
FILE: app/models/components/ability_host.rb
class AbilityHost (line 2) | class AbilityHost
type InstanceHelpers (line 5) | module InstanceHelpers
function instance_user_hash (line 13) | def instance_user_hash(*roles)
function instance_instance_user_hash (line 22) | def instance_instance_user_hash(*roles)
type TimeBoundedHelpers (line 29) | module TimeBoundedHelpers
function currently_valid_hashes (line 37) | def currently_valid_hashes
function already_started_hash (line 55) | def already_started_hash
FILE: app/models/components/course/achievements_ability_component.rb
type Course::AchievementsAbilityComponent (line 2) | module Course::AchievementsAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_read_achievements (line 21) | def allow_read_achievements
function allow_user_with_achievement_show_badges (line 25) | def allow_user_with_achievement_show_badges
function allow_read_draft_achievements_and_display_badge (line 29) | def allow_read_draft_achievements_and_display_badge
function allow_manage_achievements (line 33) | def allow_manage_achievements
function do_not_allow_award_automatically_awarded_achievements (line 37) | def do_not_allow_award_automatically_awarded_achievements
FILE: app/models/components/course/announcements_ability_component.rb
type Course::AnnouncementsAbilityComponent (line 2) | module Course::AnnouncementsAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_students_show_announcements (line 17) | def allow_students_show_announcements
function allow_staff_read_announcements (line 21) | def allow_staff_read_announcements
function allow_teaching_staff_manage_announcements (line 25) | def allow_teaching_staff_manage_announcements
FILE: app/models/components/course/assessments_ability_component.rb
type Course::AssessmentsAbilityComponent (line 2) | module Course::AssessmentsAbilityComponent
FILE: app/models/components/course/conditions_ability_component.rb
type Course::ConditionsAbilityComponent (line 2) | module Course::ConditionsAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_teaching_staff_manage_conditions (line 13) | def allow_teaching_staff_manage_conditions
FILE: app/models/components/course/course_ability_component.rb
type Course::CourseAbilityComponent (line 2) | module Course::CourseAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_instructors_create_courses (line 28) | def allow_instructors_create_courses
function allow_unregistered_users_registering_courses (line 32) | def allow_unregistered_users_registering_courses
function allow_registered_users_showing_course (line 37) | def allow_registered_users_showing_course
function allow_staff_show_course_users (line 41) | def allow_staff_show_course_users
function define_teaching_staff_course_permissions (line 45) | def define_teaching_staff_course_permissions
function allow_teaching_staff_manage_personal_times (line 51) | def allow_teaching_staff_manage_personal_times
function allow_teaching_staff_analyze_videos (line 55) | def allow_teaching_staff_analyze_videos
function allow_teaching_staff_manage_course_rubrics (line 59) | def allow_teaching_staff_manage_course_rubrics
function define_owners_course_permissions (line 63) | def define_owners_course_permissions
function allow_owners_managing_course (line 67) | def allow_owners_managing_course
function disallow_managers_delete_course (line 74) | def disallow_managers_delete_course
FILE: app/models/components/course/course_user_ability_component.rb
type Course::CourseUserAbilityComponent (line 2) | module Course::CourseUserAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_course_users_show_coursemates (line 13) | def allow_course_users_show_coursemates
FILE: app/models/components/course/discussions_ability_component.rb
type Course::DiscussionsAbilityComponent (line 2) | module Course::DiscussionsAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_course_users_show_topics (line 23) | def allow_course_users_show_topics
function allow_course_users_mark_topics_as_read (line 27) | def allow_course_users_mark_topics_as_read
function allow_course_teaching_staff_manage_discussion_topics (line 31) | def allow_course_teaching_staff_manage_discussion_topics
function allow_course_users_create_posts (line 35) | def allow_course_users_create_posts
function allow_course_users_reply_and_vote_posts (line 39) | def allow_course_users_reply_and_vote_posts
function allow_course_users_view_own_anonymous_posts (line 43) | def allow_course_users_view_own_anonymous_posts
function allow_course_staff_view_anonymous_posts (line 47) | def allow_course_staff_view_anonymous_posts
function allow_course_teaching_staff_manage_posts (line 51) | def allow_course_teaching_staff_manage_posts
function allow_course_users_update_delete_own_post (line 55) | def allow_course_users_update_delete_own_post
FILE: app/models/components/course/duplication_ability_component.rb
type Course::DuplicationAbilityComponent (line 2) | module Course::DuplicationAbilityComponent
function define_permissions (line 5) | def define_permissions
function disallow_superusers_duplicate_via_frontend (line 24) | def disallow_superusers_duplicate_via_frontend
function allow_administrator_to_duplicate_cross_instances (line 29) | def allow_administrator_to_duplicate_cross_instances
function allow_instance_admin_to_duplicate_cross_instances (line 33) | def allow_instance_admin_to_duplicate_cross_instances
function allow_instance_instructor_to_duplicate_cross_instances (line 39) | def allow_instance_instructor_to_duplicate_cross_instances
function allow_managers_duplicate_to_course (line 45) | def allow_managers_duplicate_to_course
function allow_managers_duplicate_from_course (line 49) | def allow_managers_duplicate_from_course
function allow_observers_duplicate_from_course (line 53) | def allow_observers_duplicate_from_course
FILE: app/models/components/course/experience_points_disbursement_ability_component.rb
type Course::ExperiencePointsDisbursementAbilityComponent (line 2) | module Course::ExperiencePointsDisbursementAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_staff_disburse_experience_points (line 13) | def allow_staff_disburse_experience_points
FILE: app/models/components/course/experience_points_records_ability_component.rb
type Course::ExperiencePointsRecordsAbilityComponent (line 2) | module Course::ExperiencePointsRecordsAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_staff_read_all_experience_points (line 16) | def allow_staff_read_all_experience_points
function allow_manage_experience_points_records (line 21) | def allow_manage_experience_points_records
function allow_read_course_experience_points_records (line 25) | def allow_read_course_experience_points_records
function allow_read_own_experience_points_records (line 29) | def allow_read_own_experience_points_records
FILE: app/models/components/course/forums_ability_component.rb
type Course::ForumsAbilityComponent (line 2) | module Course::ForumsAbilityComponent
function define_permissions (line 5) | def define_permissions
function topic_course_hash (line 17) | def topic_course_hash
function define_all_forum_permissions (line 21) | def define_all_forum_permissions
function allow_show_forums (line 30) | def allow_show_forums
function allow_show_topics (line 35) | def allow_show_topics
function allow_create_topics (line 39) | def allow_create_topics
function allow_update_topics (line 43) | def allow_update_topics
function allow_reply_unlocked_topics (line 47) | def allow_reply_unlocked_topics
function allow_resolve_own_topics (line 52) | def allow_resolve_own_topics
function define_staff_forum_permissions (line 60) | def define_staff_forum_permissions
function allow_staff_show_all_topics (line 65) | def allow_staff_show_all_topics
function allow_staff_resolve_topics (line 70) | def allow_staff_resolve_topics
function define_teaching_staff_forum_permissions (line 74) | def define_teaching_staff_forum_permissions
function allow_teaching_staff_manage_forums (line 80) | def allow_teaching_staff_manage_forums
function allow_teaching_staff_manage_topics (line 84) | def allow_teaching_staff_manage_topics
function allow_manage_ai_responses (line 88) | def allow_manage_ai_responses
FILE: app/models/components/course/groups_ability_component.rb
type Course::GroupsAbilityComponent (line 2) | module Course::GroupsAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_staff_read_groups (line 18) | def allow_staff_read_groups
function allow_teaching_staff_manage_groups (line 23) | def allow_teaching_staff_manage_groups
function allow_group_manager_manage_group (line 28) | def allow_group_manager_manage_group
function allow_group_manager_read_group_category (line 32) | def allow_group_manager_read_group_category
function course_group_manager_hash (line 36) | def course_group_manager_hash
function course_group_category_manager_hash (line 41) | def course_group_category_manager_hash
FILE: app/models/components/course/learning_map_ability_component.rb
type Course::LearningMapAbilityComponent (line 2) | module Course::LearningMapAbilityComponent
function define_permissions (line 5) | def define_permissions
function allow_read_learning_map (line 12) | def allow_read_learning_map
FILE: app/models/components/course/lesson_plan_ability_component.rb
type Course::LessonPlanAbilityComponent (line 2) | module Course::LessonPlanAbilityComponent
function define_permissions (line 5) | def define_permissions
func
Copy disabled (too large)
Download .json
Condensed preview — 4409 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (12,274K chars).
[
{
"path": ".circleci/config.yml",
"chars": 15167,
"preview": "version: 2.1\n\norbs:\n codecov: codecov/codecov@5.4.3\n\nexecutors:\n node:\n docker:\n - image: cimg/node:22.22.0\n\n "
},
{
"path": ".codecov.yml",
"chars": 596,
"preview": "codecov:\n notify:\n require_ci_to_pass: no\n\nflags:\n frontend:\n paths:\n - client/app/\n backend:\n paths:\n "
},
{
"path": ".github/ISSUE_TEMPLATE/1-bug-report.yml",
"chars": 1410,
"preview": "name: 🐞 Bug Report\ndescription: File a bug/issue\nlabels: [\"Bug\"]\nassignees:\n - cysjonathan\n - adi-herwana-nus\nbody:\n "
},
{
"path": ".github/ISSUE_TEMPLATE/2-feature-request.yml",
"chars": 1450,
"preview": "name: 💡 Feature Request\ndescription: Suggest a new feature or enhancement\nlabels: [\"Feature\"]\nassignees:\n - cysjonathan"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 364,
"preview": "blank_issues_enabled: true\ncontact_links:\n - name: User Guide\n url: https://coursemology.github.io/coursemology-help"
},
{
"path": ".github/dependabot.yml",
"chars": 963,
"preview": "version: 2\nupdates:\n - package-ecosystem: bundler\n directory: '/'\n schedule:\n interval: daily\n open-pull-"
},
{
"path": ".gitignore",
"chars": 1599,
"preview": "# See https://help.github.com/articles/ignoring-files for more about ignoring files.\n#\n# If you find yourself ignoring t"
},
{
"path": ".gitmodules",
"chars": 362,
"preview": "[submodule \"vendor/assets/javascripts/recorderjs\"]\n\tpath = client/vendor/recorderjs\n\turl = https://github.com/mattdiamon"
},
{
"path": ".hound.yml",
"chars": 111,
"preview": "fail_on_violations: true\n\nrubocop:\n config_file: .rubocop.yml\n version: 1.22.1\n\njavascript:\n enabled: false\n"
},
{
"path": ".rspec",
"chars": 108,
"preview": "--color\n--format progress\n--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log\n"
},
{
"path": ".rubocop.unhound.yml",
"chars": 1685,
"preview": "Style/CollectionMethods:\n Enabled: true\n PreferredMethods:\n reduce:\n inject: 'reduce'\n find:\n detect: 'fin"
},
{
"path": ".rubocop.yml",
"chars": 1357,
"preview": "inherit_from:\n - .rubocop.unhound.yml\n\nAllCops:\n NewCops: enable\n Exclude:\n - 'bin/*'\n - 'db/seeds.rb'\n - 'd"
},
{
"path": ".yardopts",
"chars": 70,
"preview": "--protected\n--no-private\n--embed-mixin ClassMethods\n--markup markdown\n"
},
{
"path": "CONTRIBUTING.md",
"chars": 201,
"preview": "# Contributing\n\nWe have shifted our contributing guides to our [Wiki](https://github.com/Coursemology/coursemology2/wiki"
},
{
"path": "Gemfile",
"chars": 5914,
"preview": "# frozen_string_literal: true\nsource 'https://rubygems.org'\n\nruby '3.3.5'\n\n# These gems are included in Ruby defaults fo"
},
{
"path": "LICENSE",
"chars": 1119,
"preview": "The MIT License (MIT)\n\nhttp://opensource.org/licenses/MIT\n\nCopyright (c) 2023 Coursemology.org\n\nPermission is hereby gra"
},
{
"path": "README.md",
"chars": 5619,
"preview": "<!-- markdownlint-disable MD033 MD014 -->\n\n# Coursemology [ as its backend app server. This [g"
},
{
"path": "app/assets/config/manifest.js",
"chars": 0,
"preview": ""
},
{
"path": "app/channels/application_cable/channel.rb",
"chars": 414,
"preview": "# frozen_string_literal: true\nclass ApplicationCable::Channel < ActionCable::Channel::Base\n include ApplicationCableMul"
},
{
"path": "app/channels/application_cable/connection.rb",
"chars": 362,
"preview": "# frozen_string_literal: true\nclass ApplicationCable::Connection < ActionCable::Connection::Base\n identified_by :curren"
},
{
"path": "app/channels/concerns/application_cable_ability_concern.rb",
"chars": 486,
"preview": "# frozen_string_literal: true\nmodule ApplicationCableAbilityConcern\n extend ActiveSupport::Concern\n\n included do\n b"
},
{
"path": "app/channels/concerns/application_cable_authentication_concern.rb",
"chars": 752,
"preview": "# frozen_string_literal: true\nmodule ApplicationCableAuthenticationConcern\n def current_user_from_token\n token = aut"
},
{
"path": "app/channels/concerns/application_cable_component_concern.rb",
"chars": 633,
"preview": "# frozen_string_literal: true\nmodule ApplicationCableComponentConcern\n extend ActiveSupport::Concern\n\n included do\n "
},
{
"path": "app/channels/concerns/application_cable_course_concern.rb",
"chars": 467,
"preview": "# frozen_string_literal: true\nmodule ApplicationCableCourseConcern\n extend ActiveSupport::Concern\n\n included do\n be"
},
{
"path": "app/channels/concerns/application_cable_multitenancy_concern.rb",
"chars": 254,
"preview": "# frozen_string_literal: true\nmodule ApplicationCableMultitenancyConcern\n extend ActiveSupport::Concern\n include Appli"
},
{
"path": "app/channels/course/channel.rb",
"chars": 873,
"preview": "# frozen_string_literal: true\n#\n# The base channel for all `Course`-related channels. Subclasses of this channel\n# must "
},
{
"path": "app/channels/course/monitoring/heartbeat_channel.rb",
"chars": 3925,
"preview": "# frozen_string_literal: true\nclass Course::Monitoring::HeartbeatChannel < Course::Channel\n ACTIONS = { next: :next, te"
},
{
"path": "app/channels/course/monitoring/live_monitoring_channel.rb",
"chars": 4006,
"preview": "# frozen_string_literal: true\nclass Course::Monitoring::LiveMonitoringChannel < Course::Channel\n include Course::UsersH"
},
{
"path": "app/controllers/announcements_controller.rb",
"chars": 771,
"preview": "# frozen_string_literal: true\nclass AnnouncementsController < ApplicationController\n load_resource :announcement, class"
},
{
"path": "app/controllers/application_controller.rb",
"chars": 2324,
"preview": "# frozen_string_literal: true\n\nclass ApplicationController < ActionController::Base\n # Prevent CSRF attacks by providin"
},
{
"path": "app/controllers/attachment_references_controller.rb",
"chars": 1107,
"preview": "# frozen_string_literal: true\nclass AttachmentReferencesController < ApplicationController\n load_resource :attachment_r"
},
{
"path": "app/controllers/components/course/achievements_component.rb",
"chars": 363,
"preview": "# frozen_string_literal: true\nclass Course::AchievementsComponent < SimpleDelegator\n include Course::ControllerComponen"
},
{
"path": "app/controllers/components/course/announcements_component.rb",
"chars": 764,
"preview": "# frozen_string_literal: true\nclass Course::AnnouncementsComponent < SimpleDelegator\n include Course::ControllerCompone"
},
{
"path": "app/controllers/components/course/assessments_component.rb",
"chars": 1605,
"preview": "# frozen_string_literal: true\nclass Course::AssessmentsComponent < SimpleDelegator\n include Course::ControllerComponent"
},
{
"path": "app/controllers/components/course/codaveri_component.rb",
"chars": 396,
"preview": "# frozen_string_literal: true\nclass Course::CodaveriComponent < SimpleDelegator\n include Course::ControllerComponentHos"
},
{
"path": "app/controllers/components/course/controller_component_host.rb",
"chars": 6873,
"preview": "# frozen_string_literal: true\n#\n# The course component framework isolates features as components. The intent is to allow"
},
{
"path": "app/controllers/components/course/discussion/topics_component.rb",
"chars": 762,
"preview": "# frozen_string_literal: true\nclass Course::Discussion::TopicsComponent < SimpleDelegator\n include Course::ControllerCo"
},
{
"path": "app/controllers/components/course/duplication_component.rb",
"chars": 411,
"preview": "# frozen_string_literal: true\nclass Course::DuplicationComponent < SimpleDelegator\n include Course::ControllerComponent"
},
{
"path": "app/controllers/components/course/experience_points_component.rb",
"chars": 662,
"preview": "# frozen_string_literal: true\nclass Course::ExperiencePointsComponent < SimpleDelegator\n include Course::ControllerComp"
},
{
"path": "app/controllers/components/course/forums_component.rb",
"chars": 730,
"preview": "# frozen_string_literal: true\nclass Course::ForumsComponent < SimpleDelegator\n include Course::ControllerComponentHost:"
},
{
"path": "app/controllers/components/course/groups_component.rb",
"chars": 918,
"preview": "# frozen_string_literal: true\nclass Course::GroupsComponent < SimpleDelegator\n include Course::ControllerComponentHost:"
},
{
"path": "app/controllers/components/course/koditsu_platform_component.rb",
"chars": 192,
"preview": "# frozen_string_literal: true\nclass Course::KoditsuPlatformComponent < SimpleDelegator\n include Course::ControllerCompo"
},
{
"path": "app/controllers/components/course/leaderboard_component.rb",
"chars": 710,
"preview": "# frozen_string_literal: true\nclass Course::LeaderboardComponent < SimpleDelegator\n include Course::ControllerComponent"
},
{
"path": "app/controllers/components/course/learning_map_component.rb",
"chars": 365,
"preview": "# frozen_string_literal: true\nclass Course::LearningMapComponent < SimpleDelegator\n include Course::ControllerComponent"
},
{
"path": "app/controllers/components/course/lesson_plan_component.rb",
"chars": 695,
"preview": "# frozen_string_literal: true\nclass Course::LessonPlanComponent < SimpleDelegator\n include Course::ControllerComponentH"
},
{
"path": "app/controllers/components/course/levels_component.rb",
"chars": 446,
"preview": "# frozen_string_literal: true\nclass Course::LevelsComponent < SimpleDelegator\n include Course::ControllerComponentHost:"
},
{
"path": "app/controllers/components/course/materials_component.rb",
"chars": 670,
"preview": "# frozen_string_literal: true\nclass Course::MaterialsComponent < SimpleDelegator\n include Course::ControllerComponentHo"
},
{
"path": "app/controllers/components/course/monitoring_component.rb",
"chars": 187,
"preview": "# frozen_string_literal: true\nclass Course::MonitoringComponent < SimpleDelegator\n include Course::ControllerComponentH"
},
{
"path": "app/controllers/components/course/multiple_reference_timelines_component.rb",
"chars": 528,
"preview": "# frozen_string_literal: true\nclass Course::MultipleReferenceTimelinesComponent < SimpleDelegator\n include Course::Cont"
},
{
"path": "app/controllers/components/course/plagiarism_component.rb",
"chars": 470,
"preview": "# frozen_string_literal: true\nclass Course::PlagiarismComponent < SimpleDelegator\n include Course::ControllerComponentH"
},
{
"path": "app/controllers/components/course/rag_wise_component.rb",
"chars": 443,
"preview": "# frozen_string_literal: true\nclass Course::RagWiseComponent < SimpleDelegator\n include Course::ControllerComponentHost"
},
{
"path": "app/controllers/components/course/scholaistic_component.rb",
"chars": 1783,
"preview": "# frozen_string_literal: true\nclass Course::ScholaisticComponent < SimpleDelegator\n include Course::ControllerComponent"
},
{
"path": "app/controllers/components/course/settings_component.rb",
"chars": 1501,
"preview": "# frozen_string_literal: true\nclass Course::SettingsComponent < SimpleDelegator\n include Course::ControllerComponentHos"
},
{
"path": "app/controllers/components/course/statistics_component.rb",
"chars": 414,
"preview": "# frozen_string_literal: true\nclass Course::StatisticsComponent < SimpleDelegator\n include Course::ControllerComponentH"
},
{
"path": "app/controllers/components/course/stories_component.rb",
"chars": 1248,
"preview": "# frozen_string_literal: true\nclass Course::StoriesComponent < SimpleDelegator\n include Course::ControllerComponentHost"
},
{
"path": "app/controllers/components/course/survey_component.rb",
"chars": 381,
"preview": "# frozen_string_literal: true\nclass Course::SurveyComponent < SimpleDelegator\n include Course::ControllerComponentHost:"
},
{
"path": "app/controllers/components/course/users_component.rb",
"chars": 1323,
"preview": "# frozen_string_literal: true\nclass Course::UsersComponent < SimpleDelegator\n include Course::ControllerComponentHost::"
},
{
"path": "app/controllers/components/course/videos_component.rb",
"chars": 840,
"preview": "# frozen_string_literal: true\nclass Course::VideosComponent < SimpleDelegator\n include Course::ControllerComponentHost:"
},
{
"path": "app/controllers/concerns/application_ability_concern.rb",
"chars": 268,
"preview": "# frozen_string_literal: true\nmodule ApplicationAbilityConcern\n # Override of Cancancan#current_ability to provide curr"
},
{
"path": "app/controllers/concerns/application_announcements_concern.rb",
"chars": 606,
"preview": "# frozen_string_literal: true\nmodule ApplicationAnnouncementsConcern\n extend ActiveSupport::Concern\n\n # Returns active"
},
{
"path": "app/controllers/concerns/application_authentication_concern.rb",
"chars": 2049,
"preview": "# frozen_string_literal: true\nmodule ApplicationAuthenticationConcern\n extend ActiveSupport::Concern\n\n REQUIRES_AUTHEN"
},
{
"path": "app/controllers/concerns/application_components_concern.rb",
"chars": 358,
"preview": "# frozen_string_literal: true\nmodule ApplicationComponentsConcern\n extend ActiveSupport::Concern\n\n included do\n res"
},
{
"path": "app/controllers/concerns/application_controller_multitenancy_concern.rb",
"chars": 291,
"preview": "# frozen_string_literal: true\nmodule ApplicationControllerMultitenancyConcern\n extend ActiveSupport::Concern\n include "
},
{
"path": "app/controllers/concerns/application_instance_user_concern.rb",
"chars": 630,
"preview": "# frozen_string_literal: true\nmodule ApplicationInstanceUserConcern\n extend ActiveSupport::Concern\n\n included do\n b"
},
{
"path": "app/controllers/concerns/application_internationalization_concern.rb",
"chars": 454,
"preview": "# frozen_string_literal: true\nmodule ApplicationInternationalizationConcern\n extend ActiveSupport::Concern\n\n included "
},
{
"path": "app/controllers/concerns/application_multitenancy.rb",
"chars": 1395,
"preview": "# frozen_string_literal: true\nmodule ApplicationMultitenancy\n private\n\n def deduce_and_set_current_tenant\n tenant ="
},
{
"path": "app/controllers/concerns/application_pagination_concern.rb",
"chars": 362,
"preview": "# frozen_string_literal: true\nmodule ApplicationPaginationConcern\n extend ActiveSupport::Concern\n\n protected\n\n # Retr"
},
{
"path": "app/controllers/concerns/application_user_concern.rb",
"chars": 2099,
"preview": "# frozen_string_literal: true\nmodule ApplicationUserConcern\n extend ActiveSupport::Concern\n include ApplicationAuthent"
},
{
"path": "app/controllers/concerns/application_user_time_zone_concern.rb",
"chars": 362,
"preview": "# frozen_string_literal: true\nmodule ApplicationUserTimeZoneConcern\n extend ActiveSupport::Concern\n\n included do\n a"
},
{
"path": "app/controllers/concerns/codaveri_language_concern.rb",
"chars": 1113,
"preview": "# frozen_string_literal: true\nmodule CodaveriLanguageConcern\n def codaveri_language\n programming_language_map[type.c"
},
{
"path": "app/controllers/concerns/course/achievement_conditional_concern.rb",
"chars": 326,
"preview": "# frozen_string_literal: true\nmodule Course::AchievementConditionalConcern\n extend ActiveSupport::Concern\n\n def succes"
},
{
"path": "app/controllers/concerns/course/activity_feeds_concern.rb",
"chars": 370,
"preview": "# frozen_string_literal: true\nmodule Course::ActivityFeedsConcern\n extend ActiveSupport::Concern\n\n # Loads recent acti"
},
{
"path": "app/controllers/concerns/course/assessment/answer/update_answer_concern.rb",
"chars": 3067,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Answer::UpdateAnswerConcern\n extend ActiveSupport::Concern\n\n "
},
{
"path": "app/controllers/concerns/course/assessment/koditsu_assessment_concern.rb",
"chars": 3639,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::KoditsuAssessmentConcern\n extend ActiveSupport::Concern\n\n def"
},
{
"path": "app/controllers/concerns/course/assessment/koditsu_assessment_invitation_concern.rb",
"chars": 906,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::KoditsuAssessmentInvitationConcern\n extend ActiveSupport::Conc"
},
{
"path": "app/controllers/concerns/course/assessment/live_feedback/file_concern.rb",
"chars": 1382,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::LiveFeedback::FileConcern\n extend ActiveSupport::Concern\n\n de"
},
{
"path": "app/controllers/concerns/course/assessment/live_feedback/message_concern.rb",
"chars": 1170,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::LiveFeedback::MessageConcern\n extend ActiveSupport::Concern\n "
},
{
"path": "app/controllers/concerns/course/assessment/live_feedback/message_file_concern.rb",
"chars": 1451,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::LiveFeedback::MessageFileConcern\n extend ActiveSupport::Concer"
},
{
"path": "app/controllers/concerns/course/assessment/live_feedback/thread_concern.rb",
"chars": 1495,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::LiveFeedback::ThreadConcern\n extend ActiveSupport::Concern\n\n "
},
{
"path": "app/controllers/concerns/course/assessment/monitoring/seb_payload_concern.rb",
"chars": 696,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Monitoring::SebPayloadConcern\n extend ActiveSupport::Concern\n\n"
},
{
"path": "app/controllers/concerns/course/assessment/monitoring_concern.rb",
"chars": 2939,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::MonitoringConcern\n extend ActiveSupport::Concern\n\n include Co"
},
{
"path": "app/controllers/concerns/course/assessment/question/codaveri_question_concern.rb",
"chars": 1012,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Question::CodaveriQuestionConcern\n extend ActiveSupport::Conce"
},
{
"path": "app/controllers/concerns/course/assessment/question/koditsu_question_concern.rb",
"chars": 4362,
"preview": "# frozen_string_literal: true\n# rubocop:disable Metrics/ModuleLength\nmodule Course::Assessment::Question::KoditsuQuestio"
},
{
"path": "app/controllers/concerns/course/assessment/question/multiple_responses_concern.rb",
"chars": 769,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Question::MultipleResponsesConcern\n extend ActiveSupport::Conc"
},
{
"path": "app/controllers/concerns/course/assessment/question/rubric_based_response_controller_concern.rb",
"chars": 1957,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Question::RubricBasedResponseControllerConcern\n include Course"
},
{
"path": "app/controllers/concerns/course/assessment/question/rubric_based_response_question_concern.rb",
"chars": 929,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Question::RubricBasedResponseQuestionConcern\n extend ActiveSup"
},
{
"path": "app/controllers/concerns/course/assessment/question_bundle_assignment_concern.rb",
"chars": 8277,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::QuestionBundleAssignmentConcern\n extend ActiveSupport::Concern"
},
{
"path": "app/controllers/concerns/course/assessment/submission/koditsu/answers_concern.rb",
"chars": 3910,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Submission::Koditsu::AnswersConcern\n extend ActiveSupport::Con"
},
{
"path": "app/controllers/concerns/course/assessment/submission/koditsu/submission_times_concern.rb",
"chars": 668,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Submission::Koditsu::SubmissionTimesConcern\n extend ActiveSupp"
},
{
"path": "app/controllers/concerns/course/assessment/submission/koditsu/submissions_concern.rb",
"chars": 3939,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Submission::Koditsu::SubmissionsConcern\n extend ActiveSupport:"
},
{
"path": "app/controllers/concerns/course/assessment/submission/koditsu/test_cases_concern.rb",
"chars": 882,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Submission::Koditsu::TestCasesConcern\n extend ActiveSupport::C"
},
{
"path": "app/controllers/concerns/course/assessment/submission/koditsu/users_concern.rb",
"chars": 1366,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Submission::Koditsu::UsersConcern\n extend ActiveSupport::Conce"
},
{
"path": "app/controllers/concerns/course/assessment/submission/monitoring_concern.rb",
"chars": 1439,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Submission::MonitoringConcern\n extend ActiveSupport::Concern\n\n"
},
{
"path": "app/controllers/concerns/course/assessment/submission/submissions_controller_service_concern.rb",
"chars": 1461,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::Submission::SubmissionsControllerServiceConcern\n extend Active"
},
{
"path": "app/controllers/concerns/course/assessment/submission_concern.rb",
"chars": 1044,
"preview": "# frozen_string_literal: true\nmodule Course::Assessment::SubmissionConcern\n extend ActiveSupport::Concern\n\n private\n\n "
},
{
"path": "app/controllers/concerns/course/assessment_conditional_concern.rb",
"chars": 412,
"preview": "# frozen_string_literal: true\nmodule Course::AssessmentConditionalConcern\n extend ActiveSupport::Concern\n\n def success"
},
{
"path": "app/controllers/concerns/course/cikgo_chats_concern.rb",
"chars": 780,
"preview": "# frozen_string_literal: true\nmodule Course::CikgoChatsConcern\n extend ActiveSupport::Concern\n\n def find_or_create_roo"
},
{
"path": "app/controllers/concerns/course/cikgo_push_concern.rb",
"chars": 922,
"preview": "# frozen_string_literal: true\nmodule Course::CikgoPushConcern\n extend ActiveSupport::Concern\n include Cikgo::PushableI"
},
{
"path": "app/controllers/concerns/course/discussion/posts_concern.rb",
"chars": 1787,
"preview": "# frozen_string_literal: true\nmodule Course::Discussion::PostsConcern\n extend ActiveSupport::Concern\n\n included do\n "
},
{
"path": "app/controllers/concerns/course/forum/auto_answering_concern.rb",
"chars": 2588,
"preview": "# frozen_string_literal: true\nmodule Course::Forum::AutoAnsweringConcern\n extend ActiveSupport::Concern\n\n def auto_ans"
},
{
"path": "app/controllers/concerns/course/forum/topic_controller_hiding_concern.rb",
"chars": 341,
"preview": "# frozen_string_literal: true\nmodule Course::Forum::TopicControllerHidingConcern\n extend ActiveSupport::Concern\n\n def "
},
{
"path": "app/controllers/concerns/course/forum/topic_controller_locking_concern.rb",
"chars": 342,
"preview": "# frozen_string_literal: true\nmodule Course::Forum::TopicControllerLockingConcern\n extend ActiveSupport::Concern\n\n def"
},
{
"path": "app/controllers/concerns/course/forum/topic_controller_subscription_concern.rb",
"chars": 561,
"preview": "# frozen_string_literal: true\nmodule Course::Forum::TopicControllerSubscriptionConcern\n extend ActiveSupport::Concern\n\n"
},
{
"path": "app/controllers/concerns/course/group/group_manager_concern.rb",
"chars": 364,
"preview": "# frozen_string_literal: true\nmodule Course::Group::GroupManagerConcern\n extend ActiveSupport::Concern\n def manageable"
},
{
"path": "app/controllers/concerns/course/koditsu_workspace_concern.rb",
"chars": 386,
"preview": "# frozen_string_literal: true\nmodule Course::KoditsuWorkspaceConcern\n extend ActiveSupport::Concern\n\n def setup_kodits"
},
{
"path": "app/controllers/concerns/course/lesson_plan/acts_as_lesson_plan_item_concern.rb",
"chars": 878,
"preview": "# frozen_string_literal: true\nmodule Course::LessonPlan::ActsAsLessonPlanItemConcern\n extend ActiveSupport::Concern\n\n "
},
{
"path": "app/controllers/concerns/course/lesson_plan/learning_rate_concern.rb",
"chars": 7878,
"preview": "# frozen_string_literal: true\nmodule Course::LessonPlan::LearningRateConcern\n extend ActiveSupport::Concern\n\n include "
},
{
"path": "app/controllers/concerns/course/lesson_plan/personalization_concern.rb",
"chars": 3275,
"preview": "# frozen_string_literal: true\nmodule Course::LessonPlan::PersonalizationConcern\n extend ActiveSupport::Concern\n\n # Dis"
},
{
"path": "app/controllers/concerns/course/lesson_plan/stories_concern.rb",
"chars": 905,
"preview": "# frozen_string_literal: true\nmodule Course::LessonPlan::StoriesConcern\n extend ActiveSupport::Concern\n\n def delete_al"
},
{
"path": "app/controllers/concerns/course/lesson_plan/strategies/base_personalization_strategy.rb",
"chars": 4049,
"preview": "# frozen_string_literal: true\n# The BasePersonalizationStrategy declares operations common to all, if not most, personal"
},
{
"path": "app/controllers/concerns/course/lesson_plan/strategies/fixed_personalization_strategy.rb",
"chars": 1303,
"preview": "# frozen_string_literal: true\nclass Course::LessonPlan::Strategies::FixedPersonalizationStrategy <\n Course::LessonPlan:"
},
{
"path": "app/controllers/concerns/course/lesson_plan/strategies/fomo_personalization_strategy.rb",
"chars": 8185,
"preview": "# frozen_string_literal: true\nclass Course::LessonPlan::Strategies::FomoPersonalizationStrategy <\n Course::LessonPlan::"
},
{
"path": "app/controllers/concerns/course/lesson_plan/strategies/otot_personalization_strategy.rb",
"chars": 3157,
"preview": "# frozen_string_literal: true\nclass Course::LessonPlan::Strategies::OtotPersonalizationStrategy <\n Course::LessonPlan::"
},
{
"path": "app/controllers/concerns/course/lesson_plan/strategies/stragglers_personalization_strategy.rb",
"chars": 8964,
"preview": "# frozen_string_literal: true\nclass Course::LessonPlan::Strategies::StragglersPersonalizationStrategy <\n Course::Lesson"
},
{
"path": "app/controllers/concerns/course/reminder_service_concern.rb",
"chars": 656,
"preview": "# frozen_string_literal: true\nmodule Course::ReminderServiceConcern\n extend ActiveSupport::Concern\n\n # Converts a set "
},
{
"path": "app/controllers/concerns/course/scholaistic/concern.rb",
"chars": 3715,
"preview": "# frozen_string_literal: true\nmodule Course::Scholaistic::Concern\n extend ActiveSupport::Concern\n\n include Course::Use"
},
{
"path": "app/controllers/concerns/course/ssid_folder_concern.rb",
"chars": 867,
"preview": "# frozen_string_literal: true\nmodule Course::SsidFolderConcern\n extend ActiveSupport::Concern\n\n def sync_course_ssid_f"
},
{
"path": "app/controllers/concerns/course/statistics/counts_concern.rb",
"chars": 4478,
"preview": "# frozen_string_literal: true\nmodule Course::Statistics::CountsConcern\n include Course::Statistics::ReferenceTimesConce"
},
{
"path": "app/controllers/concerns/course/statistics/grades_concern.rb",
"chars": 1653,
"preview": "# frozen_string_literal: true\nmodule Course::Statistics::GradesConcern\n private\n\n def grade_statistics_hash\n return"
},
{
"path": "app/controllers/concerns/course/statistics/reference_times_concern.rb",
"chars": 3413,
"preview": "# frozen_string_literal: true\nmodule Course::Statistics::ReferenceTimesConcern\n private\n\n def personal_end_at_hash(ass"
},
{
"path": "app/controllers/concerns/course/statistics/submissions_concern.rb",
"chars": 4892,
"preview": "# frozen_string_literal: true\nmodule Course::Statistics::SubmissionsConcern\n include Course::Statistics::ReferenceTimes"
},
{
"path": "app/controllers/concerns/course/statistics/times_concern.rb",
"chars": 936,
"preview": "# frozen_string_literal: true\nmodule Course::Statistics::TimesConcern\n private\n\n def duration_statistics_hash\n retu"
},
{
"path": "app/controllers/concerns/course/statistics/users_concern.rb",
"chars": 1109,
"preview": "# frozen_string_literal: true\nmodule Course::Statistics::UsersConcern\n private\n\n def group_names_hash\n group_names "
},
{
"path": "app/controllers/concerns/course/survey/reordering_concern.rb",
"chars": 4102,
"preview": "# frozen_string_literal: true\nmodule Course::Survey::ReorderingConcern\n extend ActiveSupport::Concern\n\n def reorder_se"
},
{
"path": "app/controllers/concerns/course/unread_counts_concern.rb",
"chars": 1998,
"preview": "# frozen_string_literal: true\nmodule Course::UnreadCountsConcern\n extend ActiveSupport::Concern\n\n private\n\n def unrea"
},
{
"path": "app/controllers/concerns/course/users_controller_management_concern.rb",
"chars": 6781,
"preview": "# frozen_string_literal: true\nmodule Course::UsersControllerManagementConcern\n extend ActiveSupport::Concern\n\n include"
},
{
"path": "app/controllers/concerns/signals/emission_concern.rb",
"chars": 1000,
"preview": "# frozen_string_literal: true\nmodule Signals::EmissionConcern\n extend ActiveSupport::Concern\n\n include ActiveSupport::"
},
{
"path": "app/controllers/concerns/signals/slices/announcements.rb",
"chars": 205,
"preview": "# frozen_string_literal: true\nmodule Signals::Slices::Announcements\n include Course::UnreadCountsConcern\n\n def generat"
},
{
"path": "app/controllers/concerns/signals/slices/assessment_submissions.rb",
"chars": 242,
"preview": "# frozen_string_literal: true\nmodule Signals::Slices::AssessmentSubmissions\n include Course::UnreadCountsConcern\n\n def"
},
{
"path": "app/controllers/concerns/signals/slices/cikgo_mission_control.rb",
"chars": 178,
"preview": "# frozen_string_literal: true\nmodule Signals::Slices::CikgoMissionControl\n def generate_sync_for_cikgo_mission_control\n"
},
{
"path": "app/controllers/concerns/signals/slices/cikgo_open_threads_count.rb",
"chars": 170,
"preview": "# frozen_string_literal: true\nmodule Signals::Slices::CikgoOpenThreadsCount\n def generate_sync_for_cikgo_open_threads_c"
},
{
"path": "app/controllers/concerns/signals/slices/comments.rb",
"chars": 194,
"preview": "# frozen_string_literal: true\nmodule Signals::Slices::Comments\n include Course::UnreadCountsConcern\n\n def generate_syn"
},
{
"path": "app/controllers/concerns/signals/slices/enrol_requests.rb",
"chars": 207,
"preview": "# frozen_string_literal: true\nmodule Signals::Slices::EnrolRequests\n include Course::UnreadCountsConcern\n\n def generat"
},
{
"path": "app/controllers/concerns/signals/slices/forums.rb",
"chars": 183,
"preview": "# frozen_string_literal: true\nmodule Signals::Slices::Forums\n include Course::UnreadCountsConcern\n\n def generate_sync_"
},
{
"path": "app/controllers/concerns/signals/slices/videos.rb",
"chars": 180,
"preview": "# frozen_string_literal: true\nmodule Signals::Slices::Videos\n include Course::UnreadCountsConcern\n\n def generate_sync_"
},
{
"path": "app/controllers/course/achievement/achievements_controller.rb",
"chars": 3582,
"preview": "# frozen_string_literal: true\nclass Course::Achievement::AchievementsController < Course::Achievement::Controller\n befo"
},
{
"path": "app/controllers/course/achievement/condition/achievements_controller.rb",
"chars": 189,
"preview": "# frozen_string_literal: true\nclass Course::Achievement::Condition::AchievementsController <\n Course::Condition::Achiev"
},
{
"path": "app/controllers/course/achievement/condition/assessments_controller.rb",
"chars": 187,
"preview": "# frozen_string_literal: true\nclass Course::Achievement::Condition::AssessmentsController <\n Course::Condition::Assessm"
},
{
"path": "app/controllers/course/achievement/condition/levels_controller.rb",
"chars": 175,
"preview": "# frozen_string_literal: true\nclass Course::Achievement::Condition::LevelsController < Course::Condition::LevelsControll"
},
{
"path": "app/controllers/course/achievement/condition/scholaistic_assessments_controller.rb",
"chars": 209,
"preview": "# frozen_string_literal: true\nclass Course::Achievement::Condition::ScholaisticAssessmentsController <\n Course::Conditi"
},
{
"path": "app/controllers/course/achievement/condition/surveys_controller.rb",
"chars": 177,
"preview": "# frozen_string_literal: true\nclass Course::Achievement::Condition::SurveysController < Course::Condition::SurveysContro"
},
{
"path": "app/controllers/course/achievement/controller.rb",
"chars": 416,
"preview": "# frozen_string_literal: true\nclass Course::Achievement::Controller < Course::ComponentController\n load_and_authorize_r"
},
{
"path": "app/controllers/course/admin/admin_controller.rb",
"chars": 2130,
"preview": "# frozen_string_literal: true\nclass Course::Admin::AdminController < Course::Admin::Controller\n def index\n respond_t"
},
{
"path": "app/controllers/course/admin/announcement_settings_controller.rb",
"chars": 593,
"preview": "# frozen_string_literal: true\nclass Course::Admin::AnnouncementSettingsController < Course::Admin::Controller\n def edit"
},
{
"path": "app/controllers/course/admin/assessment_settings_controller.rb",
"chars": 2295,
"preview": "# frozen_string_literal: true\nclass Course::Admin::AssessmentSettingsController < Course::Admin::Controller\n def edit\n "
},
{
"path": "app/controllers/course/admin/assessments/categories_controller.rb",
"chars": 1258,
"preview": "# frozen_string_literal: true\nclass Course::Admin::Assessments::CategoriesController < Course::Admin::Controller\n load_"
},
{
"path": "app/controllers/course/admin/assessments/tabs_controller.rb",
"chars": 1288,
"preview": "# frozen_string_literal: true\nclass Course::Admin::Assessments::TabsController < Course::Admin::Controller\n load_and_au"
},
{
"path": "app/controllers/course/admin/codaveri_settings_controller.rb",
"chars": 2374,
"preview": "# frozen_string_literal: true\nclass Course::Admin::CodaveriSettingsController < Course::Admin::Controller\n def edit\n "
},
{
"path": "app/controllers/course/admin/component_settings_controller.rb",
"chars": 1259,
"preview": "# frozen_string_literal: true\nclass Course::Admin::ComponentSettingsController < Course::Admin::Controller\n include Cou"
},
{
"path": "app/controllers/course/admin/controller.rb",
"chars": 399,
"preview": "# frozen_string_literal: true\nclass Course::Admin::Controller < Course::ComponentController\n before_action :authorize_a"
},
{
"path": "app/controllers/course/admin/discussion/topic_settings_controller.rb",
"chars": 594,
"preview": "# frozen_string_literal: true\nclass Course::Admin::Discussion::TopicSettingsController < Course::Admin::Controller\n def"
},
{
"path": "app/controllers/course/admin/forum_settings_controller.rb",
"chars": 631,
"preview": "# frozen_string_literal: true\nclass Course::Admin::ForumSettingsController < Course::Admin::Controller\n def edit\n re"
},
{
"path": "app/controllers/course/admin/leaderboard_settings_controller.rb",
"chars": 667,
"preview": "# frozen_string_literal: true\nclass Course::Admin::LeaderboardSettingsController < Course::Admin::Controller\n def edit\n"
},
{
"path": "app/controllers/course/admin/lesson_plan_settings_controller.rb",
"chars": 1496,
"preview": "# frozen_string_literal: true\nclass Course::Admin::LessonPlanSettingsController < Course::Admin::Controller\n before_act"
},
{
"path": "app/controllers/course/admin/material_settings_controller.rb",
"chars": 573,
"preview": "# frozen_string_literal: true\nclass Course::Admin::MaterialSettingsController < Course::Admin::Controller\n def edit\n "
},
{
"path": "app/controllers/course/admin/notification_settings_controller.rb",
"chars": 903,
"preview": "# frozen_string_literal: true\nclass Course::Admin::NotificationSettingsController < Course::Admin::Controller\n def edit"
},
{
"path": "app/controllers/course/admin/rag_wise_settings_controller.rb",
"chars": 3614,
"preview": "# frozen_string_literal: true\nclass Course::Admin::RagWiseSettingsController < Course::Admin::Controller\n before_action"
},
{
"path": "app/controllers/course/admin/scholaistic_settings_controller.rb",
"chars": 2102,
"preview": "# frozen_string_literal: true\nclass Course::Admin::ScholaisticSettingsController < Course::Admin::Controller\n skip_forg"
},
{
"path": "app/controllers/course/admin/sidebar_settings_controller.rb",
"chars": 683,
"preview": "# frozen_string_literal: true\nclass Course::Admin::SidebarSettingsController < Course::Admin::Controller\n before_action"
},
{
"path": "app/controllers/course/admin/stories_settings_controller.rb",
"chars": 1007,
"preview": "# frozen_string_literal: true\nclass Course::Admin::StoriesSettingsController < Course::Admin::Controller\n include Cours"
},
{
"path": "app/controllers/course/admin/video_settings_controller.rb",
"chars": 786,
"preview": "# frozen_string_literal: true\nclass Course::Admin::VideoSettingsController < Course::Admin::Controller\n def edit\n re"
},
{
"path": "app/controllers/course/admin/videos/tabs_controller.rb",
"chars": 909,
"preview": "# frozen_string_literal: true\nclass Course::Admin::Videos::TabsController < Course::Admin::Controller\n load_and_authori"
},
{
"path": "app/controllers/course/announcements_controller.rb",
"chars": 1893,
"preview": "# frozen_string_literal: true\nclass Course::AnnouncementsController < Course::ComponentController\n include Course::User"
},
{
"path": "app/controllers/course/assessment/assessments_controller.rb",
"chars": 16403,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::AssessmentsController < Course::Assessment::Controller # rubocop"
},
{
"path": "app/controllers/course/assessment/categories_controller.rb",
"chars": 860,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::CategoriesController < Course::ComponentController\n load_and_au"
},
{
"path": "app/controllers/course/assessment/component_controller.rb",
"chars": 113,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::ComponentController < Course::Assessment::Controller\nend\n"
},
{
"path": "app/controllers/course/assessment/condition/achievements_controller.rb",
"chars": 187,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Condition::AchievementsController <\n Course::Condition::Achieve"
},
{
"path": "app/controllers/course/assessment/condition/assessments_controller.rb",
"chars": 185,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Condition::AssessmentsController <\n Course::Condition::Assessme"
},
{
"path": "app/controllers/course/assessment/condition/levels_controller.rb",
"chars": 173,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Condition::LevelsController < Course::Condition::LevelsControlle"
},
{
"path": "app/controllers/course/assessment/condition/scholaistic_assessments_controller.rb",
"chars": 207,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Condition::ScholaisticAssessmentsController <\n Course::Conditio"
},
{
"path": "app/controllers/course/assessment/condition/surveys_controller.rb",
"chars": 175,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Condition::SurveysController < Course::Condition::SurveysControl"
},
{
"path": "app/controllers/course/assessment/controller.rb",
"chars": 978,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Controller < Course::ComponentController\n before_action :load_a"
},
{
"path": "app/controllers/course/assessment/mock_answers_controller.rb",
"chars": 564,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::MockAnswersController < Course::Assessment::QuestionsController\n"
},
{
"path": "app/controllers/course/assessment/question/controller.rb",
"chars": 2469,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Question::Controller < Course::Assessment::ComponentController\n "
},
{
"path": "app/controllers/course/assessment/question/forum_post_responses_controller.rb",
"chars": 2246,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Question::ForumPostResponsesController < Course::Assessment::Que"
},
{
"path": "app/controllers/course/assessment/question/multiple_responses_controller.rb",
"chars": 5906,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Question::MultipleResponsesController < Course::Assessment::Ques"
},
{
"path": "app/controllers/course/assessment/question/programming_controller.rb",
"chars": 5534,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Question::ProgrammingController < Course::Assessment::Question::"
},
{
"path": "app/controllers/course/assessment/question/rubric_based_responses_controller.rb",
"chars": 4521,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Question::RubricBasedResponsesController < Course::Assessment::Q"
},
{
"path": "app/controllers/course/assessment/question/scribing_controller.rb",
"chars": 3278,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Question::ScribingController < Course::Assessment::Question::Con"
},
{
"path": "app/controllers/course/assessment/question/text_responses_controller.rb",
"chars": 3434,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Question::TextResponsesController < Course::Assessment::Question"
},
{
"path": "app/controllers/course/assessment/question/voice_responses_controller.rb",
"chars": 1958,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Question::VoiceResponsesController < Course::Assessment::Questio"
},
{
"path": "app/controllers/course/assessment/question_bundle_assignments_controller.rb",
"chars": 3835,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::QuestionBundleAssignmentsController < Course::Assessment::Contro"
},
{
"path": "app/controllers/course/assessment/question_bundle_questions_controller.rb",
"chars": 1909,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::QuestionBundleQuestionsController < Course::Assessment::Controll"
},
{
"path": "app/controllers/course/assessment/question_bundles_controller.rb",
"chars": 1090,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::QuestionBundlesController < Course::Assessment::Controller\n loa"
},
{
"path": "app/controllers/course/assessment/question_groups_controller.rb",
"chars": 1128,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::QuestionGroupsController < Course::Assessment::Controller\n load"
},
{
"path": "app/controllers/course/assessment/questions_controller.rb",
"chars": 2197,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::QuestionsController < Course::Assessment::Controller\n load_and_"
},
{
"path": "app/controllers/course/assessment/rubrics_controller.rb",
"chars": 5428,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::RubricsController < Course::Assessment::QuestionsController # ru"
},
{
"path": "app/controllers/course/assessment/sessions_controller.rb",
"chars": 1582,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::SessionsController < Course::Assessment::Controller\n before_act"
},
{
"path": "app/controllers/course/assessment/skill_branches_controller.rb",
"chars": 1221,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::SkillBranchesController < Course::ComponentController\n load_and"
},
{
"path": "app/controllers/course/assessment/skills_controller.rb",
"chars": 1531,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::SkillsController < Course::ComponentController\n load_and_author"
},
{
"path": "app/controllers/course/assessment/submission/answer/answers_controller.rb",
"chars": 3390,
"preview": "# frozen_string_literal: true\n\nclass Course::Assessment::Submission::Answer::AnswersController <\n Course::Assessment::S"
},
{
"path": "app/controllers/course/assessment/submission/answer/controller.rb",
"chars": 440,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Submission::Answer::Controller < \\\n Course::Assessment::Submiss"
},
{
"path": "app/controllers/course/assessment/submission/answer/forum_post_response/posts_controller.rb",
"chars": 346,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Submission::Answer::ForumPostResponse::PostsController < \\\n Cou"
},
{
"path": "app/controllers/course/assessment/submission/answer/programming/annotations_controller.rb",
"chars": 2471,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Submission::Answer::Programming::AnnotationsController < \\\n Cou"
},
{
"path": "app/controllers/course/assessment/submission/answer/programming/controller.rb",
"chars": 282,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Submission::Answer::Programming::Controller < \\\n Course::Assess"
},
{
"path": "app/controllers/course/assessment/submission/answer/programming/programming_controller.rb",
"chars": 1456,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Submission::Answer::Programming::ProgrammingController < \\\n Cou"
},
{
"path": "app/controllers/course/assessment/submission/answer/scribing/controller.rb",
"chars": 448,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Submission::Answer::Scribing::Controller < \\\n Course::Assessmen"
},
{
"path": "app/controllers/course/assessment/submission/answer/scribing/scribbles_controller.rb",
"chars": 787,
"preview": "# frozen_string_literal: true\nclass Course::Assessment::Submission::Answer::Scribing::ScribblesController < \\\n Course::"
}
]
// ... and 4209 more files (download for full content)
About this extraction
This page contains the full source code of the Coursemology/coursemology2 GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 4409 files (10.8 MB), approximately 3.1M tokens, and a symbol index with 10175 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.