--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;
}
}
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"],
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;
}
-# app/controllers/api/v2/api_controller.rb
module Api
module V2
class ApiController < ApplicationController
end
end
end
-end
\ No newline at end of file
+end
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
encrypts :otp_secret
attr_accessor :otp_plain_secret
+ has_many :api_keys, dependent: :destroy
+
validates :first_name, presence: true
validates :last_name, presence: true
<% 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' %>
<% 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 %>
<%= 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' %>
<% 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>
<%= 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>
<% 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' %>
-<% 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>
-<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 %>
<%= f.submit "Resend unlock instructions" %>
</div>
<% end %>
+</div>
+<% end %>
-<%= render "devise/shared/links" %>
+<%= render template: 'layouts/user_page_template' %>
--- /dev/null
+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
#
# 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
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