Class: Crm::CourseEnrollmentsController

Inherits:
CrmController show all
Defined in:
app/controllers/crm/course_enrollments_controller.rb

Overview

Controller: course enrollments.

Constant Summary

Constants included from Controllers::ReferenceFindable

Controllers::ReferenceFindable::ID_EMBEDDED_PATTERNS

Constants included from Controllers::AnalyticsEvents

Controllers::AnalyticsEvents::MAX_QUEUED_EVENTS, Controllers::AnalyticsEvents::SESSION_KEY

Constants included from Controllers::ErrorRendering

Controllers::ErrorRendering::NON_CONTENT_PATH_PREFIXES

Instance Method Summary collapse

Methods inherited from CrmController

#access_denied, #context_id, #context_object, #crm_home_path, #current_ability, #default_url_options, #download_temp, #get_tempfile_path_for_download, #init_status_job_collector, #initialize_crm_lazy_chunks, #persist_enqueued_status_jobs, #record_not_found, #redirect_to_job_or_fallback, #render_edit_action, #set_context, #set_download_path, #stash_file_for_temp_download, #sync_admin_presence_cookie, #touch_employee_last_seen

Methods inherited from ApplicationController

#account_impersonated?, #add_to_flash, #after_sign_in_path_for, #bypass_forgery_protection?, #chat_enabled?, #cloudflare_cleared?, #default_catalog, #default_url_options, #enable_turbo_frames, #find_publication, #fix_invalid_accept_header, #init_js_utils, #is_globals_call?, #layout_by_resource, #locale_store, #redirect_to, #require_employee_for_crm, #set_base_host, #set_real_ip, #set_report_errors_for, #should_render_layout?, #skip_layout_for_turbo_frame?, #stamp_impersonation_context, #tab_frame_breakout_request?, #warmlyyours_canada_ip?, #warmlyyours_ip?, #y

Methods included from Controllers::ReturnPathHandling

#check_for_return_path, #redirect_to_return_path_or_default

Methods included from Controllers::AnalyticsEvents

#consume_queued_analytics_events, #registration_lead_type, #track_event

Methods included from Controllers::DeviceDetection

#device_detector, #is_ie?

Methods included from Controllers::SubdomainDetection

#is_crm_request?, #is_www_request?, #json_request?

Methods included from Controllers::TurboSafeRedirect

#redirect_to

Methods included from Controllers::TrackingDetection

#bot_request?, #gdpr_country?, #gdpr_country_data, #prevent_bots, #set_tracking_cookie, #track_visitor?

Methods included from Controllers::AcceleratedFileSending

#send_file_accelerated, #send_upload_accelerated

Methods included from Controllers::ErrorRendering

#excp_string, #mail_to_for_error_reporting, #render_400, #render_404, #render_406, #render_410, #render_500, #render_invalid_authenticity_token, #render_ip_spoof_error, #render_unpermitted_parameters, #safe_referer_or_fallback

Methods included from Controllers::TurnstileVerification

#load_turnstile_script_tag, #turnstile_lazy_widget, #turnstile_script_tag, #turnstile_widget, #validate_turnstile!

Methods included from Controllers::CloudflareCaching

edge_cached, #edge_cached_action?, #reset_cloudflare_cache, #set_cloudflare_cache, #skip_edge_cache!, #skip_session

Methods included from Controllers::Webpackable

#preload_webpack_fonts, #webpack_css_include, #webpack_css_url, #webpack_js_include, #wpd_is_running?

Methods included from Controllers::Localizable

#cloudflare_country_locale, #determine_request_locale, #geocoder_locale, #guest_user_locale_check, #locale_optional_www_auth_path?, #param_locale, #set_locale, #set_request_locale, #skip_localization?, #warmlyyours_ip_locale

Methods included from Controllers::Authenticable

#access_denied, #authenticate_account, #authenticate_account!, #authenticate_account_from_login_token!, #check_is_a_manager, #check_is_a_sales_manager, #check_is_an_admin, #check_is_an_employee, #check_party, #clear_mismatched_guest_user, #create_guest_user, #credentials?, #current_or_guest_user, #current_or_guest_user_id_read_only, #current_user, #devise_mapping, #fully_logged_in?, #generate_bot_id, #guest_user, #identifiable?, #init_current_user, #initialize_guest, #load_context_user, #logging_in, #resource, #resource_name, #restrict_access_for_non_employees, #scrubbed_request_path, #user_object, #warn_on_session_guest_id_leak

Methods included from UrlsHelper

#catalog_breadcrumb_links, #catalog_link, #catalog_link_for_product_line, #catalog_link_for_sku, #cms_link, #delocalized_path, #path_to_sales_product_sku, #path_to_sales_product_sku_for_product_line, #path_to_sales_product_sku_for_product_line_slug, #product_line_from_catalog_link, #protocol_neutral_url, #sanitize_external_url, #valid_external_url?

Instance Method Details

#assign_topicObject

Assigns a topic (or topic-exam topic) to the enrollment, creating the
course-category/customer-topic rows on demand.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'app/controllers/crm/course_enrollments_controller.rb', line 70

