# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
require 'rails_helper'
require 'models/application_model_examples'
require 'models/concerns/can_be_imported_examples'
require 'models/concerns/can_csv_import_examples'
require 'models/concerns/has_history_examples'
require 'models/concerns/has_object_manager_attributes_examples'
require 'models/ticket/article/has_ticket_contact_attributes_impact_examples'
RSpec.describe Ticket::Article, type: :model do
subject(:article) { create(:ticket_article) }
it_behaves_like 'ApplicationModel', can_param: { sample_data_attribute: :body }
it_behaves_like 'CanBeImported'
it_behaves_like 'CanCsvImport'
it_behaves_like 'HasHistory'
it_behaves_like 'HasObjectManagerAttributes'
it_behaves_like 'Ticket::Article::HasTicketContactAttributesImpact'
describe 'Callbacks, Observers, & Async Transactions -' do
describe 'NULL byte handling (via ChecksAttributeValuesAndLength concern):' do
it 'removes them from #subject on creation, if necessary (postgres doesn’t like them)' do
expect(create(:ticket_article, subject: "com test 1\u0000"))
.to be_persisted
end
it 'removes them from #body on creation, if necessary (postgres doesn’t like them)' do
expect(create(:ticket_article, body: "some\u0000message 123"))
.to be_persisted
end
end
describe 'Setting of ticket_define_email_from' do
subject(:article) do
create(:ticket_article, created_by: created_by, sender_name: 'Agent', type_name: 'email')
end
context 'when AgentName' do
before do
Setting.set('ticket_define_email_from', 'AgentName')
end
context 'with real sender' do
let(:created_by) { create(:user) }
it 'sets the from to the realname of the user' do
expect(article.reload.from).to be_in(
[
"#{article.created_by.firstname} #{article.created_by.lastname} <#{article.ticket.group.email_address.email}>",
"\"#{article.created_by.firstname} #{article.created_by.lastname}\" <#{article.ticket.group.email_address.email}>",
]
)
end
end
context 'with no real sender (e.g. trigger or scheduler)' do
let(:created_by) { User.find(1) }
it 'sets the from to realname of the mail address)' do
expect(article.reload.from).to eq("#{article.ticket.group.email_address.name} <#{article.ticket.group.email_address.email}>")
end
end
end
end
describe 'Setting of ticket.create_article_{sender,type}' do
let!(:ticket) { create(:ticket) }
context 'on creation' do
context 'of first article on a ticket' do
subject(:article) do
create(:ticket_article, ticket: ticket, sender_name: 'Agent', type_name: 'email')
end
it 'sets ticket sender/type attributes based on article sender/type' do
expect { article }
.to change { ticket.reload.create_article_sender&.name }.to('Agent')
.and change { ticket.reload.create_article_type&.name }.to('email')
end
end
context 'of subsequent articles on a ticket' do
subject(:article) do
create(:ticket_article, ticket: ticket, sender_name: 'Customer', type_name: 'twitter status')
end
let!(:first_article) do
create(:ticket_article, ticket: ticket, sender_name: 'Agent', type_name: 'email')
end
it 'does not modify ticket’s sender/type attributes' do
expect { article }
.to not_change { ticket.reload.create_article_sender.name }
.and not_change { ticket.reload.create_article_type.name }
end
end
end
end
describe 'XSS protection:' do
subject(:article) { create(:ticket_article, body: body, content_type: 'text/html') }
before do
# XSS processing may run into a timeout on slow CI systems, so turn the timeout off for the test.
stub_const("#{HtmlSanitizer}::PROCESSING_TIMEOUT", nil)
end
context 'when body contains only injected JS' do
let(:body) { <<~RAW.chomp }
some other text
RAW
it 'removes
RAW
it 'removes