##// END OF EJS Templates
Add status to /users/:id API for admins (#13948)....
Jean-Baptiste Barth -
r11560:ec4dbbced5d9
parent child
Show More
@@ -1,36 +1,37
1 api.user do
1 api.user do
2 api.id @user.id
2 api.id @user.id
3 api.login @user.login if User.current.admin? || (User.current == @user)
3 api.login @user.login if User.current.admin? || (User.current == @user)
4 api.firstname @user.firstname
4 api.firstname @user.firstname
5 api.lastname @user.lastname
5 api.lastname @user.lastname
6 api.mail @user.mail if User.current.admin? || !@user.pref.hide_mail
6 api.mail @user.mail if User.current.admin? || !@user.pref.hide_mail
7 api.created_on @user.created_on
7 api.created_on @user.created_on
8 api.last_login_on @user.last_login_on
8 api.last_login_on @user.last_login_on
9 api.api_key @user.api_key if User.current.admin? || (User.current == @user)
9 api.api_key @user.api_key if User.current.admin? || (User.current == @user)
10 api.status @user.status if User.current.admin?
10
11
11 render_api_custom_values @user.visible_custom_field_values, api
12 render_api_custom_values @user.visible_custom_field_values, api
12
13
13 api.array :groups do |groups|
14 api.array :groups do |groups|
14 @user.groups.each do |group|
15 @user.groups.each do |group|
15 api.group :id => group.id, :name => group.name
16 api.group :id => group.id, :name => group.name
16 end
17 end
17 end if User.current.admin? && include_in_api_response?('groups')
18 end if User.current.admin? && include_in_api_response?('groups')
18
19
19 api.array :memberships do
20 api.array :memberships do
20 @memberships.each do |membership|
21 @memberships.each do |membership|
21 api.membership do
22 api.membership do
22 api.id membership.id
23 api.id membership.id
23 api.project :id => membership.project.id, :name => membership.project.name
24 api.project :id => membership.project.id, :name => membership.project.name
24 api.array :roles do
25 api.array :roles do
25 membership.member_roles.each do |member_role|
26 membership.member_roles.each do |member_role|
26 if member_role.role
27 if member_role.role
27 attrs = {:id => member_role.role.id, :name => member_role.role.name}
28 attrs = {:id => member_role.role.id, :name => member_role.role.name}
28 attrs.merge!(:inherited => true) if member_role.inherited_from.present?
29 attrs.merge!(:inherited => true) if member_role.inherited_from.present?
29 api.role attrs
30 api.role attrs
30 end
31 end
31 end
32 end
32 end
33 end
33 end if membership.project
34 end if membership.project
34 end
35 end
35 end if include_in_api_response?('memberships') && @memberships
36 end if include_in_api_response?('memberships') && @memberships
36 end
37 end
@@ -1,371 +1,383
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
2 # Copyright (C) 2006-2013 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class Redmine::ApiTest::UsersTest < Redmine::ApiTest::Base
20 class Redmine::ApiTest::UsersTest < Redmine::ApiTest::Base
21 fixtures :users, :members, :member_roles, :roles, :projects
21 fixtures :users, :members, :member_roles, :roles, :projects
22
22
23 def setup
23 def setup
24 Setting.rest_api_enabled = '1'
24 Setting.rest_api_enabled = '1'
25 end
25 end
26
26
27 context "GET /users" do
27 context "GET /users" do
28 should_allow_api_authentication(:get, "/users.xml")
28 should_allow_api_authentication(:get, "/users.xml")
29 should_allow_api_authentication(:get, "/users.json")
29 should_allow_api_authentication(:get, "/users.json")
30 end
30 end
31
31
32 context "GET /users/2" do
32 context "GET /users/2" do
33 context ".xml" do
33 context ".xml" do
34 should "return requested user" do
34 should "return requested user" do
35 get '/users/2.xml'
35 get '/users/2.xml'
36
36
37 assert_response :success
37 assert_response :success
38 assert_tag :tag => 'user',
38 assert_tag :tag => 'user',
39 :child => {:tag => 'id', :content => '2'}
39 :child => {:tag => 'id', :content => '2'}
40 end
40 end
41
41
42 context "with include=memberships" do
42 context "with include=memberships" do
43 should "include memberships" do
43 should "include memberships" do
44 get '/users/2.xml?include=memberships'
44 get '/users/2.xml?include=memberships'
45
45
46 assert_response :success
46 assert_response :success
47 assert_tag :tag => 'memberships',
47 assert_tag :tag => 'memberships',
48 :parent => {:tag => 'user'},
48 :parent => {:tag => 'user'},
49 :children => {:count => 1}
49 :children => {:count => 1}
50 end
50 end
51 end
51 end
52 end
52 end
53
53
54 context ".json" do
54 context ".json" do
55 should "return requested user" do
55 should "return requested user" do
56 get '/users/2.json'
56 get '/users/2.json'
57
57
58 assert_response :success
58 assert_response :success
59 json = ActiveSupport::JSON.decode(response.body)
59 json = ActiveSupport::JSON.decode(response.body)
60 assert_kind_of Hash, json
60 assert_kind_of Hash, json
61 assert_kind_of Hash, json['user']
61 assert_kind_of Hash, json['user']
62 assert_equal 2, json['user']['id']
62 assert_equal 2, json['user']['id']
63 end
63 end
64
64
65 context "with include=memberships" do
65 context "with include=memberships" do
66 should "include memberships" do
66 should "include memberships" do
67 get '/users/2.json?include=memberships'
67 get '/users/2.json?include=memberships'
68
68
69 assert_response :success
69 assert_response :success
70 json = ActiveSupport::JSON.decode(response.body)
70 json = ActiveSupport::JSON.decode(response.body)
71 assert_kind_of Array, json['user']['memberships']
71 assert_kind_of Array, json['user']['memberships']
72 assert_equal [{
72 assert_equal [{
73 "id"=>1,
73 "id"=>1,
74 "project"=>{"name"=>"eCookbook", "id"=>1},
74 "project"=>{"name"=>"eCookbook", "id"=>1},
75 "roles"=>[{"name"=>"Manager", "id"=>1}]
75 "roles"=>[{"name"=>"Manager", "id"=>1}]
76 }], json['user']['memberships']
76 }], json['user']['memberships']
77 end
77 end
78 end
78 end
79 end
79 end
80 end
80 end
81
81
82 context "GET /users/current" do
82 context "GET /users/current" do
83 context ".xml" do
83 context ".xml" do
84 should "require authentication" do
84 should "require authentication" do
85 get '/users/current.xml'
85 get '/users/current.xml'
86
86
87 assert_response 401
87 assert_response 401
88 end
88 end
89
89
90 should "return current user" do
90 should "return current user" do
91 get '/users/current.xml', {}, credentials('jsmith')
91 get '/users/current.xml', {}, credentials('jsmith')
92
92
93 assert_tag :tag => 'user',
93 assert_tag :tag => 'user',
94 :child => {:tag => 'id', :content => '2'}
94 :child => {:tag => 'id', :content => '2'}
95 end
95 end
96 end
96 end
97 end
97 end
98
98
99 test "GET /users/:id should not return login for other user" do
99 test "GET /users/:id should not return login for other user" do
100 get '/users/3.xml', {}, credentials('jsmith')
100 get '/users/3.xml', {}, credentials('jsmith')
101 assert_response :success
101 assert_response :success
102 assert_no_tag 'user', :child => {:tag => 'login'}
102 assert_no_tag 'user', :child => {:tag => 'login'}
103 end
103 end
104
104
105 test "GET /users/:id should return login for current user" do
105 test "GET /users/:id should return login for current user" do
106 get '/users/2.xml', {}, credentials('jsmith')
106 get '/users/2.xml', {}, credentials('jsmith')
107 assert_response :success
107 assert_response :success
108 assert_tag 'user', :child => {:tag => 'login', :content => 'jsmith'}
108 assert_tag 'user', :child => {:tag => 'login', :content => 'jsmith'}
109 end
109 end
110
110
111 test "GET /users/:id should not return api_key for other user" do
111 test "GET /users/:id should not return api_key for other user" do
112 get '/users/3.xml', {}, credentials('jsmith')
112 get '/users/3.xml', {}, credentials('jsmith')
113 assert_response :success
113 assert_response :success
114 assert_no_tag 'user', :child => {:tag => 'api_key'}
114 assert_no_tag 'user', :child => {:tag => 'api_key'}
115 end
115 end
116
116
117 test "GET /users/:id should return api_key for current user" do
117 test "GET /users/:id should return api_key for current user" do
118 get '/users/2.xml', {}, credentials('jsmith')
118 get '/users/2.xml', {}, credentials('jsmith')
119 assert_response :success
119 assert_response :success
120 assert_tag 'user', :child => {:tag => 'api_key', :content => User.find(2).api_key}
120 assert_tag 'user', :child => {:tag => 'api_key', :content => User.find(2).api_key}
121 end
121 end
122
122
123 test "GET /users/:id should not return status for standard user" do
124 get '/users/3.xml', {}, credentials('jsmith')
125 assert_response :success
126 assert_no_tag 'user', :child => {:tag => 'status'}
127 end
128
129 test "GET /users/:id should return status for administrators" do
130 get '/users/2.xml', {}, credentials('admin')
131 assert_response :success
132 assert_tag 'user', :child => {:tag => 'status', :content => User.find(1).status.to_s}
133 end
134
123 context "POST /users" do
135 context "POST /users" do
124 context "with valid parameters" do
136 context "with valid parameters" do
125 setup do
137 setup do
126 @parameters = {
138 @parameters = {
127 :user => {
139 :user => {
128 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
140 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
129 :mail => 'foo@example.net', :password => 'secret123',
141 :mail => 'foo@example.net', :password => 'secret123',
130 :mail_notification => 'only_assigned'
142 :mail_notification => 'only_assigned'
131 }
143 }
132 }
144 }
133 end
145 end
134
146
135 context ".xml" do
147 context ".xml" do
136 should_allow_api_authentication(:post,
148 should_allow_api_authentication(:post,
137 '/users.xml',
149 '/users.xml',
138 {:user => {
150 {:user => {
139 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
151 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
140 :mail => 'foo@example.net', :password => 'secret123'
152 :mail => 'foo@example.net', :password => 'secret123'
141 }},
153 }},
142 {:success_code => :created})
154 {:success_code => :created})
143
155
144 should "create a user with the attributes" do
156 should "create a user with the attributes" do
145 assert_difference('User.count') do
157 assert_difference('User.count') do
146 post '/users.xml', @parameters, credentials('admin')
158 post '/users.xml', @parameters, credentials('admin')
147 end
159 end
148
160
149 user = User.first(:order => 'id DESC')
161 user = User.first(:order => 'id DESC')
150 assert_equal 'foo', user.login
162 assert_equal 'foo', user.login
151 assert_equal 'Firstname', user.firstname
163 assert_equal 'Firstname', user.firstname
152 assert_equal 'Lastname', user.lastname
164 assert_equal 'Lastname', user.lastname
153 assert_equal 'foo@example.net', user.mail
165 assert_equal 'foo@example.net', user.mail
154 assert_equal 'only_assigned', user.mail_notification
166 assert_equal 'only_assigned', user.mail_notification
155 assert !user.admin?
167 assert !user.admin?
156 assert user.check_password?('secret123')
168 assert user.check_password?('secret123')
157
169
158 assert_response :created
170 assert_response :created
159 assert_equal 'application/xml', @response.content_type
171 assert_equal 'application/xml', @response.content_type
160 assert_tag 'user', :child => {:tag => 'id', :content => user.id.to_s}
172 assert_tag 'user', :child => {:tag => 'id', :content => user.id.to_s}
161 end
173 end
162 end
174 end
163
175
164 context ".json" do
176 context ".json" do
165 should_allow_api_authentication(:post,
177 should_allow_api_authentication(:post,
166 '/users.json',
178 '/users.json',
167 {:user => {
179 {:user => {
168 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
180 :login => 'foo', :firstname => 'Firstname', :lastname => 'Lastname',
169 :mail => 'foo@example.net'
181 :mail => 'foo@example.net'
170 }},
182 }},
171 {:success_code => :created})
183 {:success_code => :created})
172
184
173 should "create a user with the attributes" do
185 should "create a user with the attributes" do
174 assert_difference('User.count') do
186 assert_difference('User.count') do
175 post '/users.json', @parameters, credentials('admin')
187 post '/users.json', @parameters, credentials('admin')
176 end
188 end
177
189
178 user = User.first(:order => 'id DESC')
190 user = User.first(:order => 'id DESC')
179 assert_equal 'foo', user.login
191 assert_equal 'foo', user.login
180 assert_equal 'Firstname', user.firstname
192 assert_equal 'Firstname', user.firstname
181 assert_equal 'Lastname', user.lastname
193 assert_equal 'Lastname', user.lastname
182 assert_equal 'foo@example.net', user.mail
194 assert_equal 'foo@example.net', user.mail
183 assert !user.admin?
195 assert !user.admin?
184
196
185 assert_response :created
197 assert_response :created
186 assert_equal 'application/json', @response.content_type
198 assert_equal 'application/json', @response.content_type
187 json = ActiveSupport::JSON.decode(response.body)
199 json = ActiveSupport::JSON.decode(response.body)
188 assert_kind_of Hash, json
200 assert_kind_of Hash, json
189 assert_kind_of Hash, json['user']
201 assert_kind_of Hash, json['user']
190 assert_equal user.id, json['user']['id']
202 assert_equal user.id, json['user']['id']
191 end
203 end
192 end
204 end
193 end
205 end
194
206
195 context "with invalid parameters" do
207 context "with invalid parameters" do
196 setup do
208 setup do
197 @parameters = {:user => {:login => 'foo', :lastname => 'Lastname', :mail => 'foo'}}
209 @parameters = {:user => {:login => 'foo', :lastname => 'Lastname', :mail => 'foo'}}
198 end
210 end
199
211
200 context ".xml" do
212 context ".xml" do
201 should "return errors" do
213 should "return errors" do
202 assert_no_difference('User.count') do
214 assert_no_difference('User.count') do
203 post '/users.xml', @parameters, credentials('admin')
215 post '/users.xml', @parameters, credentials('admin')
204 end
216 end
205
217
206 assert_response :unprocessable_entity
218 assert_response :unprocessable_entity
207 assert_equal 'application/xml', @response.content_type
219 assert_equal 'application/xml', @response.content_type
208 assert_tag 'errors', :child => {
220 assert_tag 'errors', :child => {
209 :tag => 'error',
221 :tag => 'error',
210 :content => "First name can't be blank"
222 :content => "First name can't be blank"
211 }
223 }
212 end
224 end
213 end
225 end
214
226
215 context ".json" do
227 context ".json" do
216 should "return errors" do
228 should "return errors" do
217 assert_no_difference('User.count') do
229 assert_no_difference('User.count') do
218 post '/users.json', @parameters, credentials('admin')
230 post '/users.json', @parameters, credentials('admin')
219 end
231 end
220
232
221 assert_response :unprocessable_entity
233 assert_response :unprocessable_entity
222 assert_equal 'application/json', @response.content_type
234 assert_equal 'application/json', @response.content_type
223 json = ActiveSupport::JSON.decode(response.body)
235 json = ActiveSupport::JSON.decode(response.body)
224 assert_kind_of Hash, json
236 assert_kind_of Hash, json
225 assert json.has_key?('errors')
237 assert json.has_key?('errors')
226 assert_kind_of Array, json['errors']
238 assert_kind_of Array, json['errors']
227 end
239 end
228 end
240 end
229 end
241 end
230 end
242 end
231
243
232 context "PUT /users/2" do
244 context "PUT /users/2" do
233 context "with valid parameters" do
245 context "with valid parameters" do
234 setup do
246 setup do
235 @parameters = {
247 @parameters = {
236 :user => {
248 :user => {
237 :login => 'jsmith', :firstname => 'John', :lastname => 'Renamed',
249 :login => 'jsmith', :firstname => 'John', :lastname => 'Renamed',
238 :mail => 'jsmith@somenet.foo'
250 :mail => 'jsmith@somenet.foo'
239 }
251 }
240 }
252 }
241 end
253 end
242
254
243 context ".xml" do
255 context ".xml" do
244 should_allow_api_authentication(:put,
256 should_allow_api_authentication(:put,
245 '/users/2.xml',
257 '/users/2.xml',
246 {:user => {
258 {:user => {
247 :login => 'jsmith', :firstname => 'John', :lastname => 'Renamed',
259 :login => 'jsmith', :firstname => 'John', :lastname => 'Renamed',
248 :mail => 'jsmith@somenet.foo'
260 :mail => 'jsmith@somenet.foo'
249 }},
261 }},
250 {:success_code => :ok})
262 {:success_code => :ok})
251
263
252 should "update user with the attributes" do
264 should "update user with the attributes" do
253 assert_no_difference('User.count') do
265 assert_no_difference('User.count') do
254 put '/users/2.xml', @parameters, credentials('admin')
266 put '/users/2.xml', @parameters, credentials('admin')
255 end
267 end
256
268
257 user = User.find(2)
269 user = User.find(2)
258 assert_equal 'jsmith', user.login
270 assert_equal 'jsmith', user.login
259 assert_equal 'John', user.firstname
271 assert_equal 'John', user.firstname
260 assert_equal 'Renamed', user.lastname
272 assert_equal 'Renamed', user.lastname
261 assert_equal 'jsmith@somenet.foo', user.mail
273 assert_equal 'jsmith@somenet.foo', user.mail
262 assert !user.admin?
274 assert !user.admin?
263
275
264 assert_response :ok
276 assert_response :ok
265 assert_equal '', @response.body
277 assert_equal '', @response.body
266 end
278 end
267 end
279 end
268
280
269 context ".json" do
281 context ".json" do
270 should_allow_api_authentication(:put,
282 should_allow_api_authentication(:put,
271 '/users/2.json',
283 '/users/2.json',
272 {:user => {
284 {:user => {
273 :login => 'jsmith', :firstname => 'John', :lastname => 'Renamed',
285 :login => 'jsmith', :firstname => 'John', :lastname => 'Renamed',
274 :mail => 'jsmith@somenet.foo'
286 :mail => 'jsmith@somenet.foo'
275 }},
287 }},
276 {:success_code => :ok})
288 {:success_code => :ok})
277
289
278 should "update user with the attributes" do
290 should "update user with the attributes" do
279 assert_no_difference('User.count') do
291 assert_no_difference('User.count') do
280 put '/users/2.json', @parameters, credentials('admin')
292 put '/users/2.json', @parameters, credentials('admin')
281 end
293 end
282
294
283 user = User.find(2)
295 user = User.find(2)
284 assert_equal 'jsmith', user.login
296 assert_equal 'jsmith', user.login
285 assert_equal 'John', user.firstname
297 assert_equal 'John', user.firstname
286 assert_equal 'Renamed', user.lastname
298 assert_equal 'Renamed', user.lastname
287 assert_equal 'jsmith@somenet.foo', user.mail
299 assert_equal 'jsmith@somenet.foo', user.mail
288 assert !user.admin?
300 assert !user.admin?
289
301
290 assert_response :ok
302 assert_response :ok
291 assert_equal '', @response.body
303 assert_equal '', @response.body
292 end
304 end
293 end
305 end
294 end
306 end
295
307
296 context "with invalid parameters" do
308 context "with invalid parameters" do
297 setup do
309 setup do
298 @parameters = {
310 @parameters = {
299 :user => {
311 :user => {
300 :login => 'jsmith', :firstname => '', :lastname => 'Lastname',
312 :login => 'jsmith', :firstname => '', :lastname => 'Lastname',
301 :mail => 'foo'
313 :mail => 'foo'
302 }
314 }
303 }
315 }
304 end
316 end
305
317
306 context ".xml" do
318 context ".xml" do
307 should "return errors" do
319 should "return errors" do
308 assert_no_difference('User.count') do
320 assert_no_difference('User.count') do
309 put '/users/2.xml', @parameters, credentials('admin')
321 put '/users/2.xml', @parameters, credentials('admin')
310 end
322 end
311
323
312 assert_response :unprocessable_entity
324 assert_response :unprocessable_entity
313 assert_equal 'application/xml', @response.content_type
325 assert_equal 'application/xml', @response.content_type
314 assert_tag 'errors', :child => {
326 assert_tag 'errors', :child => {
315 :tag => 'error',
327 :tag => 'error',
316 :content => "First name can't be blank"
328 :content => "First name can't be blank"
317 }
329 }
318 end
330 end
319 end
331 end
320
332
321 context ".json" do
333 context ".json" do
322 should "return errors" do
334 should "return errors" do
323 assert_no_difference('User.count') do
335 assert_no_difference('User.count') do
324 put '/users/2.json', @parameters, credentials('admin')
336 put '/users/2.json', @parameters, credentials('admin')
325 end
337 end
326
338
327 assert_response :unprocessable_entity
339 assert_response :unprocessable_entity
328 assert_equal 'application/json', @response.content_type
340 assert_equal 'application/json', @response.content_type
329 json = ActiveSupport::JSON.decode(response.body)
341 json = ActiveSupport::JSON.decode(response.body)
330 assert_kind_of Hash, json
342 assert_kind_of Hash, json
331 assert json.has_key?('errors')
343 assert json.has_key?('errors')
332 assert_kind_of Array, json['errors']
344 assert_kind_of Array, json['errors']
333 end
345 end
334 end
346 end
335 end
347 end
336 end
348 end
337
349
338 context "DELETE /users/2" do
350 context "DELETE /users/2" do
339 context ".xml" do
351 context ".xml" do
340 should_allow_api_authentication(:delete,
352 should_allow_api_authentication(:delete,
341 '/users/2.xml',
353 '/users/2.xml',
342 {},
354 {},
343 {:success_code => :ok})
355 {:success_code => :ok})
344
356
345 should "delete user" do
357 should "delete user" do
346 assert_difference('User.count', -1) do
358 assert_difference('User.count', -1) do
347 delete '/users/2.xml', {}, credentials('admin')
359 delete '/users/2.xml', {}, credentials('admin')
348 end
360 end
349
361
350 assert_response :ok
362 assert_response :ok
351 assert_equal '', @response.body
363 assert_equal '', @response.body
352 end
364 end
353 end
365 end
354
366
355 context ".json" do
367 context ".json" do
356 should_allow_api_authentication(:delete,
368 should_allow_api_authentication(:delete,
357 '/users/2.xml',
369 '/users/2.xml',
358 {},
370 {},
359 {:success_code => :ok})
371 {:success_code => :ok})
360
372
361 should "delete user" do
373 should "delete user" do
362 assert_difference('User.count', -1) do
374 assert_difference('User.count', -1) do
363 delete '/users/2.json', {}, credentials('admin')
375 delete '/users/2.json', {}, credentials('admin')
364 end
376 end
365
377
366 assert_response :ok
378 assert_response :ok
367 assert_equal '', @response.body
379 assert_equal '', @response.body
368 end
380 end
369 end
381 end
370 end
382 end
371 end
383 end
General Comments 0
You need to be logged in to leave comments. Login now