diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index 944e60c..bd498cd 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -36,6 +36,8 @@ class AdminController < ApplicationController scope = scope.like(params[:name]) if params[:name].present? @projects = scope.to_a + @workspaces = Hash[Workspace.pluck(:id, :name)] + render :action => "projects", :layout => false if request.xhr? end diff --git a/app/controllers/workflows_controller.rb b/app/controllers/workflows_controller.rb index 7f92f25..511fb11 100644 --- a/app/controllers/workflows_controller.rb +++ b/app/controllers/workflows_controller.rb @@ -23,28 +23,29 @@ class WorkflowsController < ApplicationController def index @roles = Role.sorted.select(&:consider_workflow?) @trackers = Tracker.sorted - @workflow_counts = WorkflowTransition.group(:tracker_id, :role_id).count + @workspaces = Workspace.sorted + @workflow_counts = WorkflowTransition.group(:tracker_id, :role_id, :workspace_id).count end def edit find_trackers_roles_and_statuses_for_edit - if request.post? && @roles && @trackers && params[:transitions] + if request.post? && @roles && @trackers && @workspaces && params[:transitions] transitions = params[:transitions].deep_dup transitions.each do |old_status_id, transitions_by_new_status| transitions_by_new_status.each do |new_status_id, transition_by_rule| transition_by_rule.reject! {|rule, transition| transition == 'no_change'} end end - WorkflowTransition.replace_transitions(@trackers, @roles, transitions) + WorkflowTransition.replace_transitions(@trackers, @roles, transitions, @workspaces) flash[:notice] = l(:notice_successful_update) redirect_to_referer_or workflows_edit_path return end - if @trackers && @roles && @statuses.any? + if @trackers && @roles && @workspaces && @statuses.any? workflows = WorkflowTransition. - where(:role_id => @roles.map(&:id), :tracker_id => @trackers.map(&:id)). + where(:role_id => @roles.map(&:id), :tracker_id => @trackers.map(&:id), :workspace_id => @workspaces.map(&:id)). preload(:old_status, :new_status) @workflows = {} @workflows['always'] = workflows.select {|w| !w.author && !w.assignee} @@ -56,21 +57,21 @@ class WorkflowsController < ApplicationController def permissions find_trackers_roles_and_statuses_for_edit - if request.post? && @roles && @trackers && params[:permissions] + if request.post? && @roles && @trackers && @workspaces && params[:permissions] permissions = params[:permissions].deep_dup permissions.each { |field, rule_by_status_id| rule_by_status_id.reject! {|status_id, rule| rule == 'no_change'} } - WorkflowPermission.replace_permissions(@trackers, @roles, permissions) + WorkflowPermission.replace_permissions(@trackers, @roles, permissions, @workspaces) flash[:notice] = l(:notice_successful_update) redirect_to_referer_or workflows_permissions_path return end - if @roles && @trackers + if @roles && @trackers && @workspaces @fields = (Tracker::CORE_FIELDS_ALL - @trackers.map(&:disabled_core_fields).reduce(:&)).map {|field| [field, l("field_"+field.sub(/_id$/, ''))]} @custom_fields = @trackers.map(&:custom_fields).flatten.uniq.sort - @permissions = WorkflowPermission.rules_by_status_id(@trackers, @roles) + @permissions = WorkflowPermission.rules_by_status_id(@trackers, @roles, @workspaces) @statuses.each {|status| @permissions[status.id] ||= {}} end end @@ -78,6 +79,7 @@ class WorkflowsController < ApplicationController def copy @roles = Role.sorted.select(&:consider_workflow?) @trackers = Tracker.sorted + @workspaces = Workspace.sorted if params[:source_tracker_id].blank? || params[:source_tracker_id] == 'any' @source_tracker = nil @@ -89,19 +91,26 @@ class WorkflowsController < ApplicationController else @source_role = Role.find_by_id(params[:source_role_id].to_i) end + if params[:source_workspace_id].blank? || params[:source_workspace_id] == 'any' + @source_workspace = nil + else + @source_workspace = Workspace.find_by_id(params[:source_workspace_id].to_i) + end @target_trackers = params[:target_tracker_ids].blank? ? nil : Tracker.where(:id => params[:target_tracker_ids]).to_a @target_roles = params[:target_role_ids].blank? ? nil : Role.where(:id => params[:target_role_ids]).to_a + @target_workspaces = params[:target_workspace_ids].blank? ? + nil : Workspace.where(:id => params[:target_workspace_ids]).to_a if request.post? - if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?) + if params[:source_tracker_id].blank? || params[:source_role_id].blank? || params[:source_workspace_id].blank? || (@source_tracker.nil? && @source_role.nil? && @source_workspace.nil?) flash.now[:error] = l(:error_workflow_copy_source) - elsif @target_trackers.blank? || @target_roles.blank? + elsif @target_trackers.blank? || @target_roles.blank? || @target_workspaces.blank? flash.now[:error] = l(:error_workflow_copy_target) else - WorkflowRule.copy(@source_tracker, @source_role, @target_trackers, @target_roles) + WorkflowRule.copy(@source_tracker, @source_role, @source_workspace, @target_trackers, @target_roles, @target_workspaces) flash[:notice] = l(:notice_successful_update) - redirect_to workflows_copy_path(:source_tracker_id => @source_tracker, :source_role_id => @source_role) + redirect_to workflows_copy_path(:source_tracker_id => @source_tracker, :source_role_id => @source_role, :source_workspace_id => @source_workspace) end end end @@ -111,6 +120,7 @@ class WorkflowsController < ApplicationController def find_trackers_roles_and_statuses_for_edit find_roles find_trackers + find_workspaces find_statuses end @@ -134,6 +144,16 @@ class WorkflowsController < ApplicationController @trackers = nil if @trackers.blank? end + def find_workspaces + ids = Array.wrap(params[:workspace_id]) + if ids == ['all'] + @workspaces = Workspace.sorted.to_a + elsif ids.present? + @workspaces = Workspace.where(:id => ids).to_a + end + @workspaces = nil if @workspaces.blank? + end + def find_statuses @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) if @trackers && @used_statuses_only diff --git a/app/controllers/workspaces_controller.rb b/app/controllers/workspaces_controller.rb new file mode 100644 index 0000000..9161f9c --- /dev/null +++ b/app/controllers/workspaces_controller.rb @@ -0,0 +1,74 @@ +# Redmine - project management software +# Copyright (C) 2006-2015 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 WorkspacesController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + accept_api_auth :index + + def index + respond_to do |format| + format.html { + @workspace_pages, @workspaces = paginate Workspace.sorted, :per_page => 25 + render :action => "index", :layout => false if request.xhr? + } + format.api { + @workspaces = Workspace.order('position').to_a + } + end + end + + def new + @workspace = Workspace.new + end + + def create + @workspace = Workspace.new(params[:workspace]) + if @workspace.save + flash[:notice] = l(:notice_successful_create) + redirect_to workspaces_path + else + render :action => 'new' + end + end + + def edit + @workspace = Workspace.find(params[:id]) + end + + def update + @workspace = Workspace.find(params[:id]) + if @workspace.update_attributes(params[:workspace]) + flash[:notice] = l(:notice_successful_update) + redirect_to workspaces_path(:page => params[:page]) + else + render :action => 'edit' + end + end + + def destroy + unless Project.where(:workspace_id => params[:id]).any? || params[:id] == "1" + Workspace.find(params[:id]).destroy + redirect_to workspaces_path + else + flash[:error] = l(:error_unable_delete_workspace) + redirect_to workspaces_path + end + end +end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 6a47b1e..b10fb66 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -95,6 +95,18 @@ module ProjectsHelper version_options_for_select(versions, project.default_version) end + def project_workspace_options(project) + grouped = Hash.new {|h,k| h[k] = []} + Workspace.all.sorted.each do |workspace| + grouped[workspace.name] = workspace.id + end + options_for_select(grouped, project.workspace_id) + end + + def used_workspaces_by_tracker(tracker) + WorkflowTransition.where(:tracker_id => tracker).map{|t| "ws-" + t.workspace_id.to_s}.uniq.join(" ") + end + def format_version_sharing(sharing) sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing) l("label_version_sharing_#{sharing}") diff --git a/app/helpers/workflows_helper.rb b/app/helpers/workflows_helper.rb index eda4043..d35cadd 100644 --- a/app/helpers/workflows_helper.rb +++ b/app/helpers/workflows_helper.rb @@ -53,7 +53,7 @@ module WorkflowsHelper html_options = {} if perm = permissions[status.id][name] - if perm.uniq.size > 1 || perm.size < @roles.size * @trackers.size + if perm.uniq.size > 1 || perm.size < @roles.size * @trackers.size * @workspaces.size options << [l(:label_no_change_option), "no_change"] selected = 'no_change' else @@ -78,7 +78,7 @@ module WorkflowsHelper w = workflows.select {|w| w.old_status == old_status && w.new_status == new_status}.size tag_name = "transitions[#{ old_status.try(:id) || 0 }][#{new_status.id}][#{name}]" - if w == 0 || w == @roles.size * @trackers.size + if w == 0 || w == @roles.size * @trackers.size * @workspaces.size hidden_field_tag(tag_name, "0", :id => nil) + check_box_tag(tag_name, "1", w != 0, diff --git a/app/models/issue.rb b/app/models/issue.rb index f569ed0..2e48dc1 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -623,10 +623,11 @@ class Issue < ActiveRecord::Base user_real = user || User.current roles = user_real.admin ? Role.all.to_a : user_real.roles_for_project(project) roles = roles.select(&:consider_workflow?) + workspace = Project.where(:id => project).pluck(:workspace_id) return {} if roles.empty? result = {} - workflow_permissions = WorkflowPermission.where(:tracker_id => tracker_id, :old_status_id => status_id, :role_id => roles.map(&:id)).to_a + workflow_permissions = WorkflowPermission.where(:tracker_id => tracker_id, :old_status_id => status_id, :role_id => roles.map(&:id), :workspace_id => workspace).to_a if workflow_permissions.any? workflow_rules = workflow_permissions.inject({}) do |h, wp| h[wp.field_name] ||= {} @@ -925,6 +926,7 @@ class Issue < ActiveRecord::Base initial_status, user.admin ? Role.all.to_a : user.roles_for_project(project), tracker, + project.workspace_id, author == user, assignee_transitions_allowed ) diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb index 31c0f03..53b7bd6 100644 --- a/app/models/issue_status.rb +++ b/app/models/issue_status.rb @@ -45,18 +45,17 @@ class IssueStatus < ActiveRecord::Base end # Returns an array of all statuses the given role can switch to - def new_statuses_allowed_to(roles, tracker, author=false, assignee=false) - self.class.new_statuses_allowed(self, roles, tracker, author, assignee) + def new_statuses_allowed_to(roles, tracker, workspace_id, author=false, assignee=false) + self.class.new_statuses_allowed(self, roles, tracker, workspace_id, author, assignee) end alias :find_new_statuses_allowed_to :new_statuses_allowed_to - def self.new_statuses_allowed(status, roles, tracker, author=false, assignee=false) - if roles.present? && tracker + def self.new_statuses_allowed(status, roles, tracker, workspace_id, author=false, assignee=false) + if roles.present? && tracker && workspace_id status_id = status.try(:id) || 0 - scope = IssueStatus. joins(:workflow_transitions_as_new_status). - where(:workflows => {:old_status_id => status_id, :role_id => roles.map(&:id), :tracker_id => tracker.id}) + where(:workflows => {:old_status_id => status_id, :role_id => roles.map(&:id), :tracker_id => tracker.id, :workspace_id => workspace_id}) unless author && assignee if author || assignee diff --git a/app/models/project.rb b/app/models/project.rb index 4241392..d4f5fb7 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -39,6 +39,7 @@ class Project < ActiveRecord::Base has_many :issue_changes, :through => :issues, :source => :journals has_many :versions, lambda {order("#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC")}, :dependent => :destroy belongs_to :default_version, :class_name => 'Version' + belongs_to :workspace has_many :time_entries, :dependent => :destroy has_many :queries, :class_name => 'IssueQuery', :dependent => :delete_all has_many :documents, :dependent => :destroy @@ -721,7 +722,8 @@ class Project < ActiveRecord::Base 'tracker_ids', 'issue_custom_field_ids', 'parent_id', - 'default_version_id' + 'default_version_id', + 'workspace_id' safe_attributes 'enabled_module_names', :if => lambda {|project, user| project.new_record? || user.allowed_to?(:select_project_modules, project) } diff --git a/app/models/role.rb b/app/models/role.rb index acf71c5..24d491c 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -59,7 +59,7 @@ class Role < ActiveRecord::Base before_destroy :check_deletable has_many :workflow_rules, :dependent => :delete_all do def copy(source_role) - WorkflowRule.copy(nil, source_role, nil, proxy_association.owner) + WorkflowRule.copy(nil, source_role, nil, nil, proxy_association.owner, nil) end end has_and_belongs_to_many :custom_fields, :join_table => "#{table_name_prefix}custom_fields_roles#{table_name_suffix}", :foreign_key => "role_id" diff --git a/app/models/tracker.rb b/app/models/tracker.rb index 5e4a24b..2564bc9 100644 --- a/app/models/tracker.rb +++ b/app/models/tracker.rb @@ -28,7 +28,7 @@ class Tracker < ActiveRecord::Base has_many :issues has_many :workflow_rules, :dependent => :delete_all do def copy(source_tracker) - WorkflowRule.copy(source_tracker, nil, proxy_association.owner, nil) + WorkflowRule.copy(source_tracker, nil, nil, proxy_association.owner, nil, nil) end end diff --git a/app/models/workflow_permission.rb b/app/models/workflow_permission.rb index 1990b82..85ffc76 100644 --- a/app/models/workflow_permission.rb +++ b/app/models/workflow_permission.rb @@ -20,14 +20,14 @@ class WorkflowPermission < WorkflowRule validates_presence_of :old_status validate :validate_field_name - # Returns the workflow permissions for the given trackers and roles + # Returns the workflow permissions for the given trackers, roles and workspaces # grouped by status_id # # Example: - # WorkflowPermission.rules_by_status_id trackers, roles + # WorkflowPermission.rules_by_status_id trackers, roles, workspaces # # => {1 => {'start_date' => 'required', 'due_date' => 'readonly'}} - def self.rules_by_status_id(trackers, roles) - WorkflowPermission.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id)).inject({}) do |h, w| + def self.rules_by_status_id(trackers, roles, workspaces) + WorkflowPermission.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id), :workspace_id => workspaces.map(&:id)).inject({}) do |h, w| h[w.old_status_id] ||= {} h[w.old_status_id][w.field_name] ||= [] h[w.old_status_id][w.field_name] << w.rule @@ -35,22 +35,25 @@ class WorkflowPermission < WorkflowRule end end - # Replaces the workflow permissions for the given trackers and roles + # Replaces the workflow permissions for the given trackers, roles and workspaces # # Example: - # WorkflowPermission.replace_permissions trackers, roles, {'1' => {'start_date' => 'required', 'due_date' => 'readonly'}} - def self.replace_permissions(trackers, roles, permissions) + # WorkflowPermission.replace_permissions trackers, roles, {'1' => {'start_date' => 'required', 'due_date' => 'readonly'}}, workspaces + def self.replace_permissions(trackers, roles, permissions, workspaces) trackers = Array.wrap trackers roles = Array.wrap roles + workspaces = Array.wrap workspaces transaction do permissions.each { |status_id, rule_by_field| rule_by_field.each { |field, rule| - destroy_all(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id), :old_status_id => status_id, :field_name => field) + destroy_all(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id), :old_status_id => status_id, :field_name => field, :workspace_id => workspaces.map(&:id)) if rule.present? trackers.each do |tracker| roles.each do |role| - WorkflowPermission.create(:role_id => role.id, :tracker_id => tracker.id, :old_status_id => status_id, :field_name => field, :rule => rule) + workspaces.each do |workspace| + WorkflowPermission.create(:role_id => role.id, :tracker_id => tracker.id, :old_status_id => status_id, :field_name => field, :rule => rule, :workspace_id => workspace.id) + end end end end diff --git a/app/models/workflow_rule.rb b/app/models/workflow_rule.rb index 6fd4b05..dffd037 100644 --- a/app/models/workflow_rule.rb +++ b/app/models/workflow_rule.rb @@ -22,51 +22,60 @@ class WorkflowRule < ActiveRecord::Base belongs_to :tracker belongs_to :old_status, :class_name => 'IssueStatus' belongs_to :new_status, :class_name => 'IssueStatus' + belongs_to :workspace - validates_presence_of :role, :tracker + validates_presence_of :role, :tracker, :workspace attr_protected :id # Copies workflows from source to targets - def self.copy(source_tracker, source_role, target_trackers, target_roles) - unless source_tracker.is_a?(Tracker) || source_role.is_a?(Role) - raise ArgumentError.new("source_tracker or source_role must be specified") + def self.copy(source_tracker, source_role, source_workspace, target_trackers, target_roles, target_workspaces) + unless source_tracker.is_a?(Tracker) || source_role.is_a?(Role) || source_workspace.is_a?(Workspace) + raise ArgumentError.new("source_tracker, source_role or source_workspace must be specified") end target_trackers = [target_trackers].flatten.compact target_roles = [target_roles].flatten.compact + target_workspaces = [target_workspaces].flatten.compact target_trackers = Tracker.sorted.to_a if target_trackers.empty? target_roles = Role.all.select(&:consider_workflow?) if target_roles.empty? + target_workspaces = Workspace.sorted.to_a if target_workspaces.empty? target_trackers.each do |target_tracker| target_roles.each do |target_role| - copy_one(source_tracker || target_tracker, - source_role || target_role, - target_tracker, - target_role) + target_workspaces.each do |target_workspace| + copy_one(source_tracker || target_tracker, + source_role || target_role, + source_workspace || target_workspace, + target_tracker, + target_role, + target_workspace) + end end end end # Copies a single set of workflows from source to target - def self.copy_one(source_tracker, source_role, target_tracker, target_role) + def self.copy_one(source_tracker, source_role, source_workspace, target_tracker, target_role, target_workspace) unless source_tracker.is_a?(Tracker) && !source_tracker.new_record? && source_role.is_a?(Role) && !source_role.new_record? && + source_workspace.is_a?(Workspace) && !source_workspace.new_record? && target_tracker.is_a?(Tracker) && !target_tracker.new_record? && target_role.is_a?(Role) && !target_role.new_record? + target_workspace.is_a?(Workspace) && !target_workspace.new_record? raise ArgumentError.new("arguments can not be nil or unsaved objects") end - if source_tracker == target_tracker && source_role == target_role + if source_tracker == target_tracker && source_role == target_role && source_workspace == target_workspace false else transaction do - delete_all :tracker_id => target_tracker.id, :role_id => target_role.id - connection.insert "INSERT INTO #{WorkflowRule.table_name} (tracker_id, role_id, old_status_id, new_status_id, author, assignee, field_name, #{connection.quote_column_name 'rule'}, type)" + - " SELECT #{target_tracker.id}, #{target_role.id}, old_status_id, new_status_id, author, assignee, field_name, #{connection.quote_column_name 'rule'}, type" + + delete_all :tracker_id => target_tracker.id, :role_id => target_role.id, :workspace_id => target_workspace.id + connection.insert "INSERT INTO #{WorkflowRule.table_name} (tracker_id, role_id, old_status_id, new_status_id, author, assignee, field_name, #{connection.quote_column_name 'rule'}, type, workspace_id)" + + " SELECT #{target_tracker.id}, #{target_role.id}, old_status_id, new_status_id, author, assignee, field_name, #{connection.quote_column_name 'rule'}, type, #{target_workspace.id}" + " FROM #{WorkflowRule.table_name}" + - " WHERE tracker_id = #{source_tracker.id} AND role_id = #{source_role.id}" + " WHERE tracker_id = #{source_tracker.id} AND role_id = #{source_role.id} AND workspace_id = #{source_workspace.id}" end true end diff --git a/app/models/workflow_transition.rb b/app/models/workflow_transition.rb index ff75254..9b4be85 100644 --- a/app/models/workflow_transition.rb +++ b/app/models/workflow_transition.rb @@ -18,60 +18,64 @@ class WorkflowTransition < WorkflowRule validates_presence_of :new_status - def self.replace_transitions(trackers, roles, transitions) + def self.replace_transitions(trackers, roles, transitions, workspaces) trackers = Array.wrap trackers roles = Array.wrap roles + workspaces = Array.wrap workspaces transaction do - records = WorkflowTransition.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id)).to_a + records = WorkflowTransition.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id), :workspace_id => workspaces.map(&:id)).to_a transitions.each do |old_status_id, transitions_by_new_status| transitions_by_new_status.each do |new_status_id, transition_by_rule| transition_by_rule.each do |rule, transition| trackers.each do |tracker| roles.each do |role| - w = records.select {|r| - r.old_status_id == old_status_id.to_i && - r.new_status_id == new_status_id.to_i && - r.tracker_id == tracker.id && - r.role_id == role.id && - !r.destroyed? - } + workspaces.each do |workspace| + w = records.select {|r| + r.old_status_id == old_status_id.to_i && + r.new_status_id == new_status_id.to_i && + r.tracker_id == tracker.id && + r.role_id == role.id && + r.workspace_id == workspace.id && + !r.destroyed? + } - if rule == 'always' - w = w.select {|r| !r.author && !r.assignee} - else - w = w.select {|r| r.author || r.assignee} - end - if w.size > 1 - w[1..-1].each(&:destroy) - end - w = w.first - - if transition == "1" || transition == true - unless w - w = WorkflowTransition.new(:old_status_id => old_status_id, :new_status_id => new_status_id, :tracker_id => tracker.id, :role_id => role.id) - records << w - end - w.author = true if rule == "author" - w.assignee = true if rule == "assignee" - w.save if w.changed? - elsif w if rule == 'always' - w.destroy - elsif rule == 'author' - if w.assignee - w.author = false - w.save if w.changed? - else - w.destroy + w = w.select {|r| !r.author && !r.assignee} + else + w = w.select {|r| r.author || r.assignee} + end + if w.size > 1 + w[1..-1].each(&:destroy) + end + w = w.first + + if transition == "1" || transition == true + unless w + w = WorkflowTransition.new(:old_status_id => old_status_id, :new_status_id => new_status_id, :tracker_id => tracker.id, :role_id => role.id, :workspace_id => workspace.id) + records << w end - elsif rule == 'assignee' - if w.author - w.assignee = false - w.save if w.changed? - else + w.author = true if rule == "author" + w.assignee = true if rule == "assignee" + w.save if w.changed? + elsif w + if rule == 'always' w.destroy + elsif rule == 'author' + if w.assignee + w.author = false + w.save if w.changed? + else + w.destroy + end + elsif rule == 'assignee' + if w.author + w.assignee = false + w.save if w.changed? + else + w.destroy + end end end end diff --git a/app/models/workspace.rb b/app/models/workspace.rb new file mode 100644 index 0000000..65c489e --- /dev/null +++ b/app/models/workspace.rb @@ -0,0 +1,63 @@ +# Redmine - project management software +# Copyright (C) 2006-2015 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 Workspace < ActiveRecord::Base + + before_destroy :check_integrity + has_many :projects + has_many :workflow_rules, :dependent => :delete_all do + def copy(source_workflow) + WorkflowRule.copy(nil, nil, source_tracker, nil, nil, proxy_association.owner) + end + end + acts_as_list + + validates_presence_of :name + validates_uniqueness_of :name + validates_length_of :name, :maximum => 30 + attr_protected :id + + scope :sorted, lambda { order(:position) } + scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} + + # Returns an array of IssueStatus that are used + # in the tracker's workflows + def issue_statuses + if @issue_statuses + return @issue_statuses + elsif new_record? + return [] + end + + ids = WorkflowTransition. + connection.select_rows("SELECT DISTINCT old_status_id, new_status_id FROM #{WorkflowTransition.table_name} WHERE workspace_id = #{id} AND type = 'WorkflowTransition'"). + flatten. + uniq + @issue_statuses = IssueStatus.where(:id => ids).all.sort + end + + def <=>(status) + position <=> status.position + end + + def to_s; name end + +private + def check_integrity + raise Exception.new("Cannot delete workspace") if Project.where(:workspace_id => self.id).any? + end +end diff --git a/app/views/admin/projects.html.erb b/app/views/admin/projects.html.erb index 0437f9e..c57d3e5 100644 --- a/app/views/admin/projects.html.erb +++ b/app/views/admin/projects.html.erb @@ -22,6 +22,7 @@
<%= label(:project, :parent_id, l(:field_parent)) %><%= parent_project_select_tag(@project) %>
<% end %> +<% if @project.safe_attribute? 'workspace_id' %> +<%= f.select :workspace_id, project_workspace_options(@project), {}, {:onChange=>"displaytrackers(this);"} %>
+<% end %> + <% if @project.safe_attribute? 'inherit_members' %><%= f.check_box :inherit_members %>
<% end %> @@ -46,9 +50,9 @@ <% if @project.new_record? || @project.module_enabled?('issue_tracking') %> <% unless @trackers.empty? %> -