]> gitweb.mndrdr.org Git - arelpe.git/commitdiff
User styling, new migration for API key tracking
authorAidan Cornelius-Bell <[email protected]>
Thu, 9 Jan 2025 03:10:52 +0000 (13:40 +1030)
committerAidan Cornelius-Bell <[email protected]>
Thu, 9 Jan 2025 03:10:52 +0000 (13:40 +1030)
13 files changed:
app/assets/stylesheets/application.css
app/controllers/api/v2/api_controller.rb
app/models/api_key.rb
app/models/user.rb
app/views/devise/confirmations/new.html.erb
app/views/devise/passwords/new.html.erb
app/views/devise/registrations/edit.html.erb
app/views/devise/registrations/new.html.erb
app/views/devise/sessions/new.html.erb
app/views/devise/shared/_links.html.erb
app/views/devise/unlocks/new.html.erb
db/migrate/20250109020738_add_user_and_tracking_to_api_keys.rb [new file with mode: 0644]
db/schema.rb

index 008a172f7f9101389ced813f0f5d1684c0cd48f8..5ec205efb85722d8de523516de845c66ba609df9 100644 (file)
     --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 */
         --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;
 }
index f697ac136da2877d88453ffd4f94ae7a6b153f0f..7d5f526bca15ac4a4604d3d88a14a8fd234345c3 100644 (file)
@@ -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
index e78a22ad842a34fc6ce1da2d099eed10c7802d48..c0793b51c4149e7800321437f5039602032a62cf 100644 (file)
@@ -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
index fde16a6fed5d6c70714ce659892e28409a6d2672..7edf9b5adb5743ea1b860dadfb4daea2cff3462b 100644 (file)
@@ -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
 
index d8f5bf0b1f6b0467f10d907f10f32e74ce61cf74..65f02d1c62ba5e76ff650581344176c5c2972eaa 100644 (file)
@@ -1,19 +1,20 @@
 <% content_for :title do %>Resend email confirmation<% end %>
 
 <% content_for :form_content do %>
-
+<div class="reg-form">
   <%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %>
     <%= render "devise/shared/error_messages", resource: resource %>
-  
+
     <div class="field">
       <%= f.label :email %><br />
       <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %>
     </div>
-  
+
     <div class="actions">
       <%= f.submit "Resend confirmation instructions" %>
     </div>
   <% end %>
+</div>
 <% end %>
 
-<%= render template: 'layouts/user_page_template' %>
\ No newline at end of file
+<%= render template: 'layouts/user_page_template' %>
index 6e966ac5f4f715d29591382f0b942253cc675125..0e9bf007798a5d16948d170e70295a821ba2215a 100644 (file)
@@ -1,6 +1,7 @@
 <% content_for :title do %>Forgot your password?<% end %>
 
 <% content_for :form_content do %>
+<div class="reg-form">
   <%= 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" %>
     </div>
   <% end %>
+</div>
 <% end %>
 
-<%= render template: 'layouts/user_page_template' %>
\ No newline at end of file
+<%= render template: 'layouts/user_page_template' %>
index 946ed60dfc66694e16db3b506a2c25a5bd3b6b5e..1fea6f7729e116a744b7750e41436e4bf25e225f 100644 (file)
@@ -9,43 +9,41 @@
     <% elsif current_user.one_time_donor? %>
       <p>Thank you for your <%= link_to "one-time donation", subscriptions_path %>!</p>
     <% elsif current_user.non_financial_supporter? %>
-      <p>Thank you for your non-financial support!</p>
+      <p>Thank you for your support!</p>
     <% else %>
       <p>Consider <%= link_to "supporting mind reader", subscriptions_path %> to access extra features.</p>
     <% end %>
   <% end %>
 
-  <hr>
-
   <%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
     <%= render "devise/shared/error_messages", resource: resource %>
-
-  <div class="field-group">
-        <div class="field">
-            <%= f.label :first_name %>
-            <%= f.text_field :first_name %>
-        </div>
-        <div class="field">
-            <%= f.label :last_name %>
-            <%= f.text_field :last_name %>
-        </div>
-  </div>
+  <div class="reg-form">
+    <div class="field-group">
+            <div class="field">
+                <%= f.label :first_name %>
+                <%= f.text_field :first_name %>
+            </div>
+            <div class="field">
+                <%= f.label :last_name %>
+                <%= f.text_field :last_name %>
+            </div>
+    </div>
 
     <div class="field">
-      <%= f.label :email %>
-      <%= f.email_field :email, autocomplete: "email" %>
+        <%= f.label :email %>
+        <%= f.email_field :email, autocomplete: "email" %>
     </div>
 
     <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>
-      <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
+    <div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div>
     <% end %>
 
     <div class="field-group">
         <div class="field">
         <%= 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 %>
-            <em><%= @minimum_password_length %> characters minimum</em>
+            <p class="help-text"><%= @minimum_password_length %> characters minimum</pp>
         <% end %>
         </div>
 
         <%= f.password_field :password_confirmation, autocomplete: "new-password" %>
         </div>
     </div>
-
-    <hr>
-
-    <div class="field">
+  </div>
+  <br>
+    <div class="field reg-form">
     <%= f.label :hide_ai_summaries do %>
         <%= f.check_box :hide_ai_summaries %>
         Hide AI-generated summaries
     <p class="help-text">When enabled, AI-generated summaries will not be displayed on posts.</p>
     </div>
 