def assign_topic
  authorize! :update, @course_enrollment
  if params[:topic_id].present? && params[:topic_category_id].present?
    topic_category = @course.topic_categories.find(params.expect(:topic_category_id))
    topic = topic_category.topics.find(params.expect(:topic_id))
    if topic.active?
      ActiveRecord::Base.transaction do
        course_category = @course_enrollment.course_categories.find_by(topic_category_id: topic_category.id)
        category_save_failed = false
        if course_category.blank?
          # we need to create the course category first
          course_category = @course_enrollment.course_categories.new(topic_category_id: topic_category.id, position: topic_category.position)
          unless course_category.save
            flash[:error] = "Failed to create course category: #{course_category.errors.full_messages.join(', ')}"
            category_save_failed = true
          end
        end
        unless category_save_failed
          # NOTE: CustomerTopic has no topic_category_id/course_id columns — the
          # module linkage travels through course_category_id (set by the
          # association scope here).
          ct = course_category.customer_topics.new(party_id: @party.id,
                            topic_id: params[:topic_id],
                            course_enrollment_id: @course_enrollment.id,
                            state: :assigned,
                            comments: 'Manually assigned from HW')
          ct.save
          flash[:info] = 'Topic assigned successfully'
        end
      end
    else
      flash[:info] = 'Topic is not active and cannot be assigned'
    end
  elsif params[:topic_id].present? && params[:topic_exam_id].present?
    topic_exam = @course.topic_exams.find(params.expect(:topic_exam_id))
    topic = topic_exam.topics.find(params.expect(:topic_id))
    if topic.active?
      course_exam = @course_enrollment.course_exams.find_by(topic_exam_id: topic_exam.id)
      if course_exam.present?
        # NOTE: as above — course_exam_id comes from the association scope;
        # topic_exam_id/course_id are not CustomerTopic columns.
        ct = course_exam.customer_topics.new(party_id: @party.id,
                          topic_id: params[:topic_id],
                          course_enrollment_id: @course_enrollment.id,
                          state: :assigned,
                          comments: 'Manually assigned from HW')
        ct.save
        flash[:info] = 'Exam topic assigned successfully'
      else
        flash[:error] = 'Course exam not found for this enrollment'
      end
    else
      flash[:info] = 'Topic is not active and cannot be assigned'
    end
  else
    flash[:error] = 'Missing topic id or topic category id'
  end
  redirect_to @course_enrollment
end

#cancelObject

Cancel the enrollment via the state machine (new/active → cancelled)
instead of deleting it — the attempt history stays intact.



45
46
47
48
49
50
51
52
53
# File 'app/controllers/crm/course_enrollments_controller.rb', line 45

def cancel
  authorize! :update, @course_enrollment
  if @course_enrollment.cancel
    flash[:info] = 'Enrollment cancelled'
  else
    flash[:error] = "Enrollment can't be cancelled from the #{@course_enrollment.state} state"
  end
  redirect_to @course_enrollment
end

#cancel_examObject

Cancel a stuck exam attempt (new/in_progress → cancelled) so the learner
can open a fresh one; graded attempts refuse the transition.



57
58
59
60
61
62
63
64
65
66
# File 'app/controllers/crm/course_enrollments_controller.rb', line 57

def cancel_exam
  authorize! :update, @course_enrollment
  course_exam = @course_enrollment.course_exams.find(params.expect(:course_exam_id))
  if course_exam.cancel
    flash[:info] = 'Exam attempt cancelled'
  else
    flash[:error] = "Exam attempt can't be cancelled from the #{course_exam.state} state"
  end
  redirect_to @course_enrollment
end

#destroyObject

Destroys the course enrollment.



37
38
39
40
41
# File 'app/controllers/crm/course_enrollments_controller.rb', line 37

def destroy
  authorize! :destroy, @course_enrollment
  @course_enrollment.destroy
  redirect_to @party
end

#indexObject

Global, per-course (nested under /courses/:course_id) and per-customer
(nested under /customers/:customer_id) — the scope narrows to whichever
parent is present.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'app/controllers/crm/course_enrollments_controller.rb', line 12

def index
  @course = Course.find_by(id: params[:course_id]) if params[:course_id]
  @customer = Party.find_by(id: params[:customer_id]) if params[:customer_id]
  scope = CourseEnrollment.all
  scope = scope.where(course_id: @course.id) if @course
  scope = scope.where(party_id: @customer.id) if @customer
  @q = scope.ransack(params[:q])
  @q.sorts = 'created_at desc' if @q.sorts.blank?
  result = @q.result.includes(:party, :course, :customer_topics)
  respond_to do |format|
    format.html { @pagy, @course_enrollments = pagy(result, limit: 25) }
    format.csv { send_data enrollments_csv(result), filename: "course-enrollments-#{Date.current}.csv" }
  end
end

#showObject

Shows a course enrollment's dashboard stats, exam attempts, and topic assignments.



28
29
30
31
32
33
34
# File 'app/controllers/crm/course_enrollments_controller.rb', line 28

def show
  dashboard = Course::DashboardStats.call(@course)
  @topic_categories = dashboard.topic_categories
  @topic_exams = dashboard.topic_exams
  @course_exams = @course_enrollment.course_exams.includes(:topic_exam).order(created_at: :desc)
  @customer_topics_by_topic_id = build_customer_topics_lookup
end