feature(api): setup autorizations
This commit is contained in:
parent
1d7b6a6a54
commit
8a9e5754a1
6 changed files with 198 additions and 2 deletions
|
@ -6,6 +6,15 @@ class APITokensController < ApplicationController
|
|||
@name = params[:name]
|
||||
end
|
||||
|
||||
def autorisations
|
||||
@name = params[:name]
|
||||
@libelle_id_procedures = current_administrateur
|
||||
.procedures
|
||||
.order(:libelle)
|
||||
.pluck(:libelle, :id)
|
||||
.map { |libelle, id| ["#{id} - #{libelle}", id] }
|
||||
end
|
||||
|
||||
def create
|
||||
@api_token, @packed_token = APIToken.generate(current_administrateur)
|
||||
|
||||
|
|
101
app/javascript/controllers/api_token_autorisation_controller.ts
Normal file
101
app/javascript/controllers/api_token_autorisation_controller.ts
Normal file
|
@ -0,0 +1,101 @@
|
|||
import { ApplicationController } from './application_controller';
|
||||
|
||||
export class ApiTokenAutorisationController extends ApplicationController {
|
||||
static targets = [
|
||||
'procedures',
|
||||
'procedureSelect',
|
||||
'procedureSelectGroup',
|
||||
'continueButton'
|
||||
];
|
||||
|
||||
declare readonly continueButtonTarget: HTMLButtonElement;
|
||||
declare readonly procedureSelectTarget: HTMLSelectElement;
|
||||
declare readonly procedureSelectGroupTarget: HTMLElement;
|
||||
declare readonly proceduresTarget: HTMLElement;
|
||||
|
||||
connect() {
|
||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||
const targetIds = urlSearchParams.getAll('targets[]');
|
||||
const customTargets = urlSearchParams.get('target') == 'custom';
|
||||
|
||||
this.setupProceduresTarget(targetIds);
|
||||
|
||||
if (customTargets && targetIds.length > 0) {
|
||||
this.showProcedureSelectGroup();
|
||||
}
|
||||
|
||||
this.setContinueButtonState();
|
||||
}
|
||||
|
||||
setupProceduresTarget(targetIds: string[]) {
|
||||
const options = Array.from(this.procedureSelectTarget.options);
|
||||
|
||||
targetIds
|
||||
.map((id) => options.find((x) => x.value == id))
|
||||
.forEach((option) => option && this.addProcedureToSelect(option));
|
||||
}
|
||||
|
||||
addProcedure(e: Event) {
|
||||
e.preventDefault();
|
||||
const selectedOption = this.procedureSelectTarget.selectedOptions[0];
|
||||
this.addProcedureToSelect(selectedOption);
|
||||
|
||||
this.setContinueButtonState();
|
||||
}
|
||||
|
||||
addProcedureToSelect(option: HTMLOptionElement) {
|
||||
const template = [
|
||||
`<li class='flex align-center'>`,
|
||||
option.text,
|
||||
"<button class='fr-btn fr-icon-delete-line fr-btn--tertiary-no-outline fr-ml-1w' data-action='click->api-token-autorisation#deleteProcedure'></button>",
|
||||
`<input type='hidden' name='[targets][]' value='${option.value}' />`,
|
||||
`</li>`
|
||||
].join('');
|
||||
|
||||
this.proceduresTarget.insertAdjacentHTML('beforeend', template);
|
||||
}
|
||||
|
||||
deleteProcedure(e: Event) {
|
||||
e.preventDefault();
|
||||
const target = e.target as HTMLElement;
|
||||
target.closest('li')?.remove();
|
||||
this.setContinueButtonState();
|
||||
}
|
||||
|
||||
showProcedureSelectGroup() {
|
||||
this.procedureSelectGroupTarget.classList.remove('hidden');
|
||||
this.setContinueButtonState();
|
||||
}
|
||||
|
||||
hideProcedureSelectGroup() {
|
||||
this.procedureSelectGroupTarget.classList.add('hidden');
|
||||
this.setContinueButtonState();
|
||||
}
|
||||
|
||||
setContinueButtonState() {
|
||||
if (this.targetDefined() && this.accessDefined()) {
|
||||
this.continueButtonTarget.disabled = false;
|
||||
} else {
|
||||
this.continueButtonTarget.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
targetDefined() {
|
||||
if (this.element.querySelectorAll("[value='all']:checked").length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (
|
||||
this.element.querySelectorAll("[value='custom']:checked").length > 0 &&
|
||||
this.proceduresTarget.children.length > 0
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
accessDefined() {
|
||||
return this.element.querySelectorAll("[name='access']:checked").length == 1;
|
||||
}
|
||||
}
|
70
app/views/api_tokens/autorisations.html.haml
Normal file
70
app/views/api_tokens/autorisations.html.haml
Normal file
|
@ -0,0 +1,70 @@
|
|||
- content_for :title, "Privilèges du jeton « #{@name} »"
|
||||
|
||||
= render partial: 'administrateurs/breadcrumbs',
|
||||
locals: { steps: [['Tableau de bord', tableau_de_bord_helper_path],
|
||||
[t('users.profil.show.profile'), profil_path],
|
||||
[t('api_tokens.nom.new_token')]] }
|
||||
|
||||
.fr-container.fr-mt-2w
|
||||
%h1 Privilèges du jeton « #{@name} »
|
||||
= form_with url: securite_api_tokens_path,
|
||||
method: :get,
|
||||
data: { controller: 'api-token-autorisation' } do |f|
|
||||
|
||||
= render Dsfr::RadioButtonListComponent.new(form: f,
|
||||
target: :target,
|
||||
buttons: [ { label: 'certaines de mes démarches',
|
||||
value: :custom,
|
||||
checked: params[:target] == 'custom',
|
||||
data: { 'action': 'click->api-token-autorisation#showProcedureSelectGroup' } },
|
||||
{ label: 'toutes mes démarches',
|
||||
value: :all,
|
||||
hint: 'présentes et futures',
|
||||
checked: params[:target] == 'all',
|
||||
data: { 'action': 'click->api-token-autorisation#hideProcedureSelectGroup' } }]) do
|
||||
Ce jeton accède à
|
||||
|
||||
.fr-mb-4w.hidden{ 'data-api-token-autorisation-target': 'procedureSelectGroup' }
|
||||
.fr-select-group
|
||||
%label.fr-label{ for: 'procedureSelect' } Sélectionner les démarches autorisées
|
||||
.flex
|
||||
= f.select :value,
|
||||
options_for_select(@libelle_id_procedures),
|
||||
{ include_blank: true },
|
||||
{ id: 'procedureSelect',
|
||||
class: 'fr-select width-33',
|
||||
name: 'procedureSelect',
|
||||
data: { 'api-token-autorisation-target': 'procedureSelect' } }
|
||||
|
||||
%button.fr-btn.fr-btn--secondary.fr-ml-1w{
|
||||
'data-action': 'click->api-token-autorisation#addProcedure' } Ajouter
|
||||
|
||||
%style
|
||||
ul:empty { padding: 0; }
|
||||
ul:empty:before { content: "aucune démarche sélectionnée"; }
|
||||
%ul{ 'data-api-token-autorisation-target': 'procedures' }
|
||||
|
||||
%div{ 'data-action': 'click->api-token-autorisation#setContinueButtonState' }
|
||||
= render Dsfr::RadioButtonListComponent.new(form: f,
|
||||
target: :access,
|
||||
buttons: [ { label: 'de lire uniquement',
|
||||
value: :read,
|
||||
checked: params[:access] == 'read',
|
||||
hint: 'récupérer des dossiers, des pièces-jointes' },
|
||||
{ label: 'de lire et dʼécrire',
|
||||
value: :read_write,
|
||||
checked: params[:access] == 'read_write',
|
||||
hint: 'changer le statut de dossier, écrire des messages' }]) do
|
||||
Ce jeton permet
|
||||
|
||||
= f.hidden_field :name, value: @name
|
||||
|
||||
%ul.fr-btns-group.fr-btns-group--inline
|
||||
%li
|
||||
= f.button type: :submit,
|
||||
class: "fr-btn fr-btn--primary",
|
||||
disabled: true,
|
||||
'data-api-token-autorisation-target': 'continueButton' do
|
||||
= t('.continue')
|
||||
%li
|
||||
= link_to t('.cancel'), nom_api_tokens_path(name: @name), class: "fr-btn fr-btn--secondary"
|
12
config/locales/views/api_tokens.en.yml
Normal file
12
config/locales/views/api_tokens.en.yml
Normal file
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
en:
|
||||
api_tokens:
|
||||
nom:
|
||||
new_token: New token creation
|
||||
name: name of the token
|
||||
name-hint: 'examples: orus prod, presta'
|
||||
continue: continue
|
||||
cancel: back
|
||||
autorisations:
|
||||
cancel: back
|
||||
continue: continue
|
|
@ -5,5 +5,8 @@ fr:
|
|||
new_token: Création d'un nouveau jeton
|
||||
name: Nom du jeton
|
||||
name-hint: 'exemples: prod orus, test presta'
|
||||
continue: continuer
|
||||
cancel: retour
|
||||
continue: Continuer
|
||||
cancel: Retour
|
||||
autorisations:
|
||||
cancel: Retour
|
||||
continue: Continuer
|
||||
|
|
|
@ -211,6 +211,7 @@ Rails.application.routes.draw do
|
|||
resources :api_tokens, only: [:create, :destroy] do
|
||||
collection do
|
||||
get :nom
|
||||
get :autorisations
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue