summaryrefslogtreecommitdiffstats
path: root/app/models
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2016-06-06 09:41:50 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2016-06-06 09:41:50 +0000
commit6e68d008c4dc50f46585e30aabaa5bc9859bee0f (patch)
treedddbcaecd80051789282556982fad7270c2e5b9d /app/models
parent7a974437e6414682d6b318a3b1130d728f51907a (diff)
downloadredmine-6e68d008c4dc50f46585e30aabaa5bc9859bee0f.tar.gz
redmine-6e68d008c4dc50f46585e30aabaa5bc9859bee0f.zip
Merged 15430, 15464 to 15469, 15475, 15476 (#285, #7839).
git-svn-id: http://svn.redmine.org/redmine/branches/3.3-stable@15478 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app/models')
-rw-r--r--app/models/issue.rb98
-rw-r--r--app/models/issue_import.rb2
-rw-r--r--app/models/mail_handler.rb13
-rw-r--r--app/models/role.rb51
4 files changed, 136 insertions, 28 deletions
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 0ee8ff3d3..e0b99e4e6 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -120,10 +120,10 @@ class Issue < ActiveRecord::Base
# Returns a SQL conditions string used to find all issues visible by the specified user
def self.visible_condition(user, options={})
Project.allowed_to_condition(user, :view_issues, options) do |role, user|
- if user.id && user.logged?
+ sql = if user.id && user.logged?
case role.issues_visibility
when 'all'
- nil
+ '1=1'
when 'default'
user_ids = [user.id] + user.groups.map(&:id).compact
"(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
@@ -136,13 +136,22 @@ class Issue < ActiveRecord::Base
else
"(#{table_name}.is_private = #{connection.quoted_false})"
end
+ unless role.permissions_all_trackers?(:view_issues)
+ tracker_ids = role.permissions_tracker_ids(:view_issues)
+ if tracker_ids.any?
+ sql = "(#{sql} AND #{table_name}.tracker_id IN (#{tracker_ids.join(',')}))"
+ else
+ sql = '1=0'
+ end
+ end
+ sql
end
end
# Returns true if usr or current user is allowed to view the issue
def visible?(usr=nil)
(usr || User.current).allowed_to?(:view_issues, self.project) do |role, user|
- if user.logged?
+ visible = if user.logged?
case role.issues_visibility
when 'all'
true
@@ -156,17 +165,36 @@ class Issue < ActiveRecord::Base
else
!self.is_private?
end
+ unless role.permissions_all_trackers?(:view_issues)
+ visible &&= role.permissions_tracker_ids?(:view_issues, tracker_id)
+ end
+ visible
end
end
- # Returns true if user or current user is allowed to edit or add a note to the issue
+ # Returns true if user or current user is allowed to edit or add notes to the issue
def editable?(user=User.current)
- attributes_editable?(user) || user.allowed_to?(:add_issue_notes, project)
+ attributes_editable?(user) || notes_addable?(user)
end
# Returns true if user or current user is allowed to edit the issue
def attributes_editable?(user=User.current)
- user.allowed_to?(:edit_issues, project)
+ user_tracker_permission?(user, :edit_issues)
+ end
+
+ # Overrides Redmine::Acts::Attachable::InstanceMethods#attachments_editable?
+ def attachments_editable?(user=User.current)
+ attributes_editable?(user)
+ end
+
+ # Returns true if user or current user is allowed to add notes to the issue
+ def notes_addable?(user=User.current)
+ user_tracker_permission?(user, :add_issue_notes)
+ end
+
+ # Returns true if user or current user is allowed to delete the issue
+ def deletable?(user=User.current)
+ user_tracker_permission?(user, :delete_issues)
end
def initialize(attributes=nil, *args)
@@ -416,10 +444,10 @@ class Issue < ActiveRecord::Base
'custom_fields',
'lock_version',
'notes',
- :if => lambda {|issue, user| issue.new_record? || user.allowed_to?(:edit_issues, issue.project) }
+ :if => lambda {|issue, user| issue.new_record? || issue.attributes_editable?(user) }
safe_attributes 'notes',
- :if => lambda {|issue, user| user.allowed_to?(:add_issue_notes, issue.project)}
+ :if => lambda {|issue, user| issue.notes_addable?(user)}
safe_attributes 'private_notes',
:if => lambda {|issue, user| !issue.new_record? && user.allowed_to?(:set_notes_private, issue.project)}
@@ -434,7 +462,7 @@ class Issue < ActiveRecord::Base
}
safe_attributes 'parent_issue_id',
- :if => lambda {|issue, user| (issue.new_record? || user.allowed_to?(:edit_issues, issue.project)) &&
+ :if => lambda {|issue, user| (issue.new_record? || issue.attributes_editable?(user)) &&
user.allowed_to?(:manage_subtasks, issue.project)}
def safe_attribute_names(user=nil)
@@ -479,12 +507,14 @@ class Issue < ActiveRecord::Base
end
if (t = attrs.delete('tracker_id')) && safe_attribute?('tracker_id')
- self.tracker_id = t
+ if allowed_target_trackers(user).where(:id => t.to_i).exists?
+ self.tracker_id = t
+ end
end
if project
- # Set the default tracker to accept custom field values
+ # Set a default tracker to accept custom field values
# even if tracker is not specified
- self.tracker ||= project.trackers.first
+ self.tracker ||= allowed_target_trackers(user).first
end
statuses_allowed = new_statuses_allowed_to(user)
@@ -822,16 +852,6 @@ class Issue < ActiveRecord::Base
!leaf?
end
- def assignable_trackers
- trackers = project.trackers
- if new_record? && parent_issue_id.present?
- trackers = trackers.reject do |tracker|
- tracker_id != tracker.id && tracker.disabled_core_fields.include?('parent_issue_id')
- end
- end
- trackers
- end
-
# Users the issue can be assigned to
def assignable_users
users = project.assignable_users.to_a
@@ -1373,9 +1393,43 @@ class Issue < ActiveRecord::Base
end
Project.where(condition).having_trackers
end
+
+ # Returns a scope of trackers that user can assign the issue to
+ def allowed_target_trackers(user=User.current)
+ self.class.allowed_target_trackers(project, user, tracker_id_was)
+ end
+
+ # Returns a scope of trackers that user can assign project issues to
+ def self.allowed_target_trackers(project, user=User.current, current_tracker=nil)
+ if project
+ scope = project.trackers.sorted
+ unless user.admin?
+ roles = user.roles_for_project(project).select {|r| r.has_permission?(:add_issues)}
+ unless roles.any? {|r| r.permissions_all_trackers?(:add_issues)}
+ tracker_ids = roles.map {|r| r.permissions_tracker_ids(:add_issues)}.flatten.uniq
+ if current_tracker
+ tracker_ids << current_tracker
+ end
+ scope = scope.where(:id => tracker_ids)
+ end
+ end
+ scope
+ else
+ Tracker.none
+ end
+ end
private
+ def user_tracker_permission?(user, permission)
+ if user.admin?
+ true
+ else
+ roles = user.roles_for_project(project).select {|r| r.has_permission?(permission)}
+ roles.any? {|r| r.permissions_all_trackers?(permission) || r.permissions_tracker_ids?(permission, tracker_id)}
+ end
+ end
+
def after_project_change
# Update project_id on related time entries
TimeEntry.where({:issue_id => id}).update_all(["project_id = ?", project_id])
diff --git a/app/models/issue_import.rb b/app/models/issue_import.rb
index b6b20a1b1..5b19ac966 100644
--- a/app/models/issue_import.rb
+++ b/app/models/issue_import.rb
@@ -37,7 +37,7 @@ class IssueImport < Import
# Returns a scope of trackers that user is allowed to
# import issue to
def allowed_target_trackers
- project.trackers
+ Issue.allowed_target_trackers(project, user)
end
def tracker
diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb
index 40bd02a07..a619f115d 100644
--- a/app/models/mail_handler.rb
+++ b/app/models/mail_handler.rb
@@ -199,7 +199,14 @@ class MailHandler < ActionMailer::Base
end
issue = Issue.new(:author => user, :project => project)
- issue.safe_attributes = issue_attributes_from_keywords(issue)
+ attributes = issue_attributes_from_keywords(issue)
+ if handler_options[:no_permission_check]
+ issue.tracker_id = attributes['tracker_id']
+ if project
+ issue.tracker_id ||= project.trackers.first.try(:id)
+ end
+ end
+ issue.safe_attributes = attributes
issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)}
issue.subject = cleaned_up_subject
if issue.subject.blank?
@@ -420,10 +427,6 @@ class MailHandler < ActionMailer::Base
'done_ratio' => get_keyword(:done_ratio, :format => '(\d|10)?0')
}.delete_if {|k, v| v.blank? }
- if issue.new_record? && attrs['tracker_id'].nil?
- attrs['tracker_id'] = issue.project.trackers.first.try(:id)
- end
-
attrs
end
diff --git a/app/models/role.rb b/app/models/role.rb
index defbc311d..89538aa4d 100644
--- a/app/models/role.rb
+++ b/app/models/role.rb
@@ -73,6 +73,7 @@ class Role < ActiveRecord::Base
acts_as_positioned :scope => :builtin
serialize :permissions, ::Role::PermissionsAttributeCoder
+ store :settings, :accessors => [:permissions_all_trackers, :permissions_tracker_ids]
attr_protected :builtin
validates_presence_of :name
@@ -188,6 +189,56 @@ class Role < ActiveRecord::Base
setable_permissions
end
+ def permissions_tracker_ids(*args)
+ if args.any?
+ Array(permissions_tracker_ids[args.first.to_s]).map(&:to_i)
+ else
+ super || {}
+ end
+ end
+
+ def permissions_tracker_ids=(arg)
+ h = arg.to_hash
+ h.values.each {|v| v.reject!(&:blank?)}
+ super(h)
+ end
+
+ # Returns true if tracker_id belongs to the list of
+ # trackers for which permission is given
+ def permissions_tracker_ids?(permission, tracker_id)
+ permissions_tracker_ids(permission).include?(tracker_id)
+ end
+
+ def permissions_all_trackers
+ super || {}
+ end
+
+ def permissions_all_trackers=(arg)
+ super(arg.to_hash)
+ end
+
+ # Returns true if permission is given for all trackers
+ def permissions_all_trackers?(permission)
+ permissions_all_trackers[permission.to_s].to_s != '0'
+ end
+
+ # Sets the trackers that are allowed for a permission.
+ # tracker_ids can be an array of tracker ids or :all for
+ # no restrictions.
+ #
+ # Examples:
+ # role.set_permission_trackers :add_issues, [1, 3]
+ # role.set_permission_trackers :add_issues, :all
+ def set_permission_trackers(permission, tracker_ids)
+ h = {permission.to_s => (tracker_ids == :all ? '1' : '0')}
+ self.permissions_all_trackers = permissions_all_trackers.merge(h)
+
+ h = {permission.to_s => (tracker_ids == :all ? [] : tracker_ids)}
+ self.permissions_tracker_ids = permissions_tracker_ids.merge(h)
+
+ self
+ end
+
# Find all the roles that can be given to a project member
def self.find_all_givable
Role.givable.to_a