Commit 87fd342a2317567f7854570dd5624dd64dffebd4
Exists in
spb-stable
and in
2 other branches
Merge branch 'more-secure-api' into 'master'
More secure api Dont expose user email via API. Fixes #1314
Showing
17 changed files
with
161 additions
and
64 deletions
Show diff stats
CHANGELOG
| @@ -35,6 +35,7 @@ v 7.0.0 | @@ -35,6 +35,7 @@ v 7.0.0 | ||
| 35 | - Be more selective when killing stray Sidekiqs | 35 | - Be more selective when killing stray Sidekiqs |
| 36 | - Check LDAP user filter during sign-in | 36 | - Check LDAP user filter during sign-in |
| 37 | - Remove wall feature (no data loss - you can take it from database) | 37 | - Remove wall feature (no data loss - you can take it from database) |
| 38 | + - Dont expose user emails via API unless you are admin | ||
| 38 | 39 | ||
| 39 | v 6.9.2 | 40 | v 6.9.2 |
| 40 | - Revert the commit that broke the LDAP user filter | 41 | - Revert the commit that broke the LDAP user filter |
app/assets/javascripts/project_users_select.js.coffee
| @@ -37,13 +37,9 @@ | @@ -37,13 +37,9 @@ | ||
| 37 | 37 | ||
| 38 | projectUserFormatResult: (user) -> | 38 | projectUserFormatResult: (user) -> |
| 39 | if user.avatar_url | 39 | if user.avatar_url |
| 40 | - avatar = gon.relative_url_root + user.avatar_url | ||
| 41 | - else if gon.gravatar_enabled | ||
| 42 | - avatar = gon.gravatar_url | ||
| 43 | - avatar = avatar.replace('%{hash}', md5(user.email)) | ||
| 44 | - avatar = avatar.replace('%{size}', '24') | 40 | + avatar = user.avatar_url |
| 45 | else | 41 | else |
| 46 | - avatar = gon.relative_url_root + "#{image_path('no_avatar.png')}" | 42 | + avatar = gon.default_avatar_url |
| 47 | 43 | ||
| 48 | if user.id == '' | 44 | if user.id == '' |
| 49 | avatarMarkup = '' | 45 | avatarMarkup = '' |
app/assets/javascripts/users_select.js.coffee
| 1 | $ -> | 1 | $ -> |
| 2 | userFormatResult = (user) -> | 2 | userFormatResult = (user) -> |
| 3 | if user.avatar_url | 3 | if user.avatar_url |
| 4 | - avatar = gon.relative_url_root + user.avatar_url | ||
| 5 | - else if gon.gravatar_enabled | ||
| 6 | - avatar = gon.gravatar_url | ||
| 7 | - avatar = avatar.replace('%{hash}', md5(user.email)) | ||
| 8 | - avatar = avatar.replace('%{size}', '24') | 4 | + avatar = user.avatar_url |
| 9 | else | 5 | else |
| 10 | - avatar = gon.relative_url_root + "#{image_path('no_avatar.png')}" | 6 | + avatar = gon.default_avatar_url |
| 11 | 7 | ||
| 12 | "<div class='user-result'> | 8 | "<div class='user-result'> |
| 13 | <div class='user-image'><img class='avatar s24' src='#{avatar}'></div> | 9 | <div class='user-image'><img class='avatar s24' src='#{avatar}'></div> |
app/controllers/application_controller.rb
| @@ -164,9 +164,8 @@ class ApplicationController < ActionController::Base | @@ -164,9 +164,8 @@ class ApplicationController < ActionController::Base | ||
| 164 | def add_gon_variables | 164 | def add_gon_variables |
| 165 | gon.default_issues_tracker = Project.issues_tracker.default_value | 165 | gon.default_issues_tracker = Project.issues_tracker.default_value |
| 166 | gon.api_version = API::API.version | 166 | gon.api_version = API::API.version |
| 167 | - gon.gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url | ||
| 168 | gon.relative_url_root = Gitlab.config.gitlab.relative_url_root | 167 | gon.relative_url_root = Gitlab.config.gitlab.relative_url_root |
| 169 | - gon.gravatar_enabled = Gitlab.config.gravatar.enabled | 168 | + gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s |
| 170 | 169 | ||
| 171 | if current_user | 170 | if current_user |
| 172 | gon.current_user_id = current_user.id | 171 | gon.current_user_id = current_user.id |
app/helpers/application_helper.rb
| @@ -60,23 +60,21 @@ module ApplicationHelper | @@ -60,23 +60,21 @@ module ApplicationHelper | ||
| 60 | 60 | ||
| 61 | def avatar_icon(user_email = '', size = nil) | 61 | def avatar_icon(user_email = '', size = nil) |
| 62 | user = User.find_by(email: user_email) | 62 | user = User.find_by(email: user_email) |
| 63 | - if user && user.avatar.present? | ||
| 64 | - user.avatar.url | 63 | + |
| 64 | + if user | ||
| 65 | + user.avatar_url(size) || default_avatar | ||
| 65 | else | 66 | else |
| 66 | gravatar_icon(user_email, size) | 67 | gravatar_icon(user_email, size) |
| 67 | end | 68 | end |
| 68 | end | 69 | end |
| 69 | 70 | ||
| 70 | def gravatar_icon(user_email = '', size = nil) | 71 | def gravatar_icon(user_email = '', size = nil) |
| 71 | - size = 40 if size.nil? || size <= 0 | 72 | + GravatarService.new.execute(user_email, size) || |
| 73 | + default_avatar | ||
| 74 | + end | ||
| 72 | 75 | ||
| 73 | - if !Gitlab.config.gravatar.enabled || user_email.blank? | ||
| 74 | - image_path('no_avatar.png') | ||
| 75 | - else | ||
| 76 | - gravatar_url = request.ssl? || gitlab_config.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url | ||
| 77 | - user_email.strip! | ||
| 78 | - sprintf gravatar_url, hash: Digest::MD5.hexdigest(user_email.downcase), size: size, email: user_email | ||
| 79 | - end | 76 | + def default_avatar |
| 77 | + image_path('no_avatar.png') | ||
| 80 | end | 78 | end |
| 81 | 79 | ||
| 82 | def last_commit(project) | 80 | def last_commit(project) |
app/models/user.rb
| @@ -482,4 +482,12 @@ class User < ActiveRecord::Base | @@ -482,4 +482,12 @@ class User < ActiveRecord::Base | ||
| 482 | def public_profile? | 482 | def public_profile? |
| 483 | authorized_projects.public_only.any? | 483 | authorized_projects.public_only.any? |
| 484 | end | 484 | end |
| 485 | + | ||
| 486 | + def avatar_url(size = nil) | ||
| 487 | + if avatar.present? | ||
| 488 | + URI::join(Gitlab.config.gitlab.url, avatar.url).to_s | ||
| 489 | + else | ||
| 490 | + GravatarService.new.execute(email, size) | ||
| 491 | + end | ||
| 492 | + end | ||
| 485 | end | 493 | end |
| @@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
| 1 | +class GravatarService | ||
| 2 | + def execute(email, size = nil) | ||
| 3 | + if gravatar_config.enabled && email.present? | ||
| 4 | + size = 40 if size.nil? || size <= 0 | ||
| 5 | + | ||
| 6 | + sprintf gravatar_url, | ||
| 7 | + hash: Digest::MD5.hexdigest(email.strip.downcase), | ||
| 8 | + size: size, | ||
| 9 | + email: email.strip | ||
| 10 | + end | ||
| 11 | + end | ||
| 12 | + | ||
| 13 | + def gitlab_config | ||
| 14 | + Gitlab.config.gitlab | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + def gravatar_config | ||
| 18 | + Gitlab.config.gravatar | ||
| 19 | + end | ||
| 20 | + | ||
| 21 | + def gravatar_url | ||
| 22 | + if gitlab_config.https | ||
| 23 | + gravatar_config.ssl_url | ||
| 24 | + else | ||
| 25 | + gravatar_config.plain_url | ||
| 26 | + end | ||
| 27 | + end | ||
| 28 | +end |
doc/api/users.md
| @@ -6,6 +6,34 @@ Get a list of users. | @@ -6,6 +6,34 @@ Get a list of users. | ||
| 6 | 6 | ||
| 7 | This function takes pagination parameters `page` and `per_page` to restrict the list of users. | 7 | This function takes pagination parameters `page` and `per_page` to restrict the list of users. |
| 8 | 8 | ||
| 9 | +### For normal users: | ||
| 10 | + | ||
| 11 | +``` | ||
| 12 | +GET /users | ||
| 13 | +``` | ||
| 14 | + | ||
| 15 | +```json | ||
| 16 | +[ | ||
| 17 | + { | ||
| 18 | + "id": 1, | ||
| 19 | + "username": "john_smith", | ||
| 20 | + "name": "John Smith", | ||
| 21 | + "state": "active", | ||
| 22 | + "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg", | ||
| 23 | + }, | ||
| 24 | + { | ||
| 25 | + "id": 2, | ||
| 26 | + "username": "jack_smith", | ||
| 27 | + "name": "Jack Smith", | ||
| 28 | + "state": "blocked", | ||
| 29 | + "avatar_url": "http://gravatar.com/../e32131cd8.jpeg", | ||
| 30 | + } | ||
| 31 | +] | ||
| 32 | +``` | ||
| 33 | + | ||
| 34 | + | ||
| 35 | +### For admins: | ||
| 36 | + | ||
| 9 | ``` | 37 | ``` |
| 10 | GET /users | 38 | GET /users |
| 11 | ``` | 39 | ``` |
| @@ -29,6 +57,7 @@ GET /users | @@ -29,6 +57,7 @@ GET /users | ||
| 29 | "theme_id": 1, | 57 | "theme_id": 1, |
| 30 | "color_scheme_id": 2, | 58 | "color_scheme_id": 2, |
| 31 | "is_admin": false, | 59 | "is_admin": false, |
| 60 | + "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg", | ||
| 32 | "can_create_group": true | 61 | "can_create_group": true |
| 33 | }, | 62 | }, |
| 34 | { | 63 | { |
| @@ -48,6 +77,7 @@ GET /users | @@ -48,6 +77,7 @@ GET /users | ||
| 48 | "theme_id": 1, | 77 | "theme_id": 1, |
| 49 | "color_scheme_id": 3, | 78 | "color_scheme_id": 3, |
| 50 | "is_admin": false, | 79 | "is_admin": false, |
| 80 | + "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg", | ||
| 51 | "can_create_group": true, | 81 | "can_create_group": true, |
| 52 | "can_create_project": true | 82 | "can_create_project": true |
| 53 | } | 83 | } |
| @@ -62,6 +92,29 @@ Also see `def search query` in `app/models/user.rb`. | @@ -62,6 +92,29 @@ Also see `def search query` in `app/models/user.rb`. | ||
| 62 | 92 | ||
| 63 | Get a single user. | 93 | Get a single user. |
| 64 | 94 | ||
| 95 | +#### For user: | ||
| 96 | + | ||
| 97 | +``` | ||
| 98 | +GET /users/:id | ||
| 99 | +``` | ||
| 100 | + | ||
| 101 | +Parameters: | ||
| 102 | + | ||
| 103 | +- `id` (required) - The ID of a user | ||
| 104 | + | ||
| 105 | +```json | ||
| 106 | +{ | ||
| 107 | + "id": 1, | ||
| 108 | + "username": "john_smith", | ||
| 109 | + "name": "John Smith", | ||
| 110 | + "state": "active", | ||
| 111 | + "avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg", | ||
| 112 | +} | ||
| 113 | +``` | ||
| 114 | + | ||
| 115 | + | ||
| 116 | +#### For admin: | ||
| 117 | + | ||
| 65 | ``` | 118 | ``` |
| 66 | GET /users/:id | 119 | GET /users/:id |
| 67 | ``` | 120 | ``` |
lib/api/entities.rb
| 1 | module API | 1 | module API |
| 2 | module Entities | 2 | module Entities |
| 3 | - class User < Grape::Entity | ||
| 4 | - expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter, :website_url, | ||
| 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 | 3 | + class UserSafe < Grape::Entity |
| 4 | + expose :name, :username | ||
| 5 | + end | ||
| 9 | 6 | ||
| 10 | - expose :avatar_url do |user, options| | ||
| 11 | - if user.avatar.present? | ||
| 12 | - user.avatar.url | ||
| 13 | - end | ||
| 14 | - end | 7 | + class UserBasic < UserSafe |
| 8 | + expose :id, :state, :avatar_url | ||
| 15 | end | 9 | end |
| 16 | 10 | ||
| 17 | - class UserSafe < Grape::Entity | ||
| 18 | - expose :name, :username | 11 | + class User < UserBasic |
| 12 | + expose :created_at | ||
| 13 | + expose :is_admin?, as: :is_admin | ||
| 14 | + expose :bio, :skype, :linkedin, :twitter, :website_url | ||
| 19 | end | 15 | end |
| 20 | 16 | ||
| 21 | - class UserBasic < Grape::Entity | ||
| 22 | - expose :id, :username, :email, :name, :state, :created_at | 17 | + class UserFull < User |
| 18 | + expose :email | ||
| 19 | + expose :theme_id, :color_scheme_id, :extern_uid, :provider | ||
| 20 | + expose :can_create_group?, as: :can_create_group | ||
| 21 | + expose :can_create_project?, as: :can_create_project | ||
| 23 | end | 22 | end |
| 24 | 23 | ||
| 25 | - class UserLogin < User | 24 | + class UserLogin < UserFull |
| 26 | expose :private_token | 25 | expose :private_token |
| 27 | end | 26 | end |
| 28 | 27 |
lib/api/internal.rb
lib/api/projects.rb
| @@ -209,7 +209,7 @@ module API | @@ -209,7 +209,7 @@ module API | ||
| 209 | @users = User.where(id: user_project.team.users.map(&:id)) | 209 | @users = User.where(id: user_project.team.users.map(&:id)) |
| 210 | @users = @users.search(params[:search]) if params[:search].present? | 210 | @users = @users.search(params[:search]) if params[:search].present? |
| 211 | @users = paginate @users | 211 | @users = paginate @users |
| 212 | - present @users, with: Entities::User | 212 | + present @users, with: Entities::UserBasic |
| 213 | end | 213 | end |
| 214 | 214 | ||
| 215 | # Get a project labels | 215 | # Get a project labels |
lib/api/users.rb
| @@ -13,7 +13,12 @@ module API | @@ -13,7 +13,12 @@ module API | ||
| 13 | @users = @users.active if params[:active].present? | 13 | @users = @users.active if params[:active].present? |
| 14 | @users = @users.search(params[:search]) if params[:search].present? | 14 | @users = @users.search(params[:search]) if params[:search].present? |
| 15 | @users = paginate @users | 15 | @users = paginate @users |
| 16 | - present @users, with: Entities::User | 16 | + |
| 17 | + if current_user.is_admin? | ||
| 18 | + present @users, with: Entities::UserFull | ||
| 19 | + else | ||
| 20 | + present @users, with: Entities::UserBasic | ||
| 21 | + end | ||
| 17 | end | 22 | end |
| 18 | 23 | ||
| 19 | # Get a single user | 24 | # Get a single user |
| @@ -24,7 +29,12 @@ module API | @@ -24,7 +29,12 @@ module API | ||
| 24 | # GET /users/:id | 29 | # GET /users/:id |
| 25 | get ":id" do | 30 | get ":id" do |
| 26 | @user = User.find(params[:id]) | 31 | @user = User.find(params[:id]) |
| 27 | - present @user, with: Entities::User | 32 | + |
| 33 | + if current_user.is_admin? | ||
| 34 | + present @user, with: Entities::UserFull | ||
| 35 | + else | ||
| 36 | + present @user, with: Entities::UserBasic | ||
| 37 | + end | ||
| 28 | end | 38 | end |
| 29 | 39 | ||
| 30 | # Create user. Available only for admin | 40 | # Create user. Available only for admin |
| @@ -53,7 +63,7 @@ module API | @@ -53,7 +63,7 @@ module API | ||
| 53 | admin = attrs.delete(:admin) | 63 | admin = attrs.delete(:admin) |
| 54 | user.admin = admin unless admin.nil? | 64 | user.admin = admin unless admin.nil? |
| 55 | if user.save | 65 | if user.save |
| 56 | - present user, with: Entities::User | 66 | + present user, with: Entities::UserFull |
| 57 | else | 67 | else |
| 58 | not_found! | 68 | not_found! |
| 59 | end | 69 | end |
| @@ -87,7 +97,7 @@ module API | @@ -87,7 +97,7 @@ module API | ||
| 87 | admin = attrs.delete(:admin) | 97 | admin = attrs.delete(:admin) |
| 88 | user.admin = admin unless admin.nil? | 98 | user.admin = admin unless admin.nil? |
| 89 | if user.update_attributes(attrs, as: :admin) | 99 | if user.update_attributes(attrs, as: :admin) |
| 90 | - present user, with: Entities::User | 100 | + present user, with: Entities::UserFull |
| 91 | else | 101 | else |
| 92 | not_found! | 102 | not_found! |
| 93 | end | 103 | end |
spec/helpers/application_helper_spec.rb
| @@ -67,10 +67,9 @@ describe ApplicationHelper do | @@ -67,10 +67,9 @@ describe ApplicationHelper do | ||
| 67 | end | 67 | end |
| 68 | 68 | ||
| 69 | it "should call gravatar_icon when no avatar is present" do | 69 | it "should call gravatar_icon when no avatar is present" do |
| 70 | - user = create(:user) | 70 | + user = create(:user, email: 'test@example.com') |
| 71 | user.save! | 71 | user.save! |
| 72 | - allow(self).to receive(:gravatar_icon).and_return('gravatar_method_called') | ||
| 73 | - avatar_icon(user.email).to_s.should == "gravatar_method_called" | 72 | + avatar_icon(user.email).to_s.should == "http://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=40&d=mm" |
| 74 | end | 73 | end |
| 75 | end | 74 | end |
| 76 | 75 | ||
| @@ -87,12 +86,12 @@ describe ApplicationHelper do | @@ -87,12 +86,12 @@ describe ApplicationHelper do | ||
| 87 | end | 86 | end |
| 88 | 87 | ||
| 89 | it "should return default gravatar url" do | 88 | it "should return default gravatar url" do |
| 90 | - allow(self).to receive(:request).and_return(double(:ssl? => false)) | 89 | + Gitlab.config.gitlab.stub(https: false) |
| 91 | gravatar_icon(user_email).should match('http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118') | 90 | gravatar_icon(user_email).should match('http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118') |
| 92 | end | 91 | end |
| 93 | 92 | ||
| 94 | it "should use SSL when appropriate" do | 93 | it "should use SSL when appropriate" do |
| 95 | - allow(self).to receive(:request).and_return(double(:ssl? => true)) | 94 | + Gitlab.config.gitlab.stub(https: true) |
| 96 | gravatar_icon(user_email).should match('https://secure.gravatar.com') | 95 | gravatar_icon(user_email).should match('https://secure.gravatar.com') |
| 97 | end | 96 | end |
| 98 | 97 |
spec/requests/api/notes_spec.rb
| @@ -93,7 +93,7 @@ describe API::API, api: true do | @@ -93,7 +93,7 @@ describe API::API, api: true do | ||
| 93 | post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!' | 93 | post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!' |
| 94 | response.status.should == 201 | 94 | response.status.should == 201 |
| 95 | json_response['body'].should == 'hi!' | 95 | json_response['body'].should == 'hi!' |
| 96 | - json_response['author']['email'].should == user.email | 96 | + json_response['author']['username'].should == user.username |
| 97 | end | 97 | end |
| 98 | 98 | ||
| 99 | it "should return a 400 bad request error if body not given" do | 99 | it "should return a 400 bad request error if body not given" do |
| @@ -112,7 +112,7 @@ describe API::API, api: true do | @@ -112,7 +112,7 @@ describe API::API, api: true do | ||
| 112 | post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!' | 112 | post api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user), body: 'hi!' |
| 113 | response.status.should == 201 | 113 | response.status.should == 201 |
| 114 | json_response['body'].should == 'hi!' | 114 | json_response['body'].should == 'hi!' |
| 115 | - json_response['author']['email'].should == user.email | 115 | + json_response['author']['username'].should == user.username |
| 116 | end | 116 | end |
| 117 | 117 | ||
| 118 | it "should return a 400 bad request error if body not given" do | 118 | it "should return a 400 bad request error if body not given" do |
spec/requests/api/project_members_spec.rb
| @@ -21,7 +21,7 @@ describe API::API, api: true do | @@ -21,7 +21,7 @@ describe API::API, api: true do | ||
| 21 | response.status.should == 200 | 21 | response.status.should == 200 |
| 22 | json_response.should be_an Array | 22 | json_response.should be_an Array |
| 23 | json_response.count.should == 2 | 23 | json_response.count.should == 2 |
| 24 | - json_response.map { |u| u['email'] }.should include user.email | 24 | + json_response.map { |u| u['username'] }.should include user.username |
| 25 | end | 25 | end |
| 26 | 26 | ||
| 27 | it "finds team members with query string" do | 27 | it "finds team members with query string" do |
| @@ -29,7 +29,7 @@ describe API::API, api: true do | @@ -29,7 +29,7 @@ describe API::API, api: true do | ||
| 29 | response.status.should == 200 | 29 | response.status.should == 200 |
| 30 | json_response.should be_an Array | 30 | json_response.should be_an Array |
| 31 | json_response.count.should == 1 | 31 | json_response.count.should == 1 |
| 32 | - json_response.first['email'].should == user.email | 32 | + json_response.first['username'].should == user.username |
| 33 | end | 33 | end |
| 34 | 34 | ||
| 35 | it "should return a 404 error if id not found" do | 35 | it "should return a 404 error if id not found" do |
| @@ -44,7 +44,7 @@ describe API::API, api: true do | @@ -44,7 +44,7 @@ describe API::API, api: true do | ||
| 44 | it "should return project team member" do | 44 | it "should return project team member" do |
| 45 | get api("/projects/#{project.id}/members/#{user.id}", user) | 45 | get api("/projects/#{project.id}/members/#{user.id}", user) |
| 46 | response.status.should == 200 | 46 | response.status.should == 200 |
| 47 | - json_response['email'].should == user.email | 47 | + json_response['username'].should == user.username |
| 48 | json_response['access_level'].should == UsersProject::MASTER | 48 | json_response['access_level'].should == UsersProject::MASTER |
| 49 | end | 49 | end |
| 50 | 50 | ||
| @@ -62,7 +62,7 @@ describe API::API, api: true do | @@ -62,7 +62,7 @@ describe API::API, api: true do | ||
| 62 | }.to change { UsersProject.count }.by(1) | 62 | }.to change { UsersProject.count }.by(1) |
| 63 | 63 | ||
| 64 | response.status.should == 201 | 64 | response.status.should == 201 |
| 65 | - json_response['email'].should == user2.email | 65 | + json_response['username'].should == user2.username |
| 66 | json_response['access_level'].should == UsersProject::DEVELOPER | 66 | json_response['access_level'].should == UsersProject::DEVELOPER |
| 67 | end | 67 | end |
| 68 | 68 | ||
| @@ -75,7 +75,7 @@ describe API::API, api: true do | @@ -75,7 +75,7 @@ describe API::API, api: true do | ||
| 75 | }.not_to change { UsersProject.count }.by(1) | 75 | }.not_to change { UsersProject.count }.by(1) |
| 76 | 76 | ||
| 77 | response.status.should == 201 | 77 | response.status.should == 201 |
| 78 | - json_response['email'].should == user2.email | 78 | + json_response['username'].should == user2.username |
| 79 | json_response['access_level'].should == UsersProject::DEVELOPER | 79 | json_response['access_level'].should == UsersProject::DEVELOPER |
| 80 | end | 80 | end |
| 81 | 81 | ||
| @@ -101,7 +101,7 @@ describe API::API, api: true do | @@ -101,7 +101,7 @@ describe API::API, api: true do | ||
| 101 | it "should update project team member" do | 101 | it "should update project team member" do |
| 102 | put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: UsersProject::MASTER | 102 | put api("/projects/#{project.id}/members/#{user3.id}", user), access_level: UsersProject::MASTER |
| 103 | response.status.should == 200 | 103 | response.status.should == 200 |
| 104 | - json_response['email'].should == user3.email | 104 | + json_response['username'].should == user3.username |
| 105 | json_response['access_level'].should == UsersProject::MASTER | 105 | json_response['access_level'].should == UsersProject::MASTER |
| 106 | end | 106 | end |
| 107 | 107 |
spec/requests/api/projects_spec.rb
| @@ -37,7 +37,7 @@ describe API::API, api: true do | @@ -37,7 +37,7 @@ describe API::API, api: true do | ||
| 37 | response.status.should == 200 | 37 | response.status.should == 200 |
| 38 | json_response.should be_an Array | 38 | json_response.should be_an Array |
| 39 | json_response.first['name'].should == project.name | 39 | json_response.first['name'].should == project.name |
| 40 | - json_response.first['owner']['email'].should == user.email | 40 | + json_response.first['owner']['username'].should == user.username |
| 41 | end | 41 | end |
| 42 | end | 42 | end |
| 43 | end | 43 | end |
| @@ -65,7 +65,7 @@ describe API::API, api: true do | @@ -65,7 +65,7 @@ describe API::API, api: true do | ||
| 65 | response.status.should == 200 | 65 | response.status.should == 200 |
| 66 | json_response.should be_an Array | 66 | json_response.should be_an Array |
| 67 | json_response.first['name'].should == project.name | 67 | json_response.first['name'].should == project.name |
| 68 | - json_response.first['owner']['email'].should == user.email | 68 | + json_response.first['owner']['username'].should == user.username |
| 69 | end | 69 | end |
| 70 | end | 70 | end |
| 71 | end | 71 | end |
| @@ -270,7 +270,7 @@ describe API::API, api: true do | @@ -270,7 +270,7 @@ describe API::API, api: true do | ||
| 270 | get api("/projects/#{project.id}", user) | 270 | get api("/projects/#{project.id}", user) |
| 271 | response.status.should == 200 | 271 | response.status.should == 200 |
| 272 | json_response['name'].should == project.name | 272 | json_response['name'].should == project.name |
| 273 | - json_response['owner']['email'].should == user.email | 273 | + json_response['owner']['username'].should == user.username |
| 274 | end | 274 | end |
| 275 | 275 | ||
| 276 | it "should return a project by path name" do | 276 | it "should return a project by path name" do |
spec/requests/api/users_spec.rb
| @@ -20,7 +20,18 @@ describe API::API, api: true do | @@ -20,7 +20,18 @@ describe API::API, api: true do | ||
| 20 | get api("/users", user) | 20 | get api("/users", user) |
| 21 | response.status.should == 200 | 21 | response.status.should == 200 |
| 22 | json_response.should be_an Array | 22 | json_response.should be_an Array |
| 23 | - json_response.first['email'].should == user.email | 23 | + json_response.first['username'].should == user.username |
| 24 | + end | ||
| 25 | + end | ||
| 26 | + | ||
| 27 | + context "when admin" do | ||
| 28 | + it "should return an array of users" do | ||
| 29 | + get api("/users", admin) | ||
| 30 | + response.status.should == 200 | ||
| 31 | + json_response.should be_an Array | ||
| 32 | + json_response.first.keys.should include 'email' | ||
| 33 | + json_response.first.keys.should include 'extern_uid' | ||
| 34 | + json_response.first.keys.should include 'can_create_project' | ||
| 24 | end | 35 | end |
| 25 | end | 36 | end |
| 26 | end | 37 | end |
| @@ -29,7 +40,7 @@ describe API::API, api: true do | @@ -29,7 +40,7 @@ describe API::API, api: true do | ||
| 29 | it "should return a user by id" do | 40 | it "should return a user by id" do |
| 30 | get api("/users/#{user.id}", user) | 41 | get api("/users/#{user.id}", user) |
| 31 | response.status.should == 200 | 42 | response.status.should == 200 |
| 32 | - json_response['email'].should == user.email | 43 | + json_response['username'].should == user.username |
| 33 | end | 44 | end |
| 34 | 45 | ||
| 35 | it "should return a 401 if unauthenticated" do | 46 | it "should return a 401 if unauthenticated" do |