From a04ca24def180f28b9f8aab1be441f2eaf70d62e Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Thu, 6 Aug 2020 15:21:06 +0530 Subject: [PATCH] feat: Customisable Email Templates (#1095) --- Gemfile | 13 +-- Gemfile.lock | 2 + app/drops/account_drop.rb | 2 + app/drops/base_drop.rb | 13 +++ app/drops/conversation_drop.rb | 5 ++ app/drops/inbox_drop.rb | 2 + app/drops/user_drop.rb | 2 + .../conversation_notifications_mailer.rb | 20 +++-- app/mailers/application_mailer.rb | 44 +++++++++- app/mailers/conversation_reply_mailer.rb | 2 +- app/models/application_record.rb | 7 ++ app/models/conversation.rb | 4 +- app/models/email_template.rb | 28 ++++++ .../email_templates/db_resolver_service.rb | 87 +++++++++++++++++++ .../email_notification_service.rb | 2 +- .../{mailer.html.erb => mailer/base.liquid} | 12 +-- .../conversation_assignment.html.erb | 10 --- .../conversation_assignment.liquid | 7 ++ .../conversation_creation.html.erb | 10 --- .../conversation_creation.liquid | 8 ++ config/initializers/liquid_handler.rb | 1 + .../20200725131651_create_email_templates.rb | 13 +++ db/schema.rb | 11 +++ lib/action_view/template/handlers/liquid.rb | 62 +++++++++++++ spec/factories/email_template.rb | 5 ++ .../db_resolver_service_spec.rb | 80 +++++++++++++++++ .../mailers/confirmation_instructions_spec.rb | 1 + 27 files changed, 409 insertions(+), 44 deletions(-) create mode 100644 app/drops/account_drop.rb create mode 100644 app/drops/base_drop.rb create mode 100644 app/drops/conversation_drop.rb create mode 100644 app/drops/inbox_drop.rb create mode 100644 app/drops/user_drop.rb create mode 100644 app/models/email_template.rb create mode 100644 app/services/email_templates/db_resolver_service.rb rename app/views/layouts/{mailer.html.erb => mailer/base.liquid} (91%) delete mode 100644 app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_assignment.html.erb create mode 100644 app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_assignment.liquid delete mode 100644 app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_creation.html.erb create mode 100644 app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_creation.liquid create mode 100644 config/initializers/liquid_handler.rb create mode 100644 db/migrate/20200725131651_create_email_templates.rb create mode 100644 lib/action_view/template/handlers/liquid.rb create mode 100644 spec/factories/email_template.rb create mode 100644 spec/lib/email_templates/db_resolver_service_spec.rb diff --git a/Gemfile b/Gemfile index ec8cd8455..677d56c1a 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ gem 'rails' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', require: false -##-- rails helper gems --## +##-- rails application helper gems --## gem 'acts-as-taggable-on' gem 'attr_extras' gem 'browser' @@ -23,6 +23,12 @@ gem 'tzinfo-data' gem 'valid_email2' # compress javascript config.assets.js_compressor gem 'uglifier' +##-- used for single column multiple binary flags in notification settings/feature flagging --## +gem 'flag_shih_tzu' +# Random name generator for user names +gem 'haikunator' +# Template parsing safetly +gem 'liquid' ##-- for active storage --## gem 'aws-sdk-s3', require: false @@ -67,8 +73,6 @@ gem 'twitty' gem 'koala' # slack client gem 'slack-ruby-client' -# Random name generator -gem 'haikunator' ##--- gems for debugging and error reporting ---## # static analysis @@ -79,9 +83,6 @@ gem 'sentry-raven' ##-- background job processing --## gem 'sidekiq' -##-- used for single column multiple binary flags in notification settings/feature flagging --## -gem 'flag_shih_tzu' - ##-- Push notification service --## gem 'fcm' gem 'webpush' diff --git a/Gemfile.lock b/Gemfile.lock index 27235335d..00e93c5e1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -275,6 +275,7 @@ GEM addressable (~> 2.7) letter_opener (1.7.0) launchy (~> 2.2) + liquid (4.0.3) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -584,6 +585,7 @@ DEPENDENCIES kaminari koala letter_opener + liquid listen mini_magick mock_redis! diff --git a/app/drops/account_drop.rb b/app/drops/account_drop.rb new file mode 100644 index 000000000..2e3a2530f --- /dev/null +++ b/app/drops/account_drop.rb @@ -0,0 +1,2 @@ +class AccountDrop < BaseDrop +end diff --git a/app/drops/base_drop.rb b/app/drops/base_drop.rb new file mode 100644 index 000000000..e4b00e5d4 --- /dev/null +++ b/app/drops/base_drop.rb @@ -0,0 +1,13 @@ +class BaseDrop < Liquid::Drop + def initialize(obj) + @obj = obj + end + + def id + @obj.try(:id) + end + + def name + @obj.try(:name) + end +end diff --git a/app/drops/conversation_drop.rb b/app/drops/conversation_drop.rb new file mode 100644 index 000000000..03bab2f58 --- /dev/null +++ b/app/drops/conversation_drop.rb @@ -0,0 +1,5 @@ +class ConversationDrop < BaseDrop + def display_id + @obj.try(:display_id) + end +end diff --git a/app/drops/inbox_drop.rb b/app/drops/inbox_drop.rb new file mode 100644 index 000000000..7972e7325 --- /dev/null +++ b/app/drops/inbox_drop.rb @@ -0,0 +1,2 @@ +class InboxDrop < BaseDrop +end diff --git a/app/drops/user_drop.rb b/app/drops/user_drop.rb new file mode 100644 index 000000000..e2876a58a --- /dev/null +++ b/app/drops/user_drop.rb @@ -0,0 +1,2 @@ +class UserDrop < BaseDrop +end diff --git a/app/mailers/agent_notifications/conversation_notifications_mailer.rb b/app/mailers/agent_notifications/conversation_notifications_mailer.rb index 006cf1fb4..8bc872f20 100644 --- a/app/mailers/agent_notifications/conversation_notifications_mailer.rb +++ b/app/mailers/agent_notifications/conversation_notifications_mailer.rb @@ -1,14 +1,12 @@ class AgentNotifications::ConversationNotificationsMailer < ApplicationMailer - default from: ENV.fetch('MAILER_SENDER_EMAIL', 'accounts@chatwoot.com') - layout 'mailer' - def conversation_creation(conversation, agent) return unless smtp_config_set_or_development? @agent = agent @conversation = conversation subject = "#{@agent.available_name}, A new conversation [ID - #{@conversation.display_id}] has been created in #{@conversation.inbox&.name}." - mail(to: @agent.email, subject: subject) + @action_url = app_account_conversation_url(account_id: @conversation.account_id, id: @conversation.display_id) + send_mail_with_liquid(to: @agent.email, subject: subject) and return end def conversation_assignment(conversation, agent) @@ -16,6 +14,18 @@ class AgentNotifications::ConversationNotificationsMailer < ApplicationMailer @agent = agent @conversation = conversation - mail(to: @agent.email, subject: "#{@agent.available_name}, A new conversation [ID - #{@conversation.display_id}] has been assigned to you.") + subject = "#{@agent.available_name}, A new conversation [ID - #{@conversation.display_id}] has been assigned to you." + @action_url = app_account_conversation_url(account_id: @conversation.account_id, id: @conversation.display_id) + send_mail_with_liquid(to: @agent.email, subject: subject) and return + end + + private + + def liquid_droppables + super.merge({ + user: @agent, + conversation: @conversation, + inbox: @conversation.inbox + }) end end diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 50d50f125..c5ce00349 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -1,9 +1,13 @@ class ApplicationMailer < ActionMailer::Base - default from: ENV.fetch('MAILER_SENDER_EMAIL', 'accounts@chatwoot.com') - layout 'mailer' - append_view_path Rails.root.join('app/views/mailers') + include ActionView::Helpers::SanitizeHelper - # helpers + default from: ENV.fetch('MAILER_SENDER_EMAIL', 'accounts@chatwoot.com') + before_action { ensure_current_account(params.try(:[], :account)) } + layout 'mailer/base' + # Fetch template from Database if available + # Order: Account Specific > Installation Specific > Fallback to file + prepend_view_path ::EmailTemplate.resolver + append_view_path Rails.root.join('app/views/mailers') helper :frontend_urls helper do def global_config @@ -14,4 +18,36 @@ class ApplicationMailer < ActionMailer::Base def smtp_config_set_or_development? ENV.fetch('SMTP_ADDRESS', nil).present? || Rails.env.development? end + + private + + def send_mail_with_liquid(*args) + mail(*args) do |format| + # explored sending a multipart email containg both text type and html + # parsing the html with nokogiri will remove the links as well + # might also remove tags like b,li etc. so lets rethink about this later + # format.text { Nokogiri::HTML(render(layout: false)).text } + format.html { render } + end + end + + def liquid_droppables + # Merge additional objects into this in your mailer + # liquid template handler converts these objects into drop objects + { + account: Current.account + } + end + + def liquid_locals + # expose variables you want to be exposed in liquid + { + global_config: GlobalConfig.get('INSTALLATION_NAME', 'BRAND_URL'), + action_url: @action_url + } + end + + def ensure_current_account(account) + Current.account = account if account.present? + end end diff --git a/app/mailers/conversation_reply_mailer.rb b/app/mailers/conversation_reply_mailer.rb index 82c5b63e6..c60fb4363 100644 --- a/app/mailers/conversation_reply_mailer.rb +++ b/app/mailers/conversation_reply_mailer.rb @@ -105,6 +105,6 @@ class ConversationReplyMailer < ApplicationMailer def choose_layout return false if action_name == 'reply_without_summary' - 'mailer' + 'mailer/base' end end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 10a4cba84..62d06bd88 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -1,3 +1,10 @@ class ApplicationRecord < ActiveRecord::Base self.abstract_class = true + DROPPABLES = %w[Account Channel Conversation Inbox User].freeze + + def to_drop + return unless DROPPABLES.include?(self.class.name) + + "#{self.class.name}Drop".constantize.new(self) + end end diff --git a/app/models/conversation.rb b/app/models/conversation.rb index aad39a5ee..773fe76b6 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -52,8 +52,10 @@ class Conversation < ApplicationRecord before_create :set_display_id, unless: :display_id? before_create :set_bot_conversation - after_create :notify_conversation_creation + after_create_commit :notify_conversation_creation after_save :run_round_robin + # wanted to change this to after_update commit. But it ended up creating a loop + # reinvestigate in future and identity the implications after_update :notify_status_change, :create_activity acts_as_taggable_on :labels diff --git a/app/models/email_template.rb b/app/models/email_template.rb new file mode 100644 index 000000000..5891626a4 --- /dev/null +++ b/app/models/email_template.rb @@ -0,0 +1,28 @@ +# == Schema Information +# +# Table name: email_templates +# +# id :bigint not null, primary key +# body :text not null +# locale :integer default("en"), not null +# name :string not null +# template_type :integer default("content") +# created_at :datetime not null +# updated_at :datetime not null +# account_id :integer +# +# Indexes +# +# index_email_templates_on_name_and_account_id (name,account_id) UNIQUE +# +class EmailTemplate < ApplicationRecord + enum locale: LANGUAGES_CONFIG.map { |key, val| [val[:iso_639_1_code], key] }.to_h + enum template_type: { layout: 0, content: 1 } + belongs_to :account, optional: true + + validates :name, uniqueness: { scope: :account } + + def self.resolver(options = {}) + ::EmailTemplates::DbResolverService.using self, options + end +end diff --git a/app/services/email_templates/db_resolver_service.rb b/app/services/email_templates/db_resolver_service.rb new file mode 100644 index 000000000..341e95ee3 --- /dev/null +++ b/app/services/email_templates/db_resolver_service.rb @@ -0,0 +1,87 @@ +# Code is heavily inspired by panaromic gem +# https://github.com/andreapavoni/panoramic +# We will try to find layouts and content from database +# layout will be rendered with erb and other content in html format +# Further processing in liquid is implemented in mailers + +# Note: rails resolver looks for templates in cache first +# which we don't want to happen here +# so we are overriding find_all method in action view resolver +# If anything breaks - look into rails : actionview/lib/action_view/template/resolver.rb + +class ::EmailTemplates::DbResolverService < ActionView::Resolver + require 'singleton' + include Singleton + + # Instantiate Resolver by passing a model. + def self.using(model, options = {}) + class_variable_set(:@@model, model) + class_variable_set(:@@resolver_options, options) + instance + end + + # Since rails picks up files from cache. lets override the method + # Normalizes the arguments and passes it on to find_templates. + # rubocop:disable Metrics/ParameterLists + def find_all(name, prefix = nil, partial = false, details = {}, key = nil, locals = []) + locals = locals.map(&:to_s).sort!.freeze + _find_all(name, prefix, partial, details, key, locals) + end + # rubocop:enable Metrics/ParameterLists + + # the function has to accept(name, prefix, partial, _details, _locals = []) + # _details contain local info which we can leverage in future + # cause of codeclimate issue with 4 args, relying on (*args) + def find_templates(name, prefix, partial, *_args) + @template_name = name + @template_type = prefix.include?('layout') ? 'layout' : 'content' + @db_template = find_db_template + + return [] if @db_template.blank? + + path = build_path(prefix) + handler = ActionView::Template.registered_template_handler(:liquid) + + template_details = { + format: Mime['html'].to_sym, + updated_at: @db_template.updated_at, + virtual_path: virtual_path(path, partial) + } + + [ActionView::Template.new(@db_template.body, "DB Template - #{@db_template.id}", handler, template_details)] + end + + private + + def find_db_template + find_account_template || find_installation_template + end + + def find_account_template + return unless Current.account + + @@model.find_by(name: @template_name, template_type: @template_type, account: Current.account) + end + + def find_installation_template + @@model.find_by(name: @template_name, template_type: @template_type, account: nil) + end + + # Build path with eventual prefix + def build_path(prefix) + prefix.present? ? "#{prefix}/#{@template_name}" : @template_name + end + + # returns a path depending if its a partial or template + # params path: path/to/file.ext partial: true/false + # the function appends _to make the file name _file.ext if partial: true + def virtual_path(path, partial) + return path unless partial + + if (index = path.rindex('/')) + path.insert(index + 1, '_') + else + "_#{path}" + end + end +end diff --git a/app/services/notification/email_notification_service.rb b/app/services/notification/email_notification_service.rb index ce4184871..7f5df8307 100644 --- a/app/services/notification/email_notification_service.rb +++ b/app/services/notification/email_notification_service.rb @@ -8,7 +8,7 @@ class Notification::EmailNotificationService # TODO : Clean up whatever happening over here # Segregate the mailers properly - AgentNotifications::ConversationNotificationsMailer.public_send(notification + AgentNotifications::ConversationNotificationsMailer.with(account: notification.account).public_send(notification .notification_type.to_s, notification.primary_actor, notification.user).deliver_now end diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer/base.liquid similarity index 91% rename from app/views/layouts/mailer.html.erb rename to app/views/layouts/mailer/base.liquid index babc451f7..6eea14f4e 100644 --- a/app/views/layouts/mailer.html.erb +++ b/app/views/layouts/mailer/base.liquid @@ -81,7 +81,7 @@ - <%= yield %> + {{ content_for_layout }}
@@ -89,16 +89,16 @@ @@ -109,4 +109,4 @@ - + \ No newline at end of file diff --git a/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_assignment.html.erb b/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_assignment.html.erb deleted file mode 100644 index 32edc0a2c..000000000 --- a/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_assignment.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

Hi <%= @agent.available_name %>,

- -

Time to save the world. A new conversation has been assigned to you

- -

-Click <%= - link_to 'here', - app_account_conversation_url(account_id: @conversation.account_id, id: @conversation.display_id) -%> to get cracking. -

diff --git a/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_assignment.liquid b/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_assignment.liquid new file mode 100644 index 000000000..63e22f093 --- /dev/null +++ b/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_assignment.liquid @@ -0,0 +1,7 @@ +

Hi {{user.available_name}},

+ +

Time to save the world. A new conversation has been assigned to you

+ +

+Click here to get cracking. +

diff --git a/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_creation.html.erb b/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_creation.html.erb deleted file mode 100644 index 3dfb303e6..000000000 --- a/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_creation.html.erb +++ /dev/null @@ -1,10 +0,0 @@ -

Hi <%= @agent.available_name %>,

- -

Time to save the world. A new conversation has been created in <%= @conversation.inbox.name %>

- -

-Click <%= - link_to 'here', - app_account_conversation_url(account_id: @conversation.account_id, id: @conversation.display_id) -%> to get cracking. -

diff --git a/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_creation.liquid b/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_creation.liquid new file mode 100644 index 000000000..e324dd9e6 --- /dev/null +++ b/app/views/mailers/agent_notifications/conversation_notifications_mailer/conversation_creation.liquid @@ -0,0 +1,8 @@ +

Hi {{user.available_name}}

+ + +

Time to save the world. A new conversation has been created in {{ inbox.name }}

+ +

+Click here to get cracking. +

diff --git a/config/initializers/liquid_handler.rb b/config/initializers/liquid_handler.rb new file mode 100644 index 000000000..7ce86da51 --- /dev/null +++ b/config/initializers/liquid_handler.rb @@ -0,0 +1 @@ +ActionView::Template.register_template_handler :liquid, ActionView::Template::Handlers::Liquid diff --git a/db/migrate/20200725131651_create_email_templates.rb b/db/migrate/20200725131651_create_email_templates.rb new file mode 100644 index 000000000..00cef28eb --- /dev/null +++ b/db/migrate/20200725131651_create_email_templates.rb @@ -0,0 +1,13 @@ +class CreateEmailTemplates < ActiveRecord::Migration[6.0] + def change + create_table :email_templates do |t| + t.string :name, null: false + t.text :body, null: false + t.integer :account_id, null: true + t.integer :template_type, default: 1 + t.integer :locale, default: 0, null: false + t.timestamps + end + add_index :email_templates, [:name, :account_id], unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index de87c4a8e..0bd83d85a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -231,6 +231,17 @@ ActiveRecord::Schema.define(version: 2020_08_02_170002) do t.index ["contact_inbox_id"], name: "index_conversations_on_contact_inbox_id" end + create_table "email_templates", force: :cascade do |t| + t.string "name", null: false + t.text "body", null: false + t.integer "account_id" + t.integer "template_type", default: 1 + t.integer "locale", default: 0, null: false + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + t.index ["name", "account_id"], name: "index_email_templates_on_name_and_account_id", unique: true + end + create_table "events", force: :cascade do |t| t.string "name" t.float "value" diff --git a/lib/action_view/template/handlers/liquid.rb b/lib/action_view/template/handlers/liquid.rb new file mode 100644 index 000000000..65c0b1b3e --- /dev/null +++ b/lib/action_view/template/handlers/liquid.rb @@ -0,0 +1,62 @@ +# Code inspired by +# http://royvandermeij.com/blog/2011/09/21/create-a-liquid-handler-for-rails-3-dot-1/ +# https://github.com/chamnap/liquid-rails/blob/master/lib/liquid-rails/template_handler.rb + +class ActionView::Template::Handlers::Liquid + def self.call(template, _source) + "ActionView::Template::Handlers::Liquid.new(self).render(#{template.source.inspect}, local_assigns)" + end + + def initialize(view) + @view = view + @controller = @view.controller + @helper = ActionController::Base.helpers + end + + def render(template, local_assigns = {}) + assigns = drops + assigns['content_for_layout'] = @view.content_for(:layout) if @view.content_for?(:layout) + assigns.merge!(local_assigns) + assigns.merge!(locals) + + liquid = Liquid::Template.parse(template) + liquid.send(render_method, assigns.stringify_keys, filters: filters, registers: registers.stringify_keys) + end + + def locals + if @controller.respond_to?(:liquid_locals, true) + @controller.send(:liquid_locals) + else + {} + end + end + + def drops + droppables = @controller.send(:liquid_droppables) if @controller.respond_to?(:liquid_droppables, true) + droppables.update(droppables) { |_, obj| obj.try(:to_drop) || nil } + end + + def filters + if @controller.respond_to?(:liquid_filters, true) + @controller.send(:liquid_filters) + else + [] + end + end + + def registers + if @controller.respond_to?(:liquid_registers, true) + @controller.send(:liquid_registers) + else + {} + end + end + + def compilable? + false + end + + def render_method + ::Rails.env.development? || ::Rails.env.test? ? :render! : :render + end +end diff --git a/spec/factories/email_template.rb b/spec/factories/email_template.rb new file mode 100644 index 000000000..394eb6590 --- /dev/null +++ b/spec/factories/email_template.rb @@ -0,0 +1,5 @@ +FactoryBot.define do + factory :email_template do + name { 'MyString' } + end +end diff --git a/spec/lib/email_templates/db_resolver_service_spec.rb b/spec/lib/email_templates/db_resolver_service_spec.rb new file mode 100644 index 000000000..7bbb5c508 --- /dev/null +++ b/spec/lib/email_templates/db_resolver_service_spec.rb @@ -0,0 +1,80 @@ +require 'rails_helper' + +describe ::EmailTemplates::DbResolverService do + subject(:resolver) { described_class.using(EmailTemplate, {}) } + + describe '#find_templates' do + context 'when template does not exist in db' do + it 'return empty array' do + expect(resolver.find_templates('test', '', false, [])).to eq([]) + end + end + + context 'when installation template exist in db' do + it 'return installation template' do + email_template = create(:email_template, name: 'test', body: 'test') + handler = ActionView::Template.registered_template_handler(:liquid) + template_details = { + format: Mime['html'].to_sym, + updated_at: email_template.updated_at, + virtual_path: 'test' + } + + expect( + resolver.find_templates('test', '', false, []).first.to_json + ).to eq( + ActionView::Template.new( + email_template.body, + "DB Template - #{email_template.id}", handler, template_details + ).to_json + ) + end + end + + context 'when account template exists in db' do + let(:account) { create(:account) } + let(:installation_template) { create(:email_template, name: 'test', body: 'test') } + let(:account_template) { create(:email_template, name: 'test', body: 'test2', account: account) } + + it 'return account template for current account' do + Current.account = account + handler = ActionView::Template.registered_template_handler(:liquid) + template_details = { + format: Mime['html'].to_sym, + updated_at: account_template.updated_at, + virtual_path: 'test' + } + + expect( + resolver.find_templates('test', '', false, []).first.to_json + ).to eq( + ActionView::Template.new( + account_template.body, + "DB Template - #{account_template.id}", handler, template_details + ).to_json + ) + Current.account = nil + end + + it 'return installation template when current account dont have template' do + Current.account = create(:account) + handler = ActionView::Template.registered_template_handler(:liquid) + template_details = { + format: Mime['html'].to_sym, + updated_at: installation_template.updated_at, + virtual_path: 'test' + } + + expect( + resolver.find_templates('test', '', false, []).first.to_json + ).to eq( + ActionView::Template.new( + installation_template.body, + "DB Template - #{installation_template.id}", handler, template_details + ).to_json + ) + Current.account = nil + end + end + end +end diff --git a/spec/mailers/confirmation_instructions_spec.rb b/spec/mailers/confirmation_instructions_spec.rb index f6d908e2d..9914c1585 100644 --- a/spec/mailers/confirmation_instructions_spec.rb +++ b/spec/mailers/confirmation_instructions_spec.rb @@ -31,6 +31,7 @@ RSpec.describe 'Confirmation Instructions', type: :mailer do expect(mail.body).to match( "#{CGI.escapeHTML(inviter_val.name)}, with #{CGI.escapeHTML(inviter_val.account.name)}, has invited you to try out Chatwoot!" ) + Current.account = nil end end end