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/Gemfile b/Gemfile index 10bba5ec1..7bcb28ab3 100644 --- a/Gemfile +++ b/Gemfile @@ -26,11 +26,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 62e61ce31..ed6022a04 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) @@ -277,7 +274,6 @@ GEM railties (>= 4.2.0) thor (>= 0.14, < 2.0) json (2.18.1) - jwt (1.2.1) kt-paperclip (7.1.1) activemodel (>= 4.2.0) activesupport (>= 4.2.0) @@ -567,9 +563,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) @@ -785,7 +778,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 @@ -814,7 +806,6 @@ DEPENDENCIES jbuilder (~> 2.0) jquery-rails json (>= 2.6, < 3) - jwt (~> 1.2.1) kt-paperclip (~> 7.1.1) launchy listen @@ -828,7 +819,6 @@ DEPENDENCIES pry-coolline pry-rails puma (~> 6.0) - rack-cors rack-mini-profiler (~> 4.0) rails (~> 8.1.0) rspec-rails @@ -868,7 +858,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 @@ -951,7 +940,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 kt-paperclip (7.1.1) sha256=b9b3cedd8722c24abaf144f2fa28906e93ea666b103660fda4760ad1e855cf22 language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc launchy (3.1.1) sha256=72b847b5cc961589dde2c395af0108c86ff0119f42d4648d25b5440ebb10059e @@ -1062,7 +1050,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 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 bbd10c7d9..84cb1ff7c 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