-    <hr>
-
-    <div class="field">
-      <%= f.label :current_password %> <i>We need your current password to confirm your changes:</i>
+    <div class="field reg-form">
+      <%= f.label :current_password %><p class="help-text">We need your current password to confirm your changes:</p>
       <%= f.password_field :current_password, autocomplete: "current-password" %>
     </div>
 
       <%= f.submit "Update" %>
     </div>
   <% end %>
+
+  <br>
+  <hr>
+  <br>
   <% 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 %>
+
+  <br>
   <% if current_user&.admin? or current_user&.support_type? %>
   <h3>Account tools</h3>
   <p>You can modify your mailing list options (including easily unsubscribing) <%= link_to "on this page", mailing_lists_path %> at any time.</p>
   <p>You review, renew, modify and cancel your financial support <%= link_to "on this page", subscriptions_path %> at any time.</p>
   <h3>Account removal</h3>
   <p>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.</p>
-  <p><a href="mailto:[email protected]">Contact me here</a> and I will remove your account, subscriptions, emails and any associated data within 96 hours.</p>
+  <p><a href="mailto:[email protected]?subject=Request%20deletion:%20<%= "100-#{@user&.id}-#{@user&.created_at}" %>">Contact me here</a> and I will remove your account, subscriptions, emails and any associated data within 96 hours.</p>
   <% else %>
   <h3>Cancel my account</h3>
   <p>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 <em>not</em> be unsubscribed from dispatches at the same email address as this is a separate system.</p>
index 03fd1205e310df69fab946d7c96d1b129f6adc63..97a512c401683948788e22b1e0fc16a815985b25 100644 (file)
@@ -4,7 +4,7 @@
     <%= render "devise/shared/error_messages", resource: resource %>
 
     <h4>Hello, I’m <a href="/about">Aidan</a>, it’s great to meet a likeminded human — </h4>
-        <p class="text-indent">↓ To get started, tell me briefly about yourself:</p>
+        <p class="text-indent">↓ To get started, tell me briefly how to address you:</p>
 
     <div class="reg-form">
         <div class="field-group">
         </div>
     </div>
 
-    <h4>Now comes the choice of a lifetime</h4>
+    <h4>Now for the choice of a lifetime...</h4>
     <p class="text-indent">↓ <em>Would you like dispatches delivered directly to your email?</em></p>
 
-    <div class="field checkbox">
+    <div class="field checkbox reg-form">
       <%= f.check_box :subscribe_to_newsletter %>
       <%= f.label :subscribe_to_newsletter, "I want to receive mind reader dispatches by email newsletter", id: "sub" %>
     </div>
index 156c43335fd5a9f66a212df3db22ef2eb1185523..ee665418b69e41eaaa990eea5b488de9895ecf6e 100644 (file)
@@ -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| %>
+<div class="reg-form">
+    <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
     <div class="field">
       <%= f.label :email %>
       <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
     </div>
 
     <% if devise_mapping.rememberable? %>
-      <div class="field">
+      <div class="field checkbox">
         <%= f.check_box :remember_me %>
-        <%= f.label :remember_me %>
+        <%= f.label :remember_me, id: "sub" %>
       </div>
     <% end %>
 
     <div class="actions">
       <%= f.submit "Log in" %>
     </div>
-  <% end %>
-  
+</div>
+<% end %>
+
   <p>
-    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 %>.
   </p>
 <% end %>
 
-<%= render template: 'layouts/user_page_template' %>
\ No newline at end of file
+<%= render template: 'layouts/user_page_template' %>
index 1e70ae70933d14a8c8c7e36550c00331a32c6679..6a7941d4656f8996c4f6df0a78c17bc21a258891 100644 (file)
@@ -1,29 +1,31 @@
-<% if current_user %>
+<div class="devise-form">
+    <% if current_user %>
 
-<% else %>
-  <%- if controller_name != 'sessions' %>
-    <%= link_to "Log in", new_session_path(resource_name), class: "button" %><br />
-  <% end %>
-  
-  <%- if devise_mapping.registerable? && controller_name != 'registrations' %>
-    <%= link_to "Sign up", new_registration_path(resource_name), class: "button" %><br />
-  <% end %>
-  
-  <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
-    <%= link_to "Forgot your password?", new_password_path(resource_name), class: "button" %><br />
-  <% end %>
-  
-  <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
-    <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: "button" %><br />
-  <% 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" %><br />
-  <% 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 } %><br />
+    <% else %>
+    <%- if controller_name != 'sessions' %>
+        <%= link_to "Log in", new_session_path(resource_name), class: "button" %><br />
     <% 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" %><br />
+    <% end %>
+
+    <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %>
+        <%= link_to "Forgot your password?", new_password_path(resource_name), class: "button" %><br />
+    <% end %>
+
+    <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
+        <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name), class: "button" %><br />
+    <% 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" %><br />
+    <% 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 } %><br />
+        <% end %>
+    <% end %>
+    <% end %>
+</div>
index ffc34de8d154c48c5d6769a9805781cadf629918..17dade4d75540b35ac57300bf5737465b7b19ac1 100644 (file)
@@ -1,5 +1,7 @@
-<h2>Resend unlock instructions</h2>
+<% content_for :title do %>Resend unlock instructions<% end %>
 
+<% content_for :form_content do %>
+<div class="reg-form">
 <%= 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" %>
   </div>
 <% end %>
+</div>
+<% 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 (file)
index 0000000..3719f52
--- /dev/null
@@ -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
index dbbdc0a68ed435f99f536a721c31297f2c1d5963..2482fcdd83ec5ee91e5af1c72f5b4b947ecfb8b1 100644 (file)
@@ -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