diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 45ed4c4e1..d67f0382b 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -23,6 +23,7 @@ class GroupsController < ApplicationController
accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user
helper :custom_fields
+ helper :principal_memberships
def index
respond_to do |format|
@@ -119,23 +120,6 @@ class GroupsController < ApplicationController
end
end
- def edit_membership
- @membership = Member.edit_membership(params[:membership_id], params[:membership], @group)
- @membership.save if request.post?
- respond_to do |format|
- format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
- format.js
- end
- end
-
- def destroy_membership
- Member.find(params[:membership_id]).destroy if request.post?
- respond_to do |format|
- format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
- format.js
- end
- end
-
private
def find_group
diff --git a/app/controllers/principal_memberships_controller.rb b/app/controllers/principal_memberships_controller.rb
new file mode 100644
index 000000000..5af897b6e
--- /dev/null
+++ b/app/controllers/principal_memberships_controller.rb
@@ -0,0 +1,80 @@
+# Redmine - project management software
+# Copyright (C) 2006-2014 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 PrincipalMembershipsController < ApplicationController
+ layout 'admin'
+
+ before_filter :require_admin
+ before_filter :find_principal, :only => [:new, :create]
+ before_filter :find_membership, :only => [:update, :destroy]
+
+ def new
+ @projects = Project.active.all
+ @roles = Role.find_all_givable
+ respond_to do |format|
+ format.html
+ format.js
+ end
+ end
+
+ def create
+ @members = Member.create_principal_memberships(@principal, params[:membership])
+ respond_to do |format|
+ format.html { redirect_to_principal @principal }
+ format.js
+ end
+ end
+
+ def update
+ @membership.attributes = params[:membership]
+ @membership.save
+ respond_to do |format|
+ format.html { redirect_to_principal @principal }
+ format.js
+ end
+ end
+
+ def destroy
+ if @membership.deletable?
+ @membership.destroy
+ end
+ respond_to do |format|
+ format.html { redirect_to_principal @principal }
+ format.js
+ end
+ end
+
+ private
+
+ def find_principal
+ principal_id = params[:user_id] || params[:group_id]
+ @principal = Principal.find(principal_id)
+ rescue ActiveRecord::RecordNotFound
+ render_404
+ end
+
+ def find_membership
+ @membership = Member.find(params[:id])
+ @principal = @membership.principal
+ rescue ActiveRecord::RecordNotFound
+ render_404
+ end
+
+ def redirect_to_principal(principal)
+ redirect_to edit_polymorphic_path(principal, :tab => 'memberships')
+ end
+end
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index bb56fb285..d14914af4 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -19,13 +19,14 @@ class UsersController < ApplicationController
layout 'admin'
before_filter :require_admin, :except => :show
- before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership]
+ before_filter :find_user, :only => [:show, :edit, :update, :destroy]
accept_api_auth :index, :show, :create, :update, :destroy
helper :sort
include SortHelper
helper :custom_fields
include CustomFieldsHelper
+ helper :principal_memberships
def index
sort_init 'login', 'asc'
@@ -173,26 +174,6 @@ class UsersController < ApplicationController
end
end
- def edit_membership
- @membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
- @membership.save
- respond_to do |format|
- format.html { redirect_to edit_user_path(@user, :tab => 'memberships') }
- format.js
- end
- end
-
- def destroy_membership
- @membership = Member.find(params[:membership_id])
- if @membership.deletable?
- @membership.destroy
- end
- respond_to do |format|
- format.html { redirect_to edit_user_path(@user, :tab => 'memberships') }
- format.js
- end
- end
-
private
def find_user
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 7e9cdce90..923dff581 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -252,7 +252,7 @@ module ApplicationHelper
# Renders a tree of projects as a nested set of unordered lists
# The given collection may be a subset of the whole project tree
# (eg. some intermediate nodes are private and can not be seen)
- def render_project_nested_lists(projects)
+ def render_project_nested_lists(projects, &block)
s = ''
if projects.any?
ancestors = []
@@ -272,7 +272,7 @@ module ApplicationHelper
end
classes = (ancestors.empty? ? 'root' : 'child')
s << "
"
- s << h(block_given? ? yield(project) : project.name)
+ s << h(block_given? ? capture(project, &block) : project.name)
s << "
\n"
ancestors << project
end
diff --git a/app/helpers/principal_memberships_helper.rb b/app/helpers/principal_memberships_helper.rb
new file mode 100644
index 000000000..e734f42c9
--- /dev/null
+++ b/app/helpers/principal_memberships_helper.rb
@@ -0,0 +1,56 @@
+# encoding: utf-8
+#
+# Redmine - project management software
+# Copyright (C) 2006-2014 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.
+
+module PrincipalMembershipsHelper
+ def render_principal_memberships(principal)
+ render :partial => 'principal_memberships/index', :locals => {:principal => principal}
+ end
+
+ def call_table_header_hook(principal)
+ if principal.is_a?(Group)
+ call_hook :view_groups_memberships_table_header, :group => principal
+ else
+ call_hook :view_users_memberships_table_header, :user => principal
+ end
+ end
+
+ def call_table_row_hook(principal, membership)
+ if principal.is_a?(Group)
+ call_hook :view_groups_memberships_table_row, :group => principal, :membership => membership
+ else
+ call_hook :view_users_memberships_table_row, :user => principal, :membership => membership
+ end
+ end
+
+ def new_principal_membership_path(principal, *args)
+ if principal.is_a?(Group)
+ new_group_membership_path(principal, *args)
+ else
+ new_user_membership_path(principal, *args)
+ end
+ end
+
+ def principal_membership_path(principal, membership, *args)
+ if principal.is_a?(Group)
+ group_membership_path(principal, membership, *args)
+ else
+ user_membership_path(principal, membership, *args)
+ end
+ end
+end
diff --git a/app/models/member.rb b/app/models/member.rb
index 8256d2e68..257178866 100644
--- a/app/models/member.rb
+++ b/app/models/member.rb
@@ -47,7 +47,7 @@ class Member < ActiveRecord::Base
new_role_ids = ids - role_ids
# Add new roles
- new_role_ids.each {|id| member_roles << MemberRole.new(:role_id => id) }
+ new_role_ids.each {|id| member_roles << MemberRole.new(:role_id => id, :member => self) }
# Remove roles (Rails' #role_ids= will not trigger MemberRole#on_destroy)
member_roles_to_destroy = member_roles.select {|mr| !ids.include?(mr.role_id)}
if member_roles_to_destroy.any?
@@ -102,11 +102,23 @@ class Member < ActiveRecord::Base
end
end
- # Find or initialize a Member with an id, attributes, and for a Principal
- def self.edit_membership(id, new_attributes, principal=nil)
- @membership = id.present? ? Member.find(id) : Member.new(:principal => principal)
- @membership.attributes = new_attributes
- @membership
+ # Creates memberships for principal with the attributes
+ # * project_ids : one or more project ids
+ # * role_ids : ids of the roles to give to each membership
+ #
+ # Example:
+ # Member.create_principal_memberships(user, :project_ids => [2, 5], :role_ids => [1, 3]
+ def self.create_principal_memberships(principal, attributes)
+ members = []
+ if attributes
+ project_ids = Array.wrap(attributes[:project_ids] || attributes[:project_id])
+ role_ids = attributes[:role_ids]
+ project_ids.each do |project_id|
+ members << Member.new(:principal => principal, :role_ids => role_ids, :project_id => project_id)
+ end
+ principal.members << members
+ end
+ members
end
# Finds or initilizes a Member for the given project and principal
diff --git a/app/models/principal.rb b/app/models/principal.rb
index d10241b3f..e6e6ea78e 100644
--- a/app/models/principal.rb
+++ b/app/models/principal.rb
@@ -84,6 +84,11 @@ class Principal < ActiveRecord::Base
to_s
end
+ # Return true if the principal is a member of project
+ def member_of?(project)
+ projects.to_a.include?(project)
+ end
+
def <=>(principal)
if principal.nil?
-1
diff --git a/app/models/user.rb b/app/models/user.rb
index d86627e85..3ac98620b 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -498,11 +498,6 @@ class User < Principal
end
end
- # Return true if the user is a member of project
- def member_of?(project)
- projects.to_a.include?(project)
- end
-
# Returns a hash of user's projects grouped by roles
def projects_by_role
return @projects_by_role if @projects_by_role
diff --git a/app/views/groups/_memberships.html.erb b/app/views/groups/_memberships.html.erb
index ec275c594..1242bf6e8 100644
--- a/app/views/groups/_memberships.html.erb
+++ b/app/views/groups/_memberships.html.erb
@@ -1,65 +1 @@
-<% roles = Role.find_all_givable %>
-<% projects = Project.active.to_a %>
-
-
-<% if @group.memberships.any? %>
-
-
-
<%= l(:label_project) %>
-
<%= l(:label_role_plural) %>
-
-
-
- <% @group.memberships.each do |membership| %>
- <% next if membership.new_record? %>
-