@@ -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 ' |
|
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 ' |
|
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 |
[' |
|
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 |
# |
|
1 | # Redmine - project management software | |
2 |
# Copyright (C) 2006-20 |
|
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: |
|
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 => |
|
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 != |
|
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-20 |
|
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