Commit 836104b41a557e8411d422c0dca7930e85b0de95

Authored by Dmitriy Zaporozhets
2 parents e48c6fab 5b657a65

Merge pull request #5213 from bladealslayer/feature/user_api_extended

Extended User API to expose admin and can_create_group for user creation...
doc/api/users.md
@@ -23,7 +23,9 @@ GET /users @@ -23,7 +23,9 @@ GET /users
23 "extern_uid": "john.smith", 23 "extern_uid": "john.smith",
24 "provider": "provider_name", 24 "provider": "provider_name",
25 "theme_id": 1, 25 "theme_id": 1,
26 - "color_scheme_id": 2 26 + "color_scheme_id": 2,
  27 + "is_admin": false,
  28 + "can_create_group": true
27 }, 29 },
28 { 30 {
29 "id": 2, 31 "id": 2,
@@ -39,7 +41,9 @@ GET /users @@ -39,7 +41,9 @@ GET /users
39 "extern_uid": "jack.smith", 41 "extern_uid": "jack.smith",
40 "provider": "provider_name", 42 "provider": "provider_name",
41 "theme_id": 1, 43 "theme_id": 1,
42 - "color_scheme_id": 3 44 + "color_scheme_id": 3,
  45 + "is_admin": false,
  46 + "can_create_group": true
43 } 47 }
44 ] 48 ]
45 ``` 49 ```
@@ -72,7 +76,9 @@ Parameters: @@ -72,7 +76,9 @@ Parameters:
72 "extern_uid": "john.smith", 76 "extern_uid": "john.smith",
73 "provider": "provider_name", 77 "provider": "provider_name",
74 "theme_id": 1, 78 "theme_id": 1,
75 - "color_scheme_id": 2 79 + "color_scheme_id": 2,
  80 + "is_admin": false,
  81 + "can_create_group": true
76 } 82 }
77 ``` 83 ```
78 84
@@ -87,17 +93,19 @@ POST /users @@ -87,17 +93,19 @@ POST /users
87 93
88 Parameters: 94 Parameters:
89 95
90 -+ `email` (required) - Email  
91 -+ `password` (required) - Password  
92 -+ `username` (required) - Username  
93 -+ `name` (required) - Name  
94 -+ `skype` (optional) - Skype ID  
95 -+ `linkedin` (optional) - Linkedin  
96 -+ `twitter` (optional) - Twitter account  
97 -+ `projects_limit` (optional) - Number of projects user can create  
98 -+ `extern_uid` (optional) - External UID  
99 -+ `provider` (optional) - External provider name  
100 -+ `bio` (optional) - User's bio 96 ++ `email` (required) - Email
  97 ++ `password` (required) - Password
  98 ++ `username` (required) - Username
  99 ++ `name` (required) - Name
  100 ++ `skype` (optional) - Skype ID
  101 ++ `linkedin` (optional) - Linkedin
  102 ++ `twitter` (optional) - Twitter account
  103 ++ `projects_limit` (optional) - Number of projects user can create
  104 ++ `extern_uid` (optional) - External UID
  105 ++ `provider` (optional) - External provider name
  106 ++ `bio` (optional) - User's bio
  107 ++ `admin` (optional) - User is admin - true or false (default)
  108 ++ `can_create_group` (optional) - User can create groups - true or false
101 109
102 110
103 ## User modification 111 ## User modification
@@ -121,6 +129,8 @@ Parameters: @@ -121,6 +129,8 @@ Parameters:
121 + `extern_uid` - External UID 129 + `extern_uid` - External UID
122 + `provider` - External provider name 130 + `provider` - External provider name
123 + `bio` - User's bio 131 + `bio` - User's bio
  132 ++ `admin` (optional) - User is admin - true or false (default)
  133 ++ `can_create_group` (optional) - User can create groups - true or false
