Commit 329dee47 authored by Mark Florian's avatar Mark Florian

Merge branch 'show-current-access-level-of-token-in-ui-and-api' into 'master'

Show access level of Project Access Token in UI and API

See merge request gitlab-org/gitlab!64681
parents 2df57e51 1df3db08
...@@ -54,9 +54,13 @@ module Projects ...@@ -54,9 +54,13 @@ module Projects
end end
def set_index_vars def set_index_vars
# Loading project members so that we can fetch access level of the bot
# user in the project without multiple queries.
@project.project_members.load
@scopes = Gitlab::Auth.resource_bot_scopes @scopes = Gitlab::Auth.resource_bot_scopes
@active_project_access_tokens = finder(state: 'active').execute @active_project_access_tokens = finder(state: 'active').execute.preload_users
@inactive_project_access_tokens = finder(state: 'inactive', sort: 'expires_at_asc').execute @inactive_project_access_tokens = finder(state: 'inactive', sort: 'expires_at_asc').execute.preload_users
@new_project_access_token = PersonalAccessToken.redis_getdel(key_identity) @new_project_access_token = PersonalAccessToken.redis_getdel(key_identity)
end end
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
= render 'shared/access_tokens/table', = render 'shared/access_tokens/table',
active_tokens: @active_project_access_tokens, active_tokens: @active_project_access_tokens,
project: @project,
type: type, type: type,
type_plural: type_plural, type_plural: type_plural,
revoke_route_helper: ->(token) { revoke_namespace_project_settings_access_token_path(id: token) }, revoke_route_helper: ->(token) { revoke_namespace_project_settings_access_token_path(id: token) },
......
- no_active_tokens_message = local_assigns.fetch(:no_active_tokens_message, _('This user has no active %{type}.') % { type: type_plural }) - no_active_tokens_message = local_assigns.fetch(:no_active_tokens_message, _('This user has no active %{type}.') % { type: type_plural })
- impersonation = local_assigns.fetch(:impersonation, false) - impersonation = local_assigns.fetch(:impersonation, false)
- project = local_assigns.fetch(:project, false)
%hr %hr
...@@ -20,6 +21,8 @@ ...@@ -20,6 +21,8 @@
= _('Last Used') = _('Last Used')
= link_to sprite_icon('question-o'), help_page_path('user/profile/personal_access_tokens.md', anchor: 'view-the-last-time-a-token-was-used'), target: '_blank' = link_to sprite_icon('question-o'), help_page_path('user/profile/personal_access_tokens.md', anchor: 'view-the-last-time-a-token-was-used'), target: '_blank'
%th= _('Expires') %th= _('Expires')
- if project
%th= _('Role')
%th= _('Scopes') %th= _('Scopes')
%th %th
%tbody %tbody
...@@ -42,6 +45,8 @@ ...@@ -42,6 +45,8 @@
= _('In %{time_to_now}') % { time_to_now: distance_of_time_in_words_to_now(token.expires_at) } = _('In %{time_to_now}') % { time_to_now: distance_of_time_in_words_to_now(token.expires_at) }
- else - else
%span.token-never-expires-label= _('Never') %span.token-never-expires-label= _('Never')
- if project
%td= project.project_member(token.user).human_access
%td= token.scopes.present? ? token.scopes.join(', ') : _('no scopes selected') %td= token.scopes.present? ? token.scopes.join(', ') : _('no scopes selected')
%td= link_to _('Revoke'), revoke_route_helper.call(token), method: :put, class: 'gl-button btn btn-danger btn-sm float-right qa-revoke-button', data: { confirm: _('Are you sure you want to revoke this %{type}? This action cannot be undone.') % { type: type } } %td= link_to _('Revoke'), revoke_route_helper.call(token), method: :put, class: 'gl-button btn btn-danger btn-sm float-right qa-revoke-button', data: { confirm: _('Are you sure you want to revoke this %{type}? This action cannot be undone.') % { type: type } }
- else - else
......
...@@ -38,7 +38,8 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a ...@@ -38,7 +38,8 @@ curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/a
"id" : 42, "id" : 42,
"active" : true, "active" : true,
"created_at" : "2021-01-20T22:11:48.151Z", "created_at" : "2021-01-20T22:11:48.151Z",
"revoked" : false "revoked" : false,
"access_level": 40
} }
] ]
``` ```
...@@ -80,7 +81,8 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \ ...@@ -80,7 +81,8 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" \
"user_id" : 166, "user_id" : 166,
"id" : 58, "id" : 58,
"expires_at" : "2021-01-31", "expires_at" : "2021-01-31",
"token" : "D4y...Wzr" "token" : "D4y...Wzr",
"access_level": 40
} }
``` ```
......
# frozen_string_literal: true
module API
module Entities
class ResourceAccessToken < Entities::PersonalAccessToken
expose :access_level do |token, options|
options[:project].project_member(token.user).access_level
end
end
end
end
# frozen_string_literal: true
module API
module Entities
class ResourceAccessTokenWithToken < Entities::ResourceAccessToken
expose :token
end
end
end
...@@ -21,9 +21,10 @@ module API ...@@ -21,9 +21,10 @@ module API
next unauthorized! unless current_user.can?(:read_resource_access_tokens, resource) next unauthorized! unless current_user.can?(:read_resource_access_tokens, resource)
tokens = PersonalAccessTokensFinder.new({ user: resource.bots, impersonation: false }).execute tokens = PersonalAccessTokensFinder.new({ user: resource.bots, impersonation: false }).execute.preload_users
present paginate(tokens), with: Entities::PersonalAccessToken resource.project_members.load
present paginate(tokens), with: Entities::ResourceAccessToken, project: resource
end end
desc 'Revoke a resource access token' do desc 'Revoke a resource access token' do
...@@ -69,7 +70,7 @@ module API ...@@ -69,7 +70,7 @@ module API
).execute ).execute
if token_response.success? if token_response.success?
present token_response.payload[:access_token], with: Entities::PersonalAccessTokenWithToken present token_response.payload[:access_token], with: Entities::ResourceAccessTokenWithToken, project: resource
else else
bad_request!(token_response.message) bad_request!(token_response.message)
end end
......
...@@ -68,6 +68,7 @@ RSpec.describe 'Project > Settings > Access Tokens', :js do ...@@ -68,6 +68,7 @@ RSpec.describe 'Project > Settings > Access Tokens', :js do
expect(active_project_access_tokens).to have_text('In') expect(active_project_access_tokens).to have_text('In')
expect(active_project_access_tokens).to have_text('api') expect(active_project_access_tokens).to have_text('api')
expect(active_project_access_tokens).to have_text('read_api') expect(active_project_access_tokens).to have_text('read_api')
expect(active_project_access_tokens).to have_text('Maintainer')
expect(created_project_access_token).not_to be_empty expect(created_project_access_token).not_to be_empty
end end
......
...@@ -38,6 +38,7 @@ RSpec.describe API::ResourceAccessTokens do ...@@ -38,6 +38,7 @@ RSpec.describe API::ResourceAccessTokens do
expect(api_get_token["name"]).to eq(token.name) expect(api_get_token["name"]).to eq(token.name)
expect(api_get_token["scopes"]).to eq(token.scopes) expect(api_get_token["scopes"]).to eq(token.scopes)
expect(api_get_token["access_level"]).to eq(project.team.max_member_access(token.user.id))
expect(api_get_token["expires_at"]).to eq(token.expires_at.to_date.iso8601) expect(api_get_token["expires_at"]).to eq(token.expires_at.to_date.iso8601)
expect(api_get_token).not_to have_key('token') expect(api_get_token).not_to have_key('token')
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment