From 41344221a27ce1ecdbe6a98ab78948d9aea514eb Mon Sep 17 00:00:00 2001 From: Armin Kirchner Date: Wed, 9 Jul 2025 17:20:16 +0200 Subject: [PATCH 1/3] feat: Report email with LIT authorization path To act on spam reports the teacher needs to sign in through the course to authenticate in the study group. The LTI return URL is used to link back to the course. --- app/mailers/report_mailer.rb | 3 +++ app/views/report_mailer/report_content.html.slim | 2 ++ app/views/report_mailer/report_content.text.slim | 5 +++++ config/locales/de/report.yml | 1 + config/locales/en/report.yml | 1 + spec/mailers/report_mailer_spec.rb | 9 +++++++++ 6 files changed, 21 insertions(+) diff --git a/app/mailers/report_mailer.rb b/app/mailers/report_mailer.rb index 62ef953b5..f9b0c83a3 100644 --- a/app/mailers/report_mailer.rb +++ b/app/mailers/report_mailer.rb @@ -5,6 +5,9 @@ class ReportMailer < ApplicationMailer def report_content @reported_content = params.fetch(:reported_content) + study_group = @reported_content.submission.study_group + exercise = @reported_content.exercise + @course_url = LtiParameter.find_by(study_group:, exercise:)&.lti_parameters&.[]('launch_presentation_return_url') mail(subject: I18n.t('report_mailer.report_content.subject', content_name: @reported_content.model_name.human)) end diff --git a/app/views/report_mailer/report_content.html.slim b/app/views/report_mailer/report_content.html.slim index 4f5f9f5e1..de848f652 100644 --- a/app/views/report_mailer/report_content.html.slim +++ b/app/views/report_mailer/report_content.html.slim @@ -2,3 +2,5 @@ h3 = t('.prolog') blockquote style="white-space: pre-wrap;" = @reported_content.question p = t('.take_action') p = link_to(request_for_comment_url(@reported_content), request_for_comment_url(@reported_content)) +- if @course_url.present? + p = link_to(t('.authentication'), @course_url) diff --git a/app/views/report_mailer/report_content.text.slim b/app/views/report_mailer/report_content.text.slim index 6acaf5402..dbabe03c0 100644 --- a/app/views/report_mailer/report_content.text.slim +++ b/app/views/report_mailer/report_content.text.slim @@ -5,3 +5,8 @@ == t('.take_action') == "\n\n" == request_for_comment_url(@reported_content) +== "\n\n" +- if @course_url.present? + == t('.authentication') + == "\n\n" + == @course_url diff --git a/config/locales/de/report.yml b/config/locales/de/report.yml index fe2851b06..9c9bca37e 100644 --- a/config/locales/de/report.yml +++ b/config/locales/de/report.yml @@ -2,6 +2,7 @@ de: report_mailer: report_content: + authentication: Kurs-URL für die LTI-Authentifizierung. prolog: 'Die folgenden Inhalte wurden als unangemessen gemeldet:' subject: 'Spam Report: Ein %{content_name} in CodeOcean wurde als unangemessen markiert.' take_action: Bitte ergreifen Sie gegebenenfalls Maßnahmen. diff --git a/config/locales/en/report.yml b/config/locales/en/report.yml index 48e08f387..14abaf848 100644 --- a/config/locales/en/report.yml +++ b/config/locales/en/report.yml @@ -2,6 +2,7 @@ en: report_mailer: report_content: + authentication: Course URL for LTI authentication. prolog: 'The following content has been reported as inappropriate:' subject: 'Spam Report: A %{content_name} on CodeOcean has been marked as inappropriate.' take_action: Please take action if required. diff --git a/spec/mailers/report_mailer_spec.rb b/spec/mailers/report_mailer_spec.rb index 65b14f51a..cfdc59509 100644 --- a/spec/mailers/report_mailer_spec.rb +++ b/spec/mailers/report_mailer_spec.rb @@ -22,6 +22,15 @@ expect(mail.text_part.body).to include(question) expect(mail.html_part.body).to include(question) end + + it 'includes the LTI retrun URL for course authentication' do + create(:lti_parameter, + exercise: reported_content.exercise, + study_group: reported_content.submission.study_group) + + expect(mail.text_part.body).to match(%r{https.+/courses/}) + expect(mail.html_part.body).to match(%r{https.+/courses/}) + end end end end From e283689a54c6e7fc1bc0c69b5b3e622bb8a445aa Mon Sep 17 00:00:00 2001 From: Armin Kirchner Date: Fri, 11 Jul 2025 14:47:35 +0200 Subject: [PATCH 2/3] Comment about varying URL formats. --- app/mailers/report_mailer.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/mailers/report_mailer.rb b/app/mailers/report_mailer.rb index f9b0c83a3..a18455987 100644 --- a/app/mailers/report_mailer.rb +++ b/app/mailers/report_mailer.rb @@ -7,6 +7,10 @@ def report_content @reported_content = params.fetch(:reported_content) study_group = @reported_content.submission.study_group exercise = @reported_content.exercise + + # NOTE: This implementation assumes the curse URL is static and does not vary per user. + # This is currently valid for all known use cases. However, in dynamic environments—such as + # advanced content trees in openHPI or A/B/n testing—this assumption may break. @course_url = LtiParameter.find_by(study_group:, exercise:)&.lti_parameters&.[]('launch_presentation_return_url') mail(subject: I18n.t('report_mailer.report_content.subject', content_name: @reported_content.model_name.human)) From 3edf9cfb459622223680340d7efdb8bea73abf42 Mon Sep 17 00:00:00 2001 From: Armin Kirchner Date: Fri, 11 Jul 2025 16:53:41 +0200 Subject: [PATCH 3/3] Update app/mailers/report_mailer.rb Co-authored-by: Sebastian Serth --- app/mailers/report_mailer.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/mailers/report_mailer.rb b/app/mailers/report_mailer.rb index a18455987..076ba13fd 100644 --- a/app/mailers/report_mailer.rb +++ b/app/mailers/report_mailer.rb @@ -8,9 +8,9 @@ def report_content study_group = @reported_content.submission.study_group exercise = @reported_content.exercise - # NOTE: This implementation assumes the curse URL is static and does not vary per user. - # This is currently valid for all known use cases. However, in dynamic environments—such as - # advanced content trees in openHPI or A/B/n testing—this assumption may break. + # NOTE: This implementation assumes the course URL is static and does not vary per user. + # This is currently valid for a majority of use cases. However, in dynamic scenarios (such as + # content trees in openHPI used in conjunction with A/B/n testing) this assumption may no longer hold true. @course_url = LtiParameter.find_by(study_group:, exercise:)&.lti_parameters&.[]('launch_presentation_return_url') mail(subject: I18n.t('report_mailer.report_content.subject', content_name: @reported_content.model_name.human))