From 479631aafc525efef151309ac257e60c73230ac0 Mon Sep 17 00:00:00 2001
From: Boyan Tabakov <boyan.tabakov@futurice.com>
Date: Wed, 31 Jul 2013 13:52:23 +0300
Subject: [PATCH] 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                | 39 ++++++++++++++++++++-------------
 lib/api/entities.rb             |  7 +++---
 lib/api/helpers.rb              |  2 +-
 lib/api/users.rb                | 14 +++++++++---
 spec/requests/api/users_spec.rb | 28 ++++++++++++++++++++++-
 5 files changed, 66 insertions(+), 24 deletions(-)

diff --git a/doc/api/users.md b/doc/api/users.md
index 49afbab8c..50c0f560d 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -23,7 +23,9 @@ GET /users
     "extern_uid": "john.smith",
     "provider": "provider_name",
     "theme_id": 1,
-    "color_scheme_id": 2
+    "color_scheme_id": 2,
+    "is_admin": false,
+    "can_create_group": true
   },
   {
     "id": 2,
@@ -39,7 +41,9 @@ GET /users
     "extern_uid": "jack.smith",
     "provider": "provider_name",
     "theme_id": 1,
-    "color_scheme_id": 3
+    "color_scheme_id": 3,
+    "is_admin": false,
+    "can_create_group": true
   }
 ]
 ```
@@ -72,7 +76,9 @@ Parameters:
   "extern_uid": "john.smith",
   "provider": "provider_name",
   "theme_id": 1,
-  "color_scheme_id": 2
+  "color_scheme_id": 2,
+  "is_admin": false,
+  "can_create_group": true
 }
 ```
 
@@ -87,17 +93,19 @@ POST /users
 
 Parameters:
 
-+ `email` (required)          - Email
-+ `password` (required)       - Password
-+ `username` (required)       - Username
-+ `name` (required)           - Name
-+ `skype` (optional)          - Skype ID
-+ `linkedin` (optional)       - Linkedin
-+ `twitter` (optional)        - Twitter account
-+ `projects_limit` (optional) - Number of projects user can create
-+ `extern_uid` (optional)     - External UID
-+ `provider` (optional)       - External provider name
-+ `bio` (optional)            - User's bio
++ `email` (required)            - Email
++ `password` (required)         - Password
++ `username` (required)         - Username
++ `name` (required)             - Name
++ `skype` (optional)            - Skype ID
++ `linkedin` (optional)         - Linkedin
++ `twitter` (optional)          - Twitter account
++ `projects_limit` (optional)   - Number of projects user can create
++ `extern_uid` (optional)       - External UID
++ `provider` (optional)         - External provider name
++ `bio` (optional)              - User's bio
++ `admin` (optional)            - User is admin - true or false (default)
++ `can_create_group` (optional) - User can create groups - true or false
 
 
 ## User modification
@@ -121,6 +129,8 @@ Parameters:
 + `extern_uid`                        - External UID
 + `provider`                          - External provider name
 + `bio`                               - User's bio
++ `admin` (optional)                  - User is admin - true or false (default)
++ `can_create_group` (optional)       - User can create groups - true or false
 
 Note, at the moment this method does only return a 404 error, even in cases where a 409 (Conflict) would
 be more appropriate, e.g. when renaming the email address to some existing one.
@@ -166,7 +176,6 @@ GET /user
   "color_scheme_id": 2,
   "is_admin": false,
   "can_create_group" : true,