124 134
125 Note, at the moment this method does only return a 404 error, even in cases where a 409 (Conflict) would 135 Note, at the moment this method does only return a 404 error, even in cases where a 409 (Conflict) would
126 be more appropriate, e.g. when renaming the email address to some existing one. 136 be more appropriate, e.g. when renaming the email address to some existing one.
@@ -166,7 +176,6 @@ GET /user @@ -166,7 +176,6 @@ GET /user
166 "color_scheme_id": 2, 176 "color_scheme_id": 2,
167 "is_admin": false, 177 "is_admin": false,
168 "can_create_group" : true, 178 "can_create_group" : true,
169 - "can_create_team" : true,  
170 "can_create_project" : true 179 "can_create_project" : true
171 } 180 }
172 ``` 181 ```
lib/api/entities.rb
@@ -3,6 +3,9 @@ module API @@ -3,6 +3,9 @@ module API
3 class User < Grape::Entity 3 class User < Grape::Entity
4 expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter, 4 expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter,
5 :theme_id, :color_scheme_id, :state, :created_at, :extern_uid, :provider 5 :theme_id, :color_scheme_id, :state, :created_at, :extern_uid, :provider
  6 + expose :is_admin?, as: :is_admin
  7 + expose :can_create_group?, as: :can_create_group
  8 + expose :can_create_project?, as: :can_create_project
6 end 9 end
7 10
8 class UserSafe < Grape::Entity 11 class UserSafe < Grape::Entity
@@ -15,10 +18,6 @@ module API @@ -15,10 +18,6 @@ module API
15 18
16 class UserLogin < User 19 class UserLogin < User
17 expose :private_token 20 expose :private_token
18 - expose :is_admin?, as: :is_admin  
19 - expose :can_create_group?, as: :can_create_group  
20 - expose :can_create_project?, as: :can_create_project  
21 - expose :can_create_team?, as: :can_create_team  
22 end 21 end
23 22
24 class Hook < Grape::Entity 23 class Hook < Grape::Entity
lib/api/helpers.rb
@@ -86,7 +86,7 @@ module API @@ -86,7 +86,7 @@ module API
86 def attributes_for_keys(keys) 86 def attributes_for_keys(keys)
87 attrs = {} 87 attrs = {}
88 keys.each do |key| 88 keys.each do |key|
89 - attrs[key] = params[key] if params[key].present? 89 + attrs[key] = params[key] if params[key].present? or (params.has_key?(key) and params[key] == false)
90 end 90 end
91 attrs 91 attrs
92 end 92 end
lib/api/users.rb
@@ -40,13 +40,17 @@ module API @@ -40,13 +40,17 @@ module API
40 # extern_uid - External authentication provider UID 40 # extern_uid - External authentication provider UID
41 # provider - External provider 41 # provider - External provider
42 # bio - Bio 42 # bio - Bio
  43 + # admin - User is admin - true or false (default)
  44 + # can_create_group - User can create groups - true or false
43 # Example Request: 45 # Example Request:
44 # POST /users 46 # POST /users
45 post do 47 post do
46 authenticated_as_admin! 48 authenticated_as_admin!
47 required_attributes! [:email, :password, :name, :username] 49 required_attributes! [:email, :password, :name, :username]
48 - attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] 50 + attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio, :can_create_group, :admin]
49 user = User.build_user(attrs, as: :admin) 51 user = User.build_user(attrs, as: :admin)
  52 + admin = attrs.delete(:admin)
  53 + user.admin = admin unless admin.nil?
50 if user.save 54 if user.save
51 present user, with: Entities::User 55 present user, with: Entities::User
52 else 56 else
@@ -67,16 +71,20 @@ module API @@ -67,16 +71,20 @@ module API
67 # extern_uid - External authentication provider UID 71 # extern_uid - External authentication provider UID
68 # provider - External provider 72 # provider - External provider
69 # bio - Bio 73 # bio - Bio
  74 + # admin - User is admin - true or false (default)
  75 + # can_create_group - User can create groups - true or false
70 # Example Request: 76 # Example Request:
71 # PUT /users/:id 77 # PUT /users/:id
72 put ":id" do 78 put ":id" do
73 authenticated_as_admin! 79 authenticated_as_admin!
74 80
75 - attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio] 81 + attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio, :can_create_group, :admin]
76 user = User.find(params[:id]) 82 user = User.find(params[:id])
77 not_found!("User not found") unless user 83 not_found!("User not found") unless user
78 84
79 - if user.update_attributes(attrs) 85 + admin = attrs.delete(:admin)
  86 + user.admin = admin unless admin.nil?
  87 + if user.update_attributes(attrs, as: :admin)
