#-- encoding: UTF-8 #-- copyright # OpenProject is a project management system. # Copyright (C) 2012-2018 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-2017 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 docs/COPYRIGHT.rdoc for more details. #++ class Authorization::ProjectQuery < Authorization::AbstractQuery self.model = Project def self.projects_members_join(user) projects_table[:id] .eq(members_table[:project_id]) .and(members_table[:user_id].eq(user.id)) .and(project_active_condition) end def self.enabled_modules_join(action) project_enabled_module_id_eq_condition .and(enabled_module_name_eq_condition(action)) .and(project_active_condition) end def self.role_permissions_join permission_roles_table[:id] .eq(role_permissions_table[:role_id]) end def self.project_enabled_module_id_eq_condition projects_table[:id] .eq(enabled_modules_table[:project_id]) end def self.enabled_module_name_eq_condition(action) modules = action_project_modules(action) enabled_modules_table[:name].in(modules) end def self.project_active_condition projects_table[:status].eq(Project::STATUS_ACTIVE) end def self.members_member_roles_join members_table[:id].eq(member_roles_table[:member_id]) end def self.roles_having_permissions(action) permissions_names = permissions(action).map(&:name) role_permissions_table[:permission].in(permissions_names) end def self.projects_table Project.arel_table end def self.enabled_modules_table EnabledModule.arel_table end def self.member_roles_table MemberRole.arel_table end def self.members_table Member.arel_table end def self.role_permissions_table RolePermission.arel_table end def self.permission_roles_table Role.arel_table.alias('permission_roles') end def self.assigned_roles_table Role.arel_table.alias('assigned_roles') end def self.role_has_permission_and_is_assigned(user, action) role_has_permission_condition(action) .and(project_active_condition) .and(assigned_roles_table[:id] .eq(member_roles_table[:role_id]) .or(project_public_and_builtin_role_condition(user))) end def self.role_has_permission_condition(action) if action_public?(action) Arel::Nodes::Equality.new(1, 1) else assigned_roles_table[:id].eq(permission_roles_table[:id]) end end def self.project_public_and_builtin_role_condition(user) builtin_role = if user.logged? Role::BUILTIN_NON_MEMBER else Role::BUILTIN_ANONYMOUS end projects_table[:is_public] .eq(true) .and(assigned_roles_table[:builtin].eq(builtin_role)) .and(member_roles_table[:id].eq(nil)) end def self.permissions(action) if action.is_a?(Hash) Redmine::AccessControl.allow_actions(action) else [Redmine::AccessControl.permission(action)].compact end end def self.action_project_modules(action) permissions(action).map(&:project_module).compact.uniq end def self.action_public?(action) permissions(action).all?(&:public?) end transformations.register :all, :members_join do |statement, user| if user.admin? statement else statement .outer_join(members_table) .on(projects_members_join(user)) end end transformations.register :all, :enabled_modules_join, after: [:members_join] do |statement, _, action| if action_project_modules(action).empty? statement else statement.join(enabled_modules_table) .on(enabled_modules_join(action)) end end transformations.register :all, :role_permissions_join, after: [:enabled_modules_join] do |statement, user, action| if action_public?(action) || user.admin? statement else statement.join(role_permissions_table) .on(roles_having_permissions(action)) end end transformations.register :all, :members_member_roles_join, after: [:members_join] do |statement, user| if user.admin? statement else statement.outer_join(member_roles_table) .on(members_member_roles_join) end end transformations.register :all, :permission_roles_join, after: [:role_permissions_join] do |statement, user, action| if action_public?(action) || user.admin? statement else statement.join(permission_roles_table) .on(role_permissions_join) end end transformations.register :all, :assigned_roles_join, after: [:permission_roles_join, :members_member_roles_join] do |statement, user, action| if user.admin? statement else statement.outer_join(assigned_roles_table) .on(role_has_permission_and_is_assigned(user, action)) end end transformations.register :all, :assigned_role_exists_condition do |statement, user| if user.admin? statement.where(project_active_condition) else statement.where(assigned_roles_table[:id].not_eq(nil)) end end end