Commit adab5dba authored by Rémy Coutable's avatar Rémy Coutable

Fix permission for setting an issue's due date

Signed-off-by: default avatarRémy Coutable <remy@rymai.me>
parent 7d79a943
......@@ -7,6 +7,7 @@ v 8.13.0 (unreleased)
- Log LDAP lookup errors and don't swallow unrelated exceptions. !6103 (Markus Koller)
- Add more tests for calendar contribution (ClemMakesApps)
- Avoid database queries on Banzai::ReferenceParser::BaseParser for nodes without references
- Fix permission for setting an issue's due date
- Fix robots.txt disallowing access to groups starting with "s" (Matt Harrison)
- Only update issuable labels if they have been changed
- Revoke button in Applications Settings underlines on hover.
......
......@@ -50,6 +50,7 @@ class IssuableBaseService < BaseService
params.delete(:remove_label_ids)
params.delete(:label_ids)
params.delete(:assignee_id)
params.delete(:due_date)
end
end
......
......@@ -195,7 +195,7 @@ module SlashCommands
params '<in 2 days | this Friday | December 31st>'
condition do
issuable.respond_to?(:due_date) &&
current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
current_user.can?(:"admin_#{issuable.to_ability_name}", project)
end
command :due do |due_date_param|
due_date = Chronic.parse(due_date_param).try(:to_date)
......@@ -208,7 +208,7 @@ module SlashCommands
issuable.persisted? &&
issuable.respond_to?(:due_date) &&
issuable.due_date? &&
current_user.can?(:"update_#{issuable.to_ability_name}", issuable)
current_user.can?(:"admin_#{issuable.to_ability_name}", project)
end
command :remove_due_date do
@updates[:due_date] = nil
......
......@@ -25,6 +25,7 @@ feature 'Issues > User uses slash commands', feature: true, js: true do
describe 'adding a due date from note' do
let(:issue) { create(:issue, project: project) }
context 'when the current user can update the due date' do
it 'does not create a note, and sets the due date accordingly' do
write_note("/due 2016-08-28")
......@@ -37,9 +38,32 @@ feature 'Issues > User uses slash commands', feature: true, js: true do
end
end
context 'when the current user cannot update the due date' do
let(:guest) { create(:user) }
before do
project.team << [guest, :guest]
logout
login_with(guest)
visit namespace_project_issue_path(project.namespace, project, issue)
end
it 'does not create a note, and sets the due date accordingly' do
write_note("/due 2016-08-28")
expect(page).to have_content '/due 2016-08-28'
expect(page).not_to have_content 'Your commands have been executed!'
issue.reload
expect(issue.due_date).to be_nil
end
end
end
describe 'removing a due date from note' do
let(:issue) { create(:issue, project: project, due_date: Date.new(2016, 8, 28)) }
context 'when the current user can update the due date' do
it 'does not create a note, and removes the due date accordingly' do
expect(issue.due_date).to eq Date.new(2016, 8, 28)
......@@ -53,5 +77,27 @@ feature 'Issues > User uses slash commands', feature: true, js: true do
expect(issue.due_date).to be_nil
end
end
context 'when the current user cannot update the due date' do
let(:guest) { create(:user) }
before do
project.team << [guest, :guest]
logout
login_with(guest)
visit namespace_project_issue_path(project.namespace, project, issue)
end
it 'does not create a note, and sets the due date accordingly' do
write_note("/remove_due_date")
expect(page).to have_content '/remove_due_date'
expect(page).not_to have_content 'Your commands have been executed!'
issue.reload
expect(issue.due_date).to eq Date.new(2016, 8, 28)
end
end
end
end
end
......@@ -20,16 +20,38 @@ describe Issues::CreateService, services: true do
let(:opts) do
{ title: 'Awesome issue',
description: 'please fix',
assignee: assignee,
assignee_id: assignee.id,
label_ids: labels.map(&:id),
milestone_id: milestone.id }
milestone_id: milestone.id,
due_date: Date.tomorrow }
end
it 'creates the issue with the given params' do
expect(issue).to be_persisted
expect(issue.title).to eq('Awesome issue')
expect(issue.assignee).to eq assignee
expect(issue.labels).to match_array labels
expect(issue.milestone).to eq milestone
expect(issue.due_date).to eq Date.tomorrow
end
it { expect(issue).to be_valid }
it { expect(issue.title).to eq('Awesome issue') }
it { expect(issue.assignee).to eq assignee }
it { expect(issue.labels).to match_array labels }
it { expect(issue.milestone).to eq milestone }
context 'when current user cannot admin issues in the project' do
let(:guest) { create(:user) }
before do
project.team << [guest, :guest]
end
it 'filters out params that cannot be set without the :admin_issue permission' do
issue = described_class.new(project, guest, opts).execute
expect(issue).to be_persisted
expect(issue.title).to eq('Awesome issue')
expect(issue.assignee).to be_nil
expect(issue.labels).to be_empty
expect(issue.milestone).to be_nil
expect(issue.due_date).to be_nil
end
end
it 'creates a pending todo for new assignee' do
attributes = {
......
......@@ -32,27 +32,55 @@ describe Issues::UpdateService, services: true do
described_class.new(project, user, opts).execute(issue)
end
context "valid params" do
before do
opts = {
context 'valid params' do
let(:opts) do
{
title: 'New title',
description: 'Also please fix',
assignee_id: user2.id,
state_event: 'close',
label_ids: [label.id]
label_ids: [label.id],
due_date: Date.tomorrow
}
end
perform_enqueued_jobs do
it 'updates the issue with the given params' do
update_issue(opts)
expect(issue).to be_valid
expect(issue.title).to eq 'New title'
expect(issue.description).to eq 'Also please fix'
expect(issue.assignee).to eq user2
expect(issue).to be_closed
expect(issue.labels).to match_array [label]
expect(issue.due_date).to eq Date.tomorrow
end
context 'when current user cannot admin issues in the project' do
let(:guest) { create(:user) }
before do
project.team << [guest, :guest]
end
it { expect(issue).to be_valid }
it { expect(issue.title).to eq('New title') }
it { expect(issue.assignee).to eq(user2) }
it { expect(issue).to be_closed }
it { expect(issue.labels.count).to eq(1) }
it { expect(issue.labels.first.title).to eq(label.name) }
it 'filters out params that cannot be set without the :admin_issue permission' do
described_class.new(project, guest, opts).execute(issue)
expect(issue).to be_valid
expect(issue.title).to eq 'New title'
expect(issue.description).to eq 'Also please fix'
expect(issue.assignee).to eq user3
expect(issue.labels).to be_empty
expect(issue.milestone).to be_nil
expect(issue.due_date).to be_nil
end
end
context 'with background jobs processed' do
before do
perform_enqueued_jobs do
update_issue(opts)
end
end
it 'sends email to user2 about assign of new issue and email to user3 about issue unassignment' do
deliveries = ActionMailer::Base.deliveries
......@@ -83,6 +111,7 @@ describe Issues::UpdateService, services: true do
expect(note.note).to eq 'Changed title: **{-Old-} title** → **{+New+} title**'
end
end
end
context 'when issue turns confidential' do
let(:opts) do
......
require 'spec_helper'
describe SlashCommands::InterpretService, services: true do
let(:project) { create(:project) }
let(:user) { create(:user) }
let(:project) { create(:empty_project, :public) }
let(:developer) { create(:user) }
let(:issue) { create(:issue, project: project) }
let(:milestone) { create(:milestone, project: project, title: '9.10') }
let(:inprogress) { create(:label, project: project, title: 'In Progress') }
let(:bug) { create(:label, project: project, title: 'Bug') }
before do
project.team << [user, :developer]
project.team << [developer, :developer]
end
describe '#execute' do
let(:service) { described_class.new(project, user) }
let(:service) { described_class.new(project, developer) }
let(:merge_request) { create(:merge_request, source_project: project) }
shared_examples 'reopen command' do
......@@ -45,13 +45,13 @@ describe SlashCommands::InterpretService, services: true do
it 'fetches assignee and populates assignee_id if content contains /assign' do
_, updates = service.execute(content, issuable)
expect(updates).to eq(assignee_id: user.id)
expect(updates).to eq(assignee_id: developer.id)
end
end
shared_examples 'unassign command' do
it 'populates assignee_id: nil if content contains /unassign' do
issuable.update(assignee_id: user.id)
issuable.update(assignee_id: developer.id)
_, updates = service.execute(content, issuable)
expect(updates).to eq(assignee_id: nil)
......@@ -124,7 +124,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'done command' do
it 'populates todo_event: "done" if content contains /done' do
TodoService.new.mark_todo(issuable, user)
TodoService.new.mark_todo(issuable, developer)
_, updates = service.execute(content, issuable)
expect(updates).to eq(todo_event: 'done')
......@@ -141,7 +141,7 @@ describe SlashCommands::InterpretService, services: true do
shared_examples 'unsubscribe command' do
it 'populates subscription_event: "unsubscribe" if content contains /unsubscribe' do
issuable.subscribe(user)
issuable.subscribe(developer)
_, updates = service.execute(content, issuable)
expect(updates).to eq(subscription_event: 'unsubscribe')
......@@ -209,12 +209,12 @@ describe SlashCommands::InterpretService, services: true do
end
it_behaves_like 'assign command' do
let(:content) { "/assign @#{user.username}" }
let(:content) { "/assign @#{developer.username}" }
let(:issuable) { issue }
end
it_behaves_like 'assign command' do
let(:content) { "/assign @#{user.username}" }
let(:content) { "/assign @#{developer.username}" }
let(:issuable) { merge_request }
end
......@@ -380,5 +380,56 @@ describe SlashCommands::InterpretService, services: true do
let(:content) { '/remove_due_date' }
let(:issuable) { merge_request }
end
context 'when current_user cannot :admin_issue' do
let(:visitor) { create(:user) }
let(:issue) { create(:issue, project: project, author: visitor) }
let(:service) { described_class.new(project, visitor) }
it_behaves_like 'empty command' do
let(:content) { "/assign @#{developer.username}" }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
let(:content) { '/unassign' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
let(:content) { "/milestone %#{milestone.title}" }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
let(:content) { '/remove_milestone' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
let(:content) { %(/label ~"#{inprogress.title}" ~#{bug.title} ~unknown) }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
let(:content) { %(/unlabel ~"#{inprogress.title}") }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
let(:content) { %(/relabel ~"#{inprogress.title}") }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
let(:content) { '/due tomorrow' }
let(:issuable) { issue }
end
it_behaves_like 'empty command' do
let(:content) { '/remove_due_date' }
let(:issuable) { issue }
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment