From 72ceb0812a4ebdffcd5e94a798c169765f3d1e3d Mon Sep 17 00:00:00 2001 From: Aidan Cornelius-Bell Date: Thu, 9 Jan 2025 13:40:52 +1030 Subject: [PATCH] User styling, new migration for API key tracking --- app/assets/stylesheets/application.css | 35 ++++++++--- app/controllers/api/v2/api_controller.rb | 3 +- app/models/api_key.rb | 7 +++ app/models/user.rb | 2 + app/views/devise/confirmations/new.html.erb | 9 +-- app/views/devise/passwords/new.html.erb | 4 +- app/views/devise/registrations/edit.html.erb | 61 ++++++++++--------- app/views/devise/registrations/new.html.erb | 6 +- app/views/devise/sessions/new.html.erb | 16 ++--- app/views/devise/shared/_links.html.erb | 56 +++++++++-------- app/views/devise/unlocks/new.html.erb | 8 ++- ...20738_add_user_and_tracking_to_api_keys.rb | 7 +++ db/schema.rb | 3 +- 13 files changed, 133 insertions(+), 84 deletions(-) create mode 100644 db/migrate/20250109020738_add_user_and_tracking_to_api_keys.rb diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 008a172..5ec205e 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -104,6 +104,11 @@ --filter-button: #3d3d3d; --filter-button-active: #847091; --filter-button-hover: #63546d; + + --standout-bg: #191724; + --standout-text: #fff; + --standout-form-bg: #fdf9eb; + --standout-form-text: #fff; } /* Light mode */ @@ -125,6 +130,11 @@ --filter-button: #e8d1c0; --filter-button-active: #f2a76c; --filter-button-hover: #f2a76c; + + --standout-bg: #ffeee2; + --standout-form-text: #333333; + --standout-text: #333333; + --standout-form-bg: #fff; } } @@ -203,13 +213,6 @@ abbr { padding: 4px 8px; } -.reg-form { - border: 1px solid var(--accent-a); - border-radius: 3px; - padding: 4px 8px; - background: var(--quote-bg); -} - /* Style for all form inputs */ input[type="text"], input[type="email"], @@ -253,6 +256,24 @@ label { display: block; } +.reg-form { + border: 1px solid var(--accent-a); + border-radius: 3px; + padding: 1em 2em; + background: var(--standout-bg); + color: var(--standout-text); +} + +.reg-form input { + background-color: var(--standout-form-bg) !important; + color: var(--standout-form-text) !important; +} + +.reg-form .help-text { + margin-bottom: 0; + color: var(--standout-form-text); +} + .subheading { margin-top: -25px; } diff --git a/app/controllers/api/v2/api_controller.rb b/app/controllers/api/v2/api_controller.rb index f697ac1..7d5f526 100644 --- a/app/controllers/api/v2/api_controller.rb +++ b/app/controllers/api/v2/api_controller.rb @@ -1,4 +1,3 @@ -# app/controllers/api/v2/api_controller.rb module Api module V2 class ApiController < ApplicationController @@ -15,4 +14,4 @@ module Api end end end -end \ No newline at end of file +end diff --git a/app/models/api_key.rb b/app/models/api_key.rb index e78a22a..c0793b5 100644 --- a/app/models/api_key.rb +++ b/app/models/api_key.rb @@ -1,8 +1,15 @@ class ApiKey < ApplicationRecord + belongs_to :user validates :key, presence: true, uniqueness: true + validates :user, presence: true + validates :description, presence: true before_validation :generate_key, on: :create + def track_usage! + update_column(:last_used_at, Time.current) + end + private def generate_key diff --git a/app/models/user.rb b/app/models/user.rb index fde16a6..7edf9b5 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -9,6 +9,8 @@ class User < ApplicationRecord encrypts :otp_secret attr_accessor :otp_plain_secret + has_many :api_keys, dependent: :destroy + validates :first_name, presence: true validates :last_name, presence: true diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb index d8f5bf0..65f02d1 100644 --- a/app/views/devise/confirmations/new.html.erb +++ b/app/views/devise/confirmations/new.html.erb @@ -1,19 +1,20 @@ <% content_for :title do %>Resend email confirmation<% end %> <% content_for :form_content do %> - +
<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> - +
<%= f.label :email %>
<%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
- +
<%= f.submit "Resend confirmation instructions" %>
<% end %> +
<% end %> -<%= render template: 'layouts/user_page_template' %> \ No newline at end of file +<%= render template: 'layouts/user_page_template' %> diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb index 6e966ac..0e9bf00 100644 --- a/app/views/devise/passwords/new.html.erb +++ b/app/views/devise/passwords/new.html.erb @@ -1,6 +1,7 @@ <% content_for :title do %>Forgot your password?<% end %> <% content_for :form_content do %> +
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> @@ -13,6 +14,7 @@ <%= f.submit "Send me reset password instructions" %>
<% end %> + <% end %> -<%= render template: 'layouts/user_page_template' %> \ No newline at end of file +<%= render template: 'layouts/user_page_template' %> diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb index 946ed60..1fea6f7 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -9,43 +9,41 @@ <% elsif current_user.one_time_donor? %>

