# Routes
# This file defines all application routes (Higher priority routes first)
# ~~~~

# Only POST.
# Don't use PUT, DELETE or PATCH. Use POST only. That's simpler — one won't
# need to wonder, which method to use. Also, using only POST, encourages descriptive
# url paths, like '/delete-comment' instead of just /comment (and method DELETE)
# which is helpful when understanding what the url path does, and someone else
# didn't tell you which method hen had in mind.

# Rare compilation problem tips:
# If there's ever again any impossibly weird error like:
#   [error] /home/kajmagnus/me-dev/debiki/all/debiki-server/conf/routes:14:
#     too many arguments for method apply:
#     (name: String, constraint: String)play.core.DynamicPart in object DynamicPart
#   [error] GET /-/login/:provider  controllers.AppLogin.loginWith(provider, returnToUrl)
# Then, in project/Build.scala, add nonTransitive() to perhaps the play-plugins-mailer
# dependency ? see:
#   https://groups.google.com/forum/?fromgroups=#!topic/play-framework/cVqBvywCs4k

GET   /-/login                  controllers.LoginController.showLoginPage(as: Option[String], to: Option[String])
GET   /-/login-popup            controllers.LoginController.showLoginPopup(mode: Int, returnToUrl)
GET   /-/logout                 controllers.LoginController.logout_get_post(currentUrlPath: Option[String])
POST  /-/logout                 controllers.LoginController.logout_get_post(currentUrlPath: Option[String])
POST  /-/resend-owner-email-addr-verif-email controllers.LoginController.resendSiteOwnerAddrVerifEmail

# REFACTOR Would like to remove, use  /-/authn/password/
POST  /-/login-guest            controllers.LoginAsGuestController.loginGuest
POST  /-/login-password         controllers.LoginWithPasswordController.login
POST  /-/login-password-create-user controllers.LoginWithPasswordController.handleCreateUserDialog
GET   /-/login-password-confirm-email controllers.LoginWithPasswordController.confirmEmailAddressAndLogin(confirmationEmailId, returnToUrl)
# also: /-/v0/sso-login via ApiV0Controller

GET   /-/authn/:protocol/:providerAlias           controllers.LoginWithOpenAuthController.authnStart(protocol, providerAlias, returnToUrl, nonce, useServerGlobalIdp: Option[Boolean], selectAccountAtIdp: Option[Boolean])
GET   /-/authn/continue-at-authn-origin           controllers.LoginWithOpenAuthController.continueAtAuthnOrigin(secretNonce)
GET   /-/authn/:protocol/:providerAlias/redirback controllers.LoginWithOpenAuthController.authnRedirBack(protocol, providerAlias, state, session_state: Option[String], code: Option[String], error: Option[String], error_description: Option[String], error_uri: Option[String])
GET   /-/authn/finish-at-orig-site                controllers.LoginWithOpenAuthController.finishAtOrigSite(secretNonce)

GET   /-/authn/verif-email-ask-if-link-accounts   controllers.LoginWithOpenAuthController.verifyEmailAskIfLinkAccounts(secretNonce)
POST  /-/authn/ans-link-accounts                  controllers.LoginWithOpenAuthController.answerLinkAccounts

# Would like to remove, use /-/authn/oauth2/:name  instead:
#ET   /-/login-openauth/:providerName controllers.LoginWithOpenAuthController.startAuthentication(providerName, returnToUrl: Option[String])
# Keep this endpoint, for backwards compatibility, from before /-/authn/oauth2/:name was added.
GET   /-/login-auth-callback/:providerName  controllers.LoginWithOpenAuthController.finishAuthentication(providerName)
#ET   /-/login-oauth-then-return/:providerName controllers.LoginWithOpenAuthController.loginAtLoginOriginThenReturnToOriginalSite(providerName, returnToOrigin, xsrfToken)
#ET   /-/login-oauth-continue           controllers.LoginWithOpenAuthController.continueAtOriginalSite(oauthDetailsCacheKey, xsrfToken)
POST  /-/login-oauth-create-user  controllers.LoginWithOpenAuthController.handleCreateUserDialog

