From 88902485e1dca4ddd0f115dcd8124b5c9bbc20b4 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Tue, 2 Dec 2025 13:05:31 +0100 Subject: [PATCH] Access tokens are strictly personal --- .../my/access_tokens_controller.rb | 24 +++++++++++++ .../users/access_tokens_controller.rb | 35 ------------------- app/helpers/users_helper.rb | 4 --- .../access_tokens/_access_token.html.erb | 2 +- .../access_tokens/index.html.erb | 10 +++--- .../{users => my}/access_tokens/new.html.erb | 8 ++--- app/views/users/_developer.html.erb | 2 +- app/views/users/show.html.erb | 2 +- config/routes.rb | 2 +- 9 files changed, 36 insertions(+), 53 deletions(-) create mode 100644 app/controllers/my/access_tokens_controller.rb delete mode 100644 app/controllers/users/access_tokens_controller.rb rename app/views/{users => my}/access_tokens/_access_token.html.erb (86%) rename app/views/{users => my}/access_tokens/index.html.erb (70%) rename app/views/{users => my}/access_tokens/new.html.erb (61%) diff --git a/app/controllers/my/access_tokens_controller.rb b/app/controllers/my/access_tokens_controller.rb new file mode 100644 index 000000000..1f6c9806c --- /dev/null +++ b/app/controllers/my/access_tokens_controller.rb @@ -0,0 +1,24 @@ +class My::AccessTokensController < ApplicationController + def index + @access_tokens = Current.identity.access_tokens.order(created_at: :desc) + end + + def new + @access_token = Current.identity.access_tokens.new + end + + def create + @access_token = Current.identity.access_tokens.create!(access_token_params) + redirect_to my_access_tokens_path + end + + def destroy + Current.identity.access_tokens.find(params[:id]).destroy! + redirect_to my_access_tokens_path + end + + private + def access_token_params + params.expect(access_token: [ :description, :permission ]) + end +end diff --git a/app/controllers/users/access_tokens_controller.rb b/app/controllers/users/access_tokens_controller.rb deleted file mode 100644 index 5bc99e641..000000000 --- a/app/controllers/users/access_tokens_controller.rb +++ /dev/null @@ -1,35 +0,0 @@ -class Users::AccessTokensController < ApplicationController - before_action :set_user - before_action :set_access_token, except: %i[ index new create ] - - def index - set_page_and_extract_portion_from @user.identity.access_tokens.order(created_at: :desc) - end - - def new - @access_token = @user.identity.access_tokens.new - end - - def create - @access_token = @user.identity.access_tokens.create!(access_token_params) - redirect_to user_access_tokens_path(@user) - end - - def destroy - @access_token.destroy! - redirect_to user_access_tokens_path(@user) - end - - private - def set_user - @user = Current.account.users.active.find(params[:user_id]) - end - - def set_access_token - @access_token = @user.identity.access_tokens.find(params[:id]) - end - - def access_token_params - params.expect(access_token: [ :description, :permission ]) - end -end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 0ad5b70d2..7cccfe4ec 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -5,8 +5,4 @@ module UsersHelper else user.role.titleize end end - - def access_token_permission_options - Identity::AccessToken.permissions.keys.map { [ it.humanize, it ] } - end end diff --git a/app/views/users/access_tokens/_access_token.html.erb b/app/views/my/access_tokens/_access_token.html.erb similarity index 86% rename from app/views/users/access_tokens/_access_token.html.erb rename to app/views/my/access_tokens/_access_token.html.erb index 13025739b..cdd5afb7e 100644 --- a/app/views/users/access_tokens/_access_token.html.erb +++ b/app/views/my/access_tokens/_access_token.html.erb @@ -3,7 +3,7 @@ <%= access_token.permission.humanize %> <%= local_datetime_tag access_token.created_at, style: :datetime %> - <%= button_to user_access_token_path(@user, access_token), method: :delete, + <%= button_to my_access_token_path(access_token), method: :delete, class: "btn txt-negative btn--circle txt-x-small borderless fill-transparent", data: { turbo_confirm: "Are you sure you want to permanently revoke this access token?" } do %> <%= icon_tag "trash" %> diff --git a/app/views/users/access_tokens/index.html.erb b/app/views/my/access_tokens/index.html.erb similarity index 70% rename from app/views/users/access_tokens/index.html.erb rename to app/views/my/access_tokens/index.html.erb index 528696590..cc9b83ede 100644 --- a/app/views/users/access_tokens/index.html.erb +++ b/app/views/my/access_tokens/index.html.erb @@ -2,14 +2,14 @@ <% content_for :header do %>
- <%= back_link_to "My profile", user_path(@user), "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %> + <%= back_link_to "My profile", user_path(Current.user), "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>