80 present user, with: Entities::User 88 present user, with: Entities::User
81 else 89 else
82 not_found! 90 not_found!
spec/requests/api/users_spec.rb
@@ -52,6 +52,35 @@ describe API::API do @@ -52,6 +52,35 @@ describe API::API do
52 }.to change { User.count }.by(1) 52 }.to change { User.count }.by(1)
53 end 53 end
54 54
  55 + it "should create user with correct attributes" do
  56 + post api('/users', admin), attributes_for(:user, admin: true, can_create_group: true)
  57 + response.status.should == 201
  58 + user_id = json_response['id']
  59 + new_user = User.find(user_id)
  60 + new_user.should_not == nil
  61 + new_user.admin.should == true
  62 + new_user.can_create_group.should == true
  63 + end
  64 +
  65 + it "should create non-admin user" do
  66 + post api('/users', admin), attributes_for(:user, admin: false, can_create_group: false)
  67 + response.status.should == 201
  68 + user_id = json_response['id']
  69 + new_user = User.find(user_id)
  70 + new_user.should_not == nil
  71 + new_user.admin.should == false
  72 + new_user.can_create_group.should == false
  73 + end
  74 +
  75 + it "should create non-admin users by default" do
  76 + post api('/users', admin), attributes_for(:user)
  77 + response.status.should == 201
  78 + user_id = json_response['id']
  79 + new_user = User.find(user_id)
  80 + new_user.should_not == nil
  81 + new_user.admin.should == false
  82 + end
  83 +
55 it "should return 201 Created on success" do 84 it "should return 201 Created on success" do
56 post api("/users", admin), attributes_for(:user, projects_limit: 3) 85 post api("/users", admin), attributes_for(:user, projects_limit: 3)
57 response.status.should == 201 86 response.status.should == 201
@@ -135,6 +164,8 @@ describe API::API do @@ -135,6 +164,8 @@ describe API::API do
135 end 164 end
136 165
137 describe "PUT /users/:id" do 166 describe "PUT /users/:id" do
  167 + let!(:admin_user) { create(:admin) }
  168 +
138 before { admin } 169 before { admin }
139 170
140 it "should update user with new bio" do 171 it "should update user with new bio" do
@@ -144,6 +175,21 @@ describe API::API do @@ -144,6 +175,21 @@ describe API::API do
144 user.reload.bio.should == 'new test bio' 175 user.reload.bio.should == 'new test bio'
145 end 176 end
146 177
  178 + it "should update admin status" do
  179 + put api("/users/#{user.id}", admin), {admin: true}
  180 + response.status.should == 200
  181 + json_response['is_admin'].should == true
  182 + user.reload.admin.should == true
  183 + end
  184 +
  185 + it "should not update admin status" do
  186 + put api("/users/#{admin_user.id}", admin), {can_create_group: false}
  187 + response.status.should == 200
  188 + json_response['is_admin'].should == true
  189 + admin_user.reload.admin.should == true
  190 + admin_user.can_create_group.should == false
  191 + end
  192 +
147 it "should not allow invalid update" do 193 it "should not allow invalid update" do
148 put api("/users/#{user.id}", admin), {email: 'invalid email'} 194 put api("/users/#{user.id}", admin), {email: 'invalid email'}
149 response.status.should == 404 195 response.status.should == 404
@@ -228,7 +274,6 @@ describe API::API do @@ -228,7 +274,6 @@ describe API::API do
228 response.status.should == 200 274 response.status.should == 200
229 json_response['email'].should == user.email 275 json_response['email'].should == user.email
230 json_response['is_admin'].should == user.is_admin? 276 json_response['is_admin'].should == user.is_admin?
231 - json_response['can_create_team'].should == user.can_create_team?  
232 json_response['can_create_project'].should == user.can_create_project? 277 json_response['can_create_project'].should == user.can_create_project?
233 json_response['can_create_group'].should == user.can_create_group? 278 json_response['can_create_group'].should == user.can_create_group?
234 end 279 end