summaryrefslogtreecommitdiffstats
path: root/app/models
diff options
context:
space:
mode:
Diffstat (limited to 'app/models')
-rw-r--r--app/models/comment.rb8
-rw-r--r--app/models/custom_field.rb7
-rw-r--r--app/models/email_address.rb6
-rw-r--r--app/models/group.rb4
-rw-r--r--app/models/issue.rb23
-rw-r--r--app/models/issue_relation.rb4
-rw-r--r--app/models/journal.rb5
-rw-r--r--app/models/mail_handler.rb4
-rw-r--r--app/models/member.rb4
-rw-r--r--app/models/message.rb2
-rw-r--r--app/models/news.rb2
-rw-r--r--app/models/principal.rb7
-rw-r--r--app/models/project.rb8
-rw-r--r--app/models/reaction.rb60
-rw-r--r--app/models/repository.rb8
-rw-r--r--app/models/repository/bazaar.rb4
-rw-r--r--app/models/repository/cvs.rb4
-rw-r--r--app/models/repository/filesystem.rb4
-rw-r--r--app/models/repository/git.rb4
-rw-r--r--app/models/repository/mercurial.rb4
-rw-r--r--app/models/role.rb26
-rw-r--r--app/models/user.rb50
-rw-r--r--app/models/user_preference.rb2
-rw-r--r--app/models/version.rb10
24 files changed, 194 insertions, 66 deletions
diff --git a/app/models/comment.rb b/app/models/comment.rb
index 79eb59748..1716537af 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -19,6 +19,8 @@
class Comment < ApplicationRecord
include Redmine::SafeAttributes
+ include Redmine::Reaction::Reactable
+
belongs_to :commented, :polymorphic => true, :counter_cache => true
belongs_to :author, :class_name => 'User'
@@ -28,6 +30,8 @@ class Comment < ApplicationRecord
safe_attributes 'comments'
+ delegate :visible?, to: :commented
+
def comments=(arg)
self.content = arg
end
@@ -36,6 +40,10 @@ class Comment < ApplicationRecord
content
end
+ def project
+ commented.respond_to?(:project) ? commented.project : nil
+ end
+
private
def send_notification
diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb
index ec8c5de8d..d14b67bdb 100644
--- a/app/models/custom_field.rb
+++ b/app/models/custom_field.rb
@@ -101,7 +101,8 @@ class CustomField < ApplicationRecord
'version_status',
'extensions_allowed',
'full_width_layout',
- 'thousands_delimiter'
+ 'thousands_delimiter',
+ 'ratio_interval'
)
def copy_from(arg, options={})
@@ -335,12 +336,12 @@ class CustomField < ApplicationRecord
args.include?(field_format)
end
- def self.human_attribute_name(attribute_key_name, *args)
+ def self.human_attribute_name(attribute_key_name, *)
attr_name = attribute_key_name.to_s
if attr_name == 'url_pattern'
attr_name = "url"
end
- super(attr_name, *args)
+ super(attr_name, *)
end
def css_classes
diff --git a/app/models/email_address.rb b/app/models/email_address.rb
index 69ae8a066..de8c86531 100644
--- a/app/models/email_address.rb
+++ b/app/models/email_address.rb
@@ -74,7 +74,7 @@ class EmailAddress < ApplicationRecord
# Returns true if domain belongs to domains list.
def self.domain_in?(domain, domains)
- domain = domain.downcase
+ domain = domain.to_s.downcase
domains = domains.to_s.split(/[\s,]+/) unless domains.is_a?(Array)
domains.reject(&:blank?).map(&:downcase).any? do |s|
s.start_with?('.') ? domain.end_with?(s) : domain == s
@@ -150,6 +150,10 @@ class EmailAddress < ApplicationRecord
def validate_email_domain
domain = address.partition('@').last
+ # Skip domain validation if the email does not contain a domain part,
+ # to avoid an incomplete error message like "domain not allowed ()"
+ return if domain.empty?
+
return if self.class.valid_domain?(domain)
if User.current.logged?
diff --git a/app/models/group.rb b/app/models/group.rb
index ea5454558..300b59b46 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -94,12 +94,12 @@ class Group < Principal
destroy_all
end
- def self.human_attribute_name(attribute_key_name, *args)
+ def self.human_attribute_name(attribute_key_name, *)
attr_name = attribute_key_name.to_s
if attr_name == 'lastname'
attr_name = "name"
end
- super(attr_name, *args)
+ super(attr_name, *)
end
def self.anonymous
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 2d004a78d..576840843 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -25,6 +25,7 @@ class Issue < ApplicationRecord
before_validation :clear_disabled_fields
before_save :set_parent_id
include Redmine::NestedSet::IssueNestedSet
+ include Redmine::Reaction::Reactable
belongs_to :project
belongs_to :tracker
@@ -268,7 +269,7 @@ class Issue < ApplicationRecord
end
alias :base_reload :reload
- def reload(*args)
+ def reload(*)
@workflow_rule_by_attribute = nil
@assignable_versions = nil
@relations = nil
@@ -277,7 +278,7 @@ class Issue < ApplicationRecord
@total_estimated_hours = nil
@last_updated_by = nil
@last_notes = nil
- base_reload(*args)
+ base_reload(*)
end
# Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields
@@ -469,7 +470,7 @@ class Issue < ApplicationRecord
end
# Overrides assign_attributes so that project and tracker get assigned first
- def assign_attributes(new_attributes, *args)
+ def assign_attributes(new_attributes, *)
return if new_attributes.nil?
attrs = new_attributes.dup
@@ -480,7 +481,7 @@ class Issue < ApplicationRecord
send :"#{attr}=", attrs.delete(attr)
end
end
- super(attrs, *args)
+ super(attrs, *)
end
def attributes=(new_attributes)
@@ -916,7 +917,8 @@ class Issue < ApplicationRecord
result = journals.
preload(:details).
preload(:user => :email_address).
- reorder(:created_on, :id).to_a
+ reorder(:created_on, :id).
+ to_a
result.each_with_index {|j, i| j.indice = i + 1}
@@ -927,6 +929,9 @@ class Issue < ApplicationRecord
end
Journal.preload_journals_details_custom_fields(result)
result.select! {|journal| journal.notes? || journal.visible_details.any?}
+
+ Journal.preload_reaction_details(result)
+
result
end
@@ -1170,7 +1175,7 @@ class Issue < ApplicationRecord
if leaf?
spent_hours
else
- self_and_descendants.joins(:time_entries).sum("#{TimeEntry.table_name}.hours").to_f || 0.0
+ self_and_descendants.joins(:time_entries).sum("#{TimeEntry.table_name}.hours").to_f
end
end
@@ -1203,11 +1208,7 @@ class Issue < ApplicationRecord
end
def last_notes
- if @last_notes
- @last_notes
- else
- journals.visible.where.not(notes: '').reorder(:id => :desc).first.try(:notes)
- end
+ @last_notes || journals.visible.where.not(notes: '').reorder(:id => :desc).first.try(:notes)
end
# Preloads relations for a collection of issues
diff --git a/app/models/issue_relation.rb b/app/models/issue_relation.rb
index e55875e4d..80af22b89 100644
--- a/app/models/issue_relation.rb
+++ b/app/models/issue_relation.rb
@@ -22,9 +22,9 @@ class IssueRelation < ApplicationRecord
class Relations < Array
include Redmine::I18n
- def initialize(issue, *args)
+ def initialize(issue, *)
@issue = issue
- super(*args)
+ super(*)
end
def to_s(*args)
diff --git a/app/models/journal.rb b/app/models/journal.rb
index 179e60c24..12f2beec8 100644
--- a/app/models/journal.rb
+++ b/app/models/journal.rb
@@ -19,6 +19,7 @@
class Journal < ApplicationRecord
include Redmine::SafeAttributes
+ include Redmine::Reaction::Reactable
belongs_to :journalized, :polymorphic => true
# added as a quick fix to allow eager loading of the polymorphic association
@@ -157,8 +158,8 @@ class Journal < ApplicationRecord
end
end
- def visible?(*args)
- journalized.visible?(*args)
+ def visible?(*)
+ journalized.visible?(*)
end
# Returns a string of css classes
diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb
index b6858d96a..5d246a572 100644
--- a/app/models/mail_handler.rb
+++ b/app/models/mail_handler.rb
@@ -55,8 +55,8 @@ class MailHandler < ActionMailer::Base
end
# Receives an email and rescues any exception
- def self.safe_receive(*args)
- receive(*args)
+ def self.safe_receive(*)
+ receive(*)
rescue => e
Rails.logger.error "MailHandler: an unexpected error occurred when receiving email: #{e.message}"
return false
diff --git a/app/models/member.rb b/app/models/member.rb
index b0d5c35fc..1f597c96c 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -45,9 +45,9 @@ class Member < ApplicationRecord
end)
alias :base_reload :reload
- def reload(*args)
+ def reload(*)
@managed_roles = nil
- base_reload(*args)
+ base_reload(*)
end
def role
diff --git a/app/models/message.rb b/app/models/message.rb
index c7f78d2d9..9ac88c7d1 100644
--- a/app/models/message.rb
+++ b/app/models/message.rb
@@ -19,6 +19,8 @@
class Message < ApplicationRecord
include Redmine::SafeAttributes
+ include Redmine::Reaction::Reactable
+
belongs_to :board
belongs_to :author, :class_name => 'User'
acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
diff --git a/app/models/news.rb b/app/models/news.rb
index 40cd63db9..174e4c5ac 100644
--- a/app/models/news.rb
+++ b/app/models/news.rb
@@ -19,6 +19,8 @@
class News < ApplicationRecord
include Redmine::SafeAttributes
+ include Redmine::Reaction::Reactable
+
belongs_to :project
belongs_to :author, :class_name => 'User'
has_many :comments, lambda {order("created_on")}, :as => :commented, :dependent => :delete_all
diff --git a/app/models/principal.rb b/app/models/principal.rb
index 77f599c73..0a6c32ba2 100644
--- a/app/models/principal.rb
+++ b/app/models/principal.rb
@@ -35,6 +35,8 @@ class Principal < ApplicationRecord
:foreign_key => 'user_id'
has_many :projects, :through => :memberships
has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
+ # Always returns nil for groups
+ has_one :email_address, lambda {where :is_default => true}, :autosave => true, :foreign_key => 'user_id'
validate :validate_status
@@ -128,6 +130,11 @@ class Principal < ApplicationRecord
to_s
end
+ # Returns nil by default, subclasses should implement this method
+ def initials(formatter = nil)
+ nil
+ end
+
def mail=(*args)
nil
end
diff --git a/app/models/project.rb b/app/models/project.rb
index c438be16d..b3bf88c94 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -358,12 +358,12 @@ class Project < ApplicationRecord
end
end
- def self.find_by_param(*args)
- self.find(*args)
+ def self.find_by_param(*)
+ self.find(*)
end
alias :base_reload :reload
- def reload(*args)
+ def reload(*)
@principals = nil
@users = nil
@shared_versions = nil
@@ -382,7 +382,7 @@ class Project < ApplicationRecord
@override_members = nil
@assignable_users = nil
@last_activity_date = nil
- base_reload(*args)
+ base_reload(*)
end
def to_param
diff --git a/app/models/reaction.rb b/app/models/reaction.rb
new file mode 100644
index 000000000..184ed2d6e
--- /dev/null
+++ b/app/models/reaction.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+# Redmine - project management software
+# Copyright (C) 2006- Jean-Philippe Lang
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+class Reaction < ApplicationRecord
+ belongs_to :reactable, polymorphic: true
+ belongs_to :user
+
+ validates :reactable_type, inclusion: { in: Redmine::Reaction::REACTABLE_TYPES }
+
+ scope :by, ->(user) { where(user: user) }
+ scope :for_reactable, ->(reactable) { where(reactable: reactable) }
+ scope :visible, ->(user) { where(user: User.visible(user)) }
+
+ # Represents reaction details for a reactable object
+ Detail = Struct.new(
+ # Users who reacted and are visible to the target user
+ :visible_users,
+ # Reaction of the target user
+ :user_reaction
+ ) do
+ def initialize(visible_users: [], user_reaction: nil)
+ super
+ end
+
+ def reaction_count = visible_users.size
+ end
+
+ def self.build_detail_map_for(reactables, user)
+ reactions = visible(user)
+ .for_reactable(reactables)
+ .preload(:user)
+ .select(:id, :reactable_id, :user_id)
+ .order(id: :desc)
+
+ reactions.each_with_object({}) do |reaction, m|
+ m[reaction.reactable_id] ||= Detail.new
+
+ m[reaction.reactable_id].then do |detail|
+ detail.visible_users << reaction.user
+ detail.user_reaction = reaction if reaction.user == user
+ end
+ end
+ end
+end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index a1e81baf3..f4092fc96 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -69,12 +69,12 @@ class Repository < ApplicationRecord
end
end
- def self.human_attribute_name(attribute_key_name, *args)
+ def self.human_attribute_name(attribute_key_name, *)
attr_name = attribute_key_name.to_s
if attr_name == "log_encoding"
attr_name = "commit_logs_encoding"
end
- super(attr_name, *args)
+ super(attr_name, *)
end
# Removes leading and trailing whitespace
@@ -369,8 +369,8 @@ class Repository < ApplicationRecord
subclasses.collect {|klass| [klass.scm_name, klass.name]}
end
- def self.factory(klass_name, *args)
- repository_class(klass_name).new(*args) rescue nil
+ def self.factory(klass_name, *)
+ repository_class(klass_name).new(*) rescue nil
end
def self.repository_class(class_name)
diff --git a/app/models/repository/bazaar.rb b/app/models/repository/bazaar.rb
index d9cffe810..fc42c1235 100644
--- a/app/models/repository/bazaar.rb
+++ b/app/models/repository/bazaar.rb
@@ -22,12 +22,12 @@ require 'redmine/scm/adapters/bazaar_adapter'
class Repository::Bazaar < Repository
validates_presence_of :url, :log_encoding
- def self.human_attribute_name(attribute_key_name, *args)
+ def self.human_attribute_name(attribute_key_name, *)
attr_name = attribute_key_name.to_s
if attr_name == "url"
attr_name = "path_to_repository"
end
- super(attr_name, *args)
+ super(attr_name, *)
end
def self.scm_adapter_class
diff --git a/app/models/repository/cvs.rb b/app/models/repository/cvs.rb
index a5fce91bb..d055428a5 100644
--- a/app/models/repository/cvs.rb
+++ b/app/models/repository/cvs.rb
@@ -27,14 +27,14 @@ class Repository::Cvs < Repository
'root_url',
:if => lambda {|repository, user| repository.new_record?})
- def self.human_attribute_name(attribute_key_name, *args)
+ def self.human_attribute_name(attribute_key_name, *)
attr_name = attribute_key_name.to_s
if attr_name == "root_url"
attr_name = "cvsroot"
elsif attr_name == "url"
attr_name = "cvs_module"
end
- super(attr_name, *args)
+ super(attr_name, *)
end
def self.scm_adapter_class
diff --git a/app/models/repository/filesystem.rb b/app/models/repository/filesystem.rb
index 9347de0f3..c27044a9a 100644
--- a/app/models/repository/filesystem.rb
+++ b/app/models/repository/filesystem.rb
@@ -25,12 +25,12 @@ require 'redmine/scm/adapters/filesystem_adapter'
class Repository::Filesystem < Repository
validates_presence_of :url
- def self.human_attribute_name(attribute_key_name, *args)
+ def self.human_attribute_name(attribute_key_name, *)
attr_name = attribute_key_name.to_s
if attr_name == "url"
attr_name = "root_directory"
end
- super(attr_name, *args)
+ super(attr_name, *)
end
def self.scm_adapter_class
diff --git a/app/models/repository/git.rb b/app/models/repository/git.rb
index b6b3c8336..c94acb01d 100644
--- a/app/models/repository/git.rb
+++ b/app/models/repository/git.rb
@@ -25,10 +25,10 @@ class Repository::Git < Repository
safe_attributes 'report_last_commit'
- def self.human_attribute_name(attribute_key_name, *args)
+ def self.human_attribute_name(attribute_key_name, *)
attr_name = attribute_key_name.to_s
attr_name = 'path_to_repository' if attr_name == 'url'
- super(attr_name, *args)
+ super(attr_name, *)
end
def self.scm_adapter_class
diff --git a/app/models/repository/mercurial.rb b/app/models/repository/mercurial.rb
index 8794cde75..1d1a3c4ff 100644
--- a/app/models/repository/mercurial.rb
+++ b/app/models/repository/mercurial.rb
@@ -30,12 +30,12 @@ class Repository::Mercurial < Repository
# number of changesets to fetch at once
FETCH_AT_ONCE = 100
- def self.human_attribute_name(attribute_key_name, *args)
+ def self.human_attribute_name(attribute_key_name, *)
attr_name = attribute_key_name.to_s
if attr_name == "url"
attr_name = "path_to_repository"
end
- super(attr_name, *args)
+ super(attr_name, *)
end
def self.scm_adapter_class
diff --git a/app/models/role.rb b/app/models/role.rb
index 3ca4f92a1..870bbe945 100644
--- a/app/models/role.rb
+++ b/app/models/role.rb
@@ -198,11 +198,14 @@ class Role < ApplicationRecord
# action can be:
# * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
# * a permission Symbol (eg. :edit_project)
- def allowed_to?(action)
+ # scope can be:
+ # * an array of permissions which will be used as filter (logical AND)
+
+ def allowed_to?(action, scope=nil)
if action.is_a? Hash
- allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
+ allowed_actions(scope).include? "#{action[:controller]}/#{action[:action]}"
else
- allowed_permissions.include? action
+ allowed_permissions(scope).include? action
end
end
@@ -298,13 +301,20 @@ class Role < ApplicationRecord
private
- def allowed_permissions
- @allowed_permissions ||= permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name}
+ def allowed_permissions(scope = nil)
+ scope = scope.sort if scope.present? # to maintain stable cache keys
+ @allowed_permissions ||= {}
+ @allowed_permissions[scope] ||= begin
+ unscoped = permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name}
+ scope.present? ? unscoped & scope : unscoped
+ end
end
- def allowed_actions
- @actions_allowed ||=
- allowed_permissions.inject([]) do |actions, permission|
+ def allowed_actions(scope = nil)
+ scope = scope.sort if scope.present? # to maintain stable cache keys
+ @actions_allowed ||= {}
+ @actions_allowed[scope] ||=
+ allowed_permissions(scope).inject([]) do |actions, permission|
actions += Redmine::AccessControl.allowed_actions(permission)
end.flatten
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 4ce63f809..496084ceb 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -28,46 +28,55 @@ class User < Principal
USER_FORMATS = {
:firstname_lastname => {
:string => '#{firstname} #{lastname}',
+ :initials => '#{firstname.to_s.first}#{lastname.to_s.first}',
:order => %w(firstname lastname id),
:setting_order => 1
},
:firstname_lastinitial => {
:string => '#{firstname} #{lastname.to_s.chars.first}.',
+ :initials => '#{firstname.to_s.first}#{lastname.to_s.first}',
:order => %w(firstname lastname id),
:setting_order => 2
},
:firstinitial_lastname => {
:string => '#{firstname.to_s.gsub(/(([[:alpha:]])[[:alpha:]]*\.?)/, \'\2.\')} #{lastname}',
+ :initials => '#{firstname.to_s.gsub(/(([[:alpha:]])[[:alpha:]]*\.?)/, \'\2.\').first}#{lastname.to_s.first}',
:order => %w(firstname lastname id),
:setting_order => 2
},
:firstname => {
:string => '#{firstname}',
+ :initials => '#{firstname.to_s.first(2)}',
:order => %w(firstname id),
:setting_order => 3
},
:lastname_firstname => {
:string => '#{lastname} #{firstname}',
+ :initials => '#{lastname.to_s.first}#{firstname.to_s.first}',
:order => %w(lastname firstname id),
:setting_order => 4
},
:lastnamefirstname => {
:string => '#{lastname}#{firstname}',
+ :initials => '#{lastname.to_s.first}#{firstname.to_s.first}',
:order => %w(lastname firstname id),
:setting_order => 5
},
:lastname_comma_firstname => {
:string => '#{lastname}, #{firstname}',
+ :initials => '#{lastname.to_s.first}#{firstname.to_s.first}',
:order => %w(lastname firstname id),
:setting_order => 6
},
:lastname => {
:string => '#{lastname}',
+ :initials => '#{lastname.to_s.first(2)}',
:order => %w(lastname id),
:setting_order => 7
},
:username => {
:string => '#{login}',
+ :initials => '#{login.to_s.first(2)}',
:order => %w(login id),
:setting_order => 8
},
@@ -89,10 +98,10 @@ class User < Principal
:after_remove => Proc.new {|user, group| group.user_removed(user)}
has_many :changesets, :dependent => :nullify
has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
- has_one :atom_token, lambda {where "action='feeds'"}, :class_name => 'Token'
- has_one :api_token, lambda {where "action='api'"}, :class_name => 'Token'
- has_one :email_address, lambda {where :is_default => true}, :autosave => true
+ has_one :atom_token, lambda {where "#{table.name}.action='feeds'"}, :class_name => 'Token'
+ has_one :api_token, lambda {where "#{table.name}.action='api'"}, :class_name => 'Token'
has_many :email_addresses, :dependent => :delete_all
+ has_many :reactions, dependent: :delete_all
belongs_to :auth_source
scope :logged, lambda {where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}")}
@@ -103,6 +112,7 @@ class User < Principal
attr_accessor :password, :password_confirmation, :generate_password
attr_accessor :last_before_login_on
attr_accessor :remote_ip
+ attr_writer :oauth_scope
LOGIN_LENGTH_LIMIT = 60
MAIL_LENGTH_LIMIT = 254
@@ -170,7 +180,7 @@ class User < Principal
end
alias :base_reload :reload
- def reload(*args)
+ def reload(*)
@name = nil
@roles = nil
@projects_by_role = nil
@@ -181,7 +191,7 @@ class User < Principal
@builtin_role = nil
@visible_project_ids = nil
@managed_roles = nil
- base_reload(*args)
+ base_reload(*)
end
def mail
@@ -275,6 +285,14 @@ class User < Principal
end
end
+ # Return user's initials based on name format
+ def initials(formatter = nil)
+ f = self.class.name_formatter(formatter)
+ format = f[:initials] || USER_FORMATS[:firstname_lastname][:initials]
+ initials = eval('"' + format + '"')
+ initials.upcase
+ end
+
def registered?
self.status == STATUS_REGISTERED
end
@@ -643,7 +661,7 @@ class User < Principal
def projects_by_role
return @projects_by_role if @projects_by_role
- result = Hash.new([])
+ result = Hash.new {|_h, _k| []}
project_ids_by_role.each do |role, ids|
result[role] = Project.where(:id => ids).to_a
end
@@ -676,7 +694,7 @@ class User < Principal
hash[role_id] << project_id
end
- result = Hash.new([])
+ result = Hash.new {|_h, _k| []}
if hash.present?
roles = Role.where(:id => hash.keys).to_a
hash.each do |role_id, proj_ids|
@@ -715,6 +733,20 @@ class User < Principal
end
end
+ def admin?
+ if authorized_by_oauth?
+ # when signed in via oauth, the user only acts as admin when the admin scope is set
+ super and @oauth_scope.include?(:admin)
+ else
+ super
+ end
+ end
+
+ # true if the user has signed in via oauth
+ def authorized_by_oauth?
+ !@oauth_scope.nil?
+ end
+
# Return true if the user is allowed to do the specified action on a specific context
# Action can be:
# * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
@@ -735,7 +767,7 @@ class User < Principal
roles.any? do |role|
(context.is_public? || role.member?) &&
- role.allowed_to?(action) &&
+ role.allowed_to?(action, @oauth_scope) &&
(block ? yield(role, self) : true)
end
elsif context && context.is_a?(Array)
@@ -754,7 +786,7 @@ class User < Principal
# authorize if user has at least one role that has this permission
roles = self.roles.to_a | [builtin_role]
roles.any? do |role|
- role.allowed_to?(action) &&
+ role.allowed_to?(action, @oauth_scope) &&
(block ? yield(role, self) : true)
end
else
diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb
index 8b19d9a5a..e1842b131 100644
--- a/app/models/user_preference.rb
+++ b/app/models/user_preference.rb
@@ -73,7 +73,7 @@ class UserPreference < ApplicationRecord
if has_attribute? attr_name
super
else
- others ? others[attr_name] : nil
+ others&.[](attr_name)
end
end
diff --git a/app/models/version.rb b/app/models/version.rb
index 51c7c0417..3ca4f2bff 100644
--- a/app/models/version.rb
+++ b/app/models/version.rb
@@ -106,7 +106,7 @@ module FixedIssuesExtension
done = self.open(open).sum do |c|
estimated = c.total_estimated_hours.to_f
estimated = estimated_average unless estimated > 0.0
- ratio = c.closed? ? 100 : (c.done_ratio || 0)
+ ratio = open ? (c.done_ratio || 0) : 100
estimated * ratio
end
progress = done / (estimated_average * issues_count)
@@ -211,8 +211,8 @@ class Version < ApplicationRecord
end
# Version files have same visibility as project files
- def attachments_visible?(*args)
- project.present? && project.attachments_visible?(*args)
+ def attachments_visible?(*)
+ project.present? && project.attachments_visible?(*)
end
def attachments_deletable?(usr=User.current)
@@ -220,10 +220,10 @@ class Version < ApplicationRecord
end
alias :base_reload :reload
- def reload(*args)
+ def reload(*)
@default_project_version = nil
@visible_fixed_issues = nil
- base_reload(*args)
+ base_reload(*)
end
def start_date