<%= @page_title %>

<% end %>
- <% if @page.used? %> + <% if @access_tokens.any? %>

Tokens you have generated that can be used to access the Fizzy API.

@@ -21,16 +21,14 @@ - <%= with_automatic_pagination :access_tokens, @page do %> - <%= render partial: "users/access_tokens/access_token", collection: @page.records %> - <% end %> + <%= render partial: "my/access_tokens/access_token", collection: @access_tokens %>
<% else %>

Personal access tokens can be used like a password to access the Fizzy developer API. You can have as many tokens as you need and revoke access to each one at any time.

<% end %> - <%= link_to new_user_access_token_path(@user), class: "btn btn--link" do %> + <%= link_to new_my_access_token_path, class: "btn btn--link" do %> <%= icon_tag "add" %> Generate a new access token <% end %> diff --git a/app/views/users/access_tokens/new.html.erb b/app/views/my/access_tokens/new.html.erb similarity index 61% rename from app/views/users/access_tokens/new.html.erb rename to app/views/my/access_tokens/new.html.erb index 78f36f20f..be08e5031 100644 --- a/app/views/users/access_tokens/new.html.erb +++ b/app/views/my/access_tokens/new.html.erb @@ -2,14 +2,14 @@ <% content_for :header do %>
- <%= back_link_to "tokens", user_access_tokens_path(@user), "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %> + <%= back_link_to "tokens", my_access_tokens_path, "keydown.left@document->hotkey#click keydown.esc@document->hotkey#click" %>

<%= @page_title %>

<% end %>
- <%= form_with model: @access_token, url: user_access_tokens_path(@user), scope: :access_token, data: { controller: "form" }, html: { class: "flex flex-column gap" } do |form| %> + <%= form_with model: @access_token, url: my_access_tokens_path, scope: :access_token, data: { controller: "form" }, html: { class: "flex flex-column gap" } do |form| %>
<%= form.label :description, "Access token description" %> <%= form.text_field :description, required: true, autofocus: true, class: "input", placeholder: "e.g. Github", data: { action: "keydown.esc@document->form#cancel" } %> @@ -17,13 +17,13 @@
<%= form.label :permission %> - <%= form.select :permission, options_for_select(access_token_permission_options), {}, class: "input input--select" %> + <%= form.select :permission, options_for_select({ "Read" => "read", "Read + Write" => "write"}), {}, class: "input input--select" %>
<%= form.button type: :submit, class: "btn btn--link center txt-medium" do %> Generate access token <% end %> - <%= link_to "Cancel and go back", user_access_tokens_path(@user), data: { form_target: "cancel" }, hidden: true %> + <%= link_to "Cancel and go back", my_access_tokens_path, data: { form_target: "cancel" }, hidden: true %> <% end %>
diff --git a/app/views/users/_developer.html.erb b/app/views/users/_developer.html.erb index eb2ae4241..318606b92 100644 --- a/app/views/users/_developer.html.erb +++ b/app/views/users/_developer.html.erb @@ -4,6 +4,6 @@
- <%= link_to "Personal access tokens", user_access_tokens_path(user), class: "btn" %> + <%= link_to "Personal access tokens", my_access_tokens_path, class: "btn" %>
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb index d0a251f4f..eecea4506 100644 --- a/app/views/users/show.html.erb +++ b/app/views/users/show.html.erb @@ -43,7 +43,7 @@ <% if Current.user == @user %>
<%= render "users/transfer", user: @user %> - <%= render "users/developer", user: @user %> + <%= render "users/developer" %>
<%= button_to session_url(script_name: nil), method: :delete, class: "btn btn--plain txt-link txt-small", data: { turbo: false } do %> diff --git a/config/routes.rb b/config/routes.rb index a66cda9c9..bf9c8c3b3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -15,7 +15,6 @@ Rails.application.routes.draw do resource :events resources :push_subscriptions - resources :access_tokens resources :email_addresses, param: :token do resource :confirmation, module: :email_addresses @@ -163,6 +162,7 @@ Rails.application.routes.draw do resource :landing namespace :my do + resources :access_tokens resources :pins resource :timezone resource :menu