Thank you for your <%= link_to "one-time donation", subscriptions_path %>!

<% elsif current_user.non_financial_supporter? %> -

Thank you for your non-financial support!

+

Thank you for your support!

<% else %>

Consider <%= link_to "supporting mind reader", subscriptions_path %> to access extra features.

<% end %> <% end %> -
- <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> - -
-
- <%= f.label :first_name %> - <%= f.text_field :first_name %> -
-
- <%= f.label :last_name %> - <%= f.text_field :last_name %> -
-
+
+
+
+ <%= f.label :first_name %> + <%= f.text_field :first_name %> +
+
+ <%= f.label :last_name %> + <%= f.text_field :last_name %> +
+
- <%= f.label :email %> - <%= f.email_field :email, autocomplete: "email" %> + <%= f.label :email %> + <%= f.email_field :email, autocomplete: "email" %>
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> -
Currently waiting confirmation for: <%= resource.unconfirmed_email %>
+
Currently waiting confirmation for: <%= resource.unconfirmed_email %>
<% end %>
<%= f.label :password %> - <%= f.password_field :password, autocomplete: "new-password", placeholder: "Leave blank to keep your current password" %> + <%= f.password_field :password, autocomplete: "new-password", placeholder: "Leave this blank to keep your current password" %> <% if @minimum_password_length %> - <%= @minimum_password_length %> characters minimum +

<%= @minimum_password_length %> characters minimum <% end %>

@@ -54,10 +52,9 @@ <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
- -
- -
+
+
+
<%= f.label :hide_ai_summaries do %> <%= f.check_box :hide_ai_summaries %> Hide AI-generated summaries @@ -65,10 +62,8 @@

When enabled, AI-generated summaries will not be displayed on posts.

-
- -
- <%= f.label :current_password %> We need your current password to confirm your changes: +
+ <%= f.label :current_password %>

We need your current password to confirm your changes:

<%= f.password_field :current_password, autocomplete: "current-password" %>
@@ -76,19 +71,25 @@ <%= f.submit "Update" %>
<% end %> + +
+
+
<% if current_user.otp_required_for_login? %> - <%= link_to "Disable 2FA", two_factor_path, method: :delete, data: { confirm: "Are you sure you want to disable 2FA?" }, class: "button" %> + <%= link_to "Two factor backup codes", backup_codes_two_factor_path, data: { confirm: "Are you sure you want to disable 2FA?" }, class: "button" %> <% else %> - <%= link_to "Enable 2FA", new_two_factor_path, class: "button" %> + <%= link_to "Set up 2 factor authentication", new_two_factor_path, class: "button" %> <% end %> <%= button_to "Log out", destroy_user_session_path, method: :delete %> + +
<% if current_user&.admin? or current_user&.support_type? %>

Account tools

You can modify your mailing list options (including easily unsubscribing) <%= link_to "on this page", mailing_lists_path %> at any time.

You review, renew, modify and cancel your financial support <%= link_to "on this page", subscriptions_path %> at any time.

Account removal

As an author, member, or past financial contributor to mind reader you cannot delete your account here. You will need to contact Aidan to request deletion, this way we can ensure you do not incur any expense or friction when leaving.

-

Contact me here and I will remove your account, subscriptions, emails and any associated data within 96 hours.

+

">Contact me here and I will remove your account, subscriptions, emails and any associated data within 96 hours.

<% else %>

Cancel my account

If you wish, you may delete your registration with this website. Please be aware, by doing this you will lose access to any content you have purchased or been granted. You will not be unsubscribed from dispatches at the same email address as this is a separate system.

diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb index 03fd120..97a512c 100644 --- a/app/views/devise/registrations/new.html.erb +++ b/app/views/devise/registrations/new.html.erb @@ -4,7 +4,7 @@ <%= render "devise/shared/error_messages", resource: resource %>

Hello, I’m Aidan, it’s great to meet a likeminded human —

-

↓ To get started, tell me briefly about yourself:

+

↓ To get started, tell me briefly how to address you:

