PageRenderTime 8ms CodeModel.GetById 3ms app.highlight 153ms RepoModel.GetById 1ms app.codeStats 1ms

/config/routes.rb

https://bitbucket.org/bitworkvn/cs_discourse
Ruby | 805 lines | 667 code | 119 blank | 19 comment | 5 complexity | dd52055db3fa323fd7c0522e0112589f MD5 | raw file
  1require "sidekiq/web"
  2require_dependency "scheduler/web"
  3require_dependency "admin_constraint"
  4require_dependency "staff_constraint"
  5require_dependency "homepage_constraint"
  6require_dependency "permalink_constraint"
  7
  8# The following constants have been replaced with `RouteFormat` and are deprecated.
  9USERNAME_ROUTE_FORMAT = /[\w.\-]+?/ unless defined? USERNAME_ROUTE_FORMAT
 10BACKUP_ROUTE_FORMAT = /.+\.(sql\.gz|tar\.gz|tgz)/i unless defined? BACKUP_ROUTE_FORMAT
 11
 12Discourse::Application.routes.draw do
 13  relative_url_root = (defined?(Rails.configuration.relative_url_root) && Rails.configuration.relative_url_root) ? Rails.configuration.relative_url_root + '/' : '/'
 14
 15  match "/404", to: "exceptions#not_found", via: [:get, :post]
 16  get "/404-body" => "exceptions#not_found_body"
 17
 18  post "webhooks/mailgun"  => "webhooks#mailgun"
 19  post "webhooks/sendgrid" => "webhooks#sendgrid"
 20  post "webhooks/mailjet"  => "webhooks#mailjet"
 21  post "webhooks/mandrill" => "webhooks#mandrill"
 22  post "webhooks/sparkpost" => "webhooks#sparkpost"
 23
 24  if Rails.env.development?
 25    mount Sidekiq::Web => "/sidekiq"
 26    mount Logster::Web => "/logs"
 27  else
 28    # only allow sidekiq in master site
 29    mount Sidekiq::Web => "/sidekiq", constraints: AdminConstraint.new(require_master: true)
 30    mount Logster::Web => "/logs", constraints: AdminConstraint.new
 31  end
 32
 33  resources :about do
 34    collection do
 35      get "live_post_counts"
 36    end
 37  end
 38
 39  get "finish-installation" => "finish_installation#index"
 40  get "finish-installation/register" => "finish_installation#register"
 41  post "finish-installation/register" => "finish_installation#register"
 42  get "finish-installation/confirm-email" => "finish_installation#confirm_email"
 43  put "finish-installation/resend-email" => "finish_installation#resend_email"
 44
 45  resources :directory_items
 46
 47  get "site" => "site#site"
 48  namespace :site do
 49    get "settings"
 50    get "custom_html"
 51    get "banner"
 52    get "emoji"
 53  end
 54
 55  get "site/basic-info" => 'site#basic_info'
 56  get "site/statistics" => 'site#statistics'
 57
 58  get "srv/status" => "forums#status"
 59
 60  get "wizard" => "wizard#index"
 61  get "wizard/qunit" => "wizard#qunit"
 62  get 'wizard/steps' => 'steps#index'
 63  get 'wizard/steps/:id' => "wizard#index"
 64  put 'wizard/steps/:id' => "steps#update"
 65
 66  namespace :admin, constraints: StaffConstraint.new do
 67    get "" => "admin#index"
 68
 69    get 'plugins' => 'plugins#index'
 70
 71    resources :site_settings, constraints: AdminConstraint.new do
 72      collection do
 73        get "category/:id" => "site_settings#index"
 74      end
 75    end
 76
 77    get "reports/:type" => "reports#show"
 78
 79    resources :groups, constraints: AdminConstraint.new do
 80      collection do
 81        get 'bulk'
 82        get 'bulk-complete' => 'groups#bulk'
 83        put 'bulk' => 'groups#bulk_perform'
 84      end
 85      member do
 86        put "owners" => "groups#add_owners"
 87        delete "owners" => "groups#remove_owner"
 88      end
 89    end
 90
 91    get "groups/:type" => "groups#show", constraints: AdminConstraint.new
 92    get "groups/:type/:id" => "groups#show", constraints: AdminConstraint.new
 93
 94    get "moderation_history" => "moderation_history#index"
 95
 96    resources :users, id: RouteFormat.username, except: [:show] do
 97      collection do
 98        get "list" => "users#index"
 99        get "list/:query" => "users#index"
