// Package router configures web routes. package router import ( "net/http" "code.nonshy.com/nonshy/website/pkg/config" "code.nonshy.com/nonshy/website/pkg/controller/account" "code.nonshy.com/nonshy/website/pkg/controller/admin" "code.nonshy.com/nonshy/website/pkg/controller/api" "code.nonshy.com/nonshy/website/pkg/controller/api/barertc" "code.nonshy.com/nonshy/website/pkg/controller/block" "code.nonshy.com/nonshy/website/pkg/controller/chat" "code.nonshy.com/nonshy/website/pkg/controller/comment" "code.nonshy.com/nonshy/website/pkg/controller/forum" "code.nonshy.com/nonshy/website/pkg/controller/friend" "code.nonshy.com/nonshy/website/pkg/controller/htmx" "code.nonshy.com/nonshy/website/pkg/controller/inbox" "code.nonshy.com/nonshy/website/pkg/controller/index" "code.nonshy.com/nonshy/website/pkg/controller/photo" "code.nonshy.com/nonshy/website/pkg/controller/poll" "code.nonshy.com/nonshy/website/pkg/middleware" nst "code.nonshy.com/nonshy/website/pkg/templates" ) func New() http.Handler { mux := http.NewServeMux() // Register controller endpoints. mux.HandleFunc("/", index.Create()) mux.HandleFunc("GET /favicon.ico", index.Favicon()) mux.HandleFunc("GET /manifest.json", index.Manifest()) mux.HandleFunc("GET /about", index.StaticTemplate("about.html")()) mux.HandleFunc("GET /features", index.StaticTemplate("features.html")()) mux.HandleFunc("GET /faq", index.StaticTemplate("faq.html")()) mux.HandleFunc("GET /tos", index.StaticTemplate("tos.html")()) mux.HandleFunc("GET /privacy", index.StaticTemplate("privacy.html")()) mux.HandleFunc("/contact", index.Contact()) mux.HandleFunc("/login", account.Login()) mux.HandleFunc("GET /logout", account.Logout()) mux.Handle("/signup", middleware.GeoGate(account.Signup())) mux.HandleFunc("/forgot-password", account.ForgotPassword()) mux.HandleFunc("GET /settings/confirm-email", account.ConfirmEmailChange()) mux.HandleFunc("GET /markdown", index.StaticTemplate("markdown.html")()) mux.HandleFunc("GET /test/geo-gate", index.StaticTemplate("errors/geo_gate.html")()) // Login Required. Pages that non-certified users can access. mux.Handle("/me", middleware.LoginRequired(account.Dashboard())) mux.Handle("/settings", middleware.LoginRequired(account.Settings())) mux.Handle("/settings/age-gate", middleware.LoginRequired(account.AgeGate())) mux.Handle("/account/two-factor/setup", middleware.LoginRequired(account.Setup2FA())) mux.Handle("/account/delete", middleware.LoginRequired(account.Delete())) mux.Handle("/account/deactivate", middleware.LoginRequired(account.Deactivate())) mux.Handle("GET /account/reactivate", middleware.LoginRequired(account.Reactivate())) mux.Handle("GET /u/{username}", account.Profile()) // public access OK mux.Handle("GET /u/{username}/friends", middleware.CertRequired(account.UserFriends())) mux.Handle("GET /u/{username}/photos", middleware.LoginRequired(photo.UserPhotos())) mux.Handle("/u/{username}/notes", middleware.LoginRequired(account.UserNotes())) mux.Handle("/photo/upload", middleware.LoginRequired(photo.Upload())) mux.Handle("GET /photo/view", middleware.LoginRequired(photo.View())) mux.Handle("/photo/edit", middleware.LoginRequired(photo.Edit())) mux.Handle("/photo/delete", middleware.LoginRequired(photo.Delete())) mux.Handle("/photo/certification", middleware.LoginRequired(photo.Certification())) mux.Handle("GET /photo/private", middleware.LoginRequired(photo.Private())) mux.Handle("/photo/private/share", middleware.LoginRequired(photo.Share())) mux.Handle("/notes/me", middleware.LoginRequired(account.MyNotes())) mux.Handle("GET /messages", middleware.LoginRequired(inbox.Inbox())) mux.Handle("GET /messages/read/{id}", middleware.LoginRequired(inbox.Inbox())) mux.Handle("/messages/compose", middleware.LoginRequired(inbox.Compose())) mux.Handle("/messages/delete", middleware.LoginRequired(inbox.Delete())) mux.Handle("GET /friends", middleware.LoginRequired(friend.Friends())) mux.Handle("/friends/add", middleware.LoginRequired(friend.AddFriend())) mux.Handle("POST /users/block", middleware.LoginRequired(block.BlockUser())) mux.Handle("GET /users/blocked", middleware.LoginRequired(block.Blocked())) mux.Handle("GET /users/blocklist/add", middleware.LoginRequired(block.AddUser())) mux.Handle("/comments", middleware.LoginRequired(comment.PostComment())) mux.Handle("GET /comments/subscription", middleware.LoginRequired(comment.Subscription())) mux.Handle("GET /admin/unimpersonate", middleware.LoginRequired(admin.Unimpersonate())) mux.Handle("GET /inner-circle", middleware.LoginRequired(account.InnerCircle())) mux.Handle("/inner-circle/invite", middleware.LoginRequired(account.InviteCircle())) mux.Handle("GET /admin/transparency/{username}", middleware.LoginRequired(admin.Transparency())) // Certification Required. Pages that only full (verified) members can access. mux.Handle("GET /photo/gallery", middleware.CertRequired(photo.SiteGallery())) mux.Handle("GET /members", middleware.CertRequired(account.Search())) mux.Handle("/chat", middleware.CertRequired(chat.Landing())) mux.Handle("GET /forum", middleware.CertRequired(forum.Landing())) mux.Handle("/forum/post", middleware.CertRequired(forum.NewPost())) mux.Handle("GET /forum/thread/{id}", middleware.CertRequired(forum.Thread())) mux.Handle("GET /forum/newest", middleware.CertRequired(forum.Newest())) mux.Handle("GET /forum/search", middleware.CertRequired(forum.Search())) mux.Handle("GET /f/{fragment}", middleware.CertRequired(forum.Forum())) mux.Handle("POST /poll/vote", middleware.CertRequired(poll.Vote())) // Admin endpoints. mux.Handle("GET /admin", middleware.AdminRequired("", admin.Dashboard())) mux.Handle("/admin/scopes", middleware.AdminRequired("", admin.Scopes())) mux.Handle("/admin/photo/certification", middleware.AdminRequired("", photo.AdminCertification())) mux.Handle("/admin/feedback", middleware.AdminRequired(config.ScopeFeedbackAndReports, admin.Feedback())) mux.Handle("/admin/user-action", middleware.AdminRequired("", admin.UserActions())) mux.Handle("/admin/maintenance", middleware.AdminRequired(config.ScopeMaintenance, admin.Maintenance())) mux.Handle("/forum/admin", middleware.AdminRequired(config.ScopeForumAdmin, forum.Manage())) mux.Handle("/forum/admin/edit", middleware.AdminRequired(config.ScopeForumAdmin, forum.AddEdit())) mux.Handle("/inner-circle/remove", middleware.LoginRequired(account.RemoveCircle())) mux.Handle("/admin/photo/mark-explicit", middleware.AdminRequired(config.ScopePhotoModerator, admin.MarkPhotoExplicit())) mux.Handle("GET /admin/changelog", middleware.AdminRequired(config.ScopeChangeLog, admin.ChangeLog())) // JSON API endpoints. mux.HandleFunc("GET /v1/version", api.Version()) mux.HandleFunc("GET /v1/users/me", api.LoginOK()) mux.HandleFunc("POST /v1/users/check-username", api.UsernameCheck()) mux.Handle("POST /v1/likes", middleware.LoginRequired(api.Likes())) mux.Handle("GET /v1/likes/users", middleware.LoginRequired(api.WhoLikes())) mux.Handle("POST /v1/notifications/read", middleware.LoginRequired(api.ReadNotification())) mux.Handle("POST /v1/notifications/delete", middleware.LoginRequired(api.ClearNotification())) mux.Handle("POST /v1/photos/mark-explicit", middleware.LoginRequired(api.MarkPhotoExplicit())) mux.Handle("GET /v1/comment-photos/remove-orphaned", api.RemoveOrphanedCommentPhotos()) mux.Handle("POST /v1/barertc/report", barertc.Report()) mux.Handle("POST /v1/barertc/profile", barertc.Profile()) // HTMX endpoints. mux.Handle("GET /htmx/user/profile/activity", middleware.LoginRequired(htmx.UserProfileActivityCard())) // Redirect endpoints. mux.Handle("GET /go/comment", middleware.LoginRequired(comment.GoToComment())) // Static files. mux.Handle("GET /static/", http.StripPrefix("/static/", http.FileServer(http.Dir(config.StaticPath)))) // Legacy route redirects (Go 1.22 path parameters update) mux.Handle("GET /friends/u/{s}", nst.RedirectRoute("/u/%s/friends")) mux.Handle("GET /photo/u/{s}", nst.RedirectRoute("/u/%s/photos")) mux.Handle("GET /notes/u/{s}", nst.RedirectRoute("/u/%s/notes")) // Global middlewares. withCSRF := middleware.CSRF(mux) withSession := middleware.Session(withCSRF) withRecovery := middleware.Recovery(withSession) withLogger := middleware.Logging(withRecovery) return withLogger }