discourse-assign/spec/requests/assign_controller_spec.rb

566 lines
18 KiB
Ruby

# frozen_string_literal: true
require "rails_helper"
require_relative "../support/assign_allowed_group"
RSpec.describe DiscourseAssign::AssignController do
before { SiteSetting.assign_enabled = true }
fab!(:default_allowed_group) { Group.find_by(name: "staff") }
let(:user) { Fabricate(:admin, name: "Robin Ward", username: "eviltrout") }
fab!(:post) { Fabricate(:post) }
fab!(:user2) do
Fabricate(
:active_user,
name: "David Taylor",
username: "david",
groups: [default_allowed_group],
)
end
let(:non_admin) { Fabricate(:user, groups: [default_allowed_group]) }
fab!(:normal_user) { Fabricate(:user) }
fab!(:normal_admin) { Fabricate(:admin) }
describe "only allow users from allowed groups" do
before { sign_in(user2) }
it "filters requests where current_user is not member of an allowed group" do
SiteSetting.assign_allowed_on_groups = ""
put "/assign/assign.json",
params: {
target_id: post.topic_id,
target_type: "Topic",
username: user2.username,
}
expect(response.status).to eq(403)
end
it "filters requests where assigned group is not allowed" do
put "/assign/assign.json",
params: {
target_id: post.topic_id,
target_type: "Topic",
group_name: default_allowed_group.name,
}
expect(response.status).to eq(400)
end
describe "#suggestions" do
before { sign_in(user) }
it "includes users in allowed groups" do
allowed_group = Group.find_by(name: "everyone")
allowed_group.add(user2)
defaults = "#{default_allowed_group.id}|#{allowed_group.id}"
SiteSetting.assign_allowed_on_groups = defaults
Assigner.new(post.topic, user).assign(user2)
get "/assign/suggestions.json"
suggestions = JSON.parse(response.body)["suggestions"].map { |u| u["username"] }
expect(suggestions).to contain_exactly(user2.username, user.username)
end
it "does not include users from disallowed groups" do
allowed_group = Group.find_by(name: "everyone")
allowed_group.add(user2)
SiteSetting.assign_allowed_on_groups = default_allowed_group.id.to_s
Assigner.new(post.topic, user).assign(user2)
get "/assign/suggestions.json"
suggestions = JSON.parse(response.body)["suggestions"].map { |u| u["username"] }.sort
expect(suggestions).to eq(%w[david eviltrout])
end
it "does include only visible assign_allowed_on_groups" do
sign_in(non_admin) # Need to use non-admin to test. Admins can see all groups
visible_group = Fabricate(:group, visibility_level: Group.visibility_levels[:members])
visible_group.add(non_admin)
invisible_group = Fabricate(:group, visibility_level: Group.visibility_levels[:members])
SiteSetting.assign_allowed_on_groups = "#{visible_group.id}|#{invisible_group.id}"
get "/assign/suggestions.json"
assign_allowed_on_groups = JSON.parse(response.body)["assign_allowed_on_groups"]
expect(assign_allowed_on_groups).to contain_exactly(visible_group.name)
end
end
end
describe "#suggestions" do
before { sign_in(user) }
it "suggests the current user + the last 6 previously assigned users" do
assignees = 10.times.map { |_| assign_user_to_post.username }
get "/assign/suggestions.json"
suggestions = response.parsed_body["suggestions"].map { |u| u["username"] }
expect(suggestions).to contain_exactly(user.username, *assignees[4..9])
end
it "doesn't suggest users on holiday" do
user_on_vacation = assign_user_to_post
user_on_vacation.upsert_custom_fields(
DiscourseAssign::DiscourseCalendar::HOLIDAY_CUSTOM_FIELD => "t",
)
get "/assign/suggestions.json"
suggestions = response.parsed_body["suggestions"].map { |u| u["username"] }
expect(suggestions).to_not include(user_on_vacation.username)
end
it "suggests the current user even if they're on holiday" do
user.upsert_custom_fields(DiscourseAssign::DiscourseCalendar::HOLIDAY_CUSTOM_FIELD => "t")
get "/assign/suggestions.json"
suggestions = response.parsed_body["suggestions"].map { |u| u["username"] }
expect(suggestions).to include(user.username)
end
it "excludes other users from the suggestions when they already reached the max assigns limit" do
SiteSetting.max_assigned_topics = 1
another_admin = Fabricate(:admin)
Assigner.new(post.topic, user).assign(another_admin)
get "/assign/suggestions.json"
suggestions = JSON.parse(response.body)["suggestions"].map { |u| u["username"] }
expect(suggestions).to contain_exactly(user.username)
end
def assign_user_to_post
assignee = Fabricate(:user, groups: [default_allowed_group])
post = Fabricate(:post)
Assigner.new(post.topic, user).assign(assignee)
assignee
end
end
describe "#assign" do
include_context "with group that is allowed to assign"
before do
sign_in(user)
add_to_assign_allowed_group(user2)
SiteSetting.enable_assign_status = true
end
it "assigns topic to a user" do
put "/assign/assign.json",
params: {
target_id: post.topic_id,
target_type: "Topic",
username: user2.username,
}
expect(response.status).to eq(200)
expect(post.topic.reload.assignment.assigned_to_id).to eq(user2.id)
end
it "assigns topic with note to a user" do
put "/assign/assign.json",
params: {
target_id: post.topic_id,
target_type: "Topic",
username: user2.username,
note: "do dis pls",
}
expect(post.topic.reload.assignment.note).to eq("do dis pls")
end
it "assigns topic with a set status to a user" do
put "/assign/assign.json",
params: {
target_id: post.topic_id,
target_type: "Topic",
username: user2.username,
status: "In Progress",
}
expect(post.topic.reload.assignment.status).to eq("In Progress")
end
it "assigns topic with default status to a user" do
put "/assign/assign.json",
params: {
target_id: post.topic_id,
target_type: "Topic",
username: user2.username,
}
expect(post.topic.reload.assignment.status).to eq("New")
end
it "assigns topic to a group" do
put "/assign/assign.json",
params: {
target_id: post.topic_id,
target_type: "Topic",
group_name: assign_allowed_group.name,
}
expect(response.status).to eq(200)
expect(post.topic.reload.assignment.assigned_to).to eq(assign_allowed_group)
end
it "fails to assign topic to the user if its already assigned to the same user" do
put "/assign/assign.json",
params: {
target_id: post.topic_id,
target_type: "Topic",
username: user2.username,
}
expect(response.status).to eq(200)
expect(post.topic.reload.assignment.assigned_to_id).to eq(user2.id)
put "/assign/assign.json",
params: {
target_id: post.topic_id,
target_type: "Topic",
username: user2.username,
}
expect(response.status).to eq(400)
expect(JSON.parse(response.body)["error"]).to eq(
I18n.t("discourse_assign.already_assigned", username: user2.username),
)
end
it "fails to assign topic to the user if they already reached the max assigns limit" do
another_user = Fabricate(:user)
add_to_assign_allowed_group(another_user)
another_post = Fabricate(:post)
max_assigns = 1
SiteSetting.max_assigned_topics = max_assigns
Assigner.new(post.topic, user).assign(another_user)
put "/assign/assign.json",
params: {
target_id: another_post.topic_id,
target_type: "Topic",
username: another_user.username,
}
expect(response.status).to eq(400)
expect(JSON.parse(response.body)["error"]).to eq(
I18n.t(
"discourse_assign.too_many_assigns",
username: another_user.username,
max: max_assigns,
),
)
end
it "fails with a specific error message if the topic is a PM and the assignee can not see it" do
pm = Fabricate(:private_message_post, user: user).topic
another_user = Fabricate(:user)
add_to_assign_allowed_group(another_user)
put "/assign/assign.json",
params: {
target_id: pm.id,
target_type: "Topic",
username: another_user.username,
}
expect(response.parsed_body["error"]).to eq(
I18n.t(
"discourse_assign.forbidden_assignee_not_pm_participant",
username: another_user.username,
),
)
end
it "fails with a specific error message if the topic is not a PM and the assignee can not see it" do
topic = Fabricate(:topic, category: Fabricate(:private_category, group: Fabricate(:group)))
another_user = Fabricate(:user)
add_to_assign_allowed_group(another_user)
put "/assign/assign.json",
params: {
target_id: topic.id,
target_type: "Topic",
username: another_user.username,
}
expect(response.parsed_body["error"]).to eq(
I18n.t(
"discourse_assign.forbidden_assignee_cant_see_topic",
username: another_user.username,
),
)
end
end
describe "#assigned" do
include_context "with group that is allowed to assign"
fab!(:post1) { Fabricate(:post) }
fab!(:post2) { Fabricate(:post) }
fab!(:post3) { Fabricate(:post) }
before do
add_to_assign_allowed_group(user2)
freeze_time 1.hour.from_now
Assigner.new(post1.topic, user).assign(user)
freeze_time 1.hour.from_now
Assigner.new(post2.topic, user).assign(user2)
freeze_time 1.hour.from_now
Assigner.new(post3.topic, user).assign(user)
sign_in(user)
end
it "lists topics ordered by user" do
get "/assign/assigned.json"
expect(JSON.parse(response.body)["topics"].map { |t| t["id"] }).to match_array(
[post2.topic_id, post1.topic_id, post3.topic_id],
)
get "/assign/assigned.json", params: { limit: 2 }
expect(JSON.parse(response.body)["topics"].map { |t| t["id"] }).to match_array(
[post3.topic_id, post2.topic_id],
)
get "/assign/assigned.json", params: { offset: 2 }
expect(JSON.parse(response.body)["topics"].map { |t| t["id"] }).to match_array(
[post1.topic_id],
)
end
context "with custom allowed groups" do
let(:custom_allowed_group) { Fabricate(:group, name: "my-group") }
let(:other_user) { Fabricate(:user, groups: [custom_allowed_group]) }
before { SiteSetting.assign_allowed_on_groups += "|#{custom_allowed_group.id}" }
it "works for admins" do
get "/assign/assigned.json"
expect(response.status).to eq(200)
end
it "does not work for other groups" do
sign_in(other_user)
get "/assign/assigned.json"
expect(response.status).to eq(403)
end
end
end
describe "#group_members" do
include_context "with group that is allowed to assign"
fab!(:post1) { Fabricate(:post) }
fab!(:post2) { Fabricate(:post) }
fab!(:post3) { Fabricate(:post) }
before do
add_to_assign_allowed_group(user2)
add_to_assign_allowed_group(user)
Assigner.new(post1.topic, user).assign(user)
Assigner.new(post2.topic, user).assign(user2)
Assigner.new(post3.topic, user).assign(user)
end
it "list members order by assignments_count" do
sign_in(user)
get "/assign/members/#{get_assigned_allowed_group_name}.json"
expect(response.status).to eq(200)
expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array(
[user.id, user2.id],
)
end
it "doesn't include members with no assignments" do
sign_in(user)
add_to_assign_allowed_group(non_admin)
get "/assign/members/#{get_assigned_allowed_group_name}.json"
expect(response.status).to eq(200)
expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array(
[user.id, user2.id],
)
end
it "returns members as according to filter" do
sign_in(user)
get "/assign/members/#{get_assigned_allowed_group_name}.json", params: { filter: "a" }
expect(response.status).to eq(200)
expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array(
[user.id, user2.id],
)
get "/assign/members/#{get_assigned_allowed_group_name}.json", params: { filter: "david" }
expect(response.status).to eq(200)
expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array([user2.id])
get "/assign/members/#{get_assigned_allowed_group_name}.json", params: { filter: "Taylor" }
expect(response.status).to eq(200)
expect(JSON.parse(response.body)["members"].map { |m| m["id"] }).to match_array([user2.id])
end
it "404 error to non-group-members" do
sign_in(normal_user)
get "/assign/members/#{get_assigned_allowed_group_name}.json"
expect(response.status).to eq(403)
end
it "allows non-member-admin" do
sign_in(normal_admin)
get "/assign/members/#{get_assigned_allowed_group_name}.json"
expect(response.status).to eq(200)
end
end
describe "#user_menu_assigns" do
fab!(:unread_assigned_topic) { Fabricate(:post).topic }
fab!(:read_assigned_topic) { Fabricate(:post).topic }
fab!(:unread_assigned_post) { Fabricate(:post, topic: Fabricate(:post).topic) }
fab!(:read_assigned_post) { Fabricate(:post, topic: Fabricate(:post).topic) }
fab!(:read_assigned_post_in_same_topic) { Fabricate(:post, topic: Fabricate(:post).topic) }
fab!(:unread_assigned_post_in_same_topic) do
Fabricate(:post, topic: read_assigned_post_in_same_topic.topic)
end
fab!(:another_user_unread_assigned_topic) { Fabricate(:post).topic }
fab!(:another_user_read_assigned_topic) { Fabricate(:post).topic }
before do
Jobs.run_immediately!
[
unread_assigned_topic,
read_assigned_topic,
unread_assigned_post,
read_assigned_post,
unread_assigned_post_in_same_topic,
read_assigned_post_in_same_topic,
].each { |target| Assigner.new(target, normal_admin).assign(user) }
Notification
.where(
notification_type: Notification.types[:assigned],
read: false,
user_id: user.id,
topic_id: [
read_assigned_topic.id,
read_assigned_post.topic.id,
read_assigned_post_in_same_topic.topic.id,
],
)
.where.not(
topic_id: read_assigned_post_in_same_topic.topic.id,
post_number: unread_assigned_post_in_same_topic.post_number,
)
.update_all(read: true)
Assigner.new(another_user_read_assigned_topic, normal_admin).assign(user2)
Assigner.new(another_user_unread_assigned_topic, normal_admin).assign(user2)
Notification.where(
notification_type: Notification.types[:assigned],
read: false,
user_id: user2.id,
topic_id: another_user_read_assigned_topic,
).update_all(read: true)
end
context "when logged out" do
it "responds with 403" do
get "/assign/user-menu-assigns.json"
expect(response.status).to eq(403)
end
end
context "when logged in" do
before { sign_in(user) }
it "responds with 403 if the current user can't assign" do
user.update!(admin: false)
user.group_users.where(group_id: default_allowed_group.id).destroy_all
get "/assign/user-menu-assigns.json"
expect(response.status).to eq(403)
end
it "responds with 403 if the assign_enabled setting is disabled" do
SiteSetting.assign_enabled = false
get "/assign/user-menu-assigns.json"
expect(response.status).to eq(403)
end
it "sends an array of unread assigned notifications" do
get "/assign/user-menu-assigns.json"
expect(response.status).to eq(200)
notifications = response.parsed_body["notifications"]
expect(notifications.map { |n| [n["topic_id"], n["post_number"]] }).to match_array(
[
[unread_assigned_topic.id, 1],
[unread_assigned_post.topic.id, unread_assigned_post.post_number],
[
unread_assigned_post_in_same_topic.topic.id,
unread_assigned_post_in_same_topic.post_number,
],
],
)
end
it "responds with an array of assigned topics that are not associated with any of the unread assigned notifications" do
get "/assign/user-menu-assigns.json"
expect(response.status).to eq(200)
topics = response.parsed_body["topics"]
expect(topics.map { |t| t["id"] }).to eq(
[
read_assigned_post_in_same_topic.topic.id,
read_assigned_post.topic.id,
read_assigned_topic.id,
],
)
end
it "fills up the remaining of the UsersController::USER_MENU_LIST_LIMIT limit with assigned topics" do
stub_const(UsersController, "USER_MENU_LIST_LIMIT", 3) do
get "/assign/user-menu-assigns.json"
end
expect(response.status).to eq(200)
notifications = response.parsed_body["notifications"]
expect(notifications.size).to eq(3)
topics = response.parsed_body["topics"]
expect(topics.size).to eq(0)
stub_const(UsersController, "USER_MENU_LIST_LIMIT", 4) do
get "/assign/user-menu-assigns.json"
end
expect(response.status).to eq(200)
notifications = response.parsed_body["notifications"]
expect(notifications.size).to eq(3)
topics = response.parsed_body["topics"]
expect(topics.size).to eq(1)
end
end
end
end