Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions app/controllers/provider/admin/user/access_tokens_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ class AccessTokensController < BaseController
before_action :disable_client_cache
before_action :load_access_token, only: %i[edit update destroy]

def index
@access_tokens = access_tokens
end
helper_method :access_tokens, :service_tokens

def index; end

def new
@presenter = AccessTokensNewPresenter.new(current_account)
Expand All @@ -23,13 +23,13 @@ def new
def edit; end

def create
@presenter = AccessTokensNewPresenter.new(current_account)
@access_token = access_tokens.build(access_token_params)

if @access_token.save
flash[:token] = @access_token.id
redirect_to provider_admin_user_access_tokens_path, success: t('.success')
flash.now[:success] = t('.success')
render :show, locals: { token: @access_token }
else
@presenter = AccessTokensNewPresenter.new(current_account)
render :new
end
end
Expand Down Expand Up @@ -60,6 +60,10 @@ def access_tokens
@access_tokens ||= current_user.access_tokens
end

def service_tokens
@service_tokens ||= current_user.decorate.accessible_services_with_token
end

def load_access_token
@access_token = access_tokens.find(params[:id])
end
Expand Down
7 changes: 7 additions & 0 deletions app/decorators/user_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ def display_name
def informal_name
first_name.presence || last_name.presence || username
end

def accessible_services_with_token
return Service.none unless has_permission?(:plans)

accessible_services.joins(:service_tokens)
.includes(:service_tokens)
end
end
1 change: 1 addition & 0 deletions app/helpers/buttons_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ def action_button_to(action, url, options = {})
fancy_button_to(label, url, options)
end

# DEPRECATED: Replace with form to be independent of rails-ujs (data-method: 'delete')
# Button for deleting stuff.
#
# This is a shortcut for
Expand Down
23 changes: 8 additions & 15 deletions app/helpers/patternfly_components_helper.rb
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this component to be an icon button (much better looking) and that's why users page needed to be updated.

Original file line number Diff line number Diff line change
Expand Up @@ -62,27 +62,20 @@ def pf_toast_alert(title, **options)
end
end

# TODO: this action button is used only in app/views/provider/admin/account/users/index.html.slim
# right now, but could be used in other tables. Eliminate existing repetition by using this helper
def pf_delete_table_action(url, button_options = {})
form_attributes = { method: :delete }

button_class = 'pf-c-button pf-m-link pf-m-danger'

confirm = button_options.delete(:confirm) || 'It will be permanently delete. Are you sure?'
confirm = button_options.delete(:confirm) || I18n.t('shared.delete_button_confirm')
Comment thread
josemigallas marked this conversation as resolved.
title = button_options.delete(:title) || I18n.t('shared.delete_button_title')

button_attributes = { type: :submit,
class: button_class.strip,
class: 'pf-c-button pf-m-link pf-m-danger',
title:,
'data-confirm': confirm }.merge(button_options)

span = tag.span class: 'pf-c-button__icon pf-m-start' do
tag.i class: "fas fa-trash", 'aria-hidden': 'true'
end
label = 'Delete'

form_tag(url, form_attributes) do
form_tag(url, method: :delete) do
tag.button(**button_attributes) do
span + label
tag.span class: 'pf-c-button__icon pf-m-start' do
tag.i class: 'fas fa-trash', 'aria-hidden': 'true'
end
end
end
end
Expand Down
2 changes: 0 additions & 2 deletions app/javascript/packs/access_tokens.scss

This file was deleted.

7 changes: 7 additions & 0 deletions app/javascript/packs/pf_form.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import '~@patternfly/patternfly/components/ActionList/action-list.css';
@import '~@patternfly/patternfly/components/Button/button.css';
@import '~@patternfly/patternfly/components/Check/check.css';
@import '~@patternfly/patternfly/components/Form/form.css';
Expand All @@ -8,3 +9,9 @@
margin-top: var(--pf-c-check__body--MarginTop);
}
}

.pf-c-form__actions {
.pf-c-button.pf-m-danger {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will include action-list styles to every form and move Delete buttons to the far right (if the form implements action-list, which only CMS ones do and they already are in the right).

margin-left: auto;
}
}
1 change: 1 addition & 0 deletions app/javascript/packs/pf_text.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@import '@patternfly/patternfly/utilities/Text/text.css';
4 changes: 2 additions & 2 deletions app/lib/api_docs/provider_user_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ def access_token
end

def service_tokens
tokens = @user.accessible_service_tokens.map do |service_token|
{ name: service_token.service.name, value: service_token.value }
tokens = @user.decorate.accessible_services_with_token.map do |service|
{ name: service.name, value: service.active_service_token.value }
end
tokens.presence || [{ name: "You don't have access to any services, contact an administrator of this account.", value: '' }]
end
Expand Down
5 changes: 5 additions & 0 deletions app/lib/fields/patternfly_form_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ def output_html(field, options = {})
typed_input_field.input(self, builder_options)
end

def cancel_link(href, opts = {})
opts.reverse_merge!(class: 'pf-c-button pf-m-link', type: :button)
template.link_to(I18n.t('shared.cancel_button'), href, **opts)
end

def commit_button(title, opts = {})
raise ArgumentError, 'button_html prop will be ignored, use standard html attributes' if opts.key?(:button_html)

Expand Down
48 changes: 38 additions & 10 deletions app/models/access_token.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
# frozen_string_literal: true

class AccessToken < ApplicationRecord
DIGEST_PREFIX = 'SHA384$'