-  "can_create_team" : true,
   "can_create_project" : true
 }
 ```
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index 1f35e9ec5..ab949f530 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -3,6 +3,9 @@ module API
     class User < Grape::Entity
       expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter,
              :theme_id, :color_scheme_id, :state, :created_at, :extern_uid, :provider
+      expose :is_admin?, as: :is_admin
+      expose :can_create_group?, as: :can_create_group
+      expose :can_create_project?, as: :can_create_project
     end
 
     class UserSafe < Grape::Entity
@@ -15,10 +18,6 @@ module API
 
     class UserLogin < User
       expose :private_token
-      expose :is_admin?, as: :is_admin
-      expose :can_create_group?, as: :can_create_group
-      expose :can_create_project?, as: :can_create_project
-      expose :can_create_team?, as: :can_create_team
     end
 
     class Hook < Grape::Entity
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index 4f189f351..860848b29 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -82,7 +82,7 @@ module API
     def attributes_for_keys(keys)
       attrs = {}
       keys.each do |key|
-        attrs[key] = params[key] if params[key].present?
+        attrs[key] = params[key] if params[key].present? or (params.has_key?(key) and params[key] == false)
       end
       attrs
     end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index 00dc2311f..54d3aeecb 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -40,13 +40,17 @@ module API
       #   extern_uid                        - External authentication provider UID
       #   provider                          - External provider
       #   bio                               - Bio
+      #   admin                             - User is admin - true or false (default)
+      #   can_create_group                  - User can create groups - true or false
       # Example Request:
       #   POST /users
       post do
         authenticated_as_admin!
         required_attributes! [:email, :password, :name, :username]
-        attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio]
+        attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio, :can_create_group, :admin]
         user = User.build_user(attrs, as: :admin)
+        admin = attrs.delete(:admin)
+        user.admin = admin unless admin.nil?
         if user.save
           present user, with: Entities::User
         else
@@ -67,16 +71,20 @@ module API
       #   extern_uid                        - External authentication provider UID
       #   provider                          - External provider
       #   bio                               - Bio
+      #   admin                             - User is admin - true or false (default)
+      #   can_create_group                  - User can create groups - true or false
       # Example Request:
       #   PUT /users/:id
       put ":id" do
         authenticated_as_admin!
 
-        attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio]
+        attrs = attributes_for_keys [:email, :name, :password, :skype, :linkedin, :twitter, :projects_limit, :username, :extern_uid, :provider, :bio, :can_create_group, :admin]
         user = User.find(params[:id])
         not_found!("User not found") unless user
 
-        if user.update_attributes(attrs)
+        admin = attrs.delete(:admin)
+        user.admin = admin unless admin.nil?
+        if user.update_attributes(attrs, as: :admin)
           present user, with: Entities::User
         else
           not_found!
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 2fced3ec9..4a299d3d9 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -52,6 +52,16 @@ describe API::API do
       }.to change { User.count }.by(1)
     end
 
+    it "should create user with correct attributes" do
+      post api('/users', admin), attributes_for(:user, admin: true, can_create_group: true)
+      response.status.should == 201
+      user_id = json_response['id']
+      new_user = User.find(user_id)
+      new_user.should_not == nil
+      new_user.admin.should == true
+      new_user.can_create_group.should == true
+    end
+
     it "should return 201 Created on success" do
       post api("/users", admin), attributes_for(:user, projects_limit: 3)
       response.status.should == 201
@@ -135,6 +145,8 @@ describe API::API do
   end
 
   describe "PUT /users/:id" do
+    let!(:admin_user) { create(:admin) }
+
     before { admin }
 
     it "should update user with new bio" do
@@ -144,6 +156,21 @@ describe API::API do
       user.reload.bio.should == 'new test bio'
     end
 
+    it "should update admin status" do
+      put api("/users/#{user.id}", admin), {admin: true}
+      response.status.should == 200
+      json_response['is_admin'].should == true
+      user.reload.admin.should == true
+    end
+
+    it "should not update admin status" do
+      put api("/users/#{admin_user.id}", admin), {can_create_group: false}
+      response.status.should == 200
+      json_response['is_admin'].should == true
+      admin_user.reload.admin.should == true
+      admin_user.can_create_group.should == false
+    end
+
     it "should not allow invalid update" do
       put api("/users/#{user.id}", admin), {email: 'invalid email'}
       response.status.should == 404
@@ -228,7 +255,6 @@ describe API::API do
       response.status.should == 200
       json_response['email'].should == user.email
       json_response['is_admin'].should == user.is_admin?
-      json_response['can_create_team'].should == user.can_create_team?
       json_response['can_create_project'].should == user.can_create_project?
       json_response['can_create_group'].should == user.can_create_group?
     end
-- 
2.30.9