##// END OF EJS Templates
Private issues (#7414)....
Jean-Philippe Lang -
r5346:f16cddd57ae8
parent child
Show More
@@ -0,0 +1,9
1 class AddIssuesIsPrivate < ActiveRecord::Migration
2 def self.up
3 add_column :issues, :is_private, :boolean, :default => false, :null => false
4 end
5
6 def self.down
7 remove_column :issues, :is_private
8 end
9 end
@@ -61,18 +61,23 module IssuesHelper
61
61
62 def render_issue_subject_with_tree(issue)
62 def render_issue_subject_with_tree(issue)
63 s = ''
63 s = ''
64 ancestors = issue.root? ? [] : issue.ancestors.all
64 ancestors = issue.root? ? [] : issue.ancestors.visible.all
65 ancestors.each do |ancestor|
65 ancestors.each do |ancestor|
66 s << '<div>' + content_tag('p', link_to_issue(ancestor))
66 s << '<div>' + content_tag('p', link_to_issue(ancestor))
67 end
67 end
68 s << '<div>' + content_tag('h3', h(issue.subject))
68 s << '<div>'
69 subject = h(issue.subject)
70 if issue.is_private?
71 subject = content_tag('span', l(:field_is_private), :class => 'private') + ' ' + subject
72 end
73 s << content_tag('h3', subject)
69 s << '</div>' * (ancestors.size + 1)
74 s << '</div>' * (ancestors.size + 1)
70 s
75 s
71 end
76 end
72
77
73 def render_descendants_tree(issue)
78 def render_descendants_tree(issue)
74 s = '<form><table class="list issues">'
79 s = '<form><table class="list issues">'
75 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
80 issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level|
76 s << content_tag('tr',
81 s << content_tag('tr',
77 content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
82 content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
78 content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
83 content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
@@ -159,6 +164,10 module IssuesHelper
159 label = l(:field_parent_issue)
164 label = l(:field_parent_issue)
160 value = "##{detail.value}" unless detail.value.blank?
165 value = "##{detail.value}" unless detail.value.blank?
161 old_value = "##{detail.old_value}" unless detail.old_value.blank?
166 old_value = "##{detail.old_value}" unless detail.old_value.blank?
167
168 when detail.prop_key == 'is_private'
169 value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank?
170 old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank?
162 end
171 end
163 when 'cf'
172 when 'cf'
164 custom_field = CustomField.find_by_id(detail.prop_key)
173 custom_field = CustomField.find_by_id(detail.prop_key)
@@ -90,8 +90,10 class Issue < ActiveRecord::Base
90 def self.visible_condition(user, options={})
90 def self.visible_condition(user, options={})
91 Project.allowed_to_condition(user, :view_issues, options) do |role, user|
91 Project.allowed_to_condition(user, :view_issues, options) do |role, user|
92 case role.issues_visibility
92 case role.issues_visibility
93 when 'default'
93 when 'all'
94 nil
94 nil
95 when 'default'
96 "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id = #{user.id})"
95 when 'own'
97 when 'own'
96 "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id = #{user.id})"
98 "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id = #{user.id})"
97 else
99 else
@@ -104,8 +106,10 class Issue < ActiveRecord::Base
104 def visible?(usr=nil)
106 def visible?(usr=nil)
105 (usr || User.current).allowed_to?(:view_issues, self.project) do |role, user|
107 (usr || User.current).allowed_to?(:view_issues, self.project) do |role, user|
106 case role.issues_visibility
108 case role.issues_visibility
107 when 'default'
109 when 'all'
108 true
110 true
111 when 'default'
112 !self.is_private? || self.author == user || self.assigned_to == user
109 when 'own'
113 when 'own'
110 self.author == user || self.assigned_to == user
114 self.author == user || self.assigned_to == user
111 else
115 else
@@ -257,6 +261,12 class Issue < ActiveRecord::Base
257 'done_ratio',
261 'done_ratio',
258 :if => lambda {|issue, user| issue.new_statuses_allowed_to(user).any? }
262 :if => lambda {|issue, user| issue.new_statuses_allowed_to(user).any? }
259
263
264 safe_attributes 'is_private',
265 :if => lambda {|issue, user|
266 user.allowed_to?(:set_issues_private, issue.project) ||
267 (issue.author == user && user.allowed_to?(:set_own_issues_private, issue.project))
268 }
269
260 # Safely sets attributes
270 # Safely sets attributes
261 # Should be called from controllers instead of #attributes=
271 # Should be called from controllers instead of #attributes=
262 # attr_accessible is too rough because we still want things like
272 # attr_accessible is too rough because we still want things like
@@ -552,6 +562,7 class Issue < ActiveRecord::Base
552 s << ' overdue' if overdue?
562 s << ' overdue' if overdue?
553 s << ' child' if child?
563 s << ' child' if child?
554 s << ' parent' unless leaf?
564 s << ' parent' unless leaf?
565 s << ' private' if is_private?
555 s << ' created-by-me' if User.current.logged? && author_id == User.current.id
566 s << ' created-by-me' if User.current.logged? && author_id == User.current.id
556 s << ' assigned-to-me' if User.current.logged? && assigned_to_id == User.current.id
567 s << ' assigned-to-me' if User.current.logged? && assigned_to_id == User.current.id
557 s
568 s
@@ -17,4 +17,22
17
17
18 class JournalDetail < ActiveRecord::Base
18 class JournalDetail < ActiveRecord::Base
19 belongs_to :journal
19 belongs_to :journal
20 before_save :normalize_values
21
22 private
23
24 def normalize_values
25 self.value = normalize(value)
26 self.old_value = normalize(old_value)
27 end
28
29 def normalize(v)
30 if v == true
31 "1"
32 elsif v == false
33 "0"
34 else
35 v
36 end
37 end
20 end
38 end
@@ -21,7 +21,8 class Role < ActiveRecord::Base
21 BUILTIN_ANONYMOUS = 2
21 BUILTIN_ANONYMOUS = 2
22
22
23 ISSUES_VISIBILITY_OPTIONS = [
23 ISSUES_VISIBILITY_OPTIONS = [
24 ['default', :label_issues_visibility_all],
24 ['all', :label_issues_visibility_all],
25 ['default', :label_issues_visibility_public],
25 ['own', :label_issues_visibility_own]
26 ['own', :label_issues_visibility_own]
26 ]
27 ]
27
28
@@ -1,6 +1,11
1 <%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %>
1 <%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %>
2
2
3 <div id="issue_descr_fields" <%= 'style="display:none"' unless @issue.new_record? || @issue.errors.any? %>>
3 <div id="issue_descr_fields" <%= 'style="display:none"' unless @issue.new_record? || @issue.errors.any? %>>
4 <% if @issue.safe_attribute_names.include?('is_private') %>
5 <p style="float:right; margin-right:1em;">
6 <label class="inline" for="issue_is_private"><%= f.check_box :is_private, :no_label => true %> <%= l(:field_is_private) %></label>
7 </p>
8 <% end %>
4 <p><%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %></p>
9 <p><%= f.select :tracker_id, @project.trackers.collect {|t| [t.name, t.id]}, :required => true %></p>
5 <%= observe_field :issue_tracker_id, :url => { :action => :new, :project_id => @project, :id => @issue },
10 <%= observe_field :issue_tracker_id, :url => { :action => :new, :project_id => @project, :id => @issue },
6 :update => :attributes,
11 :update => :attributes,
@@ -305,6 +305,7 en:
305 field_visible: Visible
305 field_visible: Visible
306 field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text"
306 field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text"
307 field_issues_visibility: Issues visibility
307 field_issues_visibility: Issues visibility
308 field_is_private: Private
308
309
309 setting_app_title: Application title
310 setting_app_title: Application title
310 setting_app_subtitle: Application subtitle
311 setting_app_subtitle: Application subtitle
@@ -377,6 +378,8 en:
377 permission_add_issues: Add issues
378 permission_add_issues: Add issues
378 permission_edit_issues: Edit issues
379 permission_edit_issues: Edit issues
379 permission_manage_issue_relations: Manage issue relations
380 permission_manage_issue_relations: Manage issue relations
381 permission_set_issues_private: Set issues public or private
382 permission_set_own_issues_private: Set own issues public or private
380 permission_add_issue_notes: Add notes
383 permission_add_issue_notes: Add notes
381 permission_edit_issue_notes: Edit notes
384 permission_edit_issue_notes: Edit notes
382 permission_edit_own_issue_notes: Edit own notes
385 permission_edit_own_issue_notes: Edit own notes
@@ -806,6 +809,7 en:
806 label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author
809 label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author
807 label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee
810 label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee
808 label_issues_visibility_all: All issues
811 label_issues_visibility_all: All issues
812 label_issues_visibility_public: All non private issues
809 label_issues_visibility_own: Issues created by or assigned to the user
813 label_issues_visibility_own: Issues created by or assigned to the user
810
814
811 button_login: Login
815 button_login: Login
@@ -309,6 +309,7 fr:
309 field_visible: Visible
309 field_visible: Visible
310 field_warn_on_leaving_unsaved: "M'avertir lorsque je quitte une page contenant du texte non sauvegardé"
310 field_warn_on_leaving_unsaved: "M'avertir lorsque je quitte une page contenant du texte non sauvegardé"
311 field_issues_visibility: Visibilité des demandes
311 field_issues_visibility: Visibilité des demandes
312 field_is_private: Privée
312
313
313 setting_app_title: Titre de l'application
314 setting_app_title: Titre de l'application
314 setting_app_subtitle: Sous-titre de l'application
315 setting_app_subtitle: Sous-titre de l'application
@@ -378,6 +379,8 fr:
378 permission_add_issues: Créer des demandes
379 permission_add_issues: Créer des demandes
379 permission_edit_issues: Modifier les demandes
380 permission_edit_issues: Modifier les demandes
380 permission_manage_issue_relations: Gérer les relations
381 permission_manage_issue_relations: Gérer les relations
382 permission_set_issues_private: Rendre les demandes publiques ou privées
383 permission_set_own_issues_private: Rendre ses propres demandes publiques ou privées
381 permission_add_issue_notes: Ajouter des notes
384 permission_add_issue_notes: Ajouter des notes
382 permission_edit_issue_notes: Modifier les notes
385 permission_edit_issue_notes: Modifier les notes
383 permission_edit_own_issue_notes: Modifier ses propres notes
386 permission_edit_own_issue_notes: Modifier ses propres notes
@@ -793,6 +796,7 fr:
793 label_additional_workflow_transitions_for_author: Autorisations supplémentaires lorsque l'utilisateur a créé la demande
796 label_additional_workflow_transitions_for_author: Autorisations supplémentaires lorsque l'utilisateur a créé la demande
794 label_additional_workflow_transitions_for_assignee: Autorisations supplémentaires lorsque la demande est assignée à l'utilisateur
797 label_additional_workflow_transitions_for_assignee: Autorisations supplémentaires lorsque la demande est assignée à l'utilisateur
795 label_issues_visibility_all: Toutes les demandes
798 label_issues_visibility_all: Toutes les demandes
799 label_issues_visibility_public: Toutes les demandes non privées
796 label_issues_visibility_own: Demandes créées par ou assignées à l'utilisateur
800 label_issues_visibility_own: Demandes créées par ou assignées à l'utilisateur
797
801
798 button_login: Connexion
802 button_login: Connexion
@@ -71,6 +71,8 Redmine::AccessControl.map do |map|
71 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new]}
71 map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new]}
72 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
72 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
73 map.permission :manage_subtasks, {}
73 map.permission :manage_subtasks, {}
74 map.permission :set_issues_private, {}
75 map.permission :set_own_issues_private, {}
74 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]}
76 map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]}
75 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
77 map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin
76 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
78 map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin
@@ -1,5 +1,5
1 # redMine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
@@ -41,6 +41,7 module Redmine
41 Role.transaction do
41 Role.transaction do
42 # Roles
42 # Roles
43 manager = Role.create! :name => l(:default_role_manager),
43 manager = Role.create! :name => l(:default_role_manager),
44 :issues_visibility => 'all',
44 :position => 1
45 :position => 1
45 manager.permissions = manager.setable_permissions.collect {|p| p.name}
46 manager.permissions = manager.setable_permissions.collect {|p| p.name}
46 manager.save!
47 manager.save!
@@ -278,6 +278,7 div.issue div.subject div div { padding-left: 16px; }
278 div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;}
278 div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;}
279 div.issue div.subject>div>p { margin-top: 0.5em; }
279 div.issue div.subject>div>p { margin-top: 0.5em; }
280 div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;}
280 div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;}
281 div.issue span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px; -moz-border-radius: 2px;}
281
282
282 #issue_tree table.issues, #relations table.issues { border: 0; }
283 #issue_tree table.issues, #relations table.issues { border: 0; }
283 #issue_tree td.checkbox, #relations td.checkbox {display:none;}
284 #issue_tree td.checkbox, #relations td.checkbox {display:none;}
@@ -169,3 +169,16 attachments_014:
169 filename: changeset_utf8.diff
169 filename: changeset_utf8.diff
170 author_id: 2
170 author_id: 2
171 content_type: text/x-diff
171 content_type: text/x-diff
172 attachments_015:
173 id: 15
174 created_on: 2010-07-19 21:07:27 +02:00
175 container_type: Issue
176 container_id: 14
177 downloads: 0
178 disk_filename: 060719210727_changeset_utf8.diff
179 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
180 filesize: 687
181 filename: private.diff
182 author_id: 2
183 content_type: text/x-diff
184 description: attachement of a private issue
@@ -244,3 +244,21 issues_013:
244 root_id: 13
244 root_id: 13
245 lft: 1
245 lft: 1
246 rgt: 2
246 rgt: 2
247 issues_014:
248 id: 14
249 created_on: <%= 15.days.ago.to_date.to_s(:db) %>
250 project_id: 3
251 updated_on: <%= 15.days.ago.to_date.to_s(:db) %>
252 priority_id: 5
253 subject: Private issue on public project
254 fixed_version_id:
255 category_id:
256 description: This is a private issue
257 tracker_id: 1
258 assigned_to_id:
259 author_id: 2
260 status_id: 1
261 is_private: true
262 root_id: 14
263 lft: 1
264 rgt: 2
@@ -3,7 +3,7 roles_001:
3 name: Manager
3 name: Manager
4 id: 1
4 id: 1
5 builtin: 0
5 builtin: 0
6 issues_visibility: default
6 issues_visibility: all
7 permissions: |
7 permissions: |
8 ---
8 ---
9 - :add_project
9 - :add_project
@@ -86,6 +86,18 class AttachmentsControllerTest < ActionController::TestCase
86 assert_equal 'application/octet-stream', @response.content_type
86 assert_equal 'application/octet-stream', @response.content_type
87 end
87 end
88
88
89 def test_show_file_from_private_issue_without_permission
90 get :show, :id => 15
91 assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2F15'
92 end
93
94 def test_show_file_from_private_issue_with_permission
95 @request.session[:user_id] = 2
96 get :show, :id => 15
97 assert_response :success
98 assert_tag 'h2', :content => /private.diff/
99 end
100
89 def test_download_text_file
101 def test_download_text_file
90 get :download, :id => 4
102 get :download, :id => 4
91 assert_response :success
103 assert_response :success
@@ -92,6 +92,13 class IssuesControllerTest < ActionController::TestCase
92 assert_tag :tag => 'a', :content => /Subproject issue/
92 assert_tag :tag => 'a', :content => /Subproject issue/
93 end
93 end
94
94
95 def test_index_should_list_visible_issues_only
96 get :index, :per_page => 100
97 assert_response :success
98 assert_not_nil assigns(:issues)
99 assert_nil assigns(:issues).detect {|issue| !issue.visible?}
100 end
101
95 def test_index_with_project
102 def test_index_with_project
96 Setting.display_subprojects_issues = 0
103 Setting.display_subprojects_issues = 0
97 get :index, :project_id => 1
104 get :index, :project_id => 1
@@ -317,6 +324,12 class IssuesControllerTest < ActionController::TestCase
317 assert_response :redirect
324 assert_response :redirect
318 end
325 end
319
326
327 def test_show_should_deny_anonymous_access_to_private_issue
328 Issue.update_all(["is_private = ?", true], "id = 1")
329 get :show, :id => 1
330 assert_response :redirect
331 end
332
320 def test_show_should_deny_non_member_access_without_permission
333 def test_show_should_deny_non_member_access_without_permission
321 Role.non_member.remove_permission!(:view_issues)
334 Role.non_member.remove_permission!(:view_issues)
322 @request.session[:user_id] = 9
335 @request.session[:user_id] = 9
@@ -324,6 +337,13 class IssuesControllerTest < ActionController::TestCase
324 assert_response 403
337 assert_response 403
325 end
338 end
326
339
340 def test_show_should_deny_non_member_access_to_private_issue
341 Issue.update_all(["is_private = ?", true], "id = 1")
342 @request.session[:user_id] = 9
343 get :show, :id => 1
344 assert_response 403
345 end
346
327 def test_show_should_deny_member_access_without_permission
347 def test_show_should_deny_member_access_without_permission
328 Role.find(1).remove_permission!(:view_issues)
348 Role.find(1).remove_permission!(:view_issues)
329 @request.session[:user_id] = 2
349 @request.session[:user_id] = 2
@@ -331,6 +351,35 class IssuesControllerTest < ActionController::TestCase
331 assert_response 403
351 assert_response 403
332 end
352 end
333
353
354 def test_show_should_deny_member_access_to_private_issue_without_permission
355 Issue.update_all(["is_private = ?", true], "id = 1")
356 @request.session[:user_id] = 3
357 get :show, :id => 1
358 assert_response 403
359 end
360
361 def test_show_should_allow_author_access_to_private_issue
362 Issue.update_all(["is_private = ?, author_id = 3", true], "id = 1")
363 @request.session[:user_id] = 3
364 get :show, :id => 1
365 assert_response :success
366 end
367
368 def test_show_should_allow_assignee_access_to_private_issue
369 Issue.update_all(["is_private = ?, assigned_to_id = 3", true], "id = 1")
370 @request.session[:user_id] = 3
371 get :show, :id => 1
372 assert_response :success
373 end
374
375 def test_show_should_allow_member_access_to_private_issue_with_permission
376 Issue.update_all(["is_private = ?", true], "id = 1")
377 User.find(3).roles_for_project(Project.find(1)).first.update_attribute :issues_visibility, 'all'
378 @request.session[:user_id] = 3
379 get :show, :id => 1
380 assert_response :success
381 end
382
334 def test_show_should_not_disclose_relations_to_invisible_issues
383 def test_show_should_not_disclose_relations_to_invisible_issues
335 Setting.cross_project_issue_relations = '1'
384 Setting.cross_project_issue_relations = '1'
336 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
385 IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates')
@@ -74,6 +74,7 class IssueTest < ActiveSupport::TestCase
74 issues = Issue.visible(User.anonymous).all
74 issues = Issue.visible(User.anonymous).all
75 assert issues.any?
75 assert issues.any?
76 assert_nil issues.detect {|issue| !issue.project.is_public?}
76 assert_nil issues.detect {|issue| !issue.project.is_public?}
77 assert_nil issues.detect {|issue| issue.is_private?}
77 assert_visibility_match User.anonymous, issues
78 assert_visibility_match User.anonymous, issues
78 end
79 end
79
80
@@ -102,6 +103,7 class IssueTest < ActiveSupport::TestCase
102 issues = Issue.visible(user).all
103 issues = Issue.visible(user).all
103 assert issues.any?
104 assert issues.any?
104 assert_nil issues.detect {|issue| !issue.project.is_public?}
105 assert_nil issues.detect {|issue| !issue.project.is_public?}
106 assert_nil issues.detect {|issue| issue.is_private?}
105 assert_visibility_match user, issues
107 assert_visibility_match user, issues
106 end
108 end
107
109
@@ -130,10 +132,11 class IssueTest < ActiveSupport::TestCase
130 user = User.find(9)
132 user = User.find(9)
131 # User should see issues of projects for which he has view_issues permissions only
133 # User should see issues of projects for which he has view_issues permissions only
132 Role.non_member.remove_permission!(:view_issues)
134 Role.non_member.remove_permission!(:view_issues)
133 Member.create!(:principal => user, :project_id => 2, :role_ids => [1])
135 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
134 issues = Issue.visible(user).all
136 issues = Issue.visible(user).all
135 assert issues.any?
137 assert issues.any?
136 assert_nil issues.detect {|issue| issue.project_id != 2}
138 assert_nil issues.detect {|issue| issue.project_id != 3}
139 assert_nil issues.detect {|issue| issue.is_private?}
137 assert_visibility_match user, issues
140 assert_visibility_match user, issues
138 end
141 end
139
142
@@ -145,6 +148,8 class IssueTest < ActiveSupport::TestCase
145 assert issues.any?
148 assert issues.any?
146 # Admin should see issues on private projects that he does not belong to
149 # Admin should see issues on private projects that he does not belong to
147 assert issues.detect {|issue| !issue.project.is_public?}
150 assert issues.detect {|issue| !issue.project.is_public?}
151 # Admin should see private issues of other users
152 assert issues.detect {|issue| issue.is_private? && issue.author != user}
148 assert_visibility_match user, issues
153 assert_visibility_match user, issues
149 end
154 end
150
155
@@ -1,5 +1,5
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2008 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
@@ -44,10 +44,12 module Redmine
44 end
44 end
45
45
46 def attachments_visible?(user=User.current)
46 def attachments_visible?(user=User.current)
47 (respond_to?(:visible?) ? visible?(user) : true) &&
47 user.allowed_to?(self.class.attachable_options[:view_permission], self.project)
48 user.allowed_to?(self.class.attachable_options[:view_permission], self.project)
48 end
49 end
49
50
50 def attachments_deletable?(user=User.current)
51 def attachments_deletable?(user=User.current)
52 (respond_to?(:visible?) ? visible?(user) : true) &&
51 user.allowed_to?(self.class.attachable_options[:delete_permission], self.project)
53 user.allowed_to?(self.class.attachable_options[:delete_permission], self.project)
52 end
54 end
53
55
General Comments 0
You need to be logged in to leave comments. Login now