TIMESTAMP_FORMAT = '%FT%T%:z'.freeze
PAST_TIME = Time.at(0).utc.freeze
private_constant :PAST_TIME

belongs_to :owner, class_name: 'User', inverse_of: :access_tokens

attr_reader :plaintext_value

validates :name, length: { maximum: 255 }

serialize :scopes, type: Array
Expand Down Expand Up @@ -39,7 +45,7 @@ def permission_name
class Scopes
extend Forwardable

delegate %i(each count select any? map) => :scopes
delegate %i[each empty? count select any? map] => :scopes

def initialize(scopes)
@scopes = scopes
Expand Down Expand Up @@ -98,14 +104,32 @@ def self.allowed_scopes
validate :validate_scope_exists
validate :validate_expiration_date, on: %i[create]

after_initialize :generate_value
after_initialize :generate_if_missing, if: :new_record?

attr_accessible :owner, :name, :scopes, :permission, :expires_at

attr_readonly :value
def self.compute_digest(plaintext_value)
return nil if plaintext_value.blank?

hash = OpenSSL::Digest::SHA384.hexdigest(plaintext_value.to_s)
"#{DIGEST_PREFIX}#{hash}"
end

def self.find_from_value(plaintext_value)
return nil if plaintext_value.blank?

scrubbed = plaintext_value.to_s.scrub
digest = compute_digest(scrubbed)

# Fast path: find by digest (new tokens)
token = find_by(value: digest)
return token if token

def self.find_from_value(value)
find_by(value: value.to_s.scrub)
# Reject if the input looks like a stored hash (has our prefix)
return nil if scrubbed.start_with?(DIGEST_PREFIX)

# Slow path: find by plaintext (legacy tokens, no migration)
find_by(value: scrubbed)
rescue ActiveRecord::StatementInvalid, ArgumentError # utf-8 issues
nil
end
Expand Down Expand Up @@ -155,8 +179,12 @@ def validate_expiration_date
errors.add :expires_at, :invalid, message: "Date must follow ISO8601 format and be future. Example: #{1.week.from_now.utc.iso8601}."
end

def generate_value
self.value ||= self.class.random_id
def generate_if_missing
return if persisted?
return if @plaintext_value.present?

@plaintext_value = self.class.random_id
self.value = self.class.compute_digest(@plaintext_value)
end

def available_permissions
Expand All @@ -167,8 +195,8 @@ def human_permission
PERMISSIONS.key(permission)
end

def show_value?(*)
saved_changes.include?(:value)
def show_plaintext_value?(*)
@plaintext_value.present?
end

def available_scopes
Expand All @@ -180,7 +208,7 @@ def human_scopes
end

def self.random_id
SecureRandom.hex(32)
SecureRandom.hex(48)
end

def expired?
Expand Down
9 changes: 0 additions & 9 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -182,15 +182,6 @@ def allowed_access_token_scopes
AccessToken.scopes.allowed_for(self)
end

def accessible_service_tokens
if has_permission?(:plans)
accessible_services.joins(:service_tokens)
.includes(:service_tokens).map(&:active_service_token)
else
[]
end
end

def accessible_cinstances
account.provided_cinstances.permitted_for(self)

Expand Down
2 changes: 1 addition & 1 deletion app/representers/access_token_representer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ class AccessTokenRepresenter < ThreeScale::Representer
property :scopes
property :permission
property :expires_at
property :value, if: :show_value?
property :plaintext_value, as: :value, if: :show_plaintext_value?
end
20 changes: 8 additions & 12 deletions app/views/provider/admin/account/users/index.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ table class="pf-c-table pf-m-grid-lg" role="grid" aria-label="Users table" data-
- presenter.users.each do |user|
tr role="row" id=(dom_id(user))
td role="cell" data-label="Name"
- name = user.display_name
- if current_user == user
= link_to user.display_name, edit_provider_admin_user_personal_details_path(origin: 'users'),
title: t('.personal_details')
= link_to name, edit_provider_admin_user_personal_details_path(origin: 'users'),
title: t('.personal_details')
- elsif can?(:edit, user)
= link_to user.display_name, edit_provider_admin_account_user_path(user),
title: t('.edit')
= link_to name, edit_provider_admin_account_user_path(user),
title: t('.edit')
- else
= user.display_name
= name

td role="cell" data-label="Email"
= user.email
Expand Down Expand Up @@ -55,10 +56,5 @@ table class="pf-c-table pf-m-grid-lg" role="grid" aria-label="Users table" data-
- else
- if can?(:destroy, user)
div class="pf-c-overflow-menu__item"
= pf_delete_table_action provider_admin_account_user_path(user), confirm: t('.delete_user_confirm')
- if can?(:edit, user)
div class="pf-c-overflow-menu__item"
a class="pf-c-button pf-m-link" href=edit_provider_admin_account_user_path(user)
span class="pf-c-button__icon pf-m-start"
i class="fas fa-pencil-alt" aria-hidden="true"
= t('.edit')
= pf_delete_table_action provider_admin_account_user_path(user), title: t('.delete_user_title', name:),
confirm: t('.delete_user_confirm')
6 changes: 3 additions & 3 deletions app/views/provider/admin/user/access_tokens/edit.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ div class="pf-c-card"

= f.actions do
= f.commit_button t('.submit_button_label')
= f.cancel_link provider_admin_user_access_tokens_path
= f.delete_button 'Delete', provider_admin_user_access_token_path(@access_token),
data: { confirm: 'Are you sure?' },
title: 'Delete Access Token'

data: { confirm: t('.delete_confirm') },
title: t('.delete_title')
Loading