@@ -36,10 +36,10 @@
-

Now comes the choice of a lifetime

+

Now for the choice of a lifetime...

↓ Would you like dispatches delivered directly to your email?

-
+
<%= f.check_box :subscribe_to_newsletter %> <%= f.label :subscribe_to_newsletter, "I want to receive mind reader dispatches by email newsletter", id: "sub" %>
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 156c433..ee66541 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -1,7 +1,8 @@ <% content_for :title do %>Log in<% end %> <% content_for :form_content do %> - <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> +
+ <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= f.label :email %> <%= f.email_field :email, autofocus: true, autocomplete: "email" %> @@ -13,21 +14,22 @@
<% if devise_mapping.rememberable? %> -
+
<%= f.check_box :remember_me %> - <%= f.label :remember_me %> + <%= f.label :remember_me, id: "sub" %>
<% end %>
<%= f.submit "Log in" %>
- <% end %> - +
+<% end %> +

- If you have two-factor authentication enabled and were redirected here, + If you have two-factor authentication enabled and were redirected here, please <%= link_to "enter your two-factor code", users_two_factor_authentication_path %>.

<% end %> -<%= render template: 'layouts/user_page_template' %> \ No newline at end of file +<%= render template: 'layouts/user_page_template' %> diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb index 1e70ae7..6a7941d 100644 --- a/app/views/devise/shared/_links.html.erb +++ b/app/views/devise/shared/_links.html.erb @@ -1,29 +1,31 @@ -<% if current_user %> +
+ <% if current_user %> -<% else %> - <%- if controller_name != 'sessions' %> - <%= link_to "Log in", new_session_path(resource_name), class: "button" %>
- <% end %> - - <%- if devise_mapping.registerable? && controller_name != 'registrations' %> - <%= link_to "Sign up", new_registration_path(resource_name), class: "button" %>
- <% end %> - - <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> - <%= link_to "Forgot your password?", new_password_path(resource_name), class: "button" %>
- <% end %> - - <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> - <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: "button" %>
- <% end %> - - <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> - <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), class: "button" %>
- <% end %> - - <%- if devise_mapping.omniauthable? %> - <%- resource_class.omniauth_providers.each do |provider| %> - <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %>
+ <% else %> + <%- if controller_name != 'sessions' %> + <%= link_to "Log in", new_session_path(resource_name), class: "button" %>
<% end %> - <% end %> -<% end %> \ No newline at end of file + + <%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name), class: "button" %>
+ <% end %> + + <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> + <%= link_to "Forgot your password?", new_password_path(resource_name), class: "button" %>
+ <% end %> + + <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: "button" %>
+ <% end %> + + <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name), class: "button" %>
+ <% end %> + + <%- if devise_mapping.omniauthable? %> + <%- resource_class.omniauth_providers.each do |provider| %> + <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %>
+ <% end %> + <% end %> + <% end %> +
diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb index ffc34de..17dade4 100644 --- a/app/views/devise/unlocks/new.html.erb +++ b/app/views/devise/unlocks/new.html.erb @@ -1,5 +1,7 @@ -

Resend unlock instructions

+<% content_for :title do %>Resend unlock instructions<% end %> +<% content_for :form_content do %> +
<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> <%= render "devise/shared/error_messages", resource: resource %> @@ -12,5 +14,7 @@ <%= f.submit "Resend unlock instructions" %>
<% end %> +
+<% end %> -<%= render "devise/shared/links" %> +<%= render template: 'layouts/user_page_template' %> diff --git a/db/migrate/20250109020738_add_user_and_tracking_to_api_keys.rb b/db/migrate/20250109020738_add_user_and_tracking_to_api_keys.rb new file mode 100644 index 0000000..3719f52 --- /dev/null +++ b/db/migrate/20250109020738_add_user_and_tracking_to_api_keys.rb @@ -0,0 +1,7 @@ +class AddUserAndTrackingToApiKeys < ActiveRecord::Migration[7.2] + def change + add_reference :api_keys, :user, foreign_key: true + add_column :api_keys, :last_used_at, :datetime + add_column :api_keys, :description, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index dbbdc0a..2482fcd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2024_12_09_215122) do +ActiveRecord::Schema[7.2].define(version: 2025_01_09_015845) do create_table "api_keys", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t| t.string "key" t.datetime "created_at", null: false @@ -77,6 +77,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_12_09_215122) do t.boolean "otp_required_for_login" t.text "otp_backup_codes" t.boolean "hide_ai_summaries", default: false + t.integer "consumed_timestep" t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true t.index ["email"], name: "index_users_on_email", unique: true t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true -- 2.39.5