Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion app/api/communication_rules_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -690,6 +690,7 @@ def sync_set_schedules!(communication_set, raw_schedules)
requires :type, type: String
optional :subject, type: String
optional :body, type: String
optional :plain_text, type: Boolean
optional :email_tutors, type: Boolean
optional :email_convenors, type: Boolean
optional :target_grade, type: Integer
Expand All @@ -710,6 +711,7 @@ def sync_set_schedules!(communication_set, raw_schedules)
:type,
:subject,
:body,
:plain_text,
:email_tutors,
:email_convenors,
:target_grade,
Expand All @@ -729,6 +731,7 @@ def sync_set_schedules!(communication_set, raw_schedules)
optional :type, type: String
optional :subject, type: String
optional :body, type: String
optional :plain_text, type: Boolean
optional :email_tutors, type: Boolean
optional :email_convenors, type: Boolean
optional :target_grade, type: Integer
Expand All @@ -746,7 +749,7 @@ def sync_set_schedules!(communication_set, raw_schedules)
action = rule.communication_actions.find(params[:id])
action_params = ActionController::Parameters.new(params)
.require(:communication_action)
.permit(:type, :subject, :body, :email_tutors, :email_convenors, :target_grade, :task_definition_id)
.permit(:type, :subject, :body, :plain_text, :email_tutors, :email_convenors, :target_grade, :task_definition_id)

action.update!(action_params)
present action, with: Entities::CommunicationActionEntity
Expand Down
1 change: 1 addition & 0 deletions app/api/entities/communication_action_entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class CommunicationActionEntity < Grape::Entity
expose :communication_rule_id
expose :subject
expose :body
expose :plain_text
expose :email_tutors
expose :email_convenors
expose :target_grade
Expand Down
11 changes: 8 additions & 3 deletions app/mailers/communications_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
class CommunicationsMailer < ApplicationMailer
def communication_email(to:, from:, subject:, body:, recipient:, sender:, unit:, rule:)
def communication_email(to:, from:, subject:, body:, recipient:, sender:, plain_text: false)
if plain_text
@body = body.to_s
return mail(to: to, from: from, subject: subject) do |format|
format.text { render plain: @body }
end
end

@recipient = recipient
@sender = sender
@unit = unit
@rule = rule
@body = body.to_s
@body_paragraphs = @body.split(/\r?\n/).map(&:strip).reject(&:blank?)

Expand Down
2 changes: 1 addition & 1 deletion app/services/communication_transfer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class InvalidDocument < StandardError; end
type operator target_grade task_statuses task_status_count task_target_grade
activity_days spec_con_days submitted_portfolio
].freeze
ACTION_ATTRIBUTES = %w[type subject body email_tutors email_convenors target_grade].freeze
ACTION_ATTRIBUTES = %w[type subject body plain_text email_tutors email_convenors target_grade].freeze

# Abbreviated references. Campuses are shared between units; everything else
# is unit scoped. Group sets and groups are named rather than abbreviated, so
Expand Down
10 changes: 4 additions & 6 deletions app/sidekiq/execute_communication_set_job.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,9 @@ def execute_email_student_action(action, projects, unit, rule)
from: sender,
subject: subject,
body: body,
plain_text: action.plain_text,
recipient: recipient,
sender: sender_user_for(unit),
unit: unit,
rule: rule
sender: sender_user_for(unit)
).deliver_now

{
Expand Down Expand Up @@ -205,10 +204,9 @@ def execute_email_staff_action(action, projects, unit, rule)
from: sender,
subject: subject,
body: body,
plain_text: action.plain_text,
recipient: recipient,
sender: sender_user_for(unit),
unit: unit,
rule: rule
sender: sender_user_for(unit)
).deliver_now

{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddPlainTextToCommunicationActions < ActiveRecord::Migration[8.0]
def change
add_column :communication_actions, :plain_text, :boolean, default: false, null: false
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[8.0].define(version: 2026_09_16_003706) do
ActiveRecord::Schema[8.0].define(version: 2026_10_15_040755) do
create_table "activity_types", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t|
t.string "name", null: false
t.string "abbreviation", null: false
Expand Down Expand Up @@ -101,6 +101,7 @@
t.bigint "task_definition_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.boolean "plain_text", default: false, null: false
t.index ["communication_rule_id"], name: "index_communication_actions_on_communication_rule_id"
t.index ["task_definition_id"], name: "index_communication_actions_on_task_definition_id"
t.index ["type"], name: "index_communication_actions_on_type"
Expand Down
34 changes: 34 additions & 0 deletions test/mailers/communications_mailer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require 'test_helper'

class CommunicationsMailerTest < ActionMailer::TestCase
def test_plain_text_email_contains_only_the_entered_body
body = "Hello Ada,\n\nPlease review your work."
message = communication_email(body: body, plain_text: true)

assert_match %r{\Atext/plain}, message.content_type
assert_nil message.html_part
assert_equal body, message.body.decoded.gsub("\r\n", "\n")
end

def test_default_email_keeps_the_notification_layout
message = communication_email(body: 'Please review your work.')

assert message.html_part
assert message.text_part
assert_includes message.html_part.body.decoded, 'Notification'
end

private

def communication_email(body:, plain_text: false)
CommunicationsMailer.communication_email(
to: 'student@example.com',
from: 'convenor@example.com',
subject: 'Reminder',
body: body,
recipient: nil,
sender: Struct.new(:name).new('Convenor'),
plain_text: plain_text
)
end
end
11 changes: 11 additions & 0 deletions test/models/communication_transfer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ def test_importing_into_a_unit_with_the_same_task_repoints_the_reference
assert_predicate imported, :executable?
end

def test_plain_text_email_setting_survives_export_and_import
@rule.communication_actions.first.update!(plain_text: true)
document = CommunicationTransfer.export_set(@set)
target_unit = unit_with_task('T1.1')

imported = CommunicationTransfer.import_set(document, target_unit)

assert_equal true, document.dig('set', 'rules', 0, 'actions', 0, 'plain_text')
assert_predicate imported.communication_rules.first.communication_actions.first, :plain_text?
end

def test_importing_without_the_task_keeps_the_rule_but_blocks_the_set
target_unit = unit_with_task('Different')

Expand Down
Loading