GET   /-/impersonate-at-other-site  controllers.ImpersonateController.impersonateAtOtherSite(siteId: Int, userId: Int, goToSiteById: Option[Boolean])
GET   /-/impersonate-with-key   controllers.ImpersonateController.impersonateWithKey(key: String)
POST  /-/impersonate            controllers.ImpersonateController.impersonate(userId: Int)
POST  /-/view-as-other          controllers.ImpersonateController.viewAsOther(userId: Int)
POST  /-/stop-impersonating     controllers.ImpersonateController.stopImpersonating

#GET   /-/load-online-users      talkyard.server.pubsub.SubscriberController.loadOnlineUsers
GET   /-/websocket              talkyard.server.pubsub.SubscriberController.webSocket

GET   /-/embedded-comments      controllers.EmbeddedTopicsController.showTopic(embeddingUrl, discussionId: Option[String], edPageId: Option[String], category: Option[String], scriptV: Option[String])
GET   /-/embedded-editor        controllers.EmbeddedTopicsController.showEmbeddedEditor(embeddingUrl, embeddingScriptV: Option[Int])

GET   /-/search                 controllers.SearchController.showSearchPage(q: Option[String])
POST  /-/search                 controllers.SearchController.doSearch
GET   /-/v0/search              controllers.SearchController.apiV0_search_get
POST  /-/v0/search              controllers.SearchController.apiV0_search_post

GET   /-/reset-password                  controllers.ResetPasswordController.start
GET   /-/reset-password/specify-email    controllers.ResetPasswordController.showResetPasswordPage
POST  /-/reset-password/specify-email    controllers.ResetPasswordController.handleResetPasswordForm
GET   /-/reset-password/email-sent       controllers.ResetPasswordController.showEmailSentPage(isEmailAddress)
GET   /-/reset-password/choose-password/:resetPasswordEmailId  controllers.ResetPasswordController.showChooseNewPasswordPage(resetPasswordEmailId)
POST  /-/reset-password/choose-password/:resetPasswordEmailId  controllers.ResetPasswordController.handleNewPasswordForm(resetPasswordEmailId)
POST  /-/send-reset-password-email       controllers.ResetPasswordController.sendResetPasswordEmail

GET   /-/create-site                        controllers.CreateSiteController.showPage(isTest = "false")
GET   /-/create-site/embedded-comments      controllers.CreateSiteController.showPage(isTest = "false")
GET   /-/create-test-site                   controllers.CreateSiteController.showPage(isTest = "true")
GET   /-/create-test-site/embedded-comments controllers.CreateSiteController.showPage(isTest = "true")
POST  /-/v0/create-site                     controllers.CreateSiteController.apiV0_createSite
POST  /-/create-site                        controllers.CreateSiteController.createSite
POST  /-/delete-test-site                   controllers.CreateSiteController.deleteTestSite
GET   /-/_int_req/hostname-should-have-cert controllers.CreateSiteController.intReq_hostnameShouldHaveCert