100        get "ip-info" => "users#ip_info"
101        delete "delete-others-with-same-ip" => "users#delete_other_accounts_with_same_ip"
102        get "total-others-with-same-ip" => "users#total_other_accounts_with_same_ip"
103        put "approve-bulk" => "users#approve_bulk"
104        delete "reject-bulk" => "users#reject_bulk"
105      end
106      put "suspend"
107      put "delete_all_posts"
108      put "unsuspend"
109      put "revoke_admin", constraints: AdminConstraint.new
110      put "grant_admin", constraints: AdminConstraint.new
111      post "generate_api_key", constraints: AdminConstraint.new
112      delete "revoke_api_key", constraints: AdminConstraint.new
113      put "revoke_moderation", constraints: AdminConstraint.new
114      put "grant_moderation", constraints: AdminConstraint.new
115      put "approve"
116      post "refresh_browsers", constraints: AdminConstraint.new
117      post "log_out", constraints: AdminConstraint.new
118      put "activate"
119      put "deactivate"
120      put "silence"
121      put "unsilence"
122      put "trust_level"
123      put "trust_level_lock"
124      put "primary_group"
125      post "groups" => "users#add_group", constraints: AdminConstraint.new
126      delete "groups/:group_id" => "users#remove_group", constraints: AdminConstraint.new
127      get "badges"
128      get "leader_requirements" => "users#tl3_requirements"
129      get "tl3_requirements"
130      put "anonymize"
131      post "reset_bounce_score"
132      put "disable_second_factor"
133    end
134    get "users/:id.json" => 'users#show', defaults: { format: 'json' }
135    get 'users/:id/:username' => 'users#show', constraints: { username: RouteFormat.username }
136    get 'users/:id/:username/badges' => 'users#show'
137    get 'users/:id/:username/tl3_requirements' => 'users#show'
138
139    post "users/sync_sso" => "users#sync_sso", constraints: AdminConstraint.new
140    post "users/invite_admin" => "users#invite_admin", constraints: AdminConstraint.new
141
142    resources :impersonate, constraints: AdminConstraint.new
143
144    resources :email, constraints: AdminConstraint.new do
145      collection do
146        post "test"
147        get "sent"
148        get "skipped"
149        get "bounced"
150        get "received"
151        get "rejected"
152        get "/incoming/:id/raw" => "email#raw_email"
153        get "/incoming/:id" => "email#incoming"
154        get "/incoming_from_bounced/:id" => "email#incoming_from_bounced"
155        get "preview-digest" => "email#preview_digest"
156        get "send-digest" => "email#send_digest"
157        get "smtp_should_reject"
158        post "handle_mail"
159      end
160    end
161
162    scope "/logs" do
163      resources :staff_action_logs,     only: [:index]
164      get 'staff_action_logs/:id/diff' => 'staff_action_logs#diff'
165      resources :screened_emails,       only: [:index, :destroy]
166      resources :screened_ip_addresses, only: [:index, :create, :update, :destroy] do
167        collection do
168          post "roll_up"
169        end
170      end
171      resources :screened_urls,         only: [:index]
172      resources :watched_words, only: [:index, :create, :update, :destroy] do
173        collection do
174          get "action/:id" => "watched_words#index"
175        end
176      end
177      post "watched_words/upload" => "watched_words#upload"
178      resources :search_logs,           only: [:index]
179      get 'search_logs/term/:term' => 'search_logs#term'
180    end
181
182    get "/logs" => "staff_action_logs#index"
183
184    get "customize" => "color_schemes#index", constraints: AdminConstraint.new
185    get "customize/themes" => "themes#index", constraints: AdminConstraint.new
186    get "customize/colors" => "color_schemes#index", constraints: AdminConstraint.new
187    get "customize/colors/:id" => "color_schemes#index", constraints: AdminConstraint.new
188    get "customize/permalinks" => "permalinks#index", constraints: AdminConstraint.new
189    get "customize/embedding" => "embedding#show", constraints: AdminConstraint.new
190    put "customize/embedding" => "embedding#update", constraints: AdminConstraint.new
191
192    get "flags" => "flags#index"
193    get "flags/:filter" => "flags#index", as: 'flags_filtered'
194    get "flags/topics/:topic_id" => "flags#index"
195    post "flags/agree/:id" => "flags#agree"
196    post "flags/disagree/:id" => "flags#disagree"
197    post "flags/defer/:id" => "flags#defer"
198
199    resources :flagged_topics, constraints: StaffConstraint.new
200    resources :themes, constraints: AdminConstraint.new
201
202    post "themes/import" => "themes#import"
203    post "themes/upload_asset" => "themes#upload_asset"
204    post "themes/generate_key_pair" => "themes#generate_key_pair"
205    get "themes/:id/preview" => "themes#preview"
206
207    scope "/customize", constraints: AdminConstraint.new do
208      resources :user_fields, constraints: AdminConstraint.new
209      resources :emojis, constraints: AdminConstraint.new
210
211      get 'themes/:id/:target/:field_name/edit' => 'themes#index'
212      get 'themes/:id' => 'themes#index'
213
214      # They have periods in their URLs often:
215      get 'site_texts'          => 'site_texts#index'
216      get 'site_texts/(:id)'    => 'site_texts#show',   constraints: { id: /[\w.\-\+]+/i }
217      put 'site_texts/(:id)'    => 'site_texts#update', constraints: { id: /[\w.\-\+]+/i }
218      delete 'site_texts/(:id)' => 'site_texts#revert', constraints: { id: /[\w.\-\+]+/i }
219
220      get 'email_templates'          => 'email_templates#index'
221      get 'email_templates/(:id)'    => 'email_templates#show',   constraints: { id: /[0-9a-z_.]+/ }
222      put 'email_templates/(:id)'    => 'email_templates#update', constraints: { id: /[0-9a-z_.]+/ }
223      delete 'email_templates/(:id)' => 'email_templates#revert', constraints: { id: /[0-9a-z_.]+/ }
224    end
225
226    resources :embeddable_hosts, constraints: AdminConstraint.new
227    resources :color_schemes, constraints: AdminConstraint.new
228
229    resources :permalinks, constraints: AdminConstraint.new
230
231    get "version_check" => "versions#show"
232
233    get "dashboard-next" => "dashboard_next#index"
234
235    resources :dashboard, only: [:index] do
236      collection do
237        get "problems"
238      end
239    end
240
241    resources :api, only: [:index], constraints: AdminConstraint.new do
242      collection do
243        get "keys" => "api#index"
244        post "key" => "api#create_master_key"
245        put "key" => "api#regenerate_key"
246        delete "key" => "api#revoke_key"
247
248        resources :web_hooks
249        get 'web_hook_events/:id' => 'web_hooks#list_events', as: :web_hook_events
250        get 'web_hooks/:id/events' => 'web_hooks#list_events'
251        get 'web_hooks/:id/events/bulk' => 'web_hooks#bulk_events'
252        post 'web_hooks/:web_hook_id/events/:event_id/redeliver' => 'web_hooks#redeliver_event'
253        post 'web_hooks/:id/ping' => 'web_hooks#ping'
254      end
255    end
256
257    resources :backups, only: [:index, :create], constraints: AdminConstraint.new do
258      member do
259        get "" => "backups#show", constraints: { id: RouteFormat.backup }
260        put "" => "backups#email", constraints: { id: RouteFormat.backup }
261        delete "" => "backups#destroy", constraints: { id: RouteFormat.backup }
262        post "restore" => "backups#restore", constraints: { id: RouteFormat.backup }
263      end
264      collection do
265        get "logs" => "backups#logs"
266        get "status" => "backups#status"
267        delete "cancel" => "backups#cancel"
268        post "rollback" => "backups#rollback"
269        put "readonly" => "backups#readonly"
270        get "upload" => "backups#check_backup_chunk"
271        post "upload" => "backups#upload_backup_chunk"
272      end
273    end
274
275    resources :badges, constraints: AdminConstraint.new do
276      collection do
277        get "types" => "badges#badge_types"
278        post "badge_groupings" => "badges#save_badge_groupings"
279        post "preview" => "badges#preview"
280      end
281    end
282
283    get "memory_stats" => "diagnostics#memory_stats", constraints: AdminConstraint.new
284    get "dump_heap" => "diagnostics#dump_heap", constraints: AdminConstraint.new
285    get "dump_statement_cache" => "diagnostics#dump_statement_cache", constraints: AdminConstraint.new
286  end # admin namespace
287
288  get "email_preferences" => "email#preferences_redirect", :as => "email_preferences_redirect"
289
290  get "email/unsubscribe/:key" => "email#unsubscribe", as: "email_unsubscribe"
291  get "email/unsubscribed" => "email#unsubscribed", as: "email_unsubscribed"
292  post "email/unsubscribe/:key" => "email#perform_unsubscribe", as: "email_perform_unsubscribe"
293
294  get "extra-locales/:bundle" => "extra_locales#show"
295
296  resources :session, id: RouteFormat.username, only: [:create, :destroy, :become] do
297    if !Rails.env.production?
298      get 'become'
299    end
300
301    collection do
302      post "forgot_password"
303    end
304  end
305
306  get "session/sso" => "session#sso"
307  get "session/sso_login" => "session#sso_login"
308  get "session/sso_provider" => "session#sso_provider"
309  get "session/current" => "session#current"
310  get "session/csrf" => "session#csrf"
311  get "session/email-login/:token" => "session#email_login"
312  post "session/email-login/:token" => "session#email_login"
313  get "composer_messages" => "composer_messages#index"
314  post "composer/parse_html" => "composer#parse_html"
315
316  resources :static
317  post "login" => "static#enter", constraints: { format: /(json|html)/ }
318  get "login" => "static#show", id: "login", constraints: { format: /(json|html)/ }
319  get "password-reset" => "static#show", id: "password_reset", constraints: { format: /(json|html)/ }
320  get "faq" => "static#show", id: "faq", constraints: { format: /(json|html)/ }
321  get "guidelines" => "static#show", id: "guidelines", as: 'guidelines', constraints: { format: /(json|html)/ }
322  get "tos" => "static#show", id: "tos", as: 'tos', constraints: { format: /(json|html)/ }
323  get "privacy" => "static#show", id: "privacy", as: 'privacy', constraints: { format: /(json|html)/ }
324  get "signup" => "static#show", id: "signup", constraints: { format: /(json|html)/ }
325  get "login-preferences" => "static#show", id: "login", constraints: { format: /(json|html)/ }
326
327  get "my/*path", to: 'users#my_redirect'
328  get "user_preferences" => "users#user_preferences_redirect"
329
330  %w{users u}.each_with_index do |root_path, index|
331    get "#{root_path}" => "users#index", constraints: { format: 'html' }
332
333    resources :users, except: [:index, :new, :show, :update, :destroy], path: root_path do
334      collection do
335        get "check_username"
336        get "is_local_username"
337      end
338    end
339
340    post "#{root_path}/second_factors" => "users#create_second_factor"
341    put "#{root_path}/second_factor" => "users#update_second_factor"
342
343    put "#{root_path}/update-activation-email" => "users#update_activation_email"
344    get "#{root_path}/hp" => "users#get_honeypot_value"
345    post "#{root_path}/email-login" => "users#email_login"
346    get "#{root_path}/admin-login" => "users#admin_login"
347    put "#{root_path}/admin-login" => "users#admin_login"
348    get "#{root_path}/admin-login/:token" => "users#admin_login"
349    put "#{root_path}/admin-login/:token" => "users#admin_login"
350    post "#{root_path}/toggle-anon" => "users#toggle_anon"
351    post "#{root_path}/read-faq" => "users#read_faq"
352    get "#{root_path}/search/users" => "users#search_users"
353
354    get({ "#{root_path}/account-created/" => "users#account_created" }.merge(index == 1 ? { as: :users_account_created } : { as: :old_account_created }))
355
356    get "#{root_path}/account-created/resent" => "users#account_created"
357    get "#{root_path}/account-created/edit-email" => "users#account_created"
358    get({ "#{root_path}/password-reset/:token" => "users#password_reset" }.merge(index == 1 ? { as: :password_reset_token } : {}))
359    get "#{root_path}/confirm-email-token/:token" => "users#confirm_email_token", constraints: { format: 'json' }
360    put "#{root_path}/password-reset/:token" => "users#password_reset"
361    get "#{root_path}/activate-account/:token" => "users#activate_account"
362    put({ "#{root_path}/activate-account/:token" => "users#perform_account_activation" }.merge(index == 1 ? { as: 'perform_activate_account' } : {}))
363    get "#{root_path}/authorize-email/:token" => "users_email#confirm"
364    put "#{root_path}/authorize-email/:token" => "users_email#confirm"
365    get({
366      "#{root_path}/confirm-admin/:token" => "users#confirm_admin",
367      constraints: { token: /[0-9a-f]+/ }
368    }.merge(index == 1 ? { as: 'confirm_admin' } : {}))
369    post "#{root_path}/confirm-admin/:token" => "users#confirm_admin", constraints: { token: /[0-9a-f]+/ }
370    get "#{root_path}/:username/private-messages" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
371    get "#{root_path}/:username/private-messages/:filter" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
372    get "#{root_path}/:username/messages" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
373    get "#{root_path}/:username/messages/:filter" => "user_actions#private_messages", constraints: { username: RouteFormat.username }
374    get "#{root_path}/:username/messages/group/:group_name" => "user_actions#private_messages", constraints: { username: RouteFormat.username, group_name: RouteFormat.username }
375    get "#{root_path}/:username/messages/group/:group_name/archive" => "user_actions#private_messages", constraints: { username: RouteFormat.username, group_name: RouteFormat.username }
376    get "#{root_path}/:username/messages/tags/:tag_id" => "user_actions#private_messages", constraints: StaffConstraint.new
377    get "#{root_path}/:username.json" => "users#show", constraints: { username: RouteFormat.username }, defaults: { format: :json }
378    get({ "#{root_path}/:username" => "users#show", constraints: { username: RouteFormat.username, format: /(json|html)/ } }.merge(index == 1 ? { as: 'user' } : {}))
379    put "#{root_path}/:username" => "users#update", constraints: { username: RouteFormat.username }, defaults: { format: :json }
380    get "#{root_path}/:username/emails" => "users#check_emails", constraints: { username: RouteFormat.username }
381    get({ "#{root_path}/:username/preferences" => "users#preferences", constraints: { username: RouteFormat.username } }.merge(index == 1 ? { as: :email_preferences } : {}))
382    get "#{root_path}/:username/preferences/email" => "users_email#index", constraints: { username: RouteFormat.username }
383    get "#{root_path}/:username/preferences/account" => "users#preferences", constraints: { username: RouteFormat.username }
384    get "#{root_path}/:username/preferences/profile" => "users#preferences", constraints: { username: RouteFormat.username }
385    get "#{root_path}/:username/preferences/emails" => "users#preferences", constraints: { username: RouteFormat.username }
386    get "#{root_path}/:username/preferences/notifications" => "users#preferences", constraints: { username: RouteFormat.username }
387    get "#{root_path}/:username/preferences/categories" => "users#preferences", constraints: { username: RouteFormat.username }
388    get "#{root_path}/:username/preferences/tags" => "users#preferences", constraints: { username: RouteFormat.username }
389    get "#{root_path}/:username/preferences/interface" => "users#preferences", constraints: { username: RouteFormat.username }
390    get "#{root_path}/:username/preferences/apps" => "users#preferences", constraints: { username: RouteFormat.username }
391    put "#{root_path}/:username/preferences/email" => "users_email#update", constraints: { username: RouteFormat.username }
392    get "#{root_path}/:username/preferences/about-me" => "users#preferences", constraints: { username: RouteFormat.username }
393    get "#{root_path}/:username/preferences/badge_title" => "users#preferences", constraints: { username: RouteFormat.username }
394    put "#{root_path}/:username/preferences/badge_title" => "users#badge_title", constraints: { username: RouteFormat.username }
395    get "#{root_path}/:username/preferences/username" => "users#preferences", constraints: { username: RouteFormat.username }
396    put "#{root_path}/:username/preferences/username" => "users#username", constraints: { username: RouteFormat.username }
397    get "#{root_path}/:username/preferences/second-factor" => "users#preferences", constraints: { username: RouteFormat.username }
398    delete "#{root_path}/:username/preferences/user_image" => "users#destroy_user_image", constraints: { username: RouteFormat.username }
399    put "#{root_path}/:username/preferences/avatar/pick" => "users#pick_avatar", constraints: { username: RouteFormat.username }
400    get "#{root_path}/:username/preferences/card-badge" => "users#card_badge", constraints: { username: RouteFormat.username }
401    put "#{root_path}/:username/preferences/card-badge" => "users#update_card_badge", constraints: { username: RouteFormat.username }
402    get "#{root_path}/:username/staff-info" => "users#staff_info", constraints: { username: RouteFormat.username }
403    get "#{root_path}/:username/summary" => "users#summary", constraints: { username: RouteFormat.username }
404    get "#{root_path}/:username/invited" => "users#invited", constraints: { username: RouteFormat.username }
405    get "#{root_path}/:username/invited_count" => "users#invited_count", constraints: { username: RouteFormat.username }
406    get "#{root_path}/:username/invited/:filter" => "users#invited", constraints: { username: RouteFormat.username }
407    post "#{root_path}/action/send_activation_email" => "users#send_activation_email"
408    get "#{root_path}/:username/summary" => "users#show", constraints: { username: RouteFormat.username }
409    get "#{root_path}/:username/activity/topics.rss" => "list#user_topics_feed", format: :rss, constraints: { username: RouteFormat.username }
410    get "#{root_path}/:username/activity.rss" => "posts#user_posts_feed", format: :rss, constraints: { username: RouteFormat.username }
411    get "#{root_path}/:username/activity" => "users#show", constraints: { username: RouteFormat.username }
412    get "#{root_path}/:username/activity/:filter" => "users#show", constraints: { username: RouteFormat.username }
413    get "#{root_path}/:username/badges" => "users#badges", constraints: { username: RouteFormat.username }
414    get "#{root_path}/:username/notifications" => "users#show", constraints: { username: RouteFormat.username }
415    get "#{root_path}/:username/notifications/:filter" => "users#show", constraints: { username: RouteFormat.username }
416    get "#{root_path}/:username/activity/pending" => "users#show", constraints: { username: RouteFormat.username }
417    delete "#{root_path}/:username" => "users#destroy", constraints: { username: RouteFormat.username }
418    get "#{root_path}/by-external/:external_id" => "users#show", constraints: { external_id: /[^\/]+/ }
419    get "#{root_path}/:username/flagged-posts" => "users#show", constraints: { username: RouteFormat.username }
420    get "#{root_path}/:username/deleted-posts" => "users#show", constraints: { username: RouteFormat.username }
421    get "#{root_path}/:username/topic-tracking-state" => "users#topic_tracking_state", constraints: { username: RouteFormat.username }
422  end
423
424  get "user-badges/:username.json" => "user_badges#username", constraints: { username: RouteFormat.username }, defaults: { format: :json }
425  get "user-badges/:username" => "user_badges#username", constraints: { username: RouteFormat.username }
426
427  post "user_avatar/:username/refresh_gravatar" => "user_avatars#refresh_gravatar", constraints: { username: RouteFormat.username }
428  get "letter_avatar/:username/:size/:version.png" => "user_avatars#show_letter", format: false, constraints: { hostname: /[\w\.-]+/, size: /\d+/, username: RouteFormat.username }
429  get "user_avatar/:hostname/:username/:size/:version.png" => "user_avatars#show", format: false, constraints: { hostname: /[\w\.-]+/, size: /\d+/, username: RouteFormat.username }
430
431  # in most production settings this is bypassed
432  get "letter_avatar_proxy/:version/letter/:letter/:color/:size.png" => "user_avatars#show_proxy_letter"
433
434  get "highlight-js/:hostname/:version.js" => "highlight_js#show", format: false, constraints: { hostname: /[\w\.-]+/ }
435
436  get "stylesheets/:name.css.map" => "stylesheets#show_source_map", constraints: { name: /[-a-z0-9_]+/ }
437  get "stylesheets/:name.css" => "stylesheets#show", constraints: { name: /[-a-z0-9_]+/ }
438
439  post "uploads" => "uploads#create"
440  post "uploads/lookup-urls" => "uploads#lookup_urls"
441
442  # used to download original images
443  get "uploads/:site/:sha(.:extension)" => "uploads#show", constraints: { site: /\w+/, sha: /\h{40}/, extension: /[a-z0-9\.]+/i }
444  # used to download attachments
445  get "uploads/:site/original/:tree:sha(.:extension)" => "uploads#show", constraints: { site: /\w+/, tree: /([a-z0-9]+\/)+/i, sha: /\h{40}/, extension: /[a-z0-9\.]+/i }
446  # used to download attachments (old route)
447  get "uploads/:site/:id/:sha" => "uploads#show", constraints: { site: /\w+/, id: /\d+/, sha: /\h{16}/ }
448
449  get "posts" => "posts#latest", id: "latest_posts"
450  get "private-posts" => "posts#latest", id: "private_posts"
451  get "posts/by_number/:topic_id/:post_number" => "posts#by_number"
452  get "posts/:id/reply-history" => "posts#reply_history"
453  get "posts/:id/reply-ids"     => "posts#reply_ids"
454  get "posts/:username/deleted" => "posts#deleted_posts", constraints: { username: RouteFormat.username }
455  get "posts/:username/flagged" => "posts#flagged_posts", constraints: { username: RouteFormat.username }
456
457  resources :groups, id: RouteFormat.username do
458    get "posts.rss" => "groups#posts_feed", format: :rss
459    get "mentions.rss" => "groups#mentions_feed", format: :rss
460
461    get 'members'
462    get 'posts'
463    get 'mentions'
464    get 'counts'
465    get 'mentionable'
466    get 'messageable'
467    get 'logs' => 'groups#histories'
468
469    collection do
470      get 'custom/new' => 'groups#new', constraints: AdminConstraint.new
471      get "search" => "groups#search"
472    end
473
474    member do
475      %w{
476        activity
477        activity/:filter
478        messages
479        messages/inbox
480        messages/archive
481        manage
482        manage/profile
483        manage/members
484        manage/membership
485        manage/interaction
486        manage/logs
487      }.each do |path|
488        get path => 'groups#show'
489      end
490
491      put "members" => "groups#add_members"
492      delete "members" => "groups#remove_member"
493      post "request_membership" => "groups#request_membership"
494      post "notifications" => "groups#set_notifications"
495    end
496  end
497
498  # aliases so old API code works
499  delete "admin/groups/:id/members" => "groups#remove_member", constraints: AdminConstraint.new
500  put "admin/groups/:id/members" => "groups#add_members", constraints: AdminConstraint.new
501
502  resources :posts do
503    put "bookmark"
504    put "wiki"
505    put "post_type"
506    put "rebake"
507    put "unhide"
508    put "locked"
509    get "replies"
510    get "revisions/latest" => "posts#latest_revision"
511    get "revisions/:revision" => "posts#revisions", constraints: { revision: /\d+/ }
512    put "revisions/:revision/hide" => "posts#hide_revision", constraints: { revision: /\d+/ }
513    put "revisions/:revision/show" => "posts#show_revision", constraints: { revision: /\d+/ }
514    put "revisions/:revision/revert" => "posts#revert", constraints: { revision: /\d+/ }
515    put "recover"
516    collection do
517      delete "destroy_many"
518      put "merge_posts"
519    end
520  end
521
522  resources :notifications, except: :show do
523    collection do
524      put 'mark-read' => 'notifications#mark_read'
525      # creating an alias cause the api was extended to mark a single notification
526      # this allows us to cleanly target it
527      put 'read' => 'notifications#mark_read'
528    end
529  end
530
531  match "/auth/:provider/callback", to: "users/omniauth_callbacks#complete", via: [:get, :post]
532  match "/auth/failure", to: "users/omniauth_callbacks#failure", via: [:get, :post]
533
534  resources :clicks do
535    collection do
536      get "track"
537    end
538  end
539
540  get "excerpt" => "excerpt#show"
541
542  resources :post_action_users
543  resources :post_actions do
544    collection do
545      get "users"
546      post "defer_flags"
547    end
548  end
549  resources :user_actions
550
551  resources :badges, only: [:index]
552  get "/badges/:id(/:slug)" => "badges#show"
553  resources :user_badges, only: [:index, :create, :destroy]
554
555  get '/c', to: redirect(relative_url_root + 'categories')
556
557  resources :categories, except: :show
558  post "category/:category_id/move" => "categories#move"
559  post "categories/reorder" => "categories#reorder"
560  post "category/:category_id/notifications" => "categories#set_notifications"
561  put "category/:category_id/slug" => "categories#update_slug"
562
563  get "categories_and_latest" => "categories#categories_and_latest"
564  get "categories_and_top" => "categories#categories_and_top"
565
566  get "c/:id/show" => "categories#show"
567  get "c/:category_slug/find_by_slug" => "categories#find_by_slug"
568  get "c/:parent_category_slug/:category_slug/find_by_slug" => "categories#find_by_slug"
569  get "c/:category.rss" => "list#category_feed", format: :rss
570  get "c/:parent_category/:category.rss" => "list#category_feed", format: :rss
571  get "c/:category" => "list#category_default", as: "category_default"
572  get "c/:category/none" => "list#category_none_latest"
573  get "c/:parent_category/:category/(:id)" => "list#parent_category_category_latest", constraints: { id: /\d+/ }
574  get "c/:category/l/top" => "list#category_top", as: "category_top"
575  get "c/:category/none/l/top" => "list#category_none_top", as: "category_none_top"
576  get "c/:parent_category/:category/l/top" => "list#parent_category_category_top", as: "parent_category_category_top"
577
578  get "category_hashtags/check" => "category_hashtags#check"
579
580  TopTopic.periods.each do |period|
581    get "top/#{period}.rss" => "list#top_#{period}_feed", format: :rss
582    get "top/#{period}" => "list#top_#{period}"
583    get "c/:category/l/top/#{period}" => "list#category_top_#{period}", as: "category_top_#{period}"
584    get "c/:category/none/l/top/#{period}" => "list#category_none_top_#{period}", as: "category_none_top_#{period}"
585    get "c/:parent_category/:category/l/top/#{period}" => "list#parent_category_category_top_#{period}", as: "parent_category_category_top_#{period}"
586  end
587
588  Discourse.anonymous_filters.each do |filter|
589    get "#{filter}.rss" => "list##{filter}_feed", format: :rss
590  end
591
592  Discourse.filters.each do |filter|
593    get "#{filter}" => "list##{filter}", constraints: { format: /(json|html)/ }
594    get "c/:category/l/#{filter}" => "list#category_#{filter}", as: "category_#{filter}"
595    get "c/:category/none/l/#{filter}" => "list#category_none_#{filter}", as: "category_none_#{filter}"
596    get "c/:parent_category/:category/l/#{filter}" => "list#parent_category_category_#{filter}", as: "parent_category_category_#{filter}"
597  end
598
599  get "category/*path" => "categories#redirect"
600
601  get "top" => "list#top"
602  get "search/query" => "search#query"
603  get "search" => "search#show"
604  post "search/click" => "search#click"
605
606  # Topics resource
607  get "t/:id" => "topics#show"
608  put "t/:id" => "topics#update"
609  delete "t/:id" => "topics#destroy"
610  put "t/:id/archive-message" => "topics#archive_message"
611  put "t/:id/move-to-inbox" => "topics#move_to_inbox"
612  put "t/:id/convert-topic/:type" => "topics#convert_topic"
613  put "t/:id/publish" => "topics#publish"
614  put "t/:id/shared-draft" => "topics#update_shared_draft"
615  put "topics/bulk"
616  put "topics/reset-new" => 'topics#reset_new'
617  post "topics/timings"
618
619  get 'topics/similar_to' => 'similar_topics#index'
620  resources :similar_topics
621
622  get "topics/feature_stats"
623
624  scope "/topics", username: RouteFormat.username do
625    get "created-by/:username" => "list#topics_by", as: "topics_by"
626    get "private-messages/:username" => "list#private_messages", as: "topics_private_messages"
627    get "private-messages-sent/:username" => "list#private_messages_sent", as: "topics_private_messages_sent"
628    get "private-messages-archive/:username" => "list#private_messages_archive", as: "topics_private_messages_archive"
629    get "private-messages-unread/:username" => "list#private_messages_unread", as: "topics_private_messages_unread"
630    get "private-messages-tags/:username/:tag_id.json" => "list#private_messages_tag", as: "topics_private_messages_tag", constraints: StaffConstraint.new
631    get "groups/:group_name" => "list#group_topics", as: "group_topics", group_name: RouteFormat.username
632
633    scope "/private-messages-group/:username", group_name: RouteFormat.username do
634      get ":group_name.json" => "list#private_messages_group", as: "topics_private_messages_group"
635      get ":group_name/archive.json" => "list#private_messages_group_archive", as: "topics_private_messages_group_archive"
636    end
637  end
638
639  get 'embed/comments' => 'embed#comments'
640  get 'embed/count' => 'embed#count'
641  get 'embed/info' => 'embed#info'
642
643  get "new-topic" => "list#latest"
644  get "new-message" => "list#latest"
645
646  # Topic routes
647  get "t/id_for/:slug" => "topics#id_for_slug"
648  get "t/:slug/:topic_id/print" => "topics#show", format: :html, print: true, constraints: { topic_id: /\d+/ }
649  get "t/:slug/:topic_id/wordpress" => "topics#wordpress", constraints: { topic_id: /\d+/ }
650  get "t/:topic_id/wordpress" => "topics#wordpress", constraints: { topic_id: /\d+/ }
651  get "t/:slug/:topic_id/moderator-liked" => "topics#moderator_liked", constraints: { topic_id: /\d+/ }
652  get "t/:slug/:topic_id/summary" => "topics#show", defaults: { summary: true }, constraints: { topic_id: /\d+/ }
653  get "t/:topic_id/summary" => "topics#show", constraints: { topic_id: /\d+/ }
654  put "t/:slug/:topic_id" => "topics#update", constraints: { topic_id: /\d+/ }
655  put "t/:slug/:topic_id/star" => "topics#star", constraints: { topic_id: /\d+/ }
656  put "t/:topic_id/star" => "topics#star", constraints: { topic_id: /\d+/ }
657  put "t/:slug/:topic_id/status" => "topics#status", constraints: { topic_id: /\d+/ }
658  put "t/:topic_id/status" => "topics#status", constraints: { topic_id: /\d+/ }
659  put "t/:topic_id/clear-pin" => "topics#clear_pin", constraints: { topic_id: /\d+/ }
660  put "t/:topic_id/re-pin" => "topics#re_pin", constraints: { topic_id: /\d+/ }
661  put "t/:topic_id/mute" => "topics#mute", constraints: { topic_id: /\d+/ }
662  put "t/:topic_id/unmute" => "topics#unmute", constraints: { topic_id: /\d+/ }
663  post "t/:topic_id/timer" => "topics#timer", constraints: { topic_id: /\d+/ }
664  put "t/:topic_id/make-banner" => "topics#make_banner", constraints: { topic_id: /\d+/ }
665  put "t/:topic_id/remove-banner" => "topics#remove_banner", constraints: { topic_id: /\d+/ }
666  put "t/:topic_id/remove-allowed-user" => "topics#remove_allowed_user", constraints: { topic_id: /\d+/ }
667  put "t/:topic_id/remove-allowed-group" => "topics#remove_allowed_group", constraints: { topic_id: /\d+/ }
668  put "t/:topic_id/recover" => "topics#recover", constraints: { topic_id: /\d+/ }
669  get "t/:topic_id/:post_number" => "topics#show", constraints: { topic_id: /\d+/, post_number: /\d+/ }
670  get "t/:topic_id/last" => "topics#show", post_number: 99999999, constraints: { topic_id: /\d+/ }
671  get "t/:slug/:topic_id.rss" => "topics#feed", format: :rss, constraints: { topic_id: /\d+/ }
672  get "t/:slug/:topic_id" => "topics#show", constraints: { topic_id: /\d+/ }
673  get "t/:slug/:topic_id/:post_number" => "topics#show", constraints: { topic_id: /\d+/, post_number: /\d+/ }
674  get "t/:slug/:topic_id/last" => "topics#show", post_number: 99999999, constraints: { topic_id: /\d+/ }
675  get "t/:topic_id/posts" => "topics#posts", constraints: { topic_id: /\d+/ }, format: :json
676  get "t/:topic_id/excerpts" => "topics#excerpts", constraints: { topic_id: /\d+/ }, format: :json
677  post "t/:topic_id/timings" => "topics#timings", constraints: { topic_id: /\d+/ }
678  post "t/:topic_id/invite" => "topics#invite", constraints: { topic_id: /\d+/ }
679  post "t/:topic_id/invite-group" => "topics#invite_group", constraints: { topic_id: /\d+/ }
680  post "t/:topic_id/move-posts" => "topics#move_posts", constraints: { topic_id: /\d+/ }
681  post "t/:topic_id/merge-topic" => "topics#merge_topic", constraints: { topic_id: /\d+/ }
682  post "t/:topic_id/change-owner" => "topics#change_post_owners", constraints: { topic_id: /\d+/ }
683  put "t/:topic_id/change-timestamp" => "topics#change_timestamps", constraints: { topic_id: /\d+/ }
684  delete "t/:topic_id/timings" => "topics#destroy_timings", constraints: { topic_id: /\d+/ }
685  put "t/:topic_id/bookmark" => "topics#bookmark", constraints: { topic_id: /\d+/ }
686  put "t/:topic_id/remove_bookmarks" => "topics#remove_bookmarks", constraints: { topic_id: /\d+/ }
687
688  post "t/:topic_id/notifications" => "topics#set_notifications" , constraints: { topic_id: /\d+/ }
689
690  get "p/:post_id(/:user_id)" => "posts#short_link"
691  get "/posts/:id/cooked" => "posts#cooked"
692  get "/posts/:id/expand-embed" => "posts#expand_embed"
693  get "/posts/:id/raw" => "posts#markdown_id"
694  get "/posts/:id/raw-email" => "posts#raw_email"
695  get "raw/:topic_id(/:post_number)" => "posts#markdown_num"
696
697  resources :queued_posts, constraints: StaffConstraint.new
698  get 'queued-posts' => 'queued_posts#index'
699
700  resources :invites
701  post "invites/upload_csv" => "invites#upload_csv"
702  post "invites/rescind-all" => "invites#rescind_all_invites"
703  post "invites/reinvite" => "invites#resend_invite"
704  post "invites/reinvite-all" => "invites#resend_all_invites"
705  post "invites/link" => "invites#create_invite_link"
706  delete "invites" => "invites#destroy"
707  put "invites/show/:id" => "invites#perform_accept_invitation", as: 'perform_accept_invite'
708
709  resources :export_csv do
710    collection do
711      post "export_entity" => "export_csv#export_entity"
712    end
713    member do
714      get "" => "export_csv#show", constraints: { id: /[^\/]+/ }
715    end
716  end
717
718  get "onebox" => "onebox#show"
719  get "inline-onebox" => "inline_onebox#show"
720
721  get "exception" => "list#latest"
722
723  get "message-bus/poll" => "message_bus#poll"
724
725  get "draft" => "draft#show"
726  post "draft" => "draft#update"
727  delete "draft" => "draft#destroy"
728
729  if service_worker_asset = Rails.application.assets_manifest.assets['service-worker.js']
730    # https://developers.google.com/web/fundamentals/codelabs/debugging-service-workers/
731    # Normally the browser will wait until a user closes all tabs that contain the
732    # current site before updating to a new Service Worker.
733    # Support the old Service Worker path to avoid routing error filling up the
734    # logs.
735    get "/service-worker.js" => redirect(relative_url_root + service_worker_asset), format: :js
736    get service_worker_asset => "static#service_worker_asset", format: :js
737  elsif Rails.env.development?
738    get "/service-worker.js" => "static#service_worker_asset", format: :js
739  end
740
741  get "cdn_asset/:site/*path" => "static#cdn_asset", format: false
742  get "brotli_asset/*path" => "static#brotli_asset", format: false
743
744  get "favicon/proxied" => "static#favicon", format: false
745
746  get "robots.txt" => "robots_txt#index"
747  get "robots-builder.json" => "robots_txt#builder"
748  get "offline.html" => "offline#index"
749  get "manifest.json" => "metadata#manifest", as: :manifest
750  get "opensearch" => "metadata#opensearch", format: :xml
751
752  scope "/tags" do
753    get '/' => 'tags#index'
754    get '/filter/list' => 'tags#index'
755    get '/filter/search' => 'tags#search'
756    get '/check' => 'tags#check_hashtag'
757    get '/personal_messages/:username' => 'tags#personal_messages'
758    constraints(tag_id: /[^\/]+?/, format: /json|rss/) do
759      get '/:tag_id.rss' => 'tags#tag_feed'
760      get '/:tag_id' => 'tags#show', as: 'tag_show'
761      get '/c/:category/:tag_id' => 'tags#show', as: 'tag_category_show'
762      get '/c/:parent_category/:category/:tag_id' => 'tags#show', as: 'tag_parent_category_category_show'
763      get '/intersection/:tag_id/*additional_tag_ids' => 'tags#show', as: 'tag_intersection'
764      get '/:tag_id/notifications' => 'tags#notifications'
765      put '/:tag_id/notifications' => 'tags#update_notifications'
766      put '/:tag_id' => 'tags#update'
767      delete '/:tag_id' => 'tags#destroy'
768
769      Discourse.filters.each do |filter|
770        get "/:tag_id/l/#{filter}" => "tags#show_#{filter}", as: "tag_show_#{filter}"
771        get "/c/:category/:tag_id/l/#{filter}" => "tags#show_#{filter}", as: "tag_category_show_#{filter}"
772        get "/c/:parent_category/:category/:tag_id/l/#{filter}" => "tags#show_#{filter}", as: "tag_parent_category_category_show_#{filter}"
773      end
774    end
775  end
776
777  resources :tag_groups, except: [:new, :edit] do
778    collection do
779      get '/filter/search' => 'tag_groups#search'
780    end
781  end
782
783  Discourse.filters.each do |filter|
784    root to: "list##{filter}", constraints: HomePageConstraint.new("#{filter}"), as: "list_#{filter}"
785  end
786  # special case for categories
787  root to: "categories#index", constraints: HomePageConstraint.new("categories"), as: "categories_index"
788  # special case for top
789  root to: "list#top", constraints: HomePageConstraint.new("top"), as: "top_lists"
790
791  root to: 'finish_installation#index', constraints: HomePageConstraint.new("finish_installation"), as: 'installation_redirect'
792
793  get "/user-api-key/new" => "user_api_keys#new"
794  post "/user-api-key" => "user_api_keys#create"
795  post "/user-api-key/revoke" => "user_api_keys#revoke"
796  post "/user-api-key/undo-revoke" => "user_api_keys#undo_revoke"
797
798  get "/safe-mode" => "safe_mode#index"
799  post "/safe-mode" => "safe_mode#enter", as: "safe_mode_enter"
800
801  get "/themes/assets/:key" => "themes#assets"
802
803  get "*url", to: 'permalinks#show', constraints: PermalinkConstraint.new
804
805end