trabajo-afectivo/app/controllers/user_access_token_controller.rb

122 lines
3.4 KiB
Ruby
Raw Normal View History

2022-01-01 13:38:12 +00:00
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
class UserAccessTokenController < ApplicationController
prepend_before_action { authentication_check && authorize! }
=begin
Resource:
GET /api/v1/user_access_token
Response:
{
"tokens":[
{"id":1,"label":"some user access token","preferences":{"permission":["cti.agent","ticket.agent"]},"last_used_at":null,"expires_at":null,"created_at":"2018-07-11T08:18:56.947Z"}
{"id":2,"label":"some user access token 2","preferences":{"permission":[ticket.agent"]},"last_used_at":null,"expires_at":null,"created_at":"2018-07-11T08:18:56.947Z"}
],
"permissions":[
{id: 1, name: "admin", note: "Admin Interface", preferences: {}, active: true,...},
{id: 2, name: "admin.user", note: "Manage Users", preferences: {}, active: true,...},
...
]
}
Test:
curl http://localhost/api/v1/user_access_token -v -u #{login}:#{password}
=end
def index
Refactoring: Clarify complex Permission queries This commit was prepared to facilitate a larger refactoring assignment as part of the Pundit migration. As a bonus, it includes some SQL query optimizations! === Why was this refactoring necessary? It's not, strictly speaking. But the Pundit migration involves taking complex querying logic and moving it into Scope classes as appropriate, and deciding where things belong is really difficult when you can't see what they're doing. === So how does this refactoring fix the problem? * It replaces raw SQL queries with Ruby-esque ActiveRecord queries. * It replaces complex, procedural code that's full of loops and obscure local variable assignment with compact, cleanly-formatted code that follows Ruby idioms and uses meaningful variable names. In my opinion, it's much faster and easier to understand what the code does this way. === What kinds of SQL query optimizations are included? * n+1 query: user_access_token#index instantiated all active permissions and then called current_user.permissions? on _every single one._ A fresh installation of Zammad contains 57 permissions, so this was a lot of unnecessary queries. The method has been rewritten to make only one query instead. * User#permissions? used to query the DB once for each argument it was given. Now, it only queries the DB once, even when given many arguments. * We had a couple SQL queries that used both #select and #pluck. (When using #pluck, #select is redundant.) Removing #select from these calls did not improve performance, but it did clean up unnecessary code.
2020-07-07 11:14:58 +00:00
tokens = Token.select(Token.column_names - %w[persistent name])
.where(action: 'api', persistent: true, user_id: current_user.id)
.order(updated_at: :desc, label: :asc)
base_query = Permission.order(:name).where(active: true)
permission_names = current_user.permissions.pluck(:name)
Refactoring: Clarify complex Permission queries This commit was prepared to facilitate a larger refactoring assignment as part of the Pundit migration. As a bonus, it includes some SQL query optimizations! === Why was this refactoring necessary? It's not, strictly speaking. But the Pundit migration involves taking complex querying logic and moving it into Scope classes as appropriate, and deciding where things belong is really difficult when you can't see what they're doing. === So how does this refactoring fix the problem? * It replaces raw SQL queries with Ruby-esque ActiveRecord queries. * It replaces complex, procedural code that's full of loops and obscure local variable assignment with compact, cleanly-formatted code that follows Ruby idioms and uses meaningful variable names. In my opinion, it's much faster and easier to understand what the code does this way. === What kinds of SQL query optimizations are included? * n+1 query: user_access_token#index instantiated all active permissions and then called current_user.permissions? on _every single one._ A fresh installation of Zammad contains 57 permissions, so this was a lot of unnecessary queries. The method has been rewritten to make only one query instead. * User#permissions? used to query the DB once for each argument it was given. Now, it only queries the DB once, even when given many arguments. * We had a couple SQL queries that used both #select and #pluck. (When using #pluck, #select is redundant.) Removing #select from these calls did not improve performance, but it did clean up unnecessary code.
2020-07-07 11:14:58 +00:00
ancestor_names = permission_names.flat_map { |name| Permission.with_parents(name) }.uniq -
permission_names
descendant_names = permission_names.map { |name| "#{name}.%" }
permissions = base_query.where(name: [*ancestor_names, *permission_names])
descendant_names.each do |name|
permissions = permissions.or(base_query.where('permissions.name LIKE ?', name))
end
Refactoring: Clarify complex Permission queries This commit was prepared to facilitate a larger refactoring assignment as part of the Pundit migration. As a bonus, it includes some SQL query optimizations! === Why was this refactoring necessary? It's not, strictly speaking. But the Pundit migration involves taking complex querying logic and moving it into Scope classes as appropriate, and deciding where things belong is really difficult when you can't see what they're doing. === So how does this refactoring fix the problem? * It replaces raw SQL queries with Ruby-esque ActiveRecord queries. * It replaces complex, procedural code that's full of loops and obscure local variable assignment with compact, cleanly-formatted code that follows Ruby idioms and uses meaningful variable names. In my opinion, it's much faster and easier to understand what the code does this way. === What kinds of SQL query optimizations are included? * n+1 query: user_access_token#index instantiated all active permissions and then called current_user.permissions? on _every single one._ A fresh installation of Zammad contains 57 permissions, so this was a lot of unnecessary queries. The method has been rewritten to make only one query instead. * User#permissions? used to query the DB once for each argument it was given. Now, it only queries the DB once, even when given many arguments. * We had a couple SQL queries that used both #select and #pluck. (When using #pluck, #select is redundant.) Removing #select from these calls did not improve performance, but it did clean up unnecessary code.
2020-07-07 11:14:58 +00:00
permissions.select { |permission| permission.name.in?(ancestor_names) }
.each { |permission| permission.preferences['disabled'] = true }
render json: {
Refactoring: Clarify complex Permission queries This commit was prepared to facilitate a larger refactoring assignment as part of the Pundit migration. As a bonus, it includes some SQL query optimizations! === Why was this refactoring necessary? It's not, strictly speaking. But the Pundit migration involves taking complex querying logic and moving it into Scope classes as appropriate, and deciding where things belong is really difficult when you can't see what they're doing. === So how does this refactoring fix the problem? * It replaces raw SQL queries with Ruby-esque ActiveRecord queries. * It replaces complex, procedural code that's full of loops and obscure local variable assignment with compact, cleanly-formatted code that follows Ruby idioms and uses meaningful variable names. In my opinion, it's much faster and easier to understand what the code does this way. === What kinds of SQL query optimizations are included? * n+1 query: user_access_token#index instantiated all active permissions and then called current_user.permissions? on _every single one._ A fresh installation of Zammad contains 57 permissions, so this was a lot of unnecessary queries. The method has been rewritten to make only one query instead. * User#permissions? used to query the DB once for each argument it was given. Now, it only queries the DB once, even when given many arguments. * We had a couple SQL queries that used both #select and #pluck. (When using #pluck, #select is redundant.) Removing #select from these calls did not improve performance, but it did clean up unnecessary code.
2020-07-07 11:14:58 +00:00
tokens: tokens.map(&:attributes),
permissions: permissions.map(&:attributes),
}, status: :ok
end
=begin
Resource:
POST /api/v1/user_access_token
Payload:
{
"label":"some test",
"permission":["cti.agent","ticket.agent"],
"expires_at":null
}
Response:
{
"name":"new_token_only_shown_once"
}
Test:
curl http://localhost/api/v1/user_access_token -v -u #{login}:#{password} -H "Content-Type: application/json" -X PUT -d '{"label":"some test","permission":["cti.agent","ticket.agent"],"expires_at":null}'
=end
def create
if Setting.get('api_token_access') == false
raise Exceptions::UnprocessableEntity, 'API token access disabled!'
end
2017-11-21 14:25:04 +00:00
if params[:label].blank?
raise Exceptions::UnprocessableEntity, __('Need label!')
end
2017-11-21 14:25:04 +00:00
token = Token.create!(
action: 'api',
label: params[:label],
persistent: true,
user_id: current_user.id,
expires_at: params[:expires_at],
preferences: {
permission: params[:permission]
}
)
render json: {
name: token.name,
}, status: :ok
end
=begin
Resource:
DELETE /api/v1/user_access_token/{id}
Response:
{}
Test:
curl http://localhost/api/v1/user_access_token/{id} -v -u #{login}:#{password} -H "Content-Type: application/json" -X DELETE
=end
def destroy
token = Token.find_by(action: 'api', user_id: current_user.id, id: params[:id])
raise Exceptions::UnprocessableEntity, __('The API token could not be found.') if !token
2017-11-21 14:25:04 +00:00
token.destroy!
render json: {}, status: :ok
end
end