You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

issues_custom_fields_visibility_test.rb 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. # frozen_string_literal: true
  2. # Redmine - project management software
  3. # Copyright (C) 2006-2021 Jean-Philippe Lang
  4. #
  5. # This program is free software; you can redistribute it and/or
  6. # modify it under the terms of the GNU General Public License
  7. # as published by the Free Software Foundation; either version 2
  8. # of the License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, write to the Free Software
  17. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. require File.expand_path('../../test_helper', __FILE__)
  19. class IssuesCustomFieldsVisibilityTest < Redmine::ControllerTest
  20. tests IssuesController
  21. fixtures :projects,
  22. :users, :email_addresses, :user_preferences,
  23. :roles,
  24. :members,
  25. :member_roles,
  26. :issue_statuses,
  27. :trackers,
  28. :projects_trackers,
  29. :enabled_modules,
  30. :enumerations,
  31. :workflows,
  32. :custom_fields, :custom_fields_trackers
  33. def setup
  34. CustomField.destroy_all
  35. Issue.delete_all
  36. Watcher.delete_all
  37. field_attributes = {:field_format => 'string', :is_for_all => true, :is_filter => true, :trackers => Tracker.all}
  38. @fields = []
  39. @fields << (@field1 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 1', :visible => true)))
  40. @fields << (@field2 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 2', :visible => false, :role_ids => [1, 2])))
  41. @fields << (@field3 = IssueCustomField.create!(field_attributes.merge(:name => 'Field 3', :visible => false, :role_ids => [1, 3])))
  42. @issue = Issue.generate!(
  43. :author_id => 1,
  44. :project_id => 1,
  45. :tracker_id => 1,
  46. :custom_field_values => {@field1.id => 'Value0', @field2.id => 'Value1', @field3.id => 'Value2'}
  47. )
  48. @user_with_role_on_other_project = User.generate!
  49. User.add_to_project(@user_with_role_on_other_project, Project.find(2), Role.find(3))
  50. @users_to_test = {
  51. User.find(1) => [@field1, @field2, @field3],
  52. User.find(3) => [@field1, @field2],
  53. @user_with_role_on_other_project => [@field1], # should see field1 only on Project 1
  54. User.generate! => [@field1],
  55. User.anonymous => [@field1]
  56. }
  57. Member.where(:project_id => 1).each do |member|
  58. member.destroy unless @users_to_test.key?(member.principal)
  59. end
  60. end
  61. def test_show_should_show_visible_custom_fields_only
  62. @users_to_test.each do |user, fields|
  63. @request.session[:user_id] = user.id
  64. get(:show, :params => {:id => @issue.id})
  65. @fields.each_with_index do |field, i|
  66. if fields.include?(field)
  67. assert_select '.value', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name}"
  68. else
  69. assert_select '.value', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name}"
  70. end
  71. end
  72. end
  73. end
  74. def test_show_should_show_visible_custom_fields_only_in_api
  75. @users_to_test.each do |user, fields|
  76. with_settings :rest_api_enabled => '1' do
  77. get(
  78. :show,
  79. :params => {
  80. :id => @issue.id,
  81. :format => 'xml',
  82. :include => 'custom_fields',
  83. :key => user.api_key
  84. }
  85. )
  86. end
  87. @fields.each_with_index do |field, i|
  88. if fields.include?(field)
  89. assert_select "custom_field[id=?] value", field.id.to_s, {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name} in API"
  90. else
  91. assert_select "custom_field[id=?] value", field.id.to_s, {:text => "Value#{i}", :count => 0}, "User #{user.id} was not able to view #{field.name} in API"
  92. end
  93. end
  94. end
  95. end
  96. def test_show_should_show_visible_custom_fields_only_in_history
  97. @issue.init_journal(User.find(1))
  98. @issue.custom_field_values = {@field1.id => 'NewValue0', @field2.id => 'NewValue1', @field3.id => 'NewValue2'}
  99. @issue.save!
  100. @users_to_test.each do |user, fields|
  101. @request.session[:user_id] = user.id
  102. get(:show, :params => {:id => @issue.id})
  103. @fields.each_with_index do |field, i|
  104. if fields.include?(field)
  105. assert_select 'ul.details i', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name} change"
  106. else
  107. assert_select 'ul.details i', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name} change"
  108. end
  109. end
  110. end
  111. end
  112. def test_show_should_show_visible_custom_fields_only_in_history_api
  113. @issue.init_journal(User.find(1))
  114. @issue.custom_field_values = {@field1.id => 'NewValue0', @field2.id => 'NewValue1', @field3.id => 'NewValue2'}
  115. @issue.save!
  116. @users_to_test.each do |user, fields|
  117. with_settings :rest_api_enabled => '1' do
  118. get(
  119. :show,
  120. :params => {
  121. :id => @issue.id,
  122. :format => 'xml',
  123. :include => 'journals',
  124. :key => user.api_key
  125. }
  126. )
  127. end
  128. @fields.each_with_index do |field, i|
  129. if fields.include?(field)
  130. assert_select 'details old_value', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name} change in API"
  131. else
  132. assert_select 'details old_value', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name} change in API"
  133. end
  134. end
  135. end
  136. end
  137. def test_edit_should_show_visible_custom_fields_only
  138. Role.anonymous.add_permission! :edit_issues
  139. @users_to_test.each do |user, fields|
  140. @request.session[:user_id] = user.id
  141. get(:edit, :params => {:id => @issue.id})
  142. @fields.each_with_index do |field, i|
  143. if fields.include?(field)
  144. assert_select 'input[value=?]', "Value#{i}", 1, "User #{user.id} was not able to edit #{field.name}"
  145. else
  146. assert_select 'input[value=?]', "Value#{i}", 0, "User #{user.id} was able to edit #{field.name}"
  147. end
  148. end
  149. end
  150. end
  151. def test_update_should_update_visible_custom_fields_only
  152. Role.anonymous.add_permission! :edit_issues
  153. @users_to_test.each do |user, fields|
  154. @request.session[:user_id] = user.id
  155. put(
  156. :update,
  157. :params => {
  158. :id => @issue.id,
  159. :issue => {
  160. :custom_field_values => {
  161. @field1.id.to_s => "User#{user.id}Value0",
  162. @field2.id.to_s => "User#{user.id}Value1",
  163. @field3.id.to_s => "User#{user.id}Value2",
  164. }
  165. }
  166. }
  167. )
  168. @issue.reload
  169. @fields.each_with_index do |field, i|
  170. if fields.include?(field)
  171. assert_equal "User#{user.id}Value#{i}", @issue.custom_field_value(field), "User #{user.id} was not able to update #{field.name}"
  172. else
  173. assert_not_equal "User#{user.id}Value#{i}", @issue.custom_field_value(field), "User #{user.id} was able to update #{field.name}"
  174. end
  175. end
  176. end
  177. end
  178. def test_index_should_show_visible_custom_fields_only
  179. @users_to_test.each do |user, fields|
  180. @request.session[:user_id] = user.id
  181. get(
  182. :index,
  183. :params => {
  184. :c => (["subject"] + @fields.map{|f| "cf_#{f.id}"})
  185. }
  186. )
  187. @fields.each_with_index do |field, i|
  188. if fields.include?(field)
  189. assert_select 'td', {:text => "Value#{i}", :count => 1}, "User #{user.id} was not able to view #{field.name}"
  190. else
  191. assert_select 'td', {:text => "Value#{i}", :count => 0}, "User #{user.id} was able to view #{field.name}"
  192. end
  193. end
  194. end
  195. end
  196. def test_index_as_csv_should_show_visible_custom_fields_only
  197. @users_to_test.each do |user, fields|
  198. @request.session[:user_id] = user.id
  199. get(
  200. :index,
  201. :params => {
  202. :c => (["subject"] + @fields.map{|f| "cf_#{f.id}"}),
  203. :format => 'csv'
  204. }
  205. )
  206. @fields.each_with_index do |field, i|
  207. if fields.include?(field)
  208. assert_include "Value#{i}", response.body, "User #{user.id} was not able to view #{field.name} in CSV"
  209. else
  210. assert_not_include "Value#{i}", response.body, "User #{user.id} was able to view #{field.name} in CSV"
  211. end
  212. end
  213. end
  214. end
  215. def test_index_with_partial_custom_field_visibility
  216. CustomValue.delete_all
  217. Issue.delete_all
  218. p1 = Project.generate!
  219. p2 = Project.generate!
  220. user = User.generate!
  221. User.add_to_project(user, p1, Role.where(:id => [1, 3]).to_a)
  222. User.add_to_project(user, p2, Role.where(:id => 3).to_a)
  223. Issue.generate!(:project => p1, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueA'})
  224. Issue.generate!(:project => p2, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueB'})
  225. Issue.generate!(:project => p1, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueC'})
  226. @request.session[:user_id] = user.id
  227. get(
  228. :index,
  229. :params => {
  230. :c => ["subject", "cf_#{@field2.id}"]
  231. }
  232. )
  233. assert_select 'td', :text => 'ValueA'
  234. assert_select 'td', :text => 'ValueB', :count => 0
  235. assert_select 'td', :text => 'ValueC'
  236. get(:index, :params => {:sort => "cf_#{@field2.id}"})
  237. # ValueB is not visible to user and ignored while sorting
  238. assert_equal %w(ValueB ValueA ValueC), issues_in_list.map{|i| i.custom_field_value(@field2)}
  239. get(
  240. :index,
  241. :params => {
  242. :set_filter => '1', "cf_#{@field2.id}" => '*',
  243. :sort => "cf_#{@field2.id}"
  244. }
  245. )
  246. assert_equal %w(ValueA ValueC), issues_in_list.map{|i| i.custom_field_value(@field2)}
  247. CustomField.update_all(:field_format => 'list')
  248. get(:index, :params => {:group => "cf_#{@field2.id}"})
  249. assert_equal %w(ValueA ValueC), issues_in_list.map{|i| i.custom_field_value(@field2)}
  250. end
  251. def test_create_should_send_notifications_according_custom_fields_visibility
  252. # anonymous user is never notified
  253. users_to_test = @users_to_test.reject {|k, v| k.anonymous?}
  254. ActionMailer::Base.deliveries.clear
  255. @request.session[:user_id] = 1
  256. assert_difference 'Issue.count' do
  257. post(
  258. :create,
  259. :params => {
  260. :project_id => 1,
  261. :issue => {
  262. :tracker_id => 1,
  263. :status_id => 1,
  264. :subject => 'New issue',
  265. :priority_id => 5,
  266. :custom_field_values => {
  267. @field1.id.to_s => 'Value0',
  268. @field2.id.to_s => 'Value1',
  269. @field3.id.to_s => 'Value2'
  270. },
  271. :watcher_user_ids => users_to_test.keys.map(&:id)
  272. }
  273. }
  274. )
  275. assert_response 302
  276. end
  277. assert_equal users_to_test.keys.size, ActionMailer::Base.deliveries.size
  278. # tests that each user receives 1 email with the custom fields he is allowed to see only
  279. users_to_test.each do |user, fields|
  280. mails = ActionMailer::Base.deliveries.select {|m| m.to.include? user.mail}
  281. assert_equal 1, mails.size
  282. mail = mails.first
  283. @fields.each_with_index do |field, i|
  284. if fields.include?(field)
  285. assert_mail_body_match "Value#{i}", mail, "User #{user.id} was not able to view #{field.name} in notification"
  286. else
  287. assert_mail_body_no_match "Value#{i}", mail, "User #{user.id} was able to view #{field.name} in notification"
  288. end
  289. end
  290. end
  291. end
  292. def test_update_should_send_notifications_according_custom_fields_visibility
  293. # anonymous user is never notified
  294. users_to_test = @users_to_test.reject {|k, v| k.anonymous?}
  295. users_to_test.keys.each do |user|
  296. Watcher.create!(:user => user, :watchable => @issue)
  297. end
  298. ActionMailer::Base.deliveries.clear
  299. @request.session[:user_id] = 1
  300. put(
  301. :update,
  302. :params => {
  303. :id => @issue.id,
  304. :issue => {
  305. :custom_field_values => {
  306. @field1.id.to_s => 'NewValue0',
  307. @field2.id.to_s => 'NewValue1',
  308. @field3.id.to_s => 'NewValue2'
  309. }
  310. }
  311. }
  312. )
  313. assert_response 302
  314. assert_equal users_to_test.keys.size, ActionMailer::Base.deliveries.size
  315. # tests that each user receives 1 email with the custom fields he is allowed to see only
  316. users_to_test.each do |user, fields|
  317. mails = ActionMailer::Base.deliveries.select {|m| m.to.include? user.mail}
  318. assert_equal 1, mails.size
  319. mail = mails.first
  320. @fields.each_with_index do |field, i|
  321. if fields.include?(field)
  322. assert_mail_body_match "Value#{i}", mail, "User #{user.id} was not able to view #{field.name} in notification"
  323. else
  324. assert_mail_body_no_match "Value#{i}", mail, "User #{user.id} was able to view #{field.name} in notification"
  325. end
  326. end
  327. end
  328. end
  329. def test_updating_hidden_custom_fields_only_should_not_notifiy_user
  330. # anonymous user is never notified
  331. users_to_test = @users_to_test.reject {|k, v| k.anonymous?}
  332. users_to_test.keys.each do |user|
  333. Watcher.create!(:user => user, :watchable => @issue)
  334. end
  335. ActionMailer::Base.deliveries.clear
  336. @request.session[:user_id] = 1
  337. put(
  338. :update,
  339. :params => {
  340. :id => @issue.id,
  341. :issue => {
  342. :custom_field_values => {
  343. @field2.id.to_s => 'NewValue1', @field3.id.to_s => 'NewValue2'
  344. }
  345. }
  346. }
  347. )
  348. assert_response 302
  349. users_to_test.each do |user, fields|
  350. mails = ActionMailer::Base.deliveries.select {|m| m.to.include? user.mail}
  351. if (fields & [@field2, @field3]).any?
  352. assert_equal 1, mails.size, "User #{user.id} was not notified"
  353. else
  354. assert_equal 0, mails.size, "User #{user.id} was notified"
  355. end
  356. end
  357. end
  358. end