From b54f85ab0c3b4b239b6efa60b9ab6c2cd46077ff Mon Sep 17 00:00:00 2001 From: maebeale Date: Fri, 6 Mar 2026 20:28:01 -0500 Subject: [PATCH 1/2] Remove unused API controllers, apipie, and JWT auth The API (app/controllers/api/v1/) was built for a WordPress integration that never materialized or was abandoned. No frontend code calls these endpoints, no external clients consume them, and there are no tests. Removes: - 5 API v1 controllers (auth, quotes, resources, workshops) - AuthenticationToken JWT service and AuthenticationFailed error - apipie-rails gem and its Rails 8 compatibility patch - API routes and apipie documentation mount --- AGENTS.md | 5 +-- app/controllers/api/v1/api_controller.rb | 34 ------------------ .../api/v1/authentications_controller.rb | 18 ---------- app/controllers/api/v1/quotes_controller.rb | 15 -------- .../api/v1/resources_controller.rb | 11 ------ .../api/v1/workshops_controller.rb | 26 -------------- app/errors/authentication_failed.rb | 5 --- app/services/authentication_token.rb | 32 ----------------- config/initializers/apipie.rb | 8 ----- config/initializers/apipie_rails_8_fix.rb | 35 ------------------- config/routes.rb | 9 ----- 11 files changed, 1 insertion(+), 197 deletions(-) delete mode 100644 app/controllers/api/v1/api_controller.rb delete mode 100644 app/controllers/api/v1/authentications_controller.rb delete mode 100644 app/controllers/api/v1/quotes_controller.rb delete mode 100644 app/controllers/api/v1/resources_controller.rb delete mode 100644 app/controllers/api/v1/workshops_controller.rb delete mode 100644 app/errors/authentication_failed.rb delete mode 100644 app/services/authentication_token.rb delete mode 100644 config/initializers/apipie.rb delete mode 100644 config/initializers/apipie_rails_8_fix.rb diff --git a/AGENTS.md b/AGENTS.md index e3cd2a1fd..5d6786d53 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -34,7 +34,7 @@ AWBW Portal (Rails 8.1) | Directory | Purpose | Count | |---|---|---| -| `app/controllers/` | Rails controllers (admin/, api/v1/, events/) | ~66 files | +| `app/controllers/` | Rails controllers (admin/, events/) | ~61 files | | `app/views/` | ERB templates | ~434 files | | `app/decorators/` | Draper decorators for view logic | ~36 files | | `app/policies/` | ActionPolicy authorization rules | ~43 files | @@ -113,7 +113,6 @@ AWBW Portal (Rails 8.1) - **Root level** (~48 controllers): Workshops, stories, resources, events, people, organizations, etc. - **`admin/`**: HomeController, AnalyticsController, AhoyActivitiesController -- **`api/v1/`**: ApiController base, Authentications, Workshops, Quotes, Resources - **`events/`**: Registrations sub-resource (create/destroy + slug-based show at `/registration/:slug`) - **Devise overrides**: Registrations, Confirmations, Passwords @@ -153,7 +152,6 @@ end - `TaggingSearchService` — Search and filter tagging data - `PersonFromUserService` — Create Person from User account - `BulkInviteService` — Bulk send welcome instructions and reset created_at for users -- `AuthenticationToken` — JWT token generation for API - `ModelDeduper` — Deduplication logic - `NotificationServices::CreateNotification` — Notification creation - `NotificationServices::PersistDeliveredEmail` — Email delivery tracking @@ -311,7 +309,6 @@ RuboCop linting on PRs and pushes to main. | Geocoding | Geocoder + MaxMind GeoIP2 | | Email styling | Premailer-rails (inline CSS) | | Positioning | Positioning gem for ordered records | -| API | JWT tokens, Apipie docs, Rack CORS | ## Rake Tasks diff --git a/app/controllers/api/v1/api_controller.rb b/app/controllers/api/v1/api_controller.rb deleted file mode 100644 index f5f095951..000000000 --- a/app/controllers/api/v1/api_controller.rb +++ /dev/null @@ -1,34 +0,0 @@ -class Api::V1::ApiController < ActionController::API - include ActionController::RequestForgeryProtection - protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format.json? } - - rescue_from AuthenticationFailed, with: :authentication_failed - before_action :authenticate_api_user! - - def authenticate_api_user! - raise AuthenticationFailed unless current_api_user.present? - end - - def current_api_user - if http_auth_header_content - @current_user ||= User.find_by(id: AuthenticationToken.new(http_auth_header_content).user_id) - elsif current_user - @current_user - end - end - - def authentication_failed(exception) - render json: { error: exception.message }, status: :unauthorized - end - - private - - def http_auth_header_content - if request.headers["Authorization"].present? - @http_auth_header_content ||= - request.headers["Authorization"].split(" ").last - else - @http_auth_header_content ||= params["Authorization"] - end - end -end diff --git a/app/controllers/api/v1/authentications_controller.rb b/app/controllers/api/v1/authentications_controller.rb deleted file mode 100644 index 603d5f063..000000000 --- a/app/controllers/api/v1/authentications_controller.rb +++ /dev/null @@ -1,18 +0,0 @@ -class Api::V1::AuthenticationsController < Api::V1::ApiController - skip_before_action :authenticate_api_user! - api :POST, "/v1/authentications" - param :email, String, "User's email", required: true - param :password, String, "User's password", required: true - desc "With valid credentials, return's an API Authorization token" - def create - user = User.find_by_email(params[:email]) - if user.present? && user.valid_password?(params[:password]) - - sign_in user - token = AuthenticationToken.generate_token(user.id).to_s - render json: { token: token, user: user, url: "#{request.base_url}/?Authorization=#{token}" }, status: :created - else - render json: { error: "Not Authorized", status: :unauthorized } - end - end -end diff --git a/app/controllers/api/v1/quotes_controller.rb b/app/controllers/api/v1/quotes_controller.rb deleted file mode 100644 index cb04c2e21..000000000 --- a/app/controllers/api/v1/quotes_controller.rb +++ /dev/null @@ -1,15 +0,0 @@ -class Api::V1::QuotesController < Api::V1::ApiController - api :GET, "/v1/quotes" - param :Authorization, String, desc: "API Authorization token returned by successful"\ - " user authentication", required: true - # param :sector, String, desc: "One of #{Sector.all.pluck(:name).join(', ')}" - param :sector, String, desc: "Sector name" - desc "Without a Sector parameter, gives a list of all quotes grouped by Sector." - def index - sector = Sector.find_by(name: params[:sector]) || Sector.all - quotes = sector.to_json(only: :name, include: { - quotes: { only: :quote } - }) - render json: { quotes: quotes }, status: :ok - end -end diff --git a/app/controllers/api/v1/resources_controller.rb b/app/controllers/api/v1/resources_controller.rb deleted file mode 100644 index 2409f4a98..000000000 --- a/app/controllers/api/v1/resources_controller.rb +++ /dev/null @@ -1,11 +0,0 @@ -class Api::V1::ResourcesController < Api::V1::ApiController - def index - resource_type = params[:type].constantize - if resource_type - @resources = resource_type.all.to_json(include: :related_workshops) - render json: @resources, status: :ok - else - render json: {}, status: :unauthorized - end - end -end diff --git a/app/controllers/api/v1/workshops_controller.rb b/app/controllers/api/v1/workshops_controller.rb deleted file mode 100644 index 4af3c3e30..000000000 --- a/app/controllers/api/v1/workshops_controller.rb +++ /dev/null @@ -1,26 +0,0 @@ -class Api::V1::WorkshopsController < Api::V1::ApiController - api :GET, "/v1/workshops" - param :Authorization, String, desc: "API Authorization token returned by successful"\ - " user authentication", required: true - param :sector, String, desc: "A valid sector name" - desc "Without a Sector parameter, gives a list of workshops grouped by "\ - 'Sector, including quotes and images. Relates to the "Related Workshops" '\ - "view in Sector Impacts" - def index - sector = Sector.find_by_name(params[:sector]) || Sector.all - - workshops = sector.to_json(only: :name, include: { - workshops: { only: [ :id, :title, :description ], - include: [ - { windows_type: { only: :name } }, - { quotes: { only: :quote } }, - { sectors: { only: :name } } - ], - methods: [ :main_image_url, # leaving this until api is refactored - :sector_hashtags ] - } - }) - - render json: workshops, status: :ok - end -end diff --git a/app/errors/authentication_failed.rb b/app/errors/authentication_failed.rb deleted file mode 100644 index f14f6e623..000000000 --- a/app/errors/authentication_failed.rb +++ /dev/null @@ -1,5 +0,0 @@ -class AuthenticationFailed < StandardError - def initialize(message = "Not Authorized") - super(message) - end -end diff --git a/app/services/authentication_token.rb b/app/services/authentication_token.rb deleted file mode 100644 index d7e6a1f42..000000000 --- a/app/services/authentication_token.rb +++ /dev/null @@ -1,32 +0,0 @@ -class AuthenticationToken - EXPIRY_TIME = -> { 2.weeks.from_now } - - def initialize(token) - @token = token - end - - def self.generate_token(user_id, expiry = EXPIRY_TIME.call) - payload = { user_id: user_id, exp: expiry.to_i } - new(JWT.encode(payload, Rails.application.credentials.secret_key_base)) - end - - def to_s - @token - end - - def user_id - decode["user_id"] - end - - private - - def decode - begin - JWT.decode(@token, Rails.application.credentials.secret_key_base).first - rescue JWT::ExpiredSignature - raise AuthenticationFailed.new("Token Expired") - rescue JWT::DecodeError - raise AuthenticationFailed.new("Token Invalid") - end - end -end diff --git a/config/initializers/apipie.rb b/config/initializers/apipie.rb deleted file mode 100644 index 5cf12100c..000000000 --- a/config/initializers/apipie.rb +++ /dev/null @@ -1,8 +0,0 @@ -Apipie.configure do |config| - config.app_name = "Awbw" - config.api_base_url = "/api" - config.doc_base_url = "/api/v1/documentation" - # where is your API defined? - config.api_controllers_matcher = "#{Rails.root}/app/controllers/**/*.rb" - config.app_info = "AWBW Member API for WordPress Site" -end diff --git a/config/initializers/apipie_rails_8_fix.rb b/config/initializers/apipie_rails_8_fix.rb deleted file mode 100644 index 9cf836b82..000000000 --- a/config/initializers/apipie_rails_8_fix.rb +++ /dev/null @@ -1,35 +0,0 @@ -# Monkey patch to fix Rails 8.2 deprecation warnings in apipie-rails 1.5.0 -# ISSUE: The apipie-rails gem uses the old hash argument syntax for routing, -# which is deprecated in Rails 8.1 and will be removed in Rails 8.2: -# DEPRECATION WARNING: get received a hash argument as. Please use a keyword -# instead. Support to hash argument will be removed in Rails 8.2. -# -# SOLUTION: This initializer overrides the apipie routing method to use the new -# keyword argument syntax for Rails route definitions. -# -# OLD SYNTAX (deprecated): -# get 'path', :to => "controller#action", :format => "json" -# get(hash_with_path => "controller#action", :as => :name) -# -# NEW SYNTAX (Rails 8+ compatible): -# get 'path', to: "controller#action", format: "json" -# get "path", to: "controller#action", as: :name -# -# This patch can be removed once apipie-rails is updated to support Rails 8.2+ -# See: https://github.com/Apipie/apipie-rails/issues (check for related issues) -module Apipie - module Routing - module MapperExtensions - def apipie(options = {}) - namespace "apipie", path: Apipie.configuration.doc_base_url do - get "apipie_checksum", to: "apipies#apipie_checksum", format: "json" - constraints(version: %r{[^/]+}, resource: %r{[^/]+}, method: %r{[^/]+}) do - # Convert hash argument to keyword arguments for Rails 8.2 compatibility - route_options = options.reverse_merge(to: "apipies#index", as: :apipie) - get "(:version)/(:resource)/(:method)", **route_options - end - end - end - end - end -end diff --git a/config/routes.rb b/config/routes.rb index 460820e83..960a4b400 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,7 +17,6 @@ resources :images, only: [ :show ] # mount Ckeditor::Engine, at: '/admin/ckeditor', as: 'ckeditor' - apipie authenticate :user, ->(user) { user.super_user? } do mount Blazer::Engine, at: "blazer" end @@ -175,14 +174,6 @@ resources :rich_text_asset_mentions, only: [ :index ] resources :event_mentions, only: [ :index ] - namespace :api do - namespace :v1 do - resources :authentications, only: [ :create ] - resources :quotes - resources :bookmarks - end - end - namespace :home do resources :workshops, only: :index resources :resources, only: :index From c0ed71db2f04f408b419fccf08781765da265846 Mon Sep 17 00:00:00 2001 From: maebeale Date: Fri, 6 Mar 2026 20:28:13 -0500 Subject: [PATCH 2/2] Remove rack-cors and jwt gems (no longer needed) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rack-cors: This app is a traditional server-rendered Rails app using Turbo/Stimulus — all requests originate from the same domain. CORS headers are only needed when a browser makes cross-origin requests (e.g. a separate SPA or external site calling your API). With the API removed and no cross-origin consumers, rack-cors adds middleware to every request for no benefit. Rails does not include built-in CORS support, so if cross-origin needs arise later, rack-cors can be re-added with a proper initializer (one never existed here). jwt: Only used by the now-removed AuthenticationToken service for API auth. No other code references the JWT gem. --- Gemfile | 3 --- Gemfile.lock | 13 ------------- 2 files changed, 16 deletions(-) diff --git a/Gemfile b/Gemfile index 5d1360cac..c20408a38 100644 --- a/Gemfile +++ b/Gemfile @@ -25,11 +25,8 @@ gem "cocoon", "~> 1.2.6" gem "wicked" gem "search_cop" -gem "jwt", "~> 1.2.1" gem "httparty" gem "will_paginate", "~> 3.1.7" -gem "apipie-rails", "~> 1.5.0" -gem "rack-cors", require: "rack/cors" # gem "ckeditor", "~> 4.3.0" # removed given gh security scan results. still need a replacement. gem "image_processing" diff --git a/Gemfile.lock b/Gemfile.lock index baf8a1f31..bde93f6b4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -101,9 +101,6 @@ GEM activesupport (>= 7.1) device_detector (>= 1) safely_block (>= 0.4) - apipie-rails (1.5.0) - actionpack (>= 5.0) - activesupport (>= 5.0) ast (2.4.3) aws-eventstream (1.4.0) aws-partitions (1.1213.0) @@ -276,7 +273,6 @@ GEM railties (>= 4.2.0) thor (>= 0.14, < 2.0) json (2.18.1) - jwt (1.2.1) language_server-protocol (3.17.0.5) launchy (3.1.1) addressable (~> 2.8) @@ -556,9 +552,6 @@ GEM raabro (1.4.0) racc (1.8.1) rack (3.2.5) - rack-cors (3.0.0) - logger - rack (>= 3.0.14) rack-mini-profiler (4.0.1) rack (>= 1.2.0) rack-proxy (0.7.7) @@ -772,7 +765,6 @@ DEPENDENCIES action_policy (~> 0.7.6) active_storage_validations (~> 3.0) ahoy_matey - apipie-rails (~> 1.5.0) aws-sdk-s3 bcrypt (= 3.1.16) better_errors @@ -801,7 +793,6 @@ DEPENDENCIES jbuilder (~> 2.0) jquery-rails json (>= 2.6, < 3) - jwt (~> 1.2.1) launchy listen maxmind-geoip2 (~> 1.5, >= 1.5.1) @@ -814,7 +805,6 @@ DEPENDENCIES pry-coolline pry-rails puma (~> 6.0) - rack-cors rack-mini-profiler (~> 4.0) rails (~> 8.1.0) rspec-rails @@ -854,7 +844,6 @@ CHECKSUMS activesupport (8.1.2) sha256=88842578ccd0d40f658289b0e8c842acfe9af751afee2e0744a7873f50b6fdae addressable (2.8.8) sha256=7c13b8f9536cf6364c03b9d417c19986019e28f7c00ac8132da4eb0fe393b057 ahoy_matey (5.4.1) sha256=b9ccac7f497889de6982f1503b41a7e275c5a6e4e12a6947b418c69c2c2119b1 - apipie-rails (1.5.0) sha256=92c0fba527978f1d151ae381dffdae34399d01e6a711daa8e14e522e51f8b444 ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383 aws-eventstream (1.4.0) sha256=116bf85c436200d1060811e6f5d2d40c88f65448f2125bc77ffce5121e6e183b aws-partitions (1.1213.0) sha256=5ec132d91d44ef2702125b8f71f0e4fc2cd7de040e02c5d0aefb87219fd2e05e @@ -936,7 +925,6 @@ CHECKSUMS jmespath (1.6.2) sha256=238d774a58723d6c090494c8879b5e9918c19485f7e840f2c1c7532cf84ebcb1 jquery-rails (4.6.1) sha256=619f3496cdcdeaae1fd6dafa52dbac3fc45b745d4e09712da4184a16b3a8d9c0 json (2.18.1) sha256=fe112755501b8d0466b5ada6cf50c8c3f41e897fa128ac5d263ec09eedc9f986 - jwt (1.2.1) sha256=b0cfc9e85b2f851aa49931a4c07156127888fbf003e7ef971d4d6c2e91f98661 language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc launchy (3.1.1) sha256=72b847b5cc961589dde2c395af0108c86ff0119f42d4648d25b5440ebb10059e lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87 @@ -1044,7 +1032,6 @@ CHECKSUMS raabro (1.4.0) sha256=d4fa9ff5172391edb92b242eed8be802d1934b1464061ae5e70d80962c5da882 racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f rack (3.2.5) sha256=4cbd0974c0b79f7a139b4812004a62e4c60b145cba76422e288ee670601ed6d3 - rack-cors (3.0.0) sha256=7b95be61db39606906b61b83bd7203fa802b0ceaaad8fcb2fef39e097bf53f68 rack-mini-profiler (4.0.1) sha256=485810c23211f908196c896ea10cad72ed68780ee2998bec1f1dfd7558263d78 rack-proxy (0.7.7) sha256=446a4b57001022145d5c3ba73b775f66a2260eaf7420c6907483141900395c8a rack-session (2.1.1) sha256=0b6dc07dea7e4b583f58a48e8b806d4c9f1c6c9214ebc202ec94562cbea2e4e9