docbrown/config/routes.rb
Jeremy Friesen 6fb7361552
Extracting listing routes (#16338)
The fundamental goal in this refactor is to make it easier to disable the
Listings feature set.  By extracting a routes file (via the `draw` method [see
implementation details][1]), we can more easily disable those routes _en
masse_.  This "crease in the code" could mean that we wouldn't need to update
the controller action logic.  An update of that logic might mean going into
each controller action related to listing and adding a conditional for render
404 when listing is disabled.

Now, on to why this should work (not I did not open the application and click
around, but instead went with a "let the framework help me" mindset).

I believe that this should work; though there's a caveat†.  Here's why I
believe this will work for extracting the listing routes:

Before making changes I ran the following:

```sh
$ rails routes | sort > original-routes.txt
```

Let's break that down:

- `rails routes` :: renders the routing table for Rails; this is how
  Rails converts routes to the magic of stuff like `article_path(:id)`
- `| sort` :: to sort the results
- `> original-routes.txt` :: to write the results into a file.

Then I made the changes and ran the following:

```sh
$ rails routes | sort > updated-listing-routes.txt
```

And finally, I ran:

```sh
$ diff updated-routes.txt original-routes.txt
```

The results were as follows:

```sh
500c500
<                     api_organization_listings GET      (/locale/:locale)/api/organizations/:organization_username/listings(.:format)          api/v0/organizations#listings {:locale=>nil, :format=>"json", :to=>"organizations#listings"}
---
>                     api_organization_listings GET      (/locale/:locale)/api/organizations/:organization_username/listings(.:format)          api/v0/organizations#listings {:locale=>nil, :format=>"json"}
```

Note the only difference is that the above two lines, one has
`:to=>"organizations#listings"` and the other does not.  However, the
`./spec/requests/api/v0/organizations_spec.rb` exercises the route; so I
assume a hiccup/foible in the route reporting.

There was no difference between the before and after files.

† Caveat: if for some reason the order of the routes mattered, this will
have messed that up.  I don't think that is the case, but we shall see.

Related to forem/rfcs#291 and #16335
2022-01-28 10:49:52 -05:00

384 lines
17 KiB
Ruby

# rubocop:disable Metrics/BlockLength
Rails.application.routes.draw do
# Devise does not support scoping omniauth callbacks under a dynamic segment
# so this lives outside our i18n scope.
devise_for :users, controllers: {
omniauth_callbacks: "omniauth_callbacks",
registrations: "registrations",
invitations: "invitations",
passwords: "passwords",
confirmations: "confirmations"
}
devise_scope :user do
get "/enter", to: "registrations#new", as: :sign_up
get "/confirm-email", to: "confirmations#new"
delete "/sign_out", to: "devise/sessions#destroy"
end
get "/r/mobile", to: "deep_links#mobile"
get "/.well-known/apple-app-site-association", to: "deep_links#aasa"
# [@forem/delightful] - all routes are nested under this optional scope to
# begin supporting i18n.
scope "(/locale/:locale)", defaults: { locale: nil } do
get "/locale/:locale", to: "stories#index"
draw :admin
draw :listing
namespace :stories, defaults: { format: "json" } do
resource :feed, only: [:show] do
resource :pinned_article, only: %w[show update destroy]
get ":timeframe", to: "feeds#show", as: :timeframe
end
end
namespace :api, defaults: { format: "json" } do
scope module: :v0, constraints: ApiConstraints.new(version: 0, default: true) do
resources :articles, only: %i[index show create update] do
collection do
get "me(/:status)", to: "articles#me", as: :me, constraints: { status: /published|unpublished|all/ }
get "/:username/:slug", to: "articles#show_by_slug", as: :slug
get "/latest", to: "articles#index", defaults: { sort: "desc" }
end
end
resources :comments, only: %i[index show]
resources :videos, only: [:index]
resources :podcast_episodes, only: [:index]
resources :users, only: %i[show] do
collection do
get :me
end
end
resources :tags, only: [:index]
resources :follows, only: [:create] do
collection do
get :tags
end
end
namespace :followers do
get :users
get :organizations
end
resources :readinglist, only: [:index]
get "/analytics/totals", to: "analytics#totals"
get "/analytics/historical", to: "analytics#historical"
get "/analytics/past_day", to: "analytics#past_day"
get "/analytics/referrers", to: "analytics#referrers"
resources :health_checks, only: [] do
collection do
get :app
get :database
get :cache
end
end
resources :profile_images, only: %i[show], param: :username
resources :organizations, only: [:show], param: :username do
resources :users, only: [:index], to: "organizations#users"
resources :articles, only: [:index], to: "organizations#articles"
end
resource :instance, only: %i[show]
end
end
namespace :notifications do
resources :counts, only: [:index]
resources :reads, only: [:create]
end
namespace :incoming_webhooks do
get "/mailchimp/:secret/unsubscribe", to: "mailchimp_unsubscribes#index", as: :mailchimp_unsubscribe_check
post "/mailchimp/:secret/unsubscribe", to: "mailchimp_unsubscribes#create", as: :mailchimp_unsubscribe
end
resources :messages, only: [:create]
resources :articles, only: %i[update create destroy] do
patch "/admin_unpublish", to: "articles#admin_unpublish"
end
resources :article_mutes, only: %i[update]
resources :comments, only: %i[create update destroy] do
patch "/hide", to: "comments#hide"
patch "/unhide", to: "comments#unhide"
patch "/admin_delete", to: "comments#admin_delete"
collection do
post "/moderator_create", to: "comments#moderator_create"
end
end
resources :comment_mutes, only: %i[update]
resources :users, only: %i[index], defaults: { format: :json } do # internal API
collection do
resources :devices, only: %i[create destroy]
end
end
namespace :users do
resource :settings, only: %i[update]
resource :notification_settings, only: %i[update]
end
resources :users, only: %i[update]
resources :reactions, only: %i[index create]
resources :response_templates, only: %i[index create edit update destroy]
resources :feedback_messages, only: %i[index create]
resources :organizations, only: %i[update create destroy]
resources :follows, only: %i[show create] do
collection do
get "/bulk_show", to: "follows#bulk_show"
patch "/bulk_update", to: "follows#bulk_update"
end
end
resources :image_uploads, only: [:create]
resources :notifications, only: [:index]
resources :tags, only: [:index] do
collection do
get "/onboarding", to: "tags#onboarding"
get "/suggest", to: "tags#suggest", defaults: { format: :json }
end
end
resources :stripe_active_cards, only: %i[create update destroy]
resources :github_repos, only: %i[index] do
collection do
post "/update_or_create", to: "github_repos#update_or_create"
end
end
resources :videos, only: %i[index create new]
resources :video_states, only: [:create]
resources :twilio_tokens, only: [:show]
resources :html_variant_trials, only: [:create]
resources :html_variant_successes, only: [:create]
resources :tag_adjustments, only: %i[create destroy]
resources :rating_votes, only: [:create]
resources :page_views, only: %i[create update]
resources :credits, only: %i[index new create] do
get "purchase", on: :collection, to: "credits#new"
end
resources :reading_list_items, only: [:update]
resources :poll_votes, only: %i[show create]
resources :poll_skips, only: [:create]
resources :profile_pins, only: %i[create update]
resources :display_ad_events, only: [:create]
resources :badges, only: [:index]
resources :user_blocks, param: :blocked_id, only: %i[show create destroy]
resources :podcasts, only: %i[new create]
resources :article_approvals, only: %i[create]
resources :sidebars, only: %i[show]
resources :profile_preview_cards, only: %i[show]
resources :user_subscriptions, only: %i[create] do
collection do
get "/subscribed", action: "subscribed"
end
end
namespace :followings, defaults: { format: :json } do
get :users
get :tags
get :organizations
get :podcasts
end
resource :onboarding, only: :show
resources :profiles, only: %i[update]
resources :profile_field_groups, only: %i[index], defaults: { format: :json }
resources :liquid_tags, only: %i[index], defaults: { format: :json }
resources :discussion_locks, only: %i[create destroy]
get "/verify_email_ownership", to: "email_authorizations#verify", as: :verify_email_authorizations
get "/search/tags", to: "search#tags"
get "/search/usernames", to: "search#usernames"
get "/search/feed_content", to: "search#feed_content"
get "/search/reactions", to: "search#reactions"
get "/notifications/:filter", to: "notifications#index", as: :notifications_filter
get "/notifications/:filter/:org_id", to: "notifications#index", as: :notifications_filter_org
get "/notification_subscriptions/:notifiable_type/:notifiable_id", to: "notification_subscriptions#show"
post "/notification_subscriptions/:notifiable_type/:notifiable_id", to: "notification_subscriptions#upsert"
patch "/onboarding_update", to: "users#onboarding_update"
patch "/onboarding_checkbox_update", to: "users#onboarding_checkbox_update"
patch "/onboarding_notifications_checkbox_update",
to: "users/notification_settings#onboarding_notifications_checkbox_update"
get "email_subscriptions/unsubscribe"
get "/internal", to: redirect("/admin")
get "/internal/:path", to: redirect("/admin/%{path}")
get "/social_previews/article/:id", to: "social_previews#article", as: :article_social_preview
get "/social_previews/user/:id", to: "social_previews#user", as: :user_social_preview
get "/social_previews/organization/:id", to: "social_previews#organization", as: :organization_social_preview
get "/social_previews/tag/:id", to: "social_previews#tag", as: :tag_social_preview
get "/social_previews/comment/:id", to: "social_previews#comment", as: :comment_social_preview
get "/async_info/base_data", controller: "async_info#base_data", defaults: { format: :json }
# Settings
post "users/join_org", to: "users#join_org"
post "users/leave_org/:organization_id", to: "users#leave_org", as: :users_leave_org
post "users/add_org_admin", to: "users#add_org_admin"
post "users/remove_org_admin", to: "users#remove_org_admin"
post "users/remove_from_org", to: "users#remove_from_org"
delete "users/remove_identity", to: "users#remove_identity"
post "users/request_destroy", to: "users#request_destroy", as: :user_request_destroy
get "users/confirm_destroy/:token", to: "users#confirm_destroy", as: :user_confirm_destroy
delete "users/full_delete", to: "users#full_delete", as: :user_full_delete
post "organizations/generate_new_secret", to: "organizations#generate_new_secret"
post "users/api_secrets", to: "api_secrets#create", as: :users_api_secrets
delete "users/api_secrets/:id", to: "api_secrets#destroy", as: :users_api_secret
post "users/update_password", to: "users#update_password", as: :user_update_password
# The priority is based upon order of creation: first created -> highest priority.
# See how all your routes lay out with "rake routes".
# You can have the root of your site routed with "root
get "/robots.:format", to: "pages#robots"
get "/api", to: redirect("https://developers.forem.com/api")
get "/privacy", to: "pages#privacy"
get "/terms", to: "pages#terms"
get "/contact", to: "pages#contact"
get "/code-of-conduct", to: "pages#code_of_conduct"
get "/report-abuse", to: "pages#report_abuse"
get "/welcome", to: "pages#welcome"
get "/challenge", to: "pages#challenge"
get "/checkin", to: "pages#checkin"
get "/💸", to: redirect("t/hiring")
get "/survey", to: redirect("https://dev.to/ben/final-thoughts-on-the-state-of-the-web-survey-44nn")
get "/sponsors", to: "pages#sponsors"
get "/search", to: "stories/articles_search#index"
post "articles/preview", to: "articles#preview"
post "comments/preview", to: "comments#preview"
# These routes are required by links in the sites and will most likely to be replaced by a db page
get "/about", to: "pages#about"
get "/security", to: "pages#bounty"
get "/community-moderation", to: "pages#community_moderation"
get "/faq", to: "pages#faq"
get "/page/post-a-job", to: "pages#post_a_job"
get "/tag-moderation", to: "pages#tag_moderation"
get "/mod", to: "moderations#index", as: :mod
get "/mod/:tag", to: "moderations#index"
post "/fallback_activity_recorder", to: "ga_events#create"
get "/page/:slug", to: "pages#show"
scope "p" do
pages_actions = %w[welcome editor_guide publishing_from_rss_guide markdown_basics].freeze
pages_actions.each do |action|
get action, action: action, controller: "pages"
end
end
# Redirect previous settings changed after https://github.com/forem/forem/pull/11347
get "/settings/integrations", to: redirect("/settings/extensions")
get "/settings/misc", to: redirect("/settings")
get "/settings/publishing-from-rss", to: redirect("/settings/extensions")
get "/settings/ux", to: redirect("/settings/customization")
get "/settings/(:tab)", to: "users#edit", as: :user_settings
get "/settings/:tab/:org_id", to: "users#edit", constraints: { tab: /organization/ }
get "/settings/:tab/:id", to: "users#edit", constraints: { tab: /response-templates/ }
get "/signout_confirm", to: "users#signout_confirm"
get "/dashboard", to: "dashboards#show"
get "/dashboard/analytics", to: "dashboards#analytics"
get "dashboard/analytics/org/:org_id", to: "dashboards#analytics", as: :dashboard_analytics_org
get "dashboard/following", to: "dashboards#following_tags"
get "dashboard/following_tags", to: "dashboards#following_tags"
get "dashboard/following_users", to: "dashboards#following_users"
get "dashboard/following_organizations", to: "dashboards#following_organizations"
get "dashboard/following_podcasts", to: "dashboards#following_podcasts"
get "/dashboard/subscriptions", to: "dashboards#subscriptions"
get "/dashboard/:which", to: "dashboards#followers", constraints: { which: /user_followers/ }
get "/dashboard/:which/:org_id", to: "dashboards#show",
constraints: {
which: /organization/
}
get "/dashboard/:username", to: "dashboards#show"
# for testing rails mailers
unless Rails.env.production?
get "/rails/mailers", to: "rails/mailers#index"
get "/rails/mailers/*path", to: "rails/mailers#preview"
end
get "/embed/:embeddable", to: "liquid_embeds#show", as: "liquid_embed"
# serviceworkers
get "/serviceworker", to: "service_worker#index"
get "/manifest", to: "service_worker#manifest"
# open search
get "/open-search", to: "open_search#show",
constraints: { format: /xml/ }
get "/new", to: "articles#new"
get "/new/:template", to: "articles#new"
get "/pod", to: "podcast_episodes#index"
get "/podcasts", to: redirect("pod")
get "/readinglist", to: "reading_list_items#index"
get "/readinglist/:view", to: "reading_list_items#index", constraints: { view: /archive/ }
get "/feed", to: "articles#feed", as: "feed", defaults: { format: "rss" }
get "/feed/tag/:tag", to: "articles#feed", as: "tag_feed", defaults: { format: "rss" }
get "/feed/latest", to: "articles#feed", as: "latest_feed", defaults: { format: "rss" }
get "/feed/:username", to: "articles#feed", as: "user_feed", defaults: { format: "rss" }
get "/rss", to: "articles#feed", defaults: { format: "rss" }
get "/tag/:tag", to: "stories/tagged_articles#index"
get "/t/:tag", to: "stories/tagged_articles#index", as: :tag
get "/t/:tag/top/:timeframe", to: "stories/tagged_articles#index"
get "/t/:tag/page/:page", to: "stories/tagged_articles#index"
get "/t/:tag/:timeframe", to: "stories/tagged_articles#index",
constraints: { timeframe: /latest/ }
get "/t/:tag/edit", to: "tags#edit", as: :edit_tag
get "/t/:tag/admin", to: "tags#admin"
patch "/tag/:id", to: "tags#update"
get "/badge/:slug", to: "badges#show", as: :badge
get "/top/:timeframe", to: "stories#index"
get "/:timeframe", to: "stories#index", constraints: { timeframe: /latest/ }
get "/:username/series", to: "collections#index", as: "user_series"
get "/:username/series/:id", to: "collections#show"
# Legacy comment format (might still be floating around app, and external links)
get "/:username/:slug/comments", to: "comments#index"
get "/:username/:slug/comments/:id_code", to: "comments#index"
get "/:username/:slug/comments/:id_code/edit", to: "comments#edit"
get "/:username/:slug/comments/:id_code/delete_confirm", to: "comments#delete_confirm"
# Proper link format
get "/:username/comment/:id_code", to: "comments#index"
get "/:username/comment/:id_code/edit", to: "comments#edit"
get "/:username/comment/:id_code/delete_confirm", to: "comments#delete_confirm"
get "/:username/comment/:id_code/mod", to: "moderations#comment"
get "/:username/comment/:id_code/settings", to: "comments#settings"
get "/:username/:slug/:view", to: "stories#show",
constraints: { view: /moderate/ }
get "/:username/:slug/mod", to: "moderations#article"
get "/:username/:slug/actions_panel", to: "moderations#actions_panel"
get "/:username/:slug/manage", to: "articles#manage", as: :article_manage
get "/:username/:slug/edit", to: "articles#edit"
get "/:username/:slug/delete_confirm", to: "articles#delete_confirm"
get "/:username/:slug/discussion_lock_confirm", to: "articles#discussion_lock_confirm"
get "/:username/:slug/discussion_unlock_confirm", to: "articles#discussion_unlock_confirm"
get "/:username/:slug/stats", to: "articles#stats"
get "/:username/:view", to: "stories#index",
constraints: { view: /comments|moderate|admin/ }
get "/:username/:slug", to: "stories#show"
get "/:sitemap", to: "sitemaps#show",
constraints: { format: /xml/, sitemap: /sitemap-.+/ }
get "/:username", to: "stories#index", as: "user_profile"
root "stories#index"
end
end
# rubocop:enable Metrics/BlockLength