diff --git a/app/controllers/global_states_controller.rb b/app/controllers/global_states_controller.rb
index 1398287a..5b037392 100644
--- a/app/controllers/global_states_controller.rb
+++ b/app/controllers/global_states_controller.rb
@@ -2,6 +2,12 @@ class GlobalStatesController < ApplicationController
before_action :set_global_state, only: %i[edit update destroy]
after_action :verify_authorized
+ FA_COOKIE_KEYS = %w[
+ furaffinity-cookie-a
+ furaffinity-cookie-b
+ furaffinity-cookie-oaid
+ ].freeze
+
def index
authorize GlobalState
@global_states = policy_scope(GlobalState).order(:key)
@@ -44,6 +50,50 @@ class GlobalStatesController < ApplicationController
notice: "Global state was successfully deleted."
end
+ def fa_cookies
+ authorize GlobalState
+ @fa_cookies =
+ FA_COOKIE_KEYS.map do |key|
+ GlobalState.find_by(key: key) ||
+ GlobalState.new(key: key, value_type: :string)
+ end
+ end
+
+ def edit_fa_cookies
+ authorize GlobalState
+ @fa_cookies =
+ FA_COOKIE_KEYS.map do |key|
+ GlobalState.find_by(key: key) ||
+ GlobalState.new(key: key, value_type: :string)
+ end
+ end
+
+ def update_fa_cookies
+ authorize GlobalState
+
+ begin
+ ActiveRecord::Base.transaction do
+ fa_cookies_params.each do |key, value|
+ state = GlobalState.find_or_initialize_by(key: key)
+ state.value = value
+ state.value_type = :string
+ state.save!
+ end
+ end
+
+ redirect_to fa_cookies_global_states_path,
+ notice: "FA cookies were successfully updated."
+ rescue ActiveRecord::RecordInvalid => e
+ @fa_cookies =
+ FA_COOKIE_KEYS.map do |key|
+ GlobalState.find_by(key: key) ||
+ GlobalState.new(key: key, value_type: :string)
+ end
+ flash.now[:alert] = "Error updating FA cookies: #{e.message}"
+ render :edit_fa_cookies, status: :unprocessable_entity
+ end
+ end
+
private
def set_global_state
@@ -53,4 +103,8 @@ class GlobalStatesController < ApplicationController
def global_state_params
params.require(:global_state).permit(:key, :value, :value_type)
end
+
+ def fa_cookies_params
+ params.require(:fa_cookies).permit(*FA_COOKIE_KEYS)
+ end
end
diff --git a/app/policies/global_state_policy.rb b/app/policies/global_state_policy.rb
index 98e89292..e9b5204b 100644
--- a/app/policies/global_state_policy.rb
+++ b/app/policies/global_state_policy.rb
@@ -27,6 +27,18 @@ class GlobalStatePolicy < ApplicationPolicy
update?
end
+ def fa_cookies?
+ user.admin?
+ end
+
+ def edit_fa_cookies?
+ user.admin?
+ end
+
+ def update_fa_cookies?
+ user.admin?
+ end
+
class Scope < Scope
def resolve
user.admin? ? scope.all : scope.none
diff --git a/app/views/global_states/edit_fa_cookies.html.erb b/app/views/global_states/edit_fa_cookies.html.erb
new file mode 100644
index 00000000..75b9a9a3
--- /dev/null
+++ b/app/views/global_states/edit_fa_cookies.html.erb
@@ -0,0 +1,62 @@
+
+
+
+
+ Edit FurAffinity Cookies
+
+
+ Update the cookie values used for FurAffinity authentication.
+
+
+
+ <%= link_to "Back to Cookies",
+ fa_cookies_global_states_path,
+ class:
+ "bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-4 rounded" %>
+
+
+
+
+
+ <%= form_tag fa_cookies_global_states_path, method: :patch do %>
+
+
+
+ |
+ Cookie
+ |
+
+ Value
+ |
+
+
+
+ <% @fa_cookies.each do |cookie| %>
+
+ |
+ <%= cookie.key.sub("furaffinity-cookie-", "").upcase %>
+ |
+
+ <%= text_field_tag "fa_cookies[#{cookie.key}]",
+ cookie.value,
+ class:
+ "block w-full rounded-md border-slate-300 shadow-sm focus:border-sky-500 focus:ring-sky-500 sm:text-sm" %>
+ |
+
+ <% end %>
+
+
+
+
+ <%= link_to "Cancel",
+ fa_cookies_global_states_path,
+ class:
+ "rounded-md border border-slate-300 bg-white py-2 px-4 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2" %>
+ <%= submit_tag "Save",
+ class:
+ "inline-flex justify-center rounded-md border border-transparent bg-sky-600 py-2 px-4 text-sm font-medium text-white shadow-sm hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2" %>
+
+ <% end %>
+
+
+
diff --git a/app/views/global_states/fa_cookies.html.erb b/app/views/global_states/fa_cookies.html.erb
new file mode 100644
index 00000000..5ebc43f5
--- /dev/null
+++ b/app/views/global_states/fa_cookies.html.erb
@@ -0,0 +1,49 @@
+
+
+
+
FurAffinity Cookies
+
+ Manage cookies for FurAffinity authentication.
+
+
+
+ <%= link_to "Back to Global States",
+ global_states_path,
+ class:
+ "bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-4 rounded mr-3" %>
+ <%= link_to "Edit Cookies",
+ fa_cookies_edit_global_states_path,
+ class:
+ "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" %>
+
+
+
+
+
+
+
+
+ |
+ Cookie
+ |
+
+ Value
+ |
+
+
+
+ <% @fa_cookies.each do |cookie| %>
+
+ |
+ <%= cookie.key.sub("furaffinity-cookie-", "").upcase %>
+ |
+
+ <%= cookie.value.present? ? cookie.value : "(not set)" %>
+ |
+
+ <% end %>
+
+
+
+
+
diff --git a/app/views/global_states/index.html.erb b/app/views/global_states/index.html.erb
index 28507801..5c4b786c 100644
--- a/app/views/global_states/index.html.erb
+++ b/app/views/global_states/index.html.erb
@@ -3,111 +3,88 @@
Global States
- A list of all global states in the application.
+ A list of all global states in the system.
-
- <%= link_to new_global_state_path,
+
+ <%= link_to "Manage FA Cookies",
+ fa_cookies_global_states_path,
class:
- "inline-flex items-center justify-center rounded-md border border-transparent bg-sky-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2 sm:w-auto" do %>
-
- New Global State
- <% end %>
+ "bg-slate-500 hover:bg-slate-700 text-white font-bold py-2 px-4 rounded" %>
+ <%= link_to "New Global State",
+ new_global_state_path,
+ class:
+ "bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" %>
-
-
-
-
-
-
-
-
+
+
+
+
+ |
+ Key
+ |
+
+ Value Type
+ |
+
+ Value
+ |
+ Actions |
+
+
+
+ <% @global_states.each do |global_state| %>
+
+ |
+ <%= global_state.key %>
+ |
+
+ <% pill_color =
+ case global_state.value_type
+ when "string"
+ "bg-sky-100 text-sky-700"
+ when "counter"
+ "bg-emerald-100 text-emerald-700"
+ when "duration"
+ "bg-purple-100 text-purple-700"
+ when "password"
+ "bg-rose-100 text-rose-700"
+ end %>
+
- Key
-
- |
- Type
- |
-
- Value
- |
-
- Last Updated
- |
-
- Actions
- |
-
-
-
- <% @global_states.each do |global_state| %>
-
- |
- <%= global_state.key %>
- |
-
- inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium"
- >
- <%= global_state.value_type.titleize %>
-
- |
-
- <%= global_state.display_value %>
- |
-
- <%= time_ago_in_words(global_state.updated_at) %> ago
- |
-
- <%= link_to "Edit",
- edit_global_state_path(global_state),
- class: "text-sky-600 hover:text-sky-900 mr-3" %>
- <%= button_to "Delete",
- global_state_path(global_state),
- method: :delete,
- class: "text-red-600 hover:text-red-900 inline",
- form: {
- class: "inline",
- data: {
- turbo_confirm: "Are you sure?",
- },
- } %>
- |
-
- <% end %>
-
-
-
-
+ <%= global_state.value_type.humanize %>
+
+
+ |
+ <%= global_state.display_value %>
+ |
+
+ <% if policy(global_state).edit? %>
+ <%= link_to "Edit",
+ edit_global_state_path(global_state),
+ class: "text-blue-600 hover:text-blue-900 mr-3" %>
+ <% end %>
+ <% if policy(global_state).destroy? %>
+ <%= button_to "Delete",
+ global_state_path(global_state),
+ method: :delete,
+ class: "text-red-600 hover:text-red-900 inline",
+ form: {
+ class: "inline",
+ data: {
+ turbo_confirm: "Are you sure?",
+ },
+ } %>
+ <% end %>
+ |
+
+ <% end %>
+
+
diff --git a/config/routes.rb b/config/routes.rb
index a026d922..824c33d4 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -89,5 +89,11 @@ Rails.application.routes.draw do
end
end
- resources :global_states, path: "state"
+ resources :global_states, path: "state" do
+ collection do
+ get "fa-cookies", to: "global_states#fa_cookies"
+ get "fa-cookies/edit", to: "global_states#edit_fa_cookies"
+ patch "fa-cookies", to: "global_states#update_fa_cookies"
+ end
+ end
end
diff --git a/spec/controllers/global_states_controller_spec.rb b/spec/controllers/global_states_controller_spec.rb
index 738a9fa9..08756dcc 100644
--- a/spec/controllers/global_states_controller_spec.rb
+++ b/spec/controllers/global_states_controller_spec.rb
@@ -103,4 +103,151 @@ RSpec.describe GlobalStatesController, type: :controller do
expect(response).to redirect_to(global_states_path)
end
end
+
+ describe "FA Cookies Management" do
+ let(:fa_cookie_keys) do
+ %w[furaffinity-cookie-a furaffinity-cookie-b furaffinity-cookie-oaid]
+ end
+
+ describe "GET #fa_cookies" do
+ context "when no FA cookie states exist" do
+ before { GlobalState.delete_all }
+
+ it "returns a success response" do
+ get :fa_cookies
+ expect(response).to be_successful
+ end
+
+ it "assigns new GlobalState objects for all required cookies" do
+ get :fa_cookies
+ assigned_cookies = assigns(:fa_cookies)
+
+ expect(assigned_cookies.size).to eq(3)
+ expect(assigned_cookies).to all(be_new_record)
+ expect(assigned_cookies.map(&:key)).to match_array(fa_cookie_keys)
+ expect(assigned_cookies.map(&:value_type).uniq).to eq(["string"])
+ end
+ end
+
+ context "when FA cookie states exist" do
+ it "assigns all FA cookie states" do
+ cookie_states =
+ fa_cookie_keys.map do |key|
+ create(
+ :global_state,
+ key: key,
+ value: "test",
+ value_type: :string,
+ )
+ end
+
+ get :fa_cookies
+ expect(assigns(:fa_cookies)).to match_array(cookie_states)
+ end
+ end
+ end
+
+ describe "GET #edit_fa_cookies" do
+ context "when no FA cookie states exist" do
+ before { GlobalState.delete_all }
+
+ it "returns a success response" do
+ get :edit_fa_cookies
+ expect(response).to be_successful
+ end
+
+ it "assigns new GlobalState objects for all required cookies" do
+ get :edit_fa_cookies
+ assigned_cookies = assigns(:fa_cookies)
+
+ expect(assigned_cookies.size).to eq(3)
+ expect(assigned_cookies).to all(be_new_record)
+ expect(assigned_cookies.map(&:key)).to match_array(fa_cookie_keys)
+ expect(assigned_cookies.map(&:value_type).uniq).to eq(["string"])
+ end
+ end
+
+ context "when FA cookie states exist" do
+ it "assigns all FA cookie states" do
+ cookie_states =
+ fa_cookie_keys.map do |key|
+ create(
+ :global_state,
+ key: key,
+ value: "test",
+ value_type: :string,
+ )
+ end
+
+ get :edit_fa_cookies
+ expect(assigns(:fa_cookies)).to match_array(cookie_states)
+ end
+ end
+ end
+
+ describe "PATCH #update_fa_cookies" do
+ context "when no FA cookie states exist" do
+ before { GlobalState.delete_all }
+
+ let(:new_values) { fa_cookie_keys.index_with { |_key| "new_value" } }
+
+ it "creates all cookie states" do
+ expect {
+ patch :update_fa_cookies, params: { fa_cookies: new_values }
+ }.to change(GlobalState, :count).by(3)
+
+ fa_cookie_keys.each do |key|
+ state = GlobalState.find_by(key: key)
+ expect(state).to be_present
+ expect(state.value).to eq("new_value")
+ expect(state.value_type).to eq("string")
+ end
+ end
+
+ it "redirects to the fa_cookies page" do
+ patch :update_fa_cookies, params: { fa_cookies: new_values }
+ expect(response).to redirect_to(fa_cookies_global_states_path)
+ end
+ end
+
+ context "when FA cookie states exist" do
+ let(:new_values) { fa_cookie_keys.index_with { |_key| "new_value" } }
+
+ it "updates existing records" do
+ existing_states =
+ fa_cookie_keys.map do |key|
+ create(
+ :global_state,
+ key: key,
+ value: "old_value",
+ value_type: :string,
+ )
+ end
+
+ patch :update_fa_cookies, params: { fa_cookies: new_values }
+
+ existing_states.each do |state|
+ expect(state.reload.value).to eq("new_value")
+ end
+ end
+ end
+
+ context "with invalid params" do
+ let(:invalid_values) { { "furaffinity-cookie-a" => "" } }
+
+ it "returns unprocessable entity status" do
+ patch :update_fa_cookies, params: { fa_cookies: invalid_values }
+ expect(response).to have_http_status(:unprocessable_entity)
+ end
+
+ it "assigns @fa_cookies with all required keys" do
+ patch :update_fa_cookies, params: { fa_cookies: invalid_values }
+ assigned_cookies = assigns(:fa_cookies)
+
+ expect(assigned_cookies).to be_present
+ expect(assigned_cookies.map(&:key)).to match_array(fa_cookie_keys)
+ end
+ end
+ end
+ end
end