Revision 8798
Added by Jean-Philippe Lang over 13 years ago
trunk/app/controllers/members_controller.rb | ||
---|---|---|
17 | 17 |
|
18 | 18 |
class MembersController < ApplicationController |
19 | 19 |
model_object Member |
20 |
before_filter :find_model_object, :except => [:create, :autocomplete] |
|
21 |
before_filter :find_project_from_association, :except => [:create, :autocomplete] |
|
22 |
before_filter :find_project_by_project_id, :only => [:create, :autocomplete] |
|
20 |
before_filter :find_model_object, :except => [:index, :create, :autocomplete]
|
|
21 |
before_filter :find_project_from_association, :except => [:index, :create, :autocomplete]
|
|
22 |
before_filter :find_project_by_project_id, :only => [:index, :create, :autocomplete]
|
|
23 | 23 |
before_filter :authorize |
24 |
accept_api_auth :index, :show, :create, :update, :destroy |
|
24 | 25 |
|
26 |
def index |
|
27 |
@offset, @limit = api_offset_and_limit |
|
28 |
@member_count = @project.member_principals.count |
|
29 |
@member_pages = Paginator.new self, @member_count, @limit, params['page'] |
|
30 |
@offset ||= @member_pages.current.offset |
|
31 |
@members = @project.member_principals.all( |
|
32 |
:order => "#{Member.table_name}.id", |
|
33 |
:limit => @limit, |
|
34 |
:offset => @offset |
|
35 |
) |
|
36 |
|
|
37 |
respond_to do |format| |
|
38 |
format.html { head 406 } |
|
39 |
format.api |
|
40 |
end |
|
41 |
end |
|
42 |
|
|
43 |
def show |
|
44 |
respond_to do |format| |
|
45 |
format.html { head 406 } |
|
46 |
format.api |
|
47 |
end |
|
48 |
end |
|
49 |
|
|
25 | 50 |
def create |
26 | 51 |
members = [] |
27 |
if params[:membership] && request.post?
|
|
52 |
if params[:membership] && params[:membership][:user_ids]
|
|
28 | 53 |
attrs = params[:membership].dup |
29 |
if (user_ids = attrs.delete(:user_ids)) |
|
30 |
user_ids.each do |user_id| |
|
31 |
members << Member.new(attrs.merge(:user_id => user_id)) |
|
32 |
end |
|
33 |
else |
|
34 |
members << Member.new(attrs) |
|
54 |
user_ids = attrs.delete(:user_ids) |
|
55 |
user_ids.each do |user_id| |
|
56 |
members << Member.new(attrs.merge(:user_id => user_id)) |
|
35 | 57 |
end |
36 |
@project.members << members |
|
58 |
else |
|
59 |
members << Member.new(params[:membership]) |
|
37 | 60 |
end |
61 |
@project.members << members |
|
62 |
|
|
38 | 63 |
respond_to do |format| |
39 | 64 |
if members.present? && members.all? {|m| m.valid? } |
40 |
|
|
41 | 65 |
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } |
42 |
|
|
43 | 66 |
format.js { |
44 | 67 |
render(:update) {|page| |
45 | 68 |
page.replace_html "tab-content-members", :partial => 'projects/settings/members' |
... | ... | |
47 | 70 |
members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") } |
48 | 71 |
} |
49 | 72 |
} |
73 |
format.api { |
|
74 |
@member = members.first |
|
75 |
render :action => 'show', :status => :created, :location => membership_url(@member) |
|
76 |
} |
|
50 | 77 |
else |
51 |
|
|
52 | 78 |
format.js { |
53 | 79 |
render(:update) {|page| |
54 | 80 |
errors = members.collect {|m| |
... | ... | |
58 | 84 |
page.alert(l(:notice_failed_to_save_members, :errors => errors.join(', '))) |
59 | 85 |
} |
60 | 86 |
} |
61 |
|
|
87 |
format.api { render_validation_errors(members.first) } |
|
62 | 88 |
end |
63 | 89 |
end |
64 | 90 |
end |
... | ... | |
67 | 93 |
if params[:membership] |
68 | 94 |
@member.role_ids = params[:membership][:role_ids] |
69 | 95 |
end |
70 |
if request.put? && @member.save |
|
71 |
respond_to do |format| |
|
72 |
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } |
|
73 |
format.js { |
|
74 |
render(:update) {|page| |
|
75 |
page.replace_html "tab-content-members", :partial => 'projects/settings/members' |
|
76 |
page << 'hideOnLoad()' |
|
77 |
page.visual_effect(:highlight, "member-#{@member.id}") |
|
78 |
} |
|
96 |
saved = @member.save |
|
97 |
respond_to do |format| |
|
98 |
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } |
|
99 |
format.js { |
|
100 |
render(:update) {|page| |
|
101 |
page.replace_html "tab-content-members", :partial => 'projects/settings/members' |
|
102 |
page << 'hideOnLoad()' |
|
103 |
page.visual_effect(:highlight, "member-#{@member.id}") |
|
79 | 104 |
} |
80 |
end |
|
105 |
} |
|
106 |
format.api { |
|
107 |
if saved |
|
108 |
head :ok |
|
109 |
else |
|
110 |
render_validation_errors(@member) |
|
111 |
end |
|
112 |
} |
|
81 | 113 |
end |
82 | 114 |
end |
83 | 115 |
|
... | ... | |
92 | 124 |
page << 'hideOnLoad()' |
93 | 125 |
} |
94 | 126 |
} |
127 |
format.api { |
|
128 |
if @member.destroyed? |
|
129 |
head :ok |
|
130 |
else |
|
131 |
head :unprocessable_entity |
|
132 |
end |
|
133 |
} |
|
95 | 134 |
end |
96 | 135 |
end |
97 | 136 |
|
trunk/app/views/members/index.api.rsb | ||
---|---|---|
1 |
api.array :memberships, api_meta(:total_count => @member_count, :offset => @offset, :limit => @limit) do |
|
2 |
@members.each do |membership| |
|
3 |
api.membership do |
|
4 |
api.id membership.id |
|
5 |
api.project :id => membership.project.id, :name => membership.project.name |
|
6 |
api.__send__ membership.principal.class.name.underscore, :id => membership.principal.id, :name => membership.principal.name |
|
7 |
api.array :roles do |
|
8 |
membership.member_roles.each do |member_role| |
|
9 |
if member_role.role |
|
10 |
attrs = {:id => member_role.role.id, :name => member_role.role.name} |
|
11 |
attrs.merge!(:inherited => true) if member_role.inherited_from.present? |
|
12 |
api.role attrs |
|
13 |
end |
|
14 |
end |
|
15 |
end |
|
16 |
end |
|
17 |
end |
|
18 |
end |
|
0 | 19 |
trunk/app/views/members/show.api.rsb | ||
---|---|---|
1 |
api.membership do |
|
2 |
api.id @member.id |
|
3 |
api.project :id => @member.project.id, :name => @member.project.name |
|
4 |
api.__send__ @member.principal.class.name.underscore, :id => @member.principal.id, :name => @member.principal.name |
|
5 |
api.array :roles do |
|
6 |
@member.member_roles.each do |member_role| |
|
7 |
if member_role.role |
|
8 |
attrs = {:id => member_role.role.id, :name => member_role.role.name} |
|
9 |
attrs.merge!(:inherited => true) if member_role.inherited_from.present? |
|
10 |
api.role attrs |
|
11 |
end |
|
12 |
end |
|
13 |
end |
|
14 |
end |
|
0 | 15 |
trunk/config/routes.rb | ||
---|---|---|
170 | 170 |
project.resources :repositories, :shallow => true, :except => [:index, :show], |
171 | 171 |
:member => {:committers => [:get, :post]} |
172 | 172 |
project.resources :memberships, :shallow => true, :controller => 'members', |
173 |
:only => [:create, :update, :destroy], |
|
173 |
:only => [:index, :show, :create, :update, :destroy],
|
|
174 | 174 |
:collection => {:autocomplete => :get} |
175 | 175 |
|
176 | 176 |
project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get} |
trunk/lib/redmine.rb | ||
---|---|---|
52 | 52 |
map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin |
53 | 53 |
map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member |
54 | 54 |
map.permission :select_project_modules, {:projects => :modules}, :require => :member |
55 |
map.permission :manage_members, {:projects => :settings, :members => [:create, :update, :destroy, :autocomplete]}, :require => :member |
|
55 |
map.permission :manage_members, {:projects => :settings, :members => [:index, :show, :create, :update, :destroy, :autocomplete]}, :require => :member
|
|
56 | 56 |
map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member |
57 | 57 |
map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member |
58 | 58 |
|
trunk/test/integration/api_test/memberships_test.rb | ||
---|---|---|
1 |
# Redmine - project management software |
|
2 |
# Copyright (C) 2006-2012 Jean-Philippe Lang |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or |
|
5 |
# modify it under the terms of the GNU General Public License |
|
6 |
# as published by the Free Software Foundation; either version 2 |
|
7 |
# of the License, or (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU General Public License |
|
15 |
# along with this program; if not, write to the Free Software |
|
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 |
|
|
18 |
require File.expand_path('../../../test_helper', __FILE__) |
|
19 |
|
|
20 |
class ApiTest::MembershipsTest < ActionController::IntegrationTest |
|
21 |
fixtures :projects, :users, :roles, :members, :member_roles |
|
22 |
|
|
23 |
def setup |
|
24 |
Setting.rest_api_enabled = '1' |
|
25 |
end |
|
26 |
|
|
27 |
context "/projects/:project_id/memberships" do |
|
28 |
context "GET" do |
|
29 |
context "xml" do |
|
30 |
should "return memberships" do |
|
31 |
get '/projects/1/memberships.xml', {}, credentials('jsmith') |
|
32 |
|
|
33 |
assert_response :success |
|
34 |
assert_equal 'application/xml', @response.content_type |
|
35 |
assert_tag :tag => 'memberships', |
|
36 |
:attributes => {:type => 'array'}, |
|
37 |
:child => { |
|
38 |
:tag => 'membership', |
|
39 |
:child => { |
|
40 |
:tag => 'id', |
|
41 |
:content => '2', |
|
42 |
:sibling => { |
|
43 |
:tag => 'user', |
|
44 |
:attributes => {:id => '3', :name => 'Dave Lopper'}, |
|
45 |
:sibling => { |
|
46 |
:tag => 'roles', |
|
47 |
:child => { |
|
48 |
:tag => 'role', |
|
49 |
:attributes => {:id => '2', :name => 'Developer'} |
|
50 |
} |
|
51 |
} |
|
52 |
} |
|
53 |
} |
|
54 |
} |
|
55 |
end |
|
56 |
end |
|
57 |
|
|
58 |
context "json" do |
|
59 |
should "return memberships" do |
|
60 |
get '/projects/1/memberships.json', {}, credentials('jsmith') |
|
61 |
|
|
62 |
assert_response :success |
|
63 |
assert_equal 'application/json', @response.content_type |
|
64 |
json = ActiveSupport::JSON.decode(response.body) |
|
65 |
assert_equal({ |
|
66 |
"memberships" => |
|
67 |
[{"id"=>1, |
|
68 |
"project" => {"name"=>"eCookbook", "id"=>1}, |
|
69 |
"roles" => [{"name"=>"Manager", "id"=>1}], |
|
70 |
"user" => {"name"=>"John Smith", "id"=>2}}, |
|
71 |
{"id"=>2, |
|
72 |
"project" => {"name"=>"eCookbook", "id"=>1}, |
|
73 |
"roles" => [{"name"=>"Developer", "id"=>2}], |
|
74 |
"user" => {"name"=>"Dave Lopper", "id"=>3}}], |
|
75 |
"limit" => 25, |
|
76 |
"total_count" => 2, |
|
77 |
"offset" => 0}, |
|
78 |
json) |
|
79 |
end |
|
80 |
end |
|
81 |
end |
|
82 |
|
|
83 |
context "POST" do |
|
84 |
context "xml" do |
|
85 |
should "create membership" do |
|
86 |
assert_difference 'Member.count' do |
|
87 |
post '/projects/1/memberships.xml', {:membership => {:user_id => 7, :role_ids => [2,3]}}, credentials('jsmith') |
|
88 |
|
|
89 |
assert_response :created |
|
90 |
end |
|
91 |
end |
|
92 |
|
|
93 |
should "return errors on failure" do |
|
94 |
assert_no_difference 'Member.count' do |
|
95 |
post '/projects/1/memberships.xml', {:membership => {:role_ids => [2,3]}}, credentials('jsmith') |
|
96 |
|
|
97 |
assert_response :unprocessable_entity |
|
98 |
assert_equal 'application/xml', @response.content_type |
|
99 |
assert_tag 'errors', :child => {:tag => 'error', :content => "Principal can't be blank"} |
|
100 |
end |
|
101 |
end |
|
102 |
end |
|
103 |
end |
|
104 |
end |
|
105 |
|
|
106 |
context "/memberships/:id" do |
|
107 |
context "GET" do |
|
108 |
context "xml" do |
|
109 |
should "return the membership" do |
|
110 |
get '/memberships/2.xml', {}, credentials('jsmith') |
|
111 |
|
|
112 |
assert_response :success |
|
113 |
assert_equal 'application/xml', @response.content_type |
|
114 |
assert_tag :tag => 'membership', |
|
115 |
:child => { |
|
116 |
:tag => 'id', |
|
117 |
:content => '2', |
|
118 |
:sibling => { |
|
119 |
:tag => 'user', |
|
120 |
:attributes => {:id => '3', :name => 'Dave Lopper'}, |
|
121 |
:sibling => { |
|
122 |
:tag => 'roles', |
|
123 |
:child => { |
|
124 |
:tag => 'role', |
|
125 |
:attributes => {:id => '2', :name => 'Developer'} |
|
126 |
} |
|
127 |
} |
|
128 |
} |
|
129 |
} |
|
130 |
end |
|
131 |
end |
|
132 |
|
|
133 |
context "json" do |
|
134 |
should "return the membership" do |
|
135 |
get '/memberships/2.json', {}, credentials('jsmith') |
|
136 |
|
|
137 |
assert_response :success |
|
138 |
assert_equal 'application/json', @response.content_type |
|
139 |
json = ActiveSupport::JSON.decode(response.body) |
|
140 |
assert_equal( |
|
141 |
{"membership" => { |
|
142 |
"id" => 2, |
|
143 |
"project" => {"name"=>"eCookbook", "id"=>1}, |
|
144 |
"roles" => [{"name"=>"Developer", "id"=>2}], |
|
145 |
"user" => {"name"=>"Dave Lopper", "id"=>3}} |
|
146 |
}, |
|
147 |
json) |
|
148 |
end |
|
149 |
end |
|
150 |
end |
|
151 |
|
|
152 |
context "PUT" do |
|
153 |
context "xml" do |
|
154 |
should "update membership" do |
|
155 |
assert_not_equal [1,2], Member.find(2).role_ids.sort |
|
156 |
assert_no_difference 'Member.count' do |
|
157 |
put '/memberships/2.xml', {:membership => {:user_id => 3, :role_ids => [1,266]}}, credentials('jsmith') |
|
158 |
|
|
159 |
assert_response :ok |
|
160 |
end |
|
161 |
member = Member.find(2) |
|
162 |
assert_equal [1,2], member.role_ids.sort |
|
163 |
end |
|
164 |
end |
|
165 |
end |
|
166 |
|
|
167 |
context "DELETE" do |
|
168 |
context "xml" do |
|
169 |
should "destroy membership" do |
|
170 |
assert_difference 'Member.count', -1 do |
|
171 |
delete '/memberships/2.xml', {}, credentials('jsmith') |
|
172 |
|
|
173 |
assert_response :ok |
|
174 |
end |
|
175 |
assert_nil Member.find_by_id(2) |
|
176 |
end |
|
177 |
|
|
178 |
should "respond with 422 on failure" do |
|
179 |
assert_no_difference 'Member.count' do |
|
180 |
# A membership with an inherited role can't be deleted |
|
181 |
Member.find(2).member_roles.first.update_attribute :inherited_from, 99 |
|
182 |
delete '/memberships/2.xml', {}, credentials('jsmith') |
|
183 |
|
|
184 |
assert_response :unprocessable_entity |
|
185 |
end |
|
186 |
end |
|
187 |
end |
|
188 |
end |
|
189 |
end |
|
190 |
end |
|
0 | 191 |
trunk/test/integration/routing/members_test.rb | ||
---|---|---|
20 | 20 |
class RoutingMembersTest < ActionController::IntegrationTest |
21 | 21 |
def test_members |
22 | 22 |
assert_routing( |
23 |
{ :method => 'get', :path => "/projects/5234/memberships.xml" }, |
|
24 |
{ :controller => 'members', :action => 'index', :project_id => '5234', :format => 'xml' } |
|
25 |
) |
|
26 |
assert_routing( |
|
27 |
{ :method => 'get', :path => "/memberships/5234.xml" }, |
|
28 |
{ :controller => 'members', :action => 'show', :id => '5234', :format => 'xml' } |
|
29 |
) |
|
30 |
assert_routing( |
|
23 | 31 |
{ :method => 'post', :path => "/projects/5234/memberships" }, |
24 | 32 |
{ :controller => 'members', :action => 'create', :project_id => '5234' } |
25 | 33 |
) |
26 | 34 |
assert_routing( |
35 |
{ :method => 'post', :path => "/projects/5234/memberships.xml" }, |
|
36 |
{ :controller => 'members', :action => 'create', :project_id => '5234', :format => 'xml' } |
|
37 |
) |
|
38 |
assert_routing( |
|
27 | 39 |
{ :method => 'put', :path => "/memberships/5234" }, |
28 | 40 |
{ :controller => 'members', :action => 'update', :id => '5234' } |
29 | 41 |
) |
30 | 42 |
assert_routing( |
43 |
{ :method => 'put', :path => "/memberships/5234.xml" }, |
|
44 |
{ :controller => 'members', :action => 'update', :id => '5234', :format => 'xml' } |
|
45 |
) |
|
46 |
assert_routing( |
|
31 | 47 |
{ :method => 'delete', :path => "/memberships/5234" }, |
32 | 48 |
{ :controller => 'members', :action => 'destroy', :id => '5234' } |
33 | 49 |
) |
34 | 50 |
assert_routing( |
51 |
{ :method => 'delete', :path => "/memberships/5234.xml" }, |
|
52 |
{ :controller => 'members', :action => 'destroy', :id => '5234', :format => 'xml' } |
|
53 |
) |
|
54 |
assert_routing( |
|
35 | 55 |
{ :method => 'get', :path => "/projects/5234/memberships/autocomplete" }, |
36 | 56 |
{ :controller => 'members', :action => 'autocomplete', :project_id => '5234' } |
37 | 57 |
) |
Also available in: Unified diff
REST API for project memberships (#7420).