Commit 479631aafc525efef151309ac257e60c73230ac0

Authored by Boyan Tabakov
1 parent cbb5b000

Extended User API to expose admin and can_create_group for user creation/updating.

Also, is_admin and can_create_group are exposed in the user information.
Fixed attributes_for_keys to process properly keys with boolean values (since false.present? is false).
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
@@ -82,7 +82,7 @@ module API @@ -82,7 +82,7 @@ module API
82 def attributes_for_keys(keys) 82 def attributes_for_keys(keys)
83 attrs = {} 83 attrs = {}
84 keys.each do |key| 84 keys.each do |key|
85 - attrs[key] = params[key] if params[key].present? 85 + attrs[key] = params[key] if params[key].present? or (params.has_key?(key) and params[key] == false)
86 end 86 end
87 attrs 87 attrs
88 end 88 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,16 @@ describe API::API do @@ -52,6 +52,16 @@ 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 +
55 it "should return 201 Created on success" do 65 it "should return 201 Created on success" do
56 post api("/users", admin), attributes_for(:user, projects_limit: 3) 66 post api("/users", admin), attributes_for(:user, projects_limit: 3)
57 response.status.should == 201 67 response.status.should == 201
@@ -135,6 +145,8 @@ describe API::API do @@ -135,6 +145,8 @@ describe API::API do
135 end 145 end
136 146
137 describe "PUT /users/:id" do 147 describe "PUT /users/:id" do
  148 + let!(:admin_user) { create(:admin) }
  149 +
138 before { admin } 150 before { admin }
139 151
140 it "should update user with new bio" do 152 it "should update user with new bio" do
@@ -144,6 +156,21 @@ describe API::API do @@ -144,6 +156,21 @@ describe API::API do
144 user.reload.bio.should == 'new test bio' 156 user.reload.bio.should == 'new test bio'
145 end 157 end
146 158
  159 + it "should update admin status" do
  160 + put api("/users/#{user.id}", admin), {admin: true}
  161 + response.status.should == 200
  162 + json_response['is_admin'].should == true
  163 + user.reload.admin.should == true
  164 + end
  165 +
  166 + it "should not update admin status" do
  167 + put api("/users/#{admin_user.id}", admin), {can_create_group: false}
  168 + response.status.should == 200
  169 + json_response['is_admin'].should == true
  170 + admin_user.reload.admin.should == true
  171 + admin_user.can_create_group.should == false
  172 + end
  173 +
147 it "should not allow invalid update" do 174 it "should not allow invalid update" do
148 put api("/users/#{user.id}", admin), {email: 'invalid email'} 175 put api("/users/#{user.id}", admin), {email: 'invalid email'}
149 response.status.should == 404 176 response.status.should == 404
@@ -228,7 +255,6 @@ describe API::API do @@ -228,7 +255,6 @@ describe API::API do
228 response.status.should == 200 255 response.status.should == 200
229 json_response['email'].should == user.email 256 json_response['email'].should == user.email
230 json_response['is_admin'].should == user.is_admin? 257 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? 258 json_response['can_create_project'].should == user.can_create_project?
233 json_response['can_create_group'].should == user.can_create_group? 259 json_response['can_create_group'].should == user.can_create_group?
234 end 260 end