GET   /-/admin-login            controllers.AdminController.showAdminOneTimeLoginPage
POST  /-/admin-login            controllers.AdminController.handleAdminOneTimeLoginForm
GET   /-/admin                  controllers.AdminController.redirectToAdminPage
GET   /-/admin/                 controllers.AdminController.viewAdminPage(whatever = "")
GET   /-/admin/*whatever        controllers.AdminController.viewAdminPage(whatever)
GET   /-/load-dashboard         controllers.AdminController.getDashboardData
GET   /-/sso-test               controllers.AdminController.showTestSsoPage


GET   /-/load-site-settings     controllers.SettingsController.loadSiteSettings
POST  /-/save-site-settings     controllers.SettingsController.saveSiteSettings
POST  /-/change-hostname        controllers.SettingsController.changeHostname
POST  /-/update-extra-hostnames controllers.SettingsController.updateExtraHostnames
GET   /-/load-oidc-config       controllers.SettingsController.loadOidcConfig
POST  /-/upsert-oidc-config     controllers.SettingsController.upsertOidcConfig
GET   /-/gen-paseto-v2-loc-secr controllers.SettingsController.genPasetoV2LocalSecret

GET   /-/terms-of-use            controllers.LegalController.viewTermsOfUsePage
GET   /-/privacy-policy          controllers.LegalController.viewPrivacyPolicyPage

GET   /-/load-special-content   controllers.SpecialContentController.loadContent(rootPageId, contentId)
POST  /-/save-special-content   controllers.SpecialContentController.saveContent

GET   /-/load-review-tasks      controllers.ModerationController.loadReviewTasks
POST  /-/make-review-decision   controllers.ModerationController.makeReviewDecision
POST  /-/undo-review-decision   controllers.ModerationController.tryUndoReviewDecision
POST  /-/moderate-from-page     controllers.ModerationController.moderateFromPage

GET   /-/users/                 controllers.UserController.viewUserPage(whatever = "")
GET   /-/users/*whatever        controllers.UserController.viewUserPage(whatever)
GET   /-/groups/                controllers.UserController.viewUserPage(whatever = "")
GET   /-/groups/*whatever       controllers.UserController.viewUserPage(whatever)
GET   /-/load-my-page-data      controllers.UserController.loadMyPageData(pageIds)
GET   /-/download-personal-data controllers.UserController.downloadPersonalData(userId: Int)
POST  /-/track-reading          controllers.UserController.trackReadingProgress
POST  /-/track-reading-text     controllers.UserController.trackReadingProgressText
POST  /-/toggle-tips            controllers.UserController.toggleTips
GET   /-/load-notifications     controllers.UserController.loadNotifications(userId: Int, upToWhenMs: Long)
POST  /-/mark-all-notfs-as-seen controllers.UserController.markAllNotfsAsSeen
POST  /-/mark-notf-as-seen      controllers.UserController.markNotificationAsSeen
POST  /-/snooze-notfs           controllers.UserController.snoozeNotifications
POST  /-/save-content-notf-pref controllers.UserController.saveContentNotfPref
GET   /-/load-groups            controllers.UserController.loadGroups()
POST  /-/create-group           controllers.UserController.createGroup()
POST  /-/delete-group           controllers.UserController.deleteGroup()
GET   /-/list-group-members     controllers.UserController.listGroupMembers(groupId: Int)
POST  /-/add-group-members      controllers.UserController.addGroupMembers
POST  /-/remove-group-members   controllers.UserController.removeGroupMembers
GET   /-/list-all-users         controllers.UserController.listAllUsers(usernamePrefix)
GET   /-/list-usernames         controllers.UserController.listUsernames(pageId, prefix)
POST  /-/save-about-member-prefs controllers.UserController.saveAboutMemberPrefs
POST  /-/save-about-group-prefs controllers.UserController.saveAboutGroupPreferences
POST  /-/save-pat-perms         controllers.UserController.savePatPerms
POST  /-/save-ui-prefs          controllers.UserController.saveUiPreferences
GET   /-/load-cats-tags-site-notf-prefs  controllers.UserController.loadMembersCatsTagsSiteNotfPrefs(memberId: Int)
POST  /-/save-privacy-prefs     controllers.UserController.saveMemberPrivacyPrefs
POST  /-/save-guest             controllers.UserController.saveGuest
POST  /-/delete-user            controllers.UserController.deleteUser
GET   /-/list-complete-users    controllers.UserController.listCompleteUsers(whichUsers)
GET   /-/load-user-any-details  controllers.UserController.loadUserAnyDetails(who)
POST  /-/edit-member            controllers.UserController.editMember
POST  /-/lock-trust-level       controllers.UserController.lockTrustLevel
POST  /-/unlock-trust-level     controllers.UserController.unlockTrustLevel
POST  /-/lock-threat-level      controllers.UserController.lockThreatLevel
POST  /-/unlock-threat-level    controllers.UserController.unlockThreatLevel
POST  /-/suspend-user           controllers.UserController.suspendUser
POST  /-/unsuspend-user         controllers.UserController.unsuspendUser
POST  /-/block-guest            controllers.UserController.blockGuest
POST  /-/unblock-guest          controllers.UserController.unblockGuest
GET   /-/load-author-blocks     controllers.UserController.loadAuthorBlocks(postId: Int)
GET   /-/redir-to-my-last-topic controllers.UserController.redirectToMyLastTopic

GET   /-/load-email-addrs-login-methods controllers.UserController.loadUserEmailsLogins(userId: Int)
POST  /-/set-primary-email-address controllers.UserController.setPrimaryEmailAddresses
POST  /-/add-email-address      controllers.UserController.addUserEmail
POST  /-/remove-email-address   controllers.UserController.removeUserEmail
GET   /-/confirm-email-address  controllers.UserController.confirmOneMoreEmailAddress(confirmationEmailId)
POST  /-/resend-email-addr-verif-email controllers.UserController.resendEmailAddrVerifEmail

GET   /-/v0/api-secret-info     controllers.UserController.apiv0_showApiSecretInfo

GET   /-/list-sessions          talkyard.server.sess.SessionController.listSessions(patId: Int)
POST  /-/terminate-sessions     talkyard.server.sess.SessionController.terminateSessions
# Maybe move /-/logout to SessionController?

GET   /-/unsubscribe            controllers.UnsubscriptionController.showForm(emailId)
POST  /-/unsubscribe            controllers.UnsubscriptionController.handleForm(emailId)
GET   /-/unsubscribed           controllers.UnsubscriptionController.showHasBeenUnsubscribed()

GET   /-/unsub-from-summaries   talkyard.server.summaryemails.UnsubFromSummariesController.showUnsubForm(emailId)
POST  /-/unsub-from-summaries   talkyard.server.summaryemails.UnsubFromSummariesController.handleForm
GET   /-/unsub-summaries-done   talkyard.server.summaryemails.UnsubFromSummariesController.showHasBeenUnsubscribed()

GET   /-/load-invites           controllers.InviteController.loadInvites(sentById: Int)
GET   /-/load-all-invites       controllers.InviteController.loadAllInvites
POST  /-/send-invites           controllers.InviteController.sendInvites
GET   /-/accept-invite/:key     controllers.InviteController.acceptInvite(key)

POST  /-/create-embedded-comments-site  controllers.EmbeddedTopicsController.createEmbeddedCommentsForum
POST  /-/create-forum           controllers.ForumController.createForum
GET   /-/list-forums            controllers.ForumController.listForums
GET   /-/list-topics            controllers.ForumController.listTopics(categoryId: Int)
GET   /-/list-categories-all-sections controllers.ForumController.listCategoriesAllSections
GET   /-/list-categories-topics controllers.ForumController.listCategoriesAndTopics(forumId)
# Also saves security settings / permissions / PermsOnPage:s.
POST  /-/save-category          controllers.ForumController.saveCategory
GET   /-/load-category          controllers.ForumController.loadCategoryToEdit(id: Int)
POST  /-/delete-category        controllers.ForumController.deleteCategory
POST  /-/undelete-category      controllers.ForumController.undeleteCategory
GET   /-/inspect-forum          controllers.ForumController.inspectForum

GET   /-/redir-to-about         controllers.ForumController.redirectToAboutPage(categoryId: Option[Int])

POST  /-/create-page            controllers.PageController.createPage
GET   /-/list-page-ids-urls     controllers.PageController.listPageIdsUrls(pageId: Option[String])
POST  /-/save-page-ids-urls     controllers.PageController.savePageIdsUrls
POST  /-/pin-page               controllers.PageController.pinPage
POST  /-/unpin-page             controllers.PageController.unpinPage
POST  /-/toggle-page-closed     controllers.PageController.togglePageClosed
POST  /-/delete-pages           controllers.PageController.deletePages
POST  /-/undelete-pages         controllers.PageController.undeletePages
POST  /-/accept-answer          controllers.PageController.acceptAnswer
POST  /-/unaccept-answer        controllers.PageController.unacceptAnswer
POST  /-/add-users-to-page      controllers.PageController.addUsersToPage
POST  /-/remove-users-from-page controllers.PageController.removeUsersFromPage
POST  /-/join-page              controllers.PageController.joinPage
POST  /-/leave-page             controllers.PageController.leavePage
POST  /-/config-watchbar        controllers.PageController.configWatchbar
POST  /-/change-pat-node-rels   controllers.PageController.changePatNodeRels

GET   /-/list-topics-by-user    talkyard.server.talk.PostsController.listTopicsByUser(userId: Int)
GET   /-/list-posts             talkyard.server.talk.PostsController.listPostsByUser(authorId: Int, relType: Option[Int], which: Option[Int])
GET   /-/download-my-content    talkyard.server.talk.PostsController.downloadUsersContent(authorId: Int)
GET   /-/list-posts-with-tag    talkyard.server.talk.PostsController.listPostsWithTag(typeIdOrSlug)

POST  /-/reply                  controllers.ReplyController.handleReply
POST  /-/chat                   controllers.ReplyController.handleChatMessage

POST  /-/upsert-draft           controllers.DraftsController.upsertDraft
POST  /-/upsert-draft-text      controllers.DraftsController.upsertDraftBeacon
GET   /-/list-drafts            controllers.DraftsController.listDrafts(userId: Int)
POST  /-/delete-drafts          controllers.DraftsController.deleteDrafts
POST  /-/delete-drafts-text     controllers.DraftsController.deleteDraftsBeacon

POST  /-/submit-custom-form-as-json-reply controllers.CustomFormController.handleJsonReply
POST  /-/submit-custom-form-as-new-topic  controllers.CustomFormController.handleNewTopic
# Not yet:
# POST  /-/save-custom-form       controllers.CustomFormController.handleExternalForm
# GET   /-/save-custom-form       controllers.CustomFormController.sayCantUseMethodGetHere

# UsabilityTestingExchangeController = [plugin]
POST  /-/submit-usability-testing-form    talkyard.server.plugins.utx.UsabilityTestingExchangeController.handleUsabilityTestingForm
GET   /-/utx-pick-a-task        talkyard.server.plugins.utx.UsabilityTestingExchangeController.pickTask(categorySlug)

# Merge with CloseCollapseController into PostController?
POST  /-/vote                   controllers.VoteController.handleVotes
GET   /-/load-voters            controllers.VoteController.loadVoters(postId: Int, voteType: Int)
POST  /-/flag                   controllers.FlagController.flagPost

GET   /-/load-draft-and-guidelines controllers.EditController.loadDraftAndGuidelines(writingWhat: Int, draftType: Int, pageRole: Int, categoryId: Option[Int], toUserId: Option[Int], pageId: Option[String], postNr: Option[Int])
GET   /-/load-draft-and-text    controllers.EditController.loadDraftAndText(pageId, postNr: Int)
POST  /-/edit                   controllers.EditController.edit
POST  /-/edit-title-save-settings controllers.PageTitleSettingsController.editTitleSaveSettings
GET   /-/fetch-link-preview     controllers.EditController.fetchLinkPreview(url, curPageId, inline: Boolean)
POST  /-/change-post-type       controllers.EditController.changePostType
POST  /-/edit-post-settings     controllers.EditController.editPostSettings
POST  /-/delete-post            controllers.EditController.deletePost
POST  /-/move-post              controllers.EditController.movePost

GET   /-/load-post-revisions    controllers.EditController.loadPostRevisions(postId: Int, revisionNr)

POST  /-/start-private-group-talk controllers.GroupTalkController.sendMessage

GET   /-/_int_req/may-upload-file                         controllers.UploadsController.intReq_mayUploadFile(sizeBytes: Int)
GET   /-/_int_req/may-download-file/:pubSiteId/*hashPath  controllers.UploadsController.authUpload(pubSiteId, hashPath)
POST  /-/upload-public-file     controllers.UploadsController.uploadPublicFile
POST  /-/upload-avatar          controllers.UploadsController.uploadAvatar(userId: Int)
POST  /-/remove-avatar          controllers.UploadsController.removeAvatar

# CLEAN_UP remove, hardcode path in Globals instead?  [2KGLCQ4]
GET   /-/u/*relativePath        controllers.UploadsController.servePublicFile(relativePath)
#GET   /-/uploads/public/*relativePath controllers.UploadsController.servePublicFileLong(relativePath)

# Merge with CloseCollapseController into PostController?
# POST  /-/pin-at-position      controllers.PinController.pinAtPosition
POST  /-/hide-post              controllers.CloseCollapseController.hidePost
POST  /-/collapse-post          controllers.CloseCollapseController.collapsePost
POST  /-/collapse-tree          controllers.CloseCollapseController.collapseTree
POST  /-/close-tree             controllers.CloseCollapseController.closeTree
#POST  /-/reopen-tree            controllers.CloseCollapseController.reopenTree

#POST  /-/start-creating-backup  talkyard.server.sitepatch.SitePatchController.startCreatingBackup
#POST  /-/download-backup        talkyard.server.sitepatch.SitePatchController.downloadBackup
#POST  /-/delete-backup          talkyard.server.sitepatch.SitePatchController.deleteBackup
#POST  /-/upload-backup          talkyard.server.sitepatch.SitePatchController.uploadBackup
#POST  /-/import-backup          talkyard.server.sitepatch.SitePatchController.importBackup
POST   /-/restore-backup-overwrite-site talkyard.server.sitepatch.SitePatchController.restoreBackupOverwriteSite


# (Site 121 currenlty uses)
# Maybe should be POST instead so any <a href ...> won't accidentally trigger a full site dump?
GET   /-/export-site-json        talkyard.server.sitepatch.SitePatchController.exportSiteJson
#
# Or incl the word 'dump', so one undersands can be used with /-/create-site-from-dump?
# However, what if I add url params for exporting only parts of a site? Then, would get a patch, not dump.
#OST  /-/export-site-dump-json   talkyard.server.sitepatch.SitePatchController.exportSiteJson
#OST  /-/export-site-dump-zip    talkyard.server.sitepatch.SitePatchController.exportSiteZip
#OST  /-/export-site-dump-protobuf talkyard.server.sitepatch.SitePatchController.exportSiteProtobuf
#
# Or?: no, instead, nice to have 'exort-' incl in the name? + GET = risky.
#ET   /-/site-dump.json          talkyard.server.sitepatch.SitePatchController.exportSiteJson
#ET ? /-/site-dump.zip           talkyard.server.sitepatch.SitePatchController.exportSiteZip
#ET ? /-/site-dump.protobuf      talkyard.server.sitepatch.SitePatchController.exportSiteProtobuf

# RENAME? to /-/create-site-from-dump? otherwise unclear if gets imported to existing site,
# or if creates a new site.
# Remove '-json' suffix: The Content-Type can clarify if it's json, a zip or a protobuf.
POST  /-/import-site-json        talkyard.server.sitepatch.SitePatchController.importSiteJson(deleteOldSite: Option[Boolean])
POST  /-/import-test-site-json   talkyard.server.sitepatch.SitePatchController.importTestSite
# New API:
#POST  /-/v0/do-action-batch     talkyard.server.sitepatch.ActionBatchController.doActionBatch
# ... but upsert-simple deprecated?:
POST  /-/v0/upsert-simple        talkyard.server.sitepatch.SitePatchController.upsertSimpleJson
POST  /-/v0/upsert-patch         talkyard.server.sitepatch.SitePatchController.upsertPatchJson


GET  /-/view-time               controllers.DebugTestController.viewTime
POST /-/play-time               controllers.DebugTestController.playTime
POST /-/log-browser-errors      controllers.DebugTestController.logBrowserErrors
GET  /-/metrics                 controllers.DebugTestController.showMetrics(metrApiKey: Option[String])
GET  /-/num-errors-logged       controllers.DebugTestController.showNumErrorsLogged(okMinsAfterErr: Option[Int], metrApiKey: Option[String])
GET  /-/build-info              controllers.DebugTestController.showBuildInfo(metrApiKey: Option[String])
GET  /-/feature-flags           controllers.DebugTestController.showFlags
GET  /-/test-counters           controllers.DebugTestController.getE2eTestCounters
GET  /-/ping-exception-action   controllers.DebugTestController.pingExceptionAction
GET  /-/ping-session-action     controllers.DebugTestController.pingApiAction
GET  /-/ping-cache              controllers.DebugTestController.pingCache
GET  /-/ping-cache-10           controllers.DebugTestController.pingCacheTenTimes
GET  /-/ping-db                 controllers.DebugTestController.pingDatabase
GET  /-/ping-db-10              controllers.DebugTestController.pingDatabaseTenTimes
GET  /-/ping-cache-db           controllers.DebugTestController.pingCacheAndDatabase
GET  /-/ping-cache-db-10        controllers.DebugTestController.pingCacheAndDatabaseTenTimes
GET  /-/origin                  controllers.DebugTestController.origin
GET  /-/are-scripts-ready       controllers.DebugTestController.areScriptsReady
POST /-/delete-redis-key        controllers.DebugTestController.deleteRedisKey
POST /-/skip-limits             controllers.DebugTestController.skipLimitsForThisSite
POST /-/pause-jobs              controllers.DebugTestController.pauseJobs
GET  /-/create-deadlock         controllers.DebugTestController.createDeadlock
POST /-/add-admin-notice        controllers.DebugTestController.addAdminNotice
GET  /-/last-e2e-test-email     controllers.DebugTestController.showLastE2eTestEmailSent(siteId: Int, sentTo)
GET  /-/num-e2e-test-emails-sent controllers.DebugTestController.numE2eTestEmailSent(siteId: Int)
GET  /-/last-errors             controllers.DebugTestController.showLastErrors
GET  /-/log-test-error          controllers.DebugTestController.logTestError(metrApiKey: Option[String])
GET  /-/log-funny-messages      controllers.DebugTestController.logFunnyLogMessages()
GET  /-/page-top-score          controllers.DebugTestController.showPagePopularityStats(pageId, scoreAlg: Option[Int])
GET  /-/ws-state                controllers.DebugTestController.showPubSubSubscribers(siteId: Option[Int])
GET  /-/ws-state-all-sites      controllers.DebugTestController.showWebSocketClientsAllSites()

GET   /-/site/:pubSiteId/*file  controllers.SiteAssetBundlesController.customAsset(pubSiteId, file)
GET   /-/site/*file             controllers.SiteAssetBundlesController.at(file)

GET   /-/tags                   controllers.TagsController.redirect
GET   /-/tags/                  controllers.TagsController.tagsApp(whatever = "")
GET   /-/tags/*whatever         controllers.TagsController.tagsApp(whatever)
POST  /-/upsert-type            controllers.TagsController.upsertType
GET   /-/list-tag-types         controllers.TagsController.listTagTypes(forWhat: Option[Int], tagNamePrefix: Option[String])
GET   /-/load-tags-and-stats    controllers.TagsController.loadTagsAndStats
GET   /-/load-cats-and-tags     controllers.TagsController.loadCatsAndTags
POST  /-/set-tag-notf-level     controllers.TagsController.setTagNotfLevel
# Broken, after tags got reimplemented.
#ET   /-/load-my-tag-notf-levels controllers.TagsController.loadMyTagNotfLevels
POST  /-/update-tags            controllers.TagsController.updateTags

POST  /-/handle-email            talkyard.server.emails.in.EmailsInController.handleIncomingEmail(debug: Boolean = false)

GET   /-/sa                      controllers.SuperAdminController.redirect
GET   /-/super-admin             controllers.SuperAdminController.redirect
GET   /-/super-admin/            controllers.SuperAdminController.redirect
GET   /-/superadmin              controllers.SuperAdminController.redirect
GET   /-/superadmin/             controllers.SuperAdminController.superAdminApp(clientRoute = "")
GET   /-/superadmin/*clientRoute controllers.SuperAdminController.superAdminApp(clientRoute)
GET   /-/sa/list-sites           controllers.SuperAdminController.listSites
POST  /-/sa/update-sites         controllers.SuperAdminController.updateSites
POST  /-/test-reindex-sites      controllers.SuperAdminController.testIndexSites
POST  /-/sa/reindex-sites        controllers.SuperAdminController.reindexSites
POST  /-/sa/schedule-purge-sites controllers.SuperAdminController.schedulePurgeSites

POST  /-/v0/plan-maintenance     controllers.SuperAdminController.apiV0_planMaintenance

GET   /-/ams0/list-sites         controllers.SuperAdminController.listSites_amsV0
GET   /-/ams0/list-coworkers     controllers.SuperAdminController.listCoworkersAllSites_amsV0


# ----- API

GET   /-/list-webhooks          talkyard.server.events.WebhooksController.listWebhooks
POST  /-/upsert-webhooks        talkyard.server.events.WebhooksController.upsertWebhooks
POST  /-/delete-webhooks        talkyard.server.events.WebhooksController.deleteWebhooks
POST  /-/retry-webhook          talkyard.server.events.WebhooksController.retryWebhook
GET   /-/list-webhook-reqs-out  talkyard.server.events.WebhooksController.listWebhookReqsOut(webhookId: Int)

GET   /-/list-api-secrets       controllers.ApiSecretsController.listApiSecrets
POST  /-/create-api-secret      controllers.ApiSecretsController.createApiSecret
POST  /-/delete-api-secrets     controllers.ApiSecretsController.deleteApiSecrets

#GET   /-/events                 controllers.EventsController.apiV0_listEvents
POST  /-/v0/upsert-user                  talkyard.server.authn.SsoAuthnController.apiV0_upsertUser
POST  /-/v0/upsert-user-and-login        talkyard.server.authn.SsoAuthnController.apiV0_upsertUserAndLogin
POST  /-/v0/upsert-user-get-login-secret talkyard.server.authn.SsoAuthnController.apiv0_upsertUserGenLoginSecret
# Deprecated names, at least the first one in use:
POST  /-/v0/sso-upsert-user-generate-login-secret      talkyard.server.authn.SsoAuthnController.apiv0_upsertUserGenLoginSecret
POST  /-/v0/upsert-external-user-generate-login-secret talkyard.server.authn.SsoAuthnController.apiv0_upsertUserGenLoginSecret

GET   /-/v0/login-with-secret   talkyard.server.authn.SsoAuthnController.apiv0_loginWithSecret
# Deprecated name: (because login secrets are generated in more ways than just sso.
# E.g. for one-time-login via email, [305KDDN24]).
GET   /-/v0/sso-login           talkyard.server.authn.SsoAuthnController.apiv0_loginWithSecret


POST  /-/v0/get                 talkyard.server.api.GetController.apiV0_get
POST  /-/v0/list                talkyard.server.api.ListController.apiV0_list
# POST  /-/v0/search — see above
POST  /-/v0/query               talkyard.server.api.QueryDoController.apiV0_query
POST  /-/v0/do                  talkyard.server.api.QueryDoController.apiV0_do
POST  /-/v0/query-do            talkyard.server.api.QueryDoController.apiV0_queryDo

GET   /-/v0/list-users          controllers.UserController.listMembersPubApi(usernamePrefix, usersOnly: Boolean = true)
#ET   /-/v0/list-groups — only groups
#ET   /-/v0/list-members — both users and groups
# REFACTOR use ApiSecretPostJsonAction instead, move to more precise controllers?
GET   /-/v0/*apiEndpoint        controllers.ApiV0Controller.getFromApi(apiEndpoint)
POST  /-/v0/*apiEndpoint        controllers.ApiV0Controller.postToApi(apiEndpoint)

# CORS pre-flight requests — they're replied to immediately, here: [CORSPREFL].
# The actual endpoint won't get called until the real request happens.
# In fact only  /-/v0/... is allowed — but this endpoints accepts /*whatever
# so can returns developer friendly error messages outside /-/v0/  [CORSPATH].
OPTIONS  /*whatever             controllers.ApiV0Controller.getFromApi(whatever)


# ----- PWA

#GET   /talkyard.webmanifest     controllers.Application.mobileAppWebmanifest


# ----- View pages/posts

GET   /-/load-post              controllers.ViewPageController.loadPost(pageId: String, postNr: Int)

# COULD remove? use only /-/track-reading-activity ?
POST  /-/mark-as-seen           controllers.ViewPageController.markPageAsSeen(pageId)
GET   /*path                    controllers.ViewPageController.viewPage(path)
GET   /                         controllers.ViewPageController.viewPage(path = "")
