mirror of
https://github.com/opf/openproject.git
synced 2026-06-14 03:30:14 +00:00
1016 lines
32 KiB
Ruby
1016 lines
32 KiB
Ruby
#-- copyright
|
||
# OpenProject is an open source project management software.
|
||
# Copyright (C) 2012-2022 the OpenProject GmbH
|
||
#
|
||
# This program is free software; you can redistribute it and/or
|
||
# modify it under the terms of the GNU General Public License version 3.
|
||
#
|
||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||
#
|
||
# This program is free software; you can redistribute it and/or
|
||
# modify it under the terms of the GNU General Public License
|
||
# as published by the Free Software Foundation; either version 2
|
||
# of the License, or (at your option) any later version.
|
||
#
|
||
# This program is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
#
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with this program; if not, write to the Free Software
|
||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||
#
|
||
# See COPYRIGHT and LICENSE files for more details.
|
||
#++
|
||
|
||
require 'spec_helper'
|
||
|
||
describe MailHandler, type: :model do
|
||
let(:anno_user) { User.anonymous }
|
||
let(:project) { create(:valid_project, identifier: 'onlinestore', name: 'OnlineStore', public: false) }
|
||
let(:public_project) { create(:valid_project, identifier: 'onlinestore', name: 'OnlineStore', public: true) }
|
||
let(:priority_low) { create(:priority_low, is_default: true) }
|
||
|
||
before do
|
||
# we need both of these run first so the anonymous user is created and
|
||
# there is a default work package priority to save any work packages
|
||
priority_low
|
||
anno_user
|
||
|
||
allow(UserMailer)
|
||
.to receive(:incoming_email_error)
|
||
.and_return instance_double(ActionMailer::MessageDelivery, deliver_later: nil)
|
||
end
|
||
|
||
after do
|
||
User.current = nil
|
||
allow(Setting).to receive(:default_language).and_return('en')
|
||
end
|
||
|
||
shared_context 'for wp_on_given_project' do
|
||
let(:permissions) { %i[add_work_packages assign_versions work_package_assigned] }
|
||
let!(:user) do
|
||
create(:user,
|
||
mail: 'JSmith@somenet.foo',
|
||
firstname: 'John',
|
||
lastname: 'Smith',
|
||
member_in_project: project,
|
||
member_with_permissions: permissions)
|
||
end
|
||
let(:submit_options) { {} }
|
||
|
||
subject do
|
||
submit_email('wp_on_given_project.eml', **submit_options)
|
||
end
|
||
end
|
||
|
||
shared_context 'for wp_on_given_project_case_insensitive' do
|
||
let(:permissions) { %i[add_work_packages assign_versions] }
|
||
let!(:user) do
|
||
create(:user,
|
||
mail: 'JSmith@somenet.foo',
|
||
firstname: 'John',
|
||
lastname: 'Smith',
|
||
member_in_project: project,
|
||
member_with_permissions: permissions)
|
||
end
|
||
let(:submit_options) { { allow_override: 'version' } }
|
||
|
||
subject do
|
||
submit_email('wp_on_given_project_case_insensitive.eml', **submit_options)
|
||
end
|
||
end
|
||
|
||
shared_context 'for wp on given project group assignment' do
|
||
let(:permissions) { %i[add_work_packages] }
|
||
let!(:user) do
|
||
create(:user,
|
||
mail: 'JSmith@somenet.foo',
|
||
firstname: 'John',
|
||
lastname: 'Smith',
|
||
member_in_project: project,
|
||
member_with_permissions: permissions)
|
||
end
|
||
let!(:group) do
|
||
create(:group,
|
||
lastname: 'A-Team',
|
||
member_in_project: project,
|
||
member_with_permissions: [:work_package_assigned])
|
||
end
|
||
let(:submit_options) { {} }
|
||
|
||
subject do
|
||
submit_email('wp_on_given_project_group_assignment.eml', **submit_options)
|
||
end
|
||
end
|
||
|
||
shared_context 'with a reply to a wp mention with quotes above' do
|
||
let(:permissions) { %i[edit_work_packages view_work_packages] }
|
||
let!(:user) do
|
||
create(:user,
|
||
mail: 'JSmith@somenet.foo',
|
||
member_in_project: project,
|
||
member_with_permissions: permissions)
|
||
end
|
||
|
||
let!(:work_package) do
|
||
create(:work_package,
|
||
id: 2,
|
||
project:).tap do |wp|
|
||
wp.journals.last.update_column(:id, 891223)
|
||
end
|
||
end
|
||
|
||
subject do
|
||
submit_email('wp_reply_with_quoted_reply_above.eml')
|
||
end
|
||
end
|
||
|
||
shared_context 'with wp create with cc' do
|
||
let(:permissions) { %i[add_work_packages view_work_packages add_work_package_watchers] }
|
||
let!(:user) do
|
||
create(:user,
|
||
mail: 'JSmith@somenet.foo',
|
||
firstname: 'John',
|
||
lastname: 'Smith',
|
||
member_in_project: project,
|
||
member_with_permissions: permissions)
|
||
end
|
||
let!(:cc_user) do
|
||
create(:user,
|
||
mail: 'dlopper@somenet.foo',
|
||
firstname: 'D',
|
||
lastname: 'Lopper',
|
||
member_in_project: project,
|
||
member_with_permissions: permissions)
|
||
end
|
||
let(:submit_options) { { issue: { project: project.identifier } } }
|
||
|
||
subject do
|
||
submit_email('ticket_with_cc.eml', **submit_options)
|
||
end
|
||
end
|
||
|
||
shared_context 'with a reply to a wp mention' do
|
||
let(:permissions) { %i[add_work_package_notes view_work_packages] }
|
||
let!(:user) do
|
||
create(:user,
|
||
mail: 'j.doe@openproject.org',
|
||
member_in_project: project,
|
||
member_with_permissions: permissions)
|
||
end
|
||
|
||
let!(:work_package) do
|
||
create(:work_package,
|
||
subject: 'Some subject of the bug',
|
||
id: 39733,
|
||
project:).tap do |wp|
|
||
wp.journals.last.update_column(:id, 99999999)
|
||
end
|
||
end
|
||
|
||
subject do
|
||
submit_email('wp_mention_reply.eml')
|
||
end
|
||
end
|
||
|
||
shared_context 'with a reply to a wp mention with attributes' do
|
||
let(:permissions) { %i[add_work_package_notes view_work_packages edit_work_packages work_package_assigned] }
|
||
let(:role) do
|
||
create(:role, permissions:)
|
||
end
|
||
let!(:user) do
|
||
create(:user,
|
||
mail: 'j.doe@openproject.org',
|
||
member_in_project: project,
|
||
member_through_role: role)
|
||
end
|
||
|
||
let!(:work_package) do
|
||
create(:work_package,
|
||
subject: 'Some subject of the bug',
|
||
id: 39733,
|
||
project:,
|
||
status: original_status).tap do |wp|
|
||
wp.journals.last.update_column(:id, 99999999)
|
||
end
|
||
end
|
||
let!(:original_status) do
|
||
create(:default_status)
|
||
end
|
||
let!(:resolved_status) do
|
||
create(:status,
|
||
name: 'Resolved').tap do |status|
|
||
create(:workflow,
|
||
old_status: original_status,
|
||
new_status: status,
|
||
role:,
|
||
type: work_package.type)
|
||
end
|
||
end
|
||
let!(:other_user) do
|
||
create(:user,
|
||
mail: 'jsmith@somenet.foo',
|
||
member_in_project: project,
|
||
member_through_role: role)
|
||
end
|
||
let!(:float_cf) do
|
||
create(:float_wp_custom_field,
|
||
name: 'float field').tap do |cf|
|
||
project.work_package_custom_fields << cf
|
||
work_package.type.custom_fields << cf
|
||
end
|
||
end
|
||
|
||
subject do
|
||
submit_email('wp_mention_reply_with_attributes.eml')
|
||
end
|
||
end
|
||
|
||
shared_context 'with a reply to a message' do
|
||
let(:permissions) { %i[view_messages add_messages] }
|
||
let!(:user) do
|
||
create(:user,
|
||
mail: 'j.doe@openproject.org',
|
||
member_in_project: project,
|
||
member_with_permissions: permissions)
|
||
end
|
||
|
||
let!(:message) do
|
||
create(:message,
|
||
id: 70917,
|
||
forum: create(:forum, project:)).tap do |wp|
|
||
wp.journals.last.update_column(:id, 99999999)
|
||
end
|
||
end
|
||
|
||
subject do
|
||
submit_email('message_reply.eml')
|
||
end
|
||
end
|
||
|
||
describe '#receive' do
|
||
shared_examples_for 'work package created' do
|
||
it 'creates the work package' do
|
||
expect(subject)
|
||
.to be_a(WorkPackage)
|
||
|
||
expect(subject)
|
||
.to be_persisted
|
||
end
|
||
end
|
||
|
||
shared_examples_for 'journal created' do
|
||
it 'creates the journal' do
|
||
expect(subject)
|
||
.to be_a(Journal)
|
||
|
||
expect(subject)
|
||
.to be_persisted
|
||
end
|
||
end
|
||
|
||
context 'when sending a mail not as a reply' do
|
||
context 'for a given project' do
|
||
let!(:status) { create(:status, name: 'Resolved') }
|
||
let!(:version) { create(:version, name: 'alpha', project:) }
|
||
|
||
include_context 'for wp_on_given_project' do
|
||
let(:submit_options) { { allow_override: 'version' } }
|
||
end
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'sets the referenced project' do
|
||
expect(subject.project)
|
||
.to eql(project)
|
||
end
|
||
|
||
it 'sets the first type in the project' do
|
||
expect(subject.type)
|
||
.to eql(project.types.first)
|
||
end
|
||
|
||
it 'sets the subject' do
|
||
expect(subject.subject)
|
||
.to eql('New ticket on a given project')
|
||
end
|
||
|
||
it 'sets the sender as the author' do
|
||
expect(subject.author)
|
||
.to eql(user)
|
||
end
|
||
|
||
it 'set the description' do
|
||
expect(subject.description)
|
||
.to include('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
|
||
end
|
||
|
||
it 'sets the start date' do
|
||
expect(subject.start_date.to_s)
|
||
.to eql('2010-01-01')
|
||
end
|
||
|
||
it 'sets the due date' do
|
||
expect(subject.due_date.to_s)
|
||
.to eql('2010-12-31')
|
||
end
|
||
|
||
it 'sets the assignee' do
|
||
expect(subject.assigned_to)
|
||
.to eql(user)
|
||
end
|
||
|
||
it 'sets the status' do
|
||
expect(subject.status)
|
||
.to eql(status)
|
||
end
|
||
|
||
it 'sets the version' do
|
||
expect(subject.version)
|
||
.to eql(version)
|
||
end
|
||
|
||
it 'sets the estimated_hours' do
|
||
expect(subject.estimated_hours)
|
||
.to be(2.5)
|
||
end
|
||
|
||
it 'sets the done_ratio' do
|
||
expect(subject.done_ratio)
|
||
.to be(30)
|
||
end
|
||
|
||
it 'removes keywords' do
|
||
expect(subject.description)
|
||
.not_to match(/^Project:/i)
|
||
|
||
expect(subject.description)
|
||
.not_to match(/^Status:/i)
|
||
|
||
expect(subject.description)
|
||
.not_to match(/^Start Date:/i)
|
||
end
|
||
|
||
it 'sends notifications to watching users' do
|
||
# User gets all updates
|
||
user = create(:user, member_in_project: project, member_with_permissions: %i(view_work_packages))
|
||
|
||
expect do
|
||
perform_enqueued_jobs do
|
||
subject
|
||
end
|
||
end.to change(Notification.where(recipient: user), :count).by(1)
|
||
end
|
||
|
||
it 'does not send an error reply email' do
|
||
subject # send mail
|
||
|
||
expect(UserMailer).not_to have_received(:incoming_email_error)
|
||
end
|
||
end
|
||
|
||
context 'for a given project with a default type' do
|
||
let(:default_type) do
|
||
create(:type, is_default: true).tap do |t|
|
||
project.types << t
|
||
end
|
||
end
|
||
|
||
include_context 'for wp_on_given_project' do
|
||
let(:submit_options) { { issue: { type: default_type.name } } }
|
||
end
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'sets the default type' do
|
||
expect(subject.type.name)
|
||
.to eql(default_type.name)
|
||
end
|
||
end
|
||
|
||
context 'for a given project with a locked user' do
|
||
let!(:status) { create(:status, name: 'Resolved') }
|
||
|
||
before do
|
||
user.locked!
|
||
end
|
||
|
||
include_context 'for wp_on_given_project'
|
||
|
||
it 'does not create the work package' do
|
||
expect { subject }
|
||
.not_to change(WorkPackage, :count)
|
||
end
|
||
end
|
||
|
||
context 'for a given project with group assignment' do
|
||
include_context 'for wp on given project group assignment'
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'sets the assignee to the group' do
|
||
expect(subject.assigned_to)
|
||
.to eql(group)
|
||
end
|
||
end
|
||
|
||
context 'for an email by unknown user' do
|
||
context 'with unknown_user: \'create\'' do
|
||
it 'adds a work_package by create user on public project' do
|
||
Role.non_member.update_attribute :permissions, [:add_work_packages]
|
||
project.update_attribute :public, true
|
||
expect do
|
||
work_package = submit_email('ticket_by_unknown_user.eml', issue: { project: 'onlinestore' }, unknown_user: 'create')
|
||
work_package_created(work_package)
|
||
expect(work_package.author).to be_active
|
||
expect(work_package.author.mail).to eq('john.doe@somenet.foo')
|
||
expect(work_package.author.firstname).to eq('John')
|
||
expect(work_package.author.lastname).to eq('Doe')
|
||
|
||
# account information
|
||
perform_enqueued_jobs
|
||
|
||
email = ActionMailer::Base.deliveries.first
|
||
expect(email).not_to be_nil
|
||
expect(email.subject).to eq(I18n.t('mail_subject_register', value: Setting.app_title))
|
||
login = email.body.encoded.match(/\* Username: (\S+)\s?$/)[1]
|
||
password = email.body.encoded.match(/\* Password: (\S+)\s?$/)[1]
|
||
|
||
# Can't log in here since randomly assigned password must be changed
|
||
found_user = User.find_by(login:)
|
||
expect(work_package.author).to eq(found_user)
|
||
expect(found_user).to be_check_password(password)
|
||
end.to change(User, :count).by(1)
|
||
end
|
||
end
|
||
|
||
context 'with unknown_user: nil (default)' do
|
||
let(:results) { [] }
|
||
|
||
before do
|
||
results << submit_email(
|
||
'ticket_by_unknown_user.eml',
|
||
issue: { project: project.identifier },
|
||
unknown_user: nil
|
||
)
|
||
end
|
||
|
||
it "ignores the email" do
|
||
expect(results).to eq [false]
|
||
end
|
||
|
||
it "does not respond with an error email" do
|
||
expect(UserMailer).not_to have_received(:incoming_email_error)
|
||
end
|
||
end
|
||
|
||
context 'with unknown_user: \'accept\' and permission check present' do
|
||
let(:expected) do
|
||
'MailHandler: work_package could not be created by Anonymous due to ' \
|
||
'#["may not be accessed.", ' \
|
||
'"Type was attempted to be written but is not writable.", ' \
|
||
'"Project was attempted to be written but is not writable.", ' \
|
||
'"Subject was attempted to be written but is not writable.", ' \
|
||
'"Description was attempted to be written but is not writable."]'
|
||
end
|
||
let(:permission) { nil }
|
||
|
||
subject(:work_package) do
|
||
submit_email(
|
||
'ticket_by_unknown_user.eml',
|
||
issue: { project: project.identifier },
|
||
unknown_user: 'accept'
|
||
)
|
||
end
|
||
|
||
before do
|
||
allow(Rails.logger).to receive(:error).with(expected)
|
||
Role.anonymous.add_permission!(permission) if permission
|
||
end
|
||
|
||
context 'with anonymous lacking permissions' do
|
||
before do
|
||
work_package
|
||
end
|
||
|
||
it 'rejects the email' do
|
||
expect(work_package).to be false
|
||
end
|
||
|
||
it 'logs the error' do
|
||
expect(Rails.logger).to have_received(:error).with(expected)
|
||
end
|
||
|
||
context 'with report_incoming_email_errors true (default)' do
|
||
it 'responds with an error email' do
|
||
expect(UserMailer).to have_received(:incoming_email_error) do |user, mail, logs|
|
||
expect(user).to eq anno_user
|
||
expect(mail[:subject]).to eq "Ticket by unknown user"
|
||
expect(logs).to eq [expected.sub(/^MailHandler/, "error")]
|
||
end
|
||
end
|
||
end
|
||
|
||
context 'with report_incoming_email_errors false', with_settings: { report_incoming_email_errors: false } do
|
||
it 'does not respond with an error email' do
|
||
expect(UserMailer).not_to have_received(:incoming_email_error)
|
||
end
|
||
end
|
||
end
|
||
|
||
context 'with anonymous having permissions in a public project' do
|
||
let(:permission) { :add_work_packages }
|
||
|
||
before do
|
||
project.update_attribute(:public, true)
|
||
end
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'sets the author to anonymous' do
|
||
expect(work_package.author)
|
||
.to eql User.anonymous
|
||
end
|
||
|
||
it 'creates no user' do
|
||
expect { work_package }
|
||
.not_to change(User, :count)
|
||
end
|
||
end
|
||
|
||
context 'with anonymous having permissions in a private project' do
|
||
let(:permission) { :add_work_packages }
|
||
|
||
before do
|
||
project.update_attribute(:public, false)
|
||
end
|
||
|
||
it 'creates no work package' do
|
||
expect { work_package }
|
||
.not_to change(WorkPackage, :count)
|
||
end
|
||
|
||
it 'creates no user' do
|
||
expect { work_package }
|
||
.not_to change(User, :count)
|
||
end
|
||
end
|
||
end
|
||
|
||
context 'for unknown_user: \'accept\' and no_permission_check' do
|
||
subject(:work_package) do
|
||
submit_email 'ticket_by_unknown_user.eml',
|
||
issue: { project: project.identifier },
|
||
unknown_user: 'accept',
|
||
no_permission_check: 1
|
||
end
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'sets the author to anonymous' do
|
||
expect(work_package.author).to eq(User.anonymous)
|
||
end
|
||
end
|
||
|
||
context 'for unknown_user: \'accept\' and without from header' do
|
||
subject(:work_package) do
|
||
Role.anonymous.add_permission!(:add_work_packages)
|
||
|
||
submit_email 'wp_without_from_header.eml',
|
||
issue: { project: project.identifier },
|
||
unknown_user: 'accept'
|
||
end
|
||
|
||
it 'creates no work package' do
|
||
expect { work_package }
|
||
.not_to change(WorkPackage, :count)
|
||
end
|
||
end
|
||
|
||
context 'for unknown_user: \'accept\' and without permission checks and without from header' do
|
||
subject(:work_package) do
|
||
submit_email 'wp_without_from_header.eml',
|
||
issue: { project: project.identifier },
|
||
unknown_user: 'accept',
|
||
no_permission_check: 1
|
||
end
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'sets the author to anonymous' do
|
||
expect(work_package.author).to eq(User.anonymous)
|
||
end
|
||
end
|
||
end
|
||
|
||
context 'for email from emission address', with_settings: { mail_from: 'openproject@example.net' } do
|
||
before do
|
||
Role.non_member.add_permission!(:add_work_packages)
|
||
end
|
||
|
||
subject do
|
||
submit_email('ticket_from_emission_address.eml',
|
||
issue: { project: public_project.identifier },
|
||
unknown_user: 'create')
|
||
end
|
||
|
||
it 'returns false' do
|
||
expect(subject).to be_falsey
|
||
end
|
||
|
||
it 'does not create the user' do
|
||
expect { subject }
|
||
.not_to(change(User, :count))
|
||
end
|
||
|
||
it 'does not create the work_package' do
|
||
expect { subject }
|
||
.not_to(change(WorkPackage, :count))
|
||
end
|
||
|
||
it 'does not result in an error email response' do
|
||
subject # send email
|
||
|
||
expect(UserMailer).not_to have_received(:incoming_email_error)
|
||
end
|
||
end
|
||
|
||
context 'for wp with status' do
|
||
let!(:status) { create(:status, name: 'Resolved') }
|
||
|
||
# This email contains: 'Project: onlinestore' and 'Status: Resolved'
|
||
include_context 'for wp_on_given_project'
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'assigns the status to the created work package' do
|
||
expect(subject.status)
|
||
.to eql(status)
|
||
end
|
||
end
|
||
|
||
context 'for wp with status case insensitive' do
|
||
let!(:status) { create(:status, name: 'Resolved') }
|
||
let!(:priority_low) { create(:priority_low, name: 'Low', is_default: true) }
|
||
let!(:version) { create(:version, name: 'alpha', project:) }
|
||
|
||
# This email contains: 'Project: onlinestore' and 'Status: resolved'
|
||
include_context 'for wp_on_given_project_case_insensitive'
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'assigns the status to the created work package' do
|
||
expect(subject.status).to eq(status)
|
||
expect(subject.version).to eq(version)
|
||
expect(subject.priority).to eq priority_low
|
||
end
|
||
end
|
||
|
||
context 'for wp with cc' do
|
||
include_context 'with wp create with cc'
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'assigns cc and author as watcher' do
|
||
expect(subject.watcher_users)
|
||
.to match_array([user, cc_user])
|
||
end
|
||
end
|
||
end
|
||
|
||
context 'when sending a reply to work package mail' do
|
||
let!(:mail_user) { create :admin, mail: 'user@example.org' }
|
||
let!(:work_package) { create :work_package, project: }
|
||
|
||
before do
|
||
# Avoid trying to extract text
|
||
allow(OpenProject::Database).to receive(:allows_tsv?).and_return false
|
||
end
|
||
|
||
context 'with attachments to be added' do
|
||
it 'updates a work package with attachment' do
|
||
allow(WorkPackage).to receive(:find_by).with(id: 123).and_return(work_package)
|
||
|
||
# Mail with two attachemnts, one of which is skipped by signature.asc filename match
|
||
submit_email 'update_ticket_with_attachment_and_sig.eml', issue: { project: 'onlinestore' }
|
||
|
||
work_package.reload
|
||
|
||
# Expect comment
|
||
expect(work_package.journals.last.notes).to eq 'Reply to work package #123'
|
||
expect(work_package.journals.last.user).to eq mail_user
|
||
|
||
# Expect filename without signature to be saved
|
||
expect(work_package.attachments.count).to eq(1)
|
||
expect(work_package.attachments.first.filename).to eq('Photo25.jpg')
|
||
end
|
||
end
|
||
|
||
context 'with existing attachment' do
|
||
let!(:attachment) { create(:attachment, container: work_package) }
|
||
|
||
it 'does not replace it (Regression #29722)' do
|
||
work_package.reload
|
||
allow(WorkPackage).to receive(:find_by).with(id: 123).and_return(work_package)
|
||
|
||
# Mail with two attachments, one of which is skipped by signature.asc filename match
|
||
submit_email 'update_ticket_with_attachment_and_sig.eml', issue: { project: 'onlinestore' }
|
||
|
||
expect(work_package.attachments.length).to eq 2
|
||
end
|
||
end
|
||
|
||
context 'with reply text' do
|
||
include_context 'with a reply to a wp mention with quotes above'
|
||
|
||
it_behaves_like 'journal created'
|
||
|
||
it 'sends notifications' do
|
||
assignee = create(:user,
|
||
member_in_project: project,
|
||
member_with_permissions: %i(view_work_packages),
|
||
notification_settings: [build(:notification_setting, involved: true)])
|
||
|
||
work_package.update_column(:assigned_to_id, assignee.id)
|
||
|
||
# Sends notifications for the assignee and the author who is listening for all changes.
|
||
expect do
|
||
perform_enqueued_jobs do
|
||
subject
|
||
end
|
||
end.to change(Notification, :count).by(2)
|
||
end
|
||
end
|
||
|
||
context 'when replying to mention mail with only text' do
|
||
include_context 'with a reply to a wp mention'
|
||
|
||
it_behaves_like 'journal created'
|
||
|
||
it 'adds the content to the last journal' do
|
||
subject
|
||
|
||
expect(work_package.journals.reload.last.notes)
|
||
.to include 'The text of the reply.'
|
||
end
|
||
|
||
it 'does not alter any attributes' do
|
||
subject
|
||
|
||
expect(work_package.journals.reload.last.details)
|
||
.to be_empty
|
||
end
|
||
|
||
it 'performs the changes in the name of the sender' do
|
||
subject
|
||
|
||
expect(work_package.journals.reload.last.user)
|
||
.to eql user
|
||
end
|
||
end
|
||
|
||
context 'when replying to mention mail with text and attributes' do
|
||
include_context 'with a reply to a wp mention with attributes'
|
||
|
||
it_behaves_like 'journal created'
|
||
|
||
it 'adds the content to the last journal' do
|
||
subject
|
||
|
||
expect(work_package.journals.reload.last.notes)
|
||
.to include 'The text of the reply.'
|
||
end
|
||
|
||
it 'alters the attributes', with_flag: { work_packages_duration_field_active: true } do
|
||
subject
|
||
|
||
expect(work_package.journals.reload.last.details)
|
||
.to eql(
|
||
"due_date" => [nil, Date.parse("Fri, 31 Dec 2010")],
|
||
"status_id" => [original_status.id, resolved_status.id],
|
||
"assigned_to_id" => [nil, other_user.id],
|
||
"start_date" => [nil, Date.parse("Fri, 01 Jan 2010")],
|
||
"duration" => [nil, 365],
|
||
"custom_fields_#{float_cf.id}" => [nil, "52.6"]
|
||
)
|
||
end
|
||
|
||
it 'performs the changes in the name of the sender' do
|
||
subject
|
||
|
||
expect(work_package.journals.reload.last.user)
|
||
.to eql user
|
||
end
|
||
end
|
||
|
||
context 'with a custom field' do
|
||
let(:work_package) { create :work_package, project: }
|
||
let(:type) { create :type }
|
||
|
||
before do
|
||
type.custom_fields << custom_field
|
||
type.save!
|
||
|
||
allow(work_package).to receive(:available_custom_fields).and_return([custom_field])
|
||
|
||
allow(WorkPackage).to receive(:find_by).with(id: 42).and_return(work_package)
|
||
allow(User).to receive(:find_by_mail).with("h.wurst@openproject.com").and_return(mail_user)
|
||
end
|
||
|
||
context 'as type text' do
|
||
let(:custom_field) { create :text_wp_custom_field, name: "Notes" }
|
||
|
||
before do
|
||
submit_email 'wp_reply_with_text_custom_field.eml', issue: { project: project.identifier }
|
||
|
||
work_package.reload
|
||
end
|
||
|
||
it "sets the value" do
|
||
value = work_package.custom_values.where(custom_field_id: custom_field.id).pick(:value)
|
||
|
||
expect(value).to eq "some text" # as given in .eml fixture
|
||
end
|
||
end
|
||
|
||
context 'as type list' do
|
||
let(:custom_field) { create :list_wp_custom_field, name: "Letters", possible_values: %w(A B C) }
|
||
|
||
before do
|
||
submit_email 'wp_reply_with_list_custom_field.eml', issue: { project: project.identifier }
|
||
|
||
work_package.reload
|
||
end
|
||
|
||
it "sets the value" do
|
||
option = CustomOption.where(custom_field_id: custom_field.id, value: "B").first # as given in .eml fixture
|
||
value = work_package.custom_values.where(custom_field_id: custom_field.id).pick(:value)
|
||
|
||
expect(value).to eq option.id.to_s
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
context 'when sending a reply to a message mail' do
|
||
include_context 'with a reply to a message'
|
||
|
||
it 'creates a new message in the name of the sender', aggregate_failures: true do
|
||
expect(subject)
|
||
.to be_a Message
|
||
|
||
expect(subject.subject)
|
||
.to eql('Response to the original message')
|
||
|
||
expect(subject.content)
|
||
.to include('Test message')
|
||
|
||
expect(subject.author)
|
||
.to eql user
|
||
|
||
expect(subject.forum)
|
||
.to eql message.forum
|
||
|
||
expect(subject.parent)
|
||
.to eql message
|
||
end
|
||
end
|
||
|
||
describe 'truncate emails based on the Setting' do
|
||
context 'with no setting', with_settings: { mail_handler_body_delimiters: '' } do
|
||
include_context 'for wp_on_given_project'
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'adds the entire email into the work_package' do
|
||
expect(subject.description)
|
||
.to include('---')
|
||
|
||
expect(subject.description)
|
||
.to include('This paragraph is after the delimiter')
|
||
end
|
||
end
|
||
|
||
context 'with a single string', with_settings: { mail_handler_body_delimiters: '---' } do
|
||
include_context 'for wp_on_given_project'
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'truncates the email at the delimiter for the work package' do
|
||
expect(subject.description)
|
||
.to include('This paragraph is before delimiters')
|
||
|
||
expect(subject.description)
|
||
.to include('--- This line starts with a delimiter')
|
||
|
||
expect(subject.description)
|
||
.not_to match(/^---$/)
|
||
|
||
expect(subject.description)
|
||
.not_to include('This paragraph is after the delimiter')
|
||
end
|
||
end
|
||
|
||
context 'with a single quoted reply (e.g. reply to a OpenProject email notification)',
|
||
with_settings: { mail_handler_body_delimiters: '--- Reply above. Do not remove this line. ---' } do
|
||
include_context 'with a reply to a wp mention with quotes above'
|
||
|
||
it_behaves_like 'journal created'
|
||
|
||
it 'truncates the email at the delimiter with the quoted reply symbols (>)' do
|
||
expect(subject.notes)
|
||
.to include('An update to the issue by the sender.')
|
||
|
||
expect(subject.notes)
|
||
.not_to match(Regexp.escape('--- Reply above. Do not remove this line. ---'))
|
||
|
||
expect(subject.notes)
|
||
.not_to include('Looks like the JSON api for projects was missed.')
|
||
end
|
||
end
|
||
|
||
context 'with multiple strings',
|
||
with_settings: { mail_handler_body_delimiters: "---\nBREAK" } do
|
||
include_context 'for wp_on_given_project'
|
||
|
||
it_behaves_like 'work package created'
|
||
|
||
it 'truncates the email at the first delimiter found (BREAK)' do
|
||
expect(subject.description)
|
||
.to include('This paragraph is before delimiters')
|
||
|
||
expect(subject.description)
|
||
.not_to include('BREAK')
|
||
|
||
expect(subject.description)
|
||
.not_to include('This paragraph is between delimiters')
|
||
|
||
expect(subject.description)
|
||
.not_to match(/^---$/)
|
||
|
||
expect(subject.description)
|
||
.not_to include('This paragraph is after the delimiter')
|
||
end
|
||
end
|
||
end
|
||
|
||
describe 'category' do
|
||
let!(:category) { create :category, project:, name: 'Foobar' }
|
||
|
||
it 'adds a work_package with category' do
|
||
allow(Setting).to receive(:default_language).and_return('en')
|
||
Role.non_member.update_attribute :permissions, [:add_work_packages]
|
||
project.update_attribute :public, true
|
||
|
||
work_package = submit_email 'ticket_with_category.eml',
|
||
issue: { project: 'onlinestore' },
|
||
allow_override: ['category'],
|
||
unknown_user: 'create'
|
||
work_package_created(work_package)
|
||
expect(work_package.category).to eq(category)
|
||
end
|
||
end
|
||
end
|
||
|
||
describe '#cleanup_body' do
|
||
let(:input) do
|
||
"Subject:foo\nDescription:bar\n" \
|
||
">>> myserver.example.org 2016-01-27 15:56 >>>\n... (Email-Body) ..."
|
||
end
|
||
let(:handler) { described_class.send :new }
|
||
|
||
context 'with regex delimiter' do
|
||
before do
|
||
allow(Setting).to receive(:mail_handler_body_delimiter_regex).and_return('>>>.+?>>>.*')
|
||
allow(handler).to receive(:plain_text_body).and_return(input)
|
||
allow(handler).to receive(:cleaned_up_text_body).and_call_original
|
||
end
|
||
|
||
it 'removes the irrelevant lines' do
|
||
expect(handler.send(:cleaned_up_text_body)).to eq("Subject:foo\nDescription:bar")
|
||
expect(handler).to have_received(:cleaned_up_text_body)
|
||
end
|
||
end
|
||
end
|
||
|
||
private
|
||
|
||
def read_email(filename)
|
||
File.read(File.join("#{File.dirname(__FILE__)}/../fixtures/mail_handler", filename))
|
||
end
|
||
|
||
def submit_email(filename, options = {})
|
||
MailHandler.receive(read_email(filename), options)
|
||
end
|
||
|
||
def work_package_created(work_package)
|
||
expect(work_package).to be_a(WorkPackage)
|
||
expect(work_package).not_to be_new_record
|
||
work_package.reload
|
||
end
|
||
end
|