mirror of
https://codeberg.org/VnPower/PixivFE
synced 2024-12-06 19:16:23 +01:00
move router to separate package
This commit is contained in:
@@ -31,8 +31,8 @@
|
||||
"core/requests.go:lLy9SHFUtQQ": "failed to copy response body: %w",
|
||||
"core/requests.go:o8eDPgojH4w": "Incompatible response body",
|
||||
"core/user.go:T3RwaHcnsYQ": "Invalid work category: %#v. Only \"%s\", \"%s\", \"%s\", \"%s\", \"%s\" and \"%s\" are available",
|
||||
"server/middleware/router.go:HORkE0Obn1U": "Failed to redirect to %s",
|
||||
"server/middleware/router.go:Z9UG-DYmQCk": "Route not found",
|
||||
"server/router/router.go:HORkE0Obn1U": "Failed to redirect to %s",
|
||||
"server/router/router.go:Z9UG-DYmQCk": "Route not found",
|
||||
"server/routes/actions.go:2RxigvKdaDk": "Method not allowed",
|
||||
"server/routes/actions.go:PG4HiUvZvVA": "No ID provided.",
|
||||
"server/routes/actions.go:ZamBnL56VXw": "No user ID provided.",
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"codeberg.org/vnpower/pixivfe/v2/i18n"
|
||||
"codeberg.org/vnpower/pixivfe/v2/server/middleware"
|
||||
"codeberg.org/vnpower/pixivfe/v2/server/proxy_checker"
|
||||
"codeberg.org/vnpower/pixivfe/v2/server/router"
|
||||
"codeberg.org/vnpower/pixivfe/v2/server/template"
|
||||
)
|
||||
|
||||
@@ -78,7 +79,7 @@ func main() {
|
||||
|
||||
auditor.SugaredLogger.Info("Starting server...")
|
||||
|
||||
router := middleware.DefineRoutes(auditor)
|
||||
router := router.DefineRoutes(auditor)
|
||||
// the first middleware is the most outer / first executed one
|
||||
router.Use(middleware.ProvideUserContext) // needed for everything else
|
||||
router.Use(middleware.SetLocaleFromCookie) // needed for i18n.*()
|
||||
|
||||
@@ -1,167 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"codeberg.org/vnpower/pixivfe/v2/audit"
|
||||
"codeberg.org/vnpower/pixivfe/v2/i18n"
|
||||
"codeberg.org/vnpower/pixivfe/v2/server/routes"
|
||||
)
|
||||
|
||||
// AuditorHandler is a type for routes that require an auditor
|
||||
type AuditorHandler func(auditor *audit.Auditor, w http.ResponseWriter, r *http.Request) error
|
||||
|
||||
// WrapWithAuditor is a helper function to wrap AuditorHandler into CatchError
|
||||
func WrapWithAuditor(auditor *audit.Auditor, handler AuditorHandler) func(w http.ResponseWriter, r *http.Request) error {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
return handler(auditor, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// handleStripPrefix is a utility function that combines path prefix matching with
|
||||
// stripping the prefix from the request URL before passing it to the handler.
|
||||
func handleStripPrefix(router *mux.Router, pathPrefix string, handler http.Handler) *mux.Route {
|
||||
return router.PathPrefix(pathPrefix).Handler(http.StripPrefix(pathPrefix, handler))
|
||||
}
|
||||
|
||||
// serveFile returns an http.HandlerFunc that serves a specific file.
|
||||
// This is useful for serving static files like robots.txt.
|
||||
func serveFile(filename string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, filename)
|
||||
}
|
||||
}
|
||||
|
||||
// DefineRoutes sets up all the routes for the application.
|
||||
// It returns a configured mux.Router with all paths and their corresponding handlers.
|
||||
func DefineRoutes(auditor *audit.Auditor) *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
|
||||
// Tutorial: Adding new routes
|
||||
// 1. Use router.HandleFunc to define the path and handler
|
||||
// 2. Wrap the handler function, defined in package routes, with CatchError for error handling
|
||||
// 3. Specify the HTTP method(s) using .Methods()
|
||||
// 4. For URL parameters, use curly braces in the path, e.g., "/users/{id}"
|
||||
// 5. Group similar routes together for better organization
|
||||
//
|
||||
// Example (if auditor is used):
|
||||
// router.HandleFunc("/new/route/{param}", CatchError(WrapWithAuditor(auditor, routes.NewHandler))).Methods("GET", "POST")
|
||||
//
|
||||
// Example (if auditor is not used):
|
||||
// router.HandleFunc("/new/route/{param}", CatchError(routes.NewHandler)).Methods("GET", "POST")
|
||||
|
||||
// Redirect handler: strip trailing / to make router behave consistently
|
||||
// This ensures that URLs with and without trailing slashes are treated the same
|
||||
router.MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
|
||||
return r.URL.Path != "/" && strings.HasSuffix(r.URL.Path, "/")
|
||||
}).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.URL
|
||||
url.Path = url.Path[0 : len(url.Path)-1]
|
||||
// @iacore: i think this won't have open redirect vuln
|
||||
http.Redirect(w, r, url.String(), http.StatusPermanentRedirect)
|
||||
})
|
||||
|
||||
// Serve static files
|
||||
router.HandleFunc("/robots.txt", serveFile("./assets/robots.txt"))
|
||||
handleStripPrefix(router, "/img/", http.FileServer(http.Dir("./assets/img")))
|
||||
handleStripPrefix(router, "/css/", http.FileServer(http.Dir("./assets/css")))
|
||||
handleStripPrefix(router, "/js/", http.FileServer(http.Dir("./assets/js")))
|
||||
|
||||
// Proxy routes for handling image requests
|
||||
// These routes maintain cache headers set by upstream servers
|
||||
handleStripPrefix(router, "/proxy/i.pximg.net/", CatchError(routes.IPximgProxy)).Methods("GET")
|
||||
handleStripPrefix(router, "/proxy/s.pximg.net/", CatchError(routes.SPximgProxy)).Methods("GET")
|
||||
handleStripPrefix(router, "/proxy/ugoira.com/", CatchError(routes.UgoiraProxy)).Methods("GET")
|
||||
|
||||
// Main application routes
|
||||
router.HandleFunc("/", CatchError(WrapWithAuditor(auditor, routes.IndexPage))).Methods("GET")
|
||||
router.HandleFunc("/about", CatchError(routes.AboutPage)).Methods("GET")
|
||||
router.HandleFunc("/newest", CatchError(WrapWithAuditor(auditor, routes.NewestPage))).Methods("GET")
|
||||
router.HandleFunc("/discovery", CatchError(WrapWithAuditor(auditor, routes.DiscoveryPage))).Methods("GET")
|
||||
router.HandleFunc("/discovery/novel", CatchError(WrapWithAuditor(auditor, routes.NovelDiscoveryPage))).Methods("GET")
|
||||
|
||||
// Ranking related routes
|
||||
router.HandleFunc("/ranking", CatchError(WrapWithAuditor(auditor, routes.RankingPage))).Methods("GET")
|
||||
router.HandleFunc("/rankingCalendar", CatchError(WrapWithAuditor(auditor, routes.RankingCalendarPage))).Methods("GET")
|
||||
router.HandleFunc("/rankingCalendar", CatchError(routes.RankingCalendarPicker)).Methods("POST")
|
||||
|
||||
// User related routes, including Atom feeds
|
||||
router.HandleFunc("/users/{id}.atom.xml", CatchError(WrapWithAuditor(auditor, routes.UserAtomFeed))).Methods("GET")
|
||||
router.HandleFunc("/users/{id}/{category}.atom.xml", CatchError(WrapWithAuditor(auditor, routes.UserAtomFeed))).Methods("GET")
|
||||
router.HandleFunc("/users/{id}", CatchError(WrapWithAuditor(auditor, routes.UserPage))).Methods("GET")
|
||||
router.HandleFunc("/users/{id}/{category}", CatchError(WrapWithAuditor(auditor, routes.UserPage))).Methods("GET")
|
||||
|
||||
// Artwork related routes
|
||||
router.HandleFunc("/artworks/{id}", CatchError(WrapWithAuditor(auditor, routes.ArtworkPage))).Methods("GET")
|
||||
router.HandleFunc("/artworks-multi/{ids}", CatchError(WrapWithAuditor(auditor, routes.ArtworkMultiPage))).Methods("GET")
|
||||
// Legacy illust URL redirect
|
||||
router.HandleFunc("/member_illust.php", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/artworks/"+routes.GetQueryParam(r, "illust_id"), http.StatusPermanentRedirect)
|
||||
}).Methods("GET")
|
||||
|
||||
// Manga related routes
|
||||
router.HandleFunc("/users/{id}/series/{sid}", CatchError(WrapWithAuditor(auditor, routes.MangaSeriesPage))).Methods("GET")
|
||||
|
||||
// Novel related routes
|
||||
router.HandleFunc("/novel/show.php", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/novel/"+routes.GetQueryParam(r, "id"), http.StatusPermanentRedirect)
|
||||
}).Methods("GET")
|
||||
router.HandleFunc("/novel/{id}", CatchError(WrapWithAuditor(auditor, routes.NovelPage))).Methods("GET")
|
||||
router.HandleFunc("/novel/series/{id}", CatchError(WrapWithAuditor(auditor, routes.NovelSeriesPage))).Methods("GET")
|
||||
|
||||
// Pixivision related routes
|
||||
router.HandleFunc("/pixivision", CatchError(routes.PixivisionHomePage)).Methods("GET")
|
||||
router.HandleFunc("/pixivision/a/{id}", CatchError(routes.PixivisionArticlePage)).Methods("GET")
|
||||
router.HandleFunc("/pixivision/c/{id}", CatchError(routes.PixivisionCategoryPage)).Methods("GET")
|
||||
router.HandleFunc("/pixivision/t/{id}", CatchError(routes.PixivisionTagPage)).Methods("GET")
|
||||
|
||||
// Settings related routes
|
||||
router.HandleFunc("/settings", CatchError(routes.SettingsPage)).Methods("GET")
|
||||
router.HandleFunc("/settings/{type}", CatchError(WrapWithAuditor(auditor, routes.SettingsPost))).Methods("POST")
|
||||
|
||||
// User action routes (login, bookmarks, likes, etc.)
|
||||
router.HandleFunc("/self", CatchError(routes.LoginUserPage)).Methods("GET")
|
||||
router.HandleFunc("/self/followingWorks", CatchError(WrapWithAuditor(auditor, routes.FollowingWorksPage))).Methods("GET")
|
||||
router.HandleFunc("/self/bookmarks", CatchError(routes.LoginBookmarkPage)).Methods("GET")
|
||||
router.HandleFunc("/self/addBookmark/{id}", CatchError(WrapWithAuditor(auditor, routes.AddBookmarkRoute))).Methods("POST")
|
||||
router.HandleFunc("/self/deleteBookmark/{id}", CatchError(WrapWithAuditor(auditor, routes.DeleteBookmarkRoute))).Methods("POST")
|
||||
router.HandleFunc("/self/like/{id}", CatchError(WrapWithAuditor(auditor, routes.LikeRoute))).Methods("POST")
|
||||
router.HandleFunc("/self/followUser/{id}", CatchError(WrapWithAuditor(auditor, routes.FollowUserRoute))).Methods("POST")
|
||||
router.HandleFunc("/self/unfollowUser/{id}", CatchError(WrapWithAuditor(auditor, routes.UnfollowUserRoute))).Methods("POST")
|
||||
|
||||
// oEmbed endpoint for embedding Pixiv content
|
||||
router.HandleFunc("/oembed", CatchError(routes.Oembed)).Methods("GET")
|
||||
|
||||
// Tag related routes
|
||||
router.HandleFunc("/tags/{name}", CatchError(WrapWithAuditor(auditor, routes.TagPage))).Methods("GET")
|
||||
router.HandleFunc("/tags/{name}", CatchError(WrapWithAuditor(auditor, routes.TagPage))).Methods("POST")
|
||||
router.HandleFunc("/tags", CatchError(WrapWithAuditor(auditor, routes.TagPage))).Methods("GET")
|
||||
router.HandleFunc("/tags", CatchError(routes.AdvancedTagPost)).Methods("POST")
|
||||
|
||||
// Although we have ParsePixivRedirect for template. here's a fallback to catch all
|
||||
router.HandleFunc("/jump.php", func(w http.ResponseWriter, r *http.Request) {
|
||||
escaped, err := url.QueryUnescape(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
routes.ErrorPage(w, r, i18n.Errorf("Failed to redirect to %s", r.URL.RawQuery), http.StatusNotFound)
|
||||
} else {
|
||||
http.Redirect(w, r, escaped, http.StatusPermanentRedirect)
|
||||
}
|
||||
}).Methods("GET")
|
||||
|
||||
// Diagnostic routes for monitoring and debugging
|
||||
router.HandleFunc("/diagnostics", CatchError(routes.Diagnostics)).Methods("GET")
|
||||
router.HandleFunc("/diagnostics/spans.json", CatchError(routes.DiagnosticsData)).Methods("GET")
|
||||
router.HandleFunc("/diagnostics/reset", routes.ResetDiagnosticsData)
|
||||
|
||||
// Fallback route (if nothing else matches)
|
||||
// This ensures that a proper HTTP 404 error is returned for undefined routes
|
||||
router.NewRoute().HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
routes.ErrorPage(w, r, i18n.Error("Route not found"), http.StatusNotFound)
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"codeberg.org/vnpower/pixivfe/v2/audit"
|
||||
"codeberg.org/vnpower/pixivfe/v2/i18n"
|
||||
"codeberg.org/vnpower/pixivfe/v2/server/middleware"
|
||||
"codeberg.org/vnpower/pixivfe/v2/server/routes"
|
||||
)
|
||||
|
||||
// AuditorHandler is a type for routes that require an auditor
|
||||
type AuditorHandler func(auditor *audit.Auditor, w http.ResponseWriter, r *http.Request) error
|
||||
|
||||
// WrapWithAuditor is a helper function to wrap AuditorHandler into middleware.CatchError
|
||||
func WrapWithAuditor(auditor *audit.Auditor, handler AuditorHandler) func(w http.ResponseWriter, r *http.Request) error {
|
||||
return func(w http.ResponseWriter, r *http.Request) error {
|
||||
return handler(auditor, w, r)
|
||||
}
|
||||
}
|
||||
|
||||
// handleStripPrefix is a utility function that combines path prefix matching with
|
||||
// stripping the prefix from the request URL before passing it to the handler.
|
||||
func handleStripPrefix(router *mux.Router, pathPrefix string, handler http.Handler) *mux.Route {
|
||||
return router.PathPrefix(pathPrefix).Handler(http.StripPrefix(pathPrefix, handler))
|
||||
}
|
||||
|
||||
// serveFile returns an http.HandlerFunc that serves a specific file.
|
||||
// This is useful for serving static files like robots.txt.
|
||||
func serveFile(filename string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
http.ServeFile(w, r, filename)
|
||||
}
|
||||
}
|
||||
|
||||
// DefineRoutes sets up all the routes for the application.
|
||||
// It returns a configured mux.Router with all paths and their corresponding handlers.
|
||||
func DefineRoutes(auditor *audit.Auditor) *mux.Router {
|
||||
router := mux.NewRouter()
|
||||
|
||||
// Tutorial: Adding new routes
|
||||
// 1. Use router.HandleFunc to define the path and handler
|
||||
// 2. Wrap the handler function, defined in package routes, with middleware.CatchError for error handling
|
||||
// 3. Specify the HTTP method(s) using .Methods()
|
||||
// 4. For URL parameters, use curly braces in the path, e.g., "/users/{id}"
|
||||
// 5. Group similar routes together for better organization
|
||||
//
|
||||
// Example (if auditor is used):
|
||||
// router.HandleFunc("/new/route/{param}", middleware.CatchError(WrapWithAuditor(auditor, routes.NewHandler))).Methods("GET", "POST")
|
||||
//
|
||||
// Example (if auditor is not used):
|
||||
// router.HandleFunc("/new/route/{param}", middleware.CatchError(routes.NewHandler)).Methods("GET", "POST")
|
||||
|
||||
// Redirect handler: strip trailing / to make router behave consistently
|
||||
// This ensures that URLs with and without trailing slashes are treated the same
|
||||
router.MatcherFunc(func(r *http.Request, rm *mux.RouteMatch) bool {
|
||||
return r.URL.Path != "/" && strings.HasSuffix(r.URL.Path, "/")
|
||||
}).HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.URL
|
||||
url.Path = url.Path[0 : len(url.Path)-1]
|
||||
// @iacore: i think this won't have open redirect vuln
|
||||
http.Redirect(w, r, url.String(), http.StatusPermanentRedirect)
|
||||
})
|
||||
|
||||
// Serve static files
|
||||
router.HandleFunc("/robots.txt", serveFile("./assets/robots.txt"))
|
||||
handleStripPrefix(router, "/img/", http.FileServer(http.Dir("./assets/img")))
|
||||
handleStripPrefix(router, "/css/", http.FileServer(http.Dir("./assets/css")))
|
||||
handleStripPrefix(router, "/js/", http.FileServer(http.Dir("./assets/js")))
|
||||
|
||||
// Proxy routes for handling image requests
|
||||
// These routes maintain cache headers set by upstream servers
|
||||
handleStripPrefix(router, "/proxy/i.pximg.net/", middleware.CatchError(routes.IPximgProxy)).Methods("GET")
|
||||
handleStripPrefix(router, "/proxy/s.pximg.net/", middleware.CatchError(routes.SPximgProxy)).Methods("GET")
|
||||
handleStripPrefix(router, "/proxy/ugoira.com/", middleware.CatchError(routes.UgoiraProxy)).Methods("GET")
|
||||
|
||||
// Main application routes
|
||||
router.HandleFunc("/", middleware.CatchError(WrapWithAuditor(auditor, routes.IndexPage))).Methods("GET")
|
||||
router.HandleFunc("/about", middleware.CatchError(routes.AboutPage)).Methods("GET")
|
||||
router.HandleFunc("/newest", middleware.CatchError(WrapWithAuditor(auditor, routes.NewestPage))).Methods("GET")
|
||||
router.HandleFunc("/discovery", middleware.CatchError(WrapWithAuditor(auditor, routes.DiscoveryPage))).Methods("GET")
|
||||
router.HandleFunc("/discovery/novel", middleware.CatchError(WrapWithAuditor(auditor, routes.NovelDiscoveryPage))).Methods("GET")
|
||||
|
||||
// Ranking related routes
|
||||
router.HandleFunc("/ranking", middleware.CatchError(WrapWithAuditor(auditor, routes.RankingPage))).Methods("GET")
|
||||
router.HandleFunc("/rankingCalendar", middleware.CatchError(WrapWithAuditor(auditor, routes.RankingCalendarPage))).Methods("GET")
|
||||
router.HandleFunc("/rankingCalendar", middleware.CatchError(routes.RankingCalendarPicker)).Methods("POST")
|
||||
|
||||
// User related routes, including Atom feeds
|
||||
router.HandleFunc("/users/{id}.atom.xml", middleware.CatchError(WrapWithAuditor(auditor, routes.UserAtomFeed))).Methods("GET")
|
||||
router.HandleFunc("/users/{id}/{category}.atom.xml", middleware.CatchError(WrapWithAuditor(auditor, routes.UserAtomFeed))).Methods("GET")
|
||||
router.HandleFunc("/users/{id}", middleware.CatchError(WrapWithAuditor(auditor, routes.UserPage))).Methods("GET")
|
||||
router.HandleFunc("/users/{id}/{category}", middleware.CatchError(WrapWithAuditor(auditor, routes.UserPage))).Methods("GET")
|
||||
|
||||
// Artwork related routes
|
||||
router.HandleFunc("/artworks/{id}", middleware.CatchError(WrapWithAuditor(auditor, routes.ArtworkPage))).Methods("GET")
|
||||
router.HandleFunc("/artworks-multi/{ids}", middleware.CatchError(WrapWithAuditor(auditor, routes.ArtworkMultiPage))).Methods("GET")
|
||||
// Legacy illust URL redirect
|
||||
router.HandleFunc("/member_illust.php", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/artworks/"+routes.GetQueryParam(r, "illust_id"), http.StatusPermanentRedirect)
|
||||
}).Methods("GET")
|
||||
|
||||
// Manga related routes
|
||||
router.HandleFunc("/users/{id}/series/{sid}", middleware.CatchError(WrapWithAuditor(auditor, routes.MangaSeriesPage))).Methods("GET")
|
||||
|
||||
// Novel related routes
|
||||
router.HandleFunc("/novel/show.php", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/novel/"+routes.GetQueryParam(r, "id"), http.StatusPermanentRedirect)
|
||||
}).Methods("GET")
|
||||
router.HandleFunc("/novel/{id}", middleware.CatchError(WrapWithAuditor(auditor, routes.NovelPage))).Methods("GET")
|
||||
router.HandleFunc("/novel/series/{id}", middleware.CatchError(WrapWithAuditor(auditor, routes.NovelSeriesPage))).Methods("GET")
|
||||
|
||||
// Pixivision related routes
|
||||
router.HandleFunc("/pixivision", middleware.CatchError(routes.PixivisionHomePage)).Methods("GET")
|
||||
router.HandleFunc("/pixivision/a/{id}", middleware.CatchError(routes.PixivisionArticlePage)).Methods("GET")
|
||||
router.HandleFunc("/pixivision/c/{id}", middleware.CatchError(routes.PixivisionCategoryPage)).Methods("GET")
|
||||
router.HandleFunc("/pixivision/t/{id}", middleware.CatchError(routes.PixivisionTagPage)).Methods("GET")
|
||||
|
||||
// Settings related routes
|
||||
router.HandleFunc("/settings", middleware.CatchError(routes.SettingsPage)).Methods("GET")
|
||||
router.HandleFunc("/settings/{type}", middleware.CatchError(WrapWithAuditor(auditor, routes.SettingsPost))).Methods("POST")
|
||||
|
||||
// User action routes (login, bookmarks, likes, etc.)
|
||||
router.HandleFunc("/self", middleware.CatchError(routes.LoginUserPage)).Methods("GET")
|
||||
router.HandleFunc("/self/followingWorks", middleware.CatchError(WrapWithAuditor(auditor, routes.FollowingWorksPage))).Methods("GET")
|
||||
router.HandleFunc("/self/bookmarks", middleware.CatchError(routes.LoginBookmarkPage)).Methods("GET")
|
||||
router.HandleFunc("/self/addBookmark/{id}", middleware.CatchError(WrapWithAuditor(auditor, routes.AddBookmarkRoute))).Methods("POST")
|
||||
router.HandleFunc("/self/deleteBookmark/{id}", middleware.CatchError(WrapWithAuditor(auditor, routes.DeleteBookmarkRoute))).Methods("POST")
|
||||
router.HandleFunc("/self/like/{id}", middleware.CatchError(WrapWithAuditor(auditor, routes.LikeRoute))).Methods("POST")
|
||||
router.HandleFunc("/self/followUser/{id}", middleware.CatchError(WrapWithAuditor(auditor, routes.FollowUserRoute))).Methods("POST")
|
||||
router.HandleFunc("/self/unfollowUser/{id}", middleware.CatchError(WrapWithAuditor(auditor, routes.UnfollowUserRoute))).Methods("POST")
|
||||
|
||||
// oEmbed endpoint for embedding Pixiv content
|
||||
router.HandleFunc("/oembed", middleware.CatchError(routes.Oembed)).Methods("GET")
|
||||
|
||||
// Tag related routes
|
||||
router.HandleFunc("/tags/{name}", middleware.CatchError(WrapWithAuditor(auditor, routes.TagPage))).Methods("GET")
|
||||
router.HandleFunc("/tags/{name}", middleware.CatchError(WrapWithAuditor(auditor, routes.TagPage))).Methods("POST")
|
||||
router.HandleFunc("/tags", middleware.CatchError(WrapWithAuditor(auditor, routes.TagPage))).Methods("GET")
|
||||
router.HandleFunc("/tags", middleware.CatchError(routes.AdvancedTagPost)).Methods("POST")
|
||||
|
||||
// Although we have ParsePixivRedirect for template. here's a fallback to catch all
|
||||
router.HandleFunc("/jump.php", func(w http.ResponseWriter, r *http.Request) {
|
||||
escaped, err := url.QueryUnescape(r.URL.RawQuery)
|
||||
if err != nil {
|
||||
routes.ErrorPage(w, r, i18n.Errorf("Failed to redirect to %s", r.URL.RawQuery), http.StatusNotFound)
|
||||
} else {
|
||||
http.Redirect(w, r, escaped, http.StatusPermanentRedirect)
|
||||
}
|
||||
}).Methods("GET")
|
||||
|
||||
// Diagnostic routes for monitoring and debugging
|
||||
router.HandleFunc("/diagnostics", middleware.CatchError(routes.Diagnostics)).Methods("GET")
|
||||
router.HandleFunc("/diagnostics/spans.json", middleware.CatchError(routes.DiagnosticsData)).Methods("GET")
|
||||
router.HandleFunc("/diagnostics/reset", routes.ResetDiagnosticsData)
|
||||
|
||||
// Fallback route (if nothing else matches)
|
||||
// This ensures that a proper HTTP 404 error is returned for undefined routes
|
||||
router.NewRoute().HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
routes.ErrorPage(w, r, i18n.Error("Route not found"), http.StatusNotFound)
|
||||
})
|
||||
|
||||
return router
|
||||
}
|
||||
Reference in New Issue
Block a user