OpenProject is the leading open source project management software.
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.
openproject/app/models/permitted_params.rb

505 lines
15 KiB

#-- encoding: UTF-8
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# 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.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class PermittedParams < Struct.new(:params, :current_user)
# This class intends to provide a method for all params hashes coming from the
# client and that are used for mass assignment.
#
# As such, please make it a deliberate decision to whitelist attributes.
#
# This implementation depends on the strong_parameters gem. For further
# information see here: https://github.com/rails/strong_parameters
#
#
# A method should look like the following:
#
# def name_of_the_params_key_referenced
# params.require(:name_of_the_params_key_referenced).permit(list_of_whitelisted_params)
# end
#
#
# A controller could use a permitted_params method like this
#
# model_instance.attributes = permitted_params.name_of_the_params_key_referenced
#
# instead of doing something like this which will not work anymore once the
# model is protected:
#
# model_instance.attributes = params[:name_of_the_params_key_referenced]
#
#
# A model will need the following module included in order to be protected by
# strong_params
#
# include ActiveModel::ForbiddenAttributesProtection
def self.permit(key, *params)
raise(ArgumentError, "no permitted params are configured for #{key}") unless permitted_attributes.has_key?(key)
permitted_attributes[key].concat(params)
end
def auth_source
params.require(:auth_source).permit(*self.class.permitted_attributes[:auth_source])
end
def board
params.require(:board).permit(*self.class.permitted_attributes[:board])
end
def board?
params[:board] ? board : nil
end
def board_move
params.require(:board).permit(*self.class.permitted_attributes[:move_to])
end
def color
params.require(:color).permit(*self.class.permitted_attributes[:color])
end
def color_move
params.require(:color).permit(*self.class.permitted_attributes[:move_to])
end
def custom_field
params.require(:custom_field).permit(*self.class.permitted_attributes[:custom_field])
end
def custom_field_type
params.require(:type)
end
def enumeration_type
params.require(:type)
end
def enumeration
permitted_params = params.require(:enumeration).permit(*self.class.permitted_attributes[:enumeration])
permitted_params.merge!(custom_field_values(:enumeration))
permitted_params
end
def group
params.require(:group).permit(*self.class.permitted_attributes[:group])
end
def group_membership
params.permit(*self.class.permitted_attributes[:group_membership])
end
def new_work_package(args = {})
permitted = permitted_attributes(:new_work_package, args)
permitted_params = params.require(:work_package).permit(*permitted)
permitted_params.merge!(custom_field_values(:work_package))
permitted_params
end
def member
params.require(:member).permit(*self.class.permitted_attributes[:member])
end
def planning_element_type
params.require(:planning_element_type).permit(*self.class.permitted_attributes[:planning_element_type])
end
def planning_element_type_move
params.require(:planning_element_type).permit(*self.class.permitted_attributes[:move_to])
end
def planning_element(args = {})
permitted = permitted_attributes(:planning_element, args)
permitted_params = params.require(:planning_element).permit(*permitted)
permitted_params.merge!(custom_field_values(:planning_element))
permitted_params
end
def project_type
params.require(:project_type).permit(*self.class.permitted_attributes[:project_type])
end
def project_type_move
params.require(:project_type).permit(*self.class.permitted_attributes[:move_to])
end
def query
# there is a weird bug in strong_parameters gem which makes the permit call
# on the sort_criteria pattern return the sort_criteria-hash contents AND
# the sort_criteria hash itself (again with content) in the same hash.
# Here we try to circumvent this
p = params.require(:query).permit(*self.class.permitted_attributes[:query])
p[:sort_criteria] = params.require(:query).permit(:sort_criteria => {'0' => [], '1' => [], '2' => []})
p[:sort_criteria].delete :sort_criteria
p
end
def role
params.require(:role).permit(*self.class.permitted_attributes[:role])
end
def role?
params[:role] ? role : nil
end
def status
params.require(:status).permit(*self.class.permitted_attributes[:status])
end
alias :update_work_package :new_work_package
def user
permitted_params = params.require(:user).permit(*self.class.permitted_attributes[:user])
permitted_params.merge!(custom_field_values(:user))
permitted_params
end
def user_register_via_omniauth
permitted_params = params.require(:user).permit(:firstname, :lastname, :mail, :language)
permitted_params.merge!(custom_field_values(:user))
permitted_params
end
def user_update_as_admin(external_authentication, change_password_allowed)
# Found group_ids in safe_attributes and added them here as I
# didn't know the consequences of removing these.
# They were not allowed on create.
user_create_as_admin(external_authentication, change_password_allowed, [:group_ids => []])
end
def user_create_as_admin(external_authentication, change_password_allowed, additional_params = [])
if current_user.admin?
additional_params << :auth_source_id unless external_authentication
additional_params << :force_password_change if change_password_allowed
allowed_params = self.class.permitted_attributes[:user] + \
additional_params + \
[ :admin, :login ]
permitted_params = params.require(:user).permit(*allowed_params)
permitted_params.merge!(custom_field_values(:user))
permitted_params
else
params.require(:user).permit()
end
end
def type
params.require(:type).permit(*self.class.permitted_attributes[:type])
end
11 years ago
def type_move
params.require(:type).permit(*self.class.permitted_attributes[:move_to])
11 years ago
end
def work_package
params.require(:work_package).permit(:subject,
:description,
:start_date,
:due_date,
:note,
:planning_element_type_id,
:planning_element_status_comment,
:planning_element_status_id,
:parent_id,
:responsible_id,
:lock_version)
end
def wiki_page
permitted = permitted_attributes(:wiki_page)
permitted_params = params.require(:page).permit(*permitted)
permitted_params
end
def wiki_content
params.require(:content).permit(*self.class.permitted_attributes[:wiki_content])
end
protected
def custom_field_values(key)
# a hash of arbitrary values is not supported by strong params
# thus we do it by hand
values = params.require(key)[:custom_field_values] || {}
# only permit values following the schema
# 'id as string' => 'value as string'
values.reject!{ |k, v| k.to_i < 1 || !v.is_a?(String) }
values.empty? ?
{} :
{ "custom_field_values" => values }
end
def permitted_attributes(key, additions = {})
merged_args = { :params => params, :current_user => current_user }.merge(additions)
self.class.permitted_attributes[key].map do |permission|
if permission.respond_to?(:call)
permission.call(merged_args)
else
permission
end
end.compact
end
def self.permitted_attributes
@whitelisted_params ||= {
:auth_source => [
:name,
:host,
:port,
:tls,
:account,
:account_password,
:base_dn,
:onthefly_register,
:attr_login,
:attr_firstname,
:attr_lastname,
:attr_mail],
:board => [
:name,
:description],
:color => [
:name,
:hexcode,
:move_to ],
:custom_field => [
:editable,
:field_format,
:is_filter,
:is_for_all,
:is_required,
:max_length,
:min_length,
:move_to,
:name,
:possible_values,
:regexp,
:searchable,
:visible,
:translations_attributes => [
:_destroy,
:default_value,
:id,
:locale,
:name,
:possible_values],
:type_ids => []],
:enumeration => [
:active,
:is_default,
:move_to,
:name,
:reassign_to_id],
:group => [
:lastname],
:group_membership => [
:membership_id,
:membership => [
:project_id,
:role_ids => []]],
:member => [
:role_ids => []],
:new_work_package => [
# attributes common with :planning_element below
:assigned_to_id,
{ attachments: [:file, :description] },
:category_id,
:description,
:done_ratio,
:due_date,
:estimated_hours,
:fixed_version_id,
:parent_id,
:priority_id,
:responsible_id,
:start_date,
:status_id,
:type_id,
:subject,
Proc.new do |args|
# avoid costly allowed_to? if the param is not there at all
if args[:params]["work_package"] &&
args[:params]["work_package"].has_key?("watcher_user_ids") &&
args[:current_user].allowed_to?(:add_work_package_watchers, args[:project])
{ :watcher_user_ids => [] }
end
end,
Proc.new do |args|
# avoid costly allowed_to? if the param is not there at all
if args[:params]["work_package"] &&
args[:params]["work_package"].has_key?("time_entry") &&
args[:current_user].allowed_to?(:log_time, args[:project])
{ time_entry: [:hours, :activity_id, :comments] }
end
end,
# attributes unique to :new_work_package
:notes,
:lock_version ],
:planning_element => [
# attributes common with :new_work_package above
:assigned_to_id,
{ attachments: [:file, :description] },
:category_id,
:description,
:done_ratio,
:due_date,
:estimated_hours,
:fixed_version_id,
:parent_id,
:priority_id,
:responsible_id,
:start_date,
:status_id,
:type_id,
:subject,
Proc.new do |args|
# avoid costly allowed_to? if the param is not there at all
if args[:params]["planning_element"] &&
args[:params]["planning_element"].has_key?("watcher_user_ids") &&
args[:current_user].allowed_to?(:add_work_package_watchers, args[:project])
{ :watcher_user_ids => [] }
end
end,
Proc.new do |args|
# avoid costly allowed_to? if the param is not there at all
if args[:params]["planning_element"] &&
args[:params]["planning_element"].has_key?("time_entry") &&
args[:current_user].allowed_to?(:log_time, args[:project])
{ time_entry: [:hours, :activity_id, :comments] }
end
end,
# attributes unique to planning_element
:note,
:planning_element_status_comment,
:custom_fields => [ #json
:id,
:value,
:custom_field => [ # xml
:id,
:value ]]],
:planning_element_type => [
:name,
:in_aggregation,
:is_milestone,
:is_default,
:color_id ],
:project_type => [
:name,
:allows_association,
:type_ids => [],
:reported_project_status_ids => []],
:query => [
:name,
:display_sums,
:is_public,
:group_by],
:role => [
:name,
:assignable,
:move_to,
:permissions => []],
:status => [
:name,
:default_done_ratio,
:is_closed,
:is_default,
:move_to ],
:type => [
:name,
:is_in_roadmap,
:in_aggregation,
:is_milestone,
:is_default,
:color_id,
:project_ids => [],
:custom_field_ids => [] ],
:user => [
:firstname,
:lastname,
:mail,
:mail_notification,
:language,
:custom_fields ],
:wiki_page => [
:title,
:parent_id,
:redirect_existing_links ],
:wiki_content => [
:comments,
:text,
:lock_version ],
:move_to => [ :move_to ]
}
end
private
## Add attributes as permitted attributes (only to be used by the plugins plugin)
#
# attributes should be given as a Hash in the form
# {:key => [:param1, :param2]}
def self.add_permitted_attributes(attributes)
# Make sure the permitted attributes are cached in @whitelisted_params
permitted_attributes
# Check no unsupported parameters are attempted to be whitelisted (they're ignored)
unknown_keys = (attributes.keys - @whitelisted_params.keys)
if unknown_keys.size > 0
Rails.logger.warn(
"Attempt to whitelist attributes for unknown keys: #{unknown_keys}, ignoring them.")
end
attributes.each_pair do |key, attrs|
@whitelisted_params[key] += attrs unless unknown_keys.include?(key)
end
end
end