2021-05-05 20:34:32 +00:00
|
|
|
|
package hmnurl
|
|
|
|
|
|
|
|
|
|
import (
|
2021-05-25 13:12:20 +00:00
|
|
|
|
"fmt"
|
2021-05-11 22:53:23 +00:00
|
|
|
|
"net/url"
|
2021-05-05 20:34:32 +00:00
|
|
|
|
"regexp"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
2021-05-06 04:04:58 +00:00
|
|
|
|
|
2021-05-25 13:48:57 +00:00
|
|
|
|
"git.handmade.network/hmn/hmn/src/logging"
|
2021-10-27 00:45:11 +00:00
|
|
|
|
"git.handmade.network/hmn/hmn/src/models"
|
2021-05-06 04:04:58 +00:00
|
|
|
|
"git.handmade.network/hmn/hmn/src/oops"
|
2021-05-05 20:34:32 +00:00
|
|
|
|
)
|
|
|
|
|
|
2021-05-16 19:22:45 +00:00
|
|
|
|
/*
|
|
|
|
|
Any function in this package whose name starts with Build is required to be covered by a test.
|
|
|
|
|
This helps ensure that we don't generate URLs that can't be routed.
|
|
|
|
|
*/
|
|
|
|
|
|
2021-08-08 20:05:52 +00:00
|
|
|
|
var RegexOldHome = regexp.MustCompile("^/home$")
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexHomepage = regexp.MustCompile("^/$")
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
func BuildHomepage() string {
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return HMNProjectContext.BuildHomepage()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildHomepage() string {
|
|
|
|
|
return c.Url("/", nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexShowcase = regexp.MustCompile("^/showcase$")
|
|
|
|
|
|
|
|
|
|
func BuildShowcase() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
return Url("/showcase", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexStreams = regexp.MustCompile("^/streams$")
|
|
|
|
|
|
|
|
|
|
func BuildStreams() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
return Url("/streams", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-17 19:48:44 +00:00
|
|
|
|
var RegexWhenIsIt = regexp.MustCompile("^/whenisit$")
|
|
|
|
|
|
|
|
|
|
func BuildWhenIsIt() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/whenisit", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 11:26:17 +00:00
|
|
|
|
var RegexJamIndex = regexp.MustCompile("^/jam$")
|
|
|
|
|
|
|
|
|
|
func BuildJamIndex() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/jam", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-19 22:26:33 +00:00
|
|
|
|
var RegexJamIndex2021 = regexp.MustCompile("^/jam/2021$")
|
|
|
|
|
|
|
|
|
|
func BuildJamIndex2021() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/jam/2021", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexJamIndex2022 = regexp.MustCompile("^/jam/2022$")
|
|
|
|
|
|
|
|
|
|
func BuildJamIndex2022() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/jam/2022", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-07 17:37:01 +00:00
|
|
|
|
var RegexJamIndex2023_Visibility = regexp.MustCompile("^/jam/visibility-2023$")
|
2023-03-05 04:52:03 +00:00
|
|
|
|
|
2023-03-07 17:37:01 +00:00
|
|
|
|
func BuildJamIndex2023_Visibility() string {
|
2023-03-05 04:52:03 +00:00
|
|
|
|
defer CatchPanic()
|
2023-03-07 17:37:01 +00:00
|
|
|
|
return Url("/jam/visibility-2023", nil)
|
2023-03-05 04:52:03 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-06 18:54:14 +00:00
|
|
|
|
var RegexJamFeed2023_Visibility = regexp.MustCompile("^/jam/visibility-2023/feed$")
|
|
|
|
|
|
|
|
|
|
func BuildJamFeed2023_Visibility() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/jam/visibility-2023/feed", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-19 22:26:33 +00:00
|
|
|
|
var RegexJamFeed2022 = regexp.MustCompile("^/jam/2022/feed$")
|
|
|
|
|
|
|
|
|
|
func BuildJamFeed2022() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/jam/2022/feed", nil)
|
|
|
|
|
}
|
2022-06-17 22:30:18 +00:00
|
|
|
|
|
2021-05-16 19:22:45 +00:00
|
|
|
|
// QUESTION(ben): Can we change these routes?
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
var RegexLoginAction = regexp.MustCompile("^/login$")
|
|
|
|
|
|
|
|
|
|
func BuildLoginAction(redirectTo string) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
return Url("/login", []Q{{Name: "redirect", Value: redirectTo}})
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-08 20:05:52 +00:00
|
|
|
|
var RegexLoginPage = regexp.MustCompile("^/login$")
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
|
|
|
|
func BuildLoginPage(redirectTo string) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-08-08 20:05:52 +00:00
|
|
|
|
return Url("/login", []Q{{Name: "redirect", Value: redirectTo}})
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexLogoutAction = regexp.MustCompile("^/logout$")
|
|
|
|
|
|
2021-06-12 00:48:03 +00:00
|
|
|
|
func BuildLogoutAction(redir string) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-06-12 00:48:03 +00:00
|
|
|
|
if redir == "" {
|
|
|
|
|
redir = "/"
|
|
|
|
|
}
|
|
|
|
|
return Url("/logout", []Q{{"redirect", redir}})
|
2021-05-05 20:34:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-08 20:05:52 +00:00
|
|
|
|
var RegexRegister = regexp.MustCompile("^/register$")
|
2021-06-06 23:48:43 +00:00
|
|
|
|
|
2022-08-13 20:07:37 +00:00
|
|
|
|
func BuildRegister(destination string) string {
|
2021-06-06 23:48:43 +00:00
|
|
|
|
defer CatchPanic()
|
2022-08-13 20:07:37 +00:00
|
|
|
|
var query []Q
|
|
|
|
|
if destination != "" {
|
|
|
|
|
query = append(query, Q{"destination", destination})
|
|
|
|
|
}
|
|
|
|
|
return Url("/register", query)
|
2021-08-08 20:05:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexRegistrationSuccess = regexp.MustCompile("^/registered_successfully$")
|
|
|
|
|
|
|
|
|
|
func BuildRegistrationSuccess() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/registered_successfully", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexEmailConfirmation = regexp.MustCompile("^/email_confirmation/(?P<username>[^/]+)/(?P<token>[^/]+)$")
|
|
|
|
|
|
2022-08-13 19:15:00 +00:00
|
|
|
|
func BuildEmailConfirmation(username, token string, destination string) string {
|
2021-08-08 20:05:52 +00:00
|
|
|
|
defer CatchPanic()
|
2022-08-13 19:15:00 +00:00
|
|
|
|
var query []Q
|
|
|
|
|
if destination != "" {
|
|
|
|
|
query = append(query, Q{"destination", destination})
|
|
|
|
|
}
|
|
|
|
|
return Url(fmt.Sprintf("/email_confirmation/%s/%s", url.PathEscape(username), token), query)
|
2021-08-08 20:05:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-17 05:18:04 +00:00
|
|
|
|
var RegexRequestPasswordReset = regexp.MustCompile("^/password_reset$")
|
2021-08-08 20:05:52 +00:00
|
|
|
|
|
2021-08-17 05:18:04 +00:00
|
|
|
|
func BuildRequestPasswordReset() string {
|
2021-08-08 20:05:52 +00:00
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/password_reset", nil)
|
2021-06-06 23:48:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-17 05:18:04 +00:00
|
|
|
|
var RegexPasswordResetSent = regexp.MustCompile("^/password_reset/sent$")
|
|
|
|
|
|
|
|
|
|
func BuildPasswordResetSent() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/password_reset/sent", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexOldDoPasswordReset = regexp.MustCompile(`^_password_reset/(?P<username>[\w\ \.\,\-@\+\_]+)/(?P<token>[\d\w]+)[\/]?$`)
|
|
|
|
|
var RegexDoPasswordReset = regexp.MustCompile("^/password_reset/(?P<username>[^/]+)/(?P<token>[^/]+)$")
|
|
|
|
|
|
|
|
|
|
func BuildDoPasswordReset(username string, token string) string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url(fmt.Sprintf("/password_reset/%s/%s", url.PathEscape(username), token), nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* Static Pages
|
|
|
|
|
*/
|
|
|
|
|
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexManifesto = regexp.MustCompile("^/manifesto$")
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
func BuildManifesto() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
return Url("/manifesto", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexAbout = regexp.MustCompile("^/about$")
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
func BuildAbout() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
return Url("/about", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-10 21:32:19 +00:00
|
|
|
|
var RegexFoundation = regexp.MustCompile("^/foundation$")
|
|
|
|
|
|
|
|
|
|
func BuildFoundation() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/foundation", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexCommunicationGuidelines = regexp.MustCompile("^/communication-guidelines$")
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
func BuildCommunicationGuidelines() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
return Url("/communication-guidelines", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexContactPage = regexp.MustCompile("^/contact$")
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
func BuildContactPage() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
return Url("/contact", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexMonthlyUpdatePolicy = regexp.MustCompile("^/monthly-update-policy$")
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
func BuildMonthlyUpdatePolicy() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
return Url("/monthly-update-policy", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexProjectSubmissionGuidelines = regexp.MustCompile("^/project-guidelines$")
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
func BuildProjectSubmissionGuidelines() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
return Url("/project-guidelines", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-26 15:07:57 +00:00
|
|
|
|
var RegexConferences = regexp.MustCompile("^/conferences$")
|
|
|
|
|
|
|
|
|
|
func BuildConferences() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/conferences", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-10 21:32:19 +00:00
|
|
|
|
/*
|
|
|
|
|
* Volunteer/Staff Roles
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexStaffRolesIndex = regexp.MustCompile(`^/roles$`)
|
|
|
|
|
|
|
|
|
|
func BuildStaffRolesIndex() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/roles", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexStaffRole = regexp.MustCompile(`^/roles/(?P<slug>[^/]+)$`)
|
|
|
|
|
|
|
|
|
|
func BuildStaffRole(slug string) string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url(fmt.Sprintf("/roles/%s", slug), nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
/*
|
2021-06-22 09:50:40 +00:00
|
|
|
|
* User
|
2021-05-11 22:53:23 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2021-06-22 09:50:40 +00:00
|
|
|
|
var RegexUserProfile = regexp.MustCompile(`^/m/(?P<username>[^/]+)$`)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
2021-06-22 09:50:40 +00:00
|
|
|
|
func BuildUserProfile(username string) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
if len(username) == 0 {
|
|
|
|
|
panic(oops.New(nil, "Username must not be blank"))
|
|
|
|
|
}
|
2021-12-21 04:24:05 +00:00
|
|
|
|
return Url("/m/"+username, nil)
|
2021-08-08 20:05:52 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 17:58:52 +00:00
|
|
|
|
var RegexUserSettings = regexp.MustCompile(`^/settings$`)
|
2021-08-17 05:18:04 +00:00
|
|
|
|
|
|
|
|
|
func BuildUserSettings(section string) string {
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return UrlWithFragment("/settings", nil, section)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-24 00:12:46 +00:00
|
|
|
|
/*
|
|
|
|
|
* Admin
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexAdminAtomFeed = regexp.MustCompile(`^/admin/atom$`)
|
|
|
|
|
|
|
|
|
|
func BuildAdminAtomFeed() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/admin/atom", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexAdminApprovalQueue = regexp.MustCompile(`^/admin/approvals$`)
|
|
|
|
|
|
|
|
|
|
func BuildAdminApprovalQueue() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/admin/approvals", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-10 21:52:02 +00:00
|
|
|
|
var RegexAdminSetUserOptions = regexp.MustCompile(`^/admin/setuseroptions$`)
|
2021-12-15 01:17:42 +00:00
|
|
|
|
|
2022-09-10 21:52:02 +00:00
|
|
|
|
func BuildAdminSetUserOptions() string {
|
2021-12-15 01:17:42 +00:00
|
|
|
|
defer CatchPanic()
|
2022-09-10 21:52:02 +00:00
|
|
|
|
return Url("/admin/setuseroptions", nil)
|
2021-12-15 01:17:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexAdminNukeUser = regexp.MustCompile(`^/admin/nukeuser$`)
|
|
|
|
|
|
|
|
|
|
func BuildAdminNukeUser() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/admin/nukeuser", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-22 09:50:40 +00:00
|
|
|
|
/*
|
|
|
|
|
* Snippets
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexSnippet = regexp.MustCompile(`^/snippet/(?P<snippetid>\d+)$`)
|
|
|
|
|
|
|
|
|
|
func BuildSnippet(snippetId int) string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/snippet/"+strconv.Itoa(snippetId), nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-05 04:03:45 +00:00
|
|
|
|
var RegexSnippetSubmit = regexp.MustCompile(`^/snippet$`)
|
|
|
|
|
|
|
|
|
|
func BuildSnippetSubmit() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/snippet", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* Feed
|
|
|
|
|
*/
|
|
|
|
|
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexFeed = regexp.MustCompile(`^/feed(/(?P<page>.+)?)?$`)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
func BuildFeed() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
return Url("/feed", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BuildFeedWithPage(page int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
if page < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid feed page (%d), must be >= 1", page))
|
|
|
|
|
}
|
|
|
|
|
if page == 1 {
|
|
|
|
|
return BuildFeed()
|
|
|
|
|
}
|
|
|
|
|
return Url("/feed/"+strconv.Itoa(page), nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 23:23:04 +00:00
|
|
|
|
var RegexAtomFeed = regexp.MustCompile("^/atom(/(?P<feedtype>[^/]+))?(/new)?$") // NOTE(asaf): `/new` for backwards compatibility with old website
|
2021-05-30 18:35:01 +00:00
|
|
|
|
|
|
|
|
|
func BuildAtomFeed() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/atom", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BuildAtomFeedForProjects() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/atom/projects", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BuildAtomFeedForShowcase() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/atom/showcase", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-06 23:48:43 +00:00
|
|
|
|
/*
|
|
|
|
|
* Projects
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexProjectIndex = regexp.MustCompile("^/projects(/(?P<page>.+)?)?$")
|
|
|
|
|
|
|
|
|
|
func BuildProjectIndex(page int) string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
if page < 1 {
|
|
|
|
|
panic(oops.New(nil, "page must be >= 1"))
|
|
|
|
|
}
|
|
|
|
|
if page == 1 {
|
|
|
|
|
return Url("/projects", nil)
|
|
|
|
|
} else {
|
|
|
|
|
return Url(fmt.Sprintf("/projects/%d", page), nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-25 03:59:51 +00:00
|
|
|
|
var RegexProjectNew = regexp.MustCompile("^/p/new$")
|
2021-06-06 23:48:43 +00:00
|
|
|
|
|
|
|
|
|
func BuildProjectNew() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
|
2021-11-25 03:59:51 +00:00
|
|
|
|
return Url("/p/new", nil)
|
2021-06-06 23:48:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-25 13:24:04 +00:00
|
|
|
|
func BuildProjectNewJam() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
|
2022-08-13 20:07:37 +00:00
|
|
|
|
return Url("/p/new", []Q{{Name: "jam", Value: "1"}})
|
2022-06-25 13:24:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 17:34:48 +00:00
|
|
|
|
var RegexPersonalProject = regexp.MustCompile("^/p/(?P<projectid>[0-9]+)(/(?P<projectslug>[a-zA-Z0-9-]+))?")
|
2021-06-06 23:48:43 +00:00
|
|
|
|
|
2021-11-09 19:14:38 +00:00
|
|
|
|
func BuildPersonalProject(id int, slug string) string {
|
2021-06-06 23:48:43 +00:00
|
|
|
|
defer CatchPanic()
|
2021-11-08 19:16:54 +00:00
|
|
|
|
return Url(fmt.Sprintf("/p/%d/%s", id, slug), nil)
|
2021-06-06 23:48:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-09 19:14:38 +00:00
|
|
|
|
var RegexProjectEdit = regexp.MustCompile("^/edit$")
|
2021-07-08 07:40:30 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildProjectEdit(section string) string {
|
2021-07-08 07:40:30 +00:00
|
|
|
|
defer CatchPanic()
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.UrlWithFragment("/edit", nil, section)
|
2021-07-08 07:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* Podcast
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexPodcast = regexp.MustCompile(`^/podcast$`)
|
|
|
|
|
|
2021-10-27 00:45:11 +00:00
|
|
|
|
func BuildPodcast() string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-10-27 00:45:11 +00:00
|
|
|
|
return Url("/podcast", nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-23 03:09:46 +00:00
|
|
|
|
var RegexPodcastEdit = regexp.MustCompile(`^/podcast/edit$`)
|
|
|
|
|
|
2021-10-27 00:45:11 +00:00
|
|
|
|
func BuildPodcastEdit() string {
|
2021-07-23 03:09:46 +00:00
|
|
|
|
defer CatchPanic()
|
2021-10-27 00:45:11 +00:00
|
|
|
|
return Url("/podcast/edit", nil)
|
2021-07-23 03:09:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexPodcastEpisode = regexp.MustCompile(`^/podcast/ep/(?P<episodeid>[^/]+)$`)
|
|
|
|
|
|
2021-10-27 00:45:11 +00:00
|
|
|
|
func BuildPodcastEpisode(episodeGUID string) string {
|
2021-07-23 03:09:46 +00:00
|
|
|
|
defer CatchPanic()
|
2021-10-27 00:45:11 +00:00
|
|
|
|
return Url(fmt.Sprintf("/podcast/ep/%s", episodeGUID), nil)
|
2021-07-23 03:09:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexPodcastEpisodeNew = regexp.MustCompile(`^/podcast/ep/new$`)
|
|
|
|
|
|
2021-10-27 00:45:11 +00:00
|
|
|
|
func BuildPodcastEpisodeNew() string {
|
2021-07-23 03:09:46 +00:00
|
|
|
|
defer CatchPanic()
|
2021-10-27 00:45:11 +00:00
|
|
|
|
return Url("/podcast/ep/new", nil)
|
2021-07-23 03:09:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexPodcastEpisodeEdit = regexp.MustCompile(`^/podcast/ep/(?P<episodeid>[^/]+)/edit$`)
|
|
|
|
|
|
2021-10-27 00:45:11 +00:00
|
|
|
|
func BuildPodcastEpisodeEdit(episodeGUID string) string {
|
2021-07-23 03:09:46 +00:00
|
|
|
|
defer CatchPanic()
|
2021-10-27 00:45:11 +00:00
|
|
|
|
return Url(fmt.Sprintf("/podcast/ep/%s/edit", episodeGUID), nil)
|
2021-07-23 03:09:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexPodcastRSS = regexp.MustCompile(`^/podcast/podcast.xml$`)
|
|
|
|
|
|
2021-10-27 00:45:11 +00:00
|
|
|
|
func BuildPodcastRSS() string {
|
2021-07-23 03:09:46 +00:00
|
|
|
|
defer CatchPanic()
|
2021-10-27 00:45:11 +00:00
|
|
|
|
return Url("/podcast/podcast.xml", nil)
|
2021-07-23 03:09:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-27 00:45:11 +00:00
|
|
|
|
func BuildPodcastEpisodeFile(filename string) string {
|
2021-07-23 03:09:46 +00:00
|
|
|
|
defer CatchPanic()
|
2021-10-27 00:45:11 +00:00
|
|
|
|
return BuildUserFile(fmt.Sprintf("podcast/%s/%s", models.HMNProjectSlug, filename))
|
2021-07-23 03:09:46 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-12 12:45:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* Fishbowls
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexFishbowlIndex = regexp.MustCompile(`^/fishbowl$`)
|
|
|
|
|
|
|
|
|
|
func BuildFishbowlIndex() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/fishbowl", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexFishbowl = regexp.MustCompile(`^/fishbowl/(?P<slug>[^/]+)/?$`)
|
|
|
|
|
|
|
|
|
|
func BuildFishbowl(slug string) string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url(fmt.Sprintf("/fishbowl/%s/", slug), nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexFishbowlFiles = regexp.MustCompile(`^/fishbowl/(?P<slug>[^/]+)(?P<path>/.+)$`)
|
|
|
|
|
|
2022-09-10 16:29:57 +00:00
|
|
|
|
/*
|
|
|
|
|
* Education
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexEducationIndex = regexp.MustCompile(`^/education$`)
|
|
|
|
|
|
|
|
|
|
func BuildEducationIndex() string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
return Url("/education", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexEducationGlossary = regexp.MustCompile(`^/education/glossary(/(?P<slug>[^/]+))?$`)
|
|
|
|
|
|
|
|
|
|
func BuildEducationGlossary(termSlug string) string {
|
|
|
|
|
defer CatchPanic()
|
|
|
|
|
|
|
|
|
|
if termSlug == "" {
|
|
|
|
|
return Url("/education/glossary", nil)
|
|
|
|
|
} else {
|
|
|
|
|
return Url(fmt.Sprintf("/education/glossary/%s", termSlug), nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexEducationArticle = regexp.MustCompile(`^/education/(?P<slug>[^/]+)$`)
|
|
|
|
|
|
|
|
|
|
func BuildEducationArticle(slug string) string {
|
|
|
|
|
return Url(fmt.Sprintf("/education/%s", slug), nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexEducationArticleNew = regexp.MustCompile(`^/education/new$`)
|
|
|
|
|
|
|
|
|
|
func BuildEducationArticleNew() string {
|
|
|
|
|
return Url("/education/new", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexEducationArticleEdit = regexp.MustCompile(`^/education/(?P<slug>[^/]+)/edit$`)
|
|
|
|
|
|
|
|
|
|
func BuildEducationArticleEdit(slug string) string {
|
|
|
|
|
return Url(fmt.Sprintf("/education/%s/edit", slug), nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexEducationArticleDelete = regexp.MustCompile(`^/education/(?P<slug>[^/]+)/delete$`)
|
|
|
|
|
|
|
|
|
|
func BuildEducationArticleDelete(slug string) string {
|
|
|
|
|
return Url(fmt.Sprintf("/education/%s/delete", slug), nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-20 01:26:43 +00:00
|
|
|
|
var RegexEducationRerender = regexp.MustCompile(`^/education/rerender$`)
|
|
|
|
|
|
|
|
|
|
func BuildEducationRerender() string {
|
|
|
|
|
return Url("/education/rerender", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* Forums
|
|
|
|
|
*/
|
|
|
|
|
|
2021-08-28 17:07:45 +00:00
|
|
|
|
// NOTE(asaf): This also matches urls generated by BuildForumThread (/t/ is identified as a subforum, and the threadid as a page)
|
|
|
|
|
// Make sure to match Thread before Subforum in the router.
|
2021-07-30 03:40:47 +00:00
|
|
|
|
var RegexForum = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?(/(?P<page>\d+))?$`)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) Url(path string, query []Q) string {
|
|
|
|
|
return c.UrlWithFragment(path, query, "")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *UrlContext) UrlWithFragment(path string, query []Q, fragment string) string {
|
|
|
|
|
if c == nil {
|
|
|
|
|
logging.Warn().Stack().Msg("URL context was nil; defaulting to the HMN URL context")
|
|
|
|
|
c = &HMNProjectContext
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if c.PersonalProject {
|
|
|
|
|
url := url.URL{
|
|
|
|
|
Scheme: baseUrlParsed.Scheme,
|
|
|
|
|
Host: baseUrlParsed.Host,
|
|
|
|
|
Path: fmt.Sprintf("p/%d/%s/%s", c.ProjectID, models.GeneratePersonalProjectSlug(c.ProjectName), trim(path)),
|
|
|
|
|
RawQuery: encodeQuery(query),
|
|
|
|
|
Fragment: fragment,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return url.String()
|
|
|
|
|
} else {
|
|
|
|
|
subdomain := c.ProjectSlug
|
|
|
|
|
if c.ProjectSlug == models.HMNProjectSlug {
|
|
|
|
|
subdomain = ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
host := baseUrlParsed.Host
|
|
|
|
|
if len(subdomain) > 0 {
|
|
|
|
|
host = c.ProjectSlug + "." + host
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
url := url.URL{
|
|
|
|
|
Scheme: baseUrlParsed.Scheme,
|
|
|
|
|
Host: host,
|
|
|
|
|
Path: trim(path),
|
|
|
|
|
RawQuery: encodeQuery(query),
|
|
|
|
|
Fragment: fragment,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return url.String()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (c *UrlContext) BuildForum(subforums []string, page int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
if page < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid forum thread page (%d), must be >= 1", page))
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
builder := buildSubforumPath(subforums)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
2021-05-05 20:34:32 +00:00
|
|
|
|
if page > 1 {
|
|
|
|
|
builder.WriteRune('/')
|
|
|
|
|
builder.WriteString(strconv.Itoa(page))
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
var RegexForumNewThread = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/new$`)
|
|
|
|
|
var RegexForumNewThreadSubmit = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/new/submit$`)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildForumNewThread(subforums []string, submit bool) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-07-30 03:40:47 +00:00
|
|
|
|
builder := buildSubforumPath(subforums)
|
2021-06-12 03:51:07 +00:00
|
|
|
|
builder.WriteString("/t/new")
|
|
|
|
|
if submit {
|
|
|
|
|
builder.WriteString("/submit")
|
|
|
|
|
}
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
var RegexForumThread = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)(-([^/]+))?(/(?P<page>\d+))?$`)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildForumThread(subforums []string, threadId int, title string, page int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildForumThreadPath(subforums, threadId, title, page)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildForumThreadWithPostHash(subforums []string, threadId int, title string, page int, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildForumThreadPath(subforums, threadId, title, page)
|
|
|
|
|
|
2021-11-10 17:34:48 +00:00
|
|
|
|
return c.UrlWithFragment(builder.String(), nil, strconv.Itoa(postId))
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
var RegexForumPost = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)$`)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildForumPost(subforums []string, threadId int, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildForumPostPath(subforums, threadId, postId)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
var RegexForumPostDelete = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)/delete$`)
|
2021-05-06 05:57:14 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildForumPostDelete(subforums []string, threadId int, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildForumPostPath(subforums, threadId, postId)
|
|
|
|
|
builder.WriteString("/delete")
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-06 05:57:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
var RegexForumPostEdit = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)/edit$`)
|
2021-05-06 05:57:14 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildForumPostEdit(subforums []string, threadId int, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildForumPostPath(subforums, threadId, postId)
|
|
|
|
|
builder.WriteString("/edit")
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-06 05:57:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
var RegexForumPostReply = regexp.MustCompile(`^/forums(/(?P<subforums>[^\d/]+(/[^\d]+)*))?/t/(?P<threadid>\d+)/p/(?P<postid>\d+)/reply$`)
|
2021-05-06 05:57:14 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildForumPostReply(subforums []string, threadId int, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildForumPostPath(subforums, threadId, postId)
|
|
|
|
|
builder.WriteString("/reply")
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-06 05:57:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-09 00:43:24 +00:00
|
|
|
|
var RegexWikiArticle = regexp.MustCompile(`^/wiki/(?P<threadid>\d+)(-([^/]+))?$`)
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* Blog
|
|
|
|
|
*/
|
|
|
|
|
|
2021-09-20 15:17:53 +00:00
|
|
|
|
var RegexBlogsRedirect = regexp.MustCompile(`^/blogs(?P<remainder>.*)`)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
|
|
|
|
var RegexBlog = regexp.MustCompile(`^/blog(/(?P<page>\d+))?$`)
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildBlog(page int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
if page < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid blog page (%d), must be >= 1", page))
|
|
|
|
|
}
|
|
|
|
|
path := "/blog"
|
|
|
|
|
|
|
|
|
|
if page > 1 {
|
|
|
|
|
path += "/" + strconv.Itoa(page)
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(path, nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 22:32:19 +00:00
|
|
|
|
var RegexBlogThread = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)(-([^/]+))?$`)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildBlogThread(threadId int, title string) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-07-30 22:32:19 +00:00
|
|
|
|
builder := buildBlogThreadPath(threadId, title)
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildBlogThreadWithPostHash(threadId int, title string, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-07-30 22:32:19 +00:00
|
|
|
|
builder := buildBlogThreadPath(threadId, title)
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.UrlWithFragment(builder.String(), nil, strconv.Itoa(postId))
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 23:08:42 +00:00
|
|
|
|
var RegexBlogNewThread = regexp.MustCompile(`^/blog/new$`)
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildBlogNewThread() string {
|
2021-07-30 23:08:42 +00:00
|
|
|
|
defer CatchPanic()
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url("/blog/new", nil)
|
2021-07-30 23:08:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
var RegexBlogPost = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)$`)
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildBlogPost(threadId int, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildBlogPostPath(threadId, postId)
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexBlogPostDelete = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)/delete$`)
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildBlogPostDelete(threadId int, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildBlogPostPath(threadId, postId)
|
|
|
|
|
builder.WriteString("/delete")
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexBlogPostEdit = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)/edit$`)
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildBlogPostEdit(threadId int, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildBlogPostPath(threadId, postId)
|
|
|
|
|
builder.WriteString("/edit")
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexBlogPostReply = regexp.MustCompile(`^/blog/p/(?P<threadid>\d+)/e/(?P<postid>\d+)/reply$`)
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildBlogPostReply(threadId int, postId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-11 22:53:23 +00:00
|
|
|
|
builder := buildBlogPostPath(threadId, postId)
|
|
|
|
|
builder.WriteString("/reply")
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2022-11-05 21:23:12 +00:00
|
|
|
|
* Library (old)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
*/
|
|
|
|
|
|
2021-10-23 16:14:10 +00:00
|
|
|
|
var RegexLibraryAny = regexp.MustCompile(`^/library`)
|
|
|
|
|
|
2021-08-28 10:40:13 +00:00
|
|
|
|
/*
|
|
|
|
|
* Episode Guide
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexEpisodeList = regexp.MustCompile(`^/episode(/(?P<topic>[^/]+))?$`)
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildEpisodeList(topic string) string {
|
2021-08-28 10:40:13 +00:00
|
|
|
|
defer CatchPanic()
|
|
|
|
|
|
|
|
|
|
var builder strings.Builder
|
|
|
|
|
builder.WriteString("/episode")
|
|
|
|
|
if topic != "" {
|
|
|
|
|
builder.WriteString("/")
|
|
|
|
|
builder.WriteString(topic)
|
|
|
|
|
}
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-08-28 10:40:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexEpisode = regexp.MustCompile(`^/episode/(?P<topic>[^/]+)/(?P<episode>[^/]+)$`)
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildEpisode(topic string, episode string) string {
|
2021-08-28 10:40:13 +00:00
|
|
|
|
defer CatchPanic()
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(fmt.Sprintf("/episode/%s/%s", topic, episode), nil)
|
2021-08-28 10:40:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexCineraIndex = regexp.MustCompile(`^/(?P<topic>[^/]+).index$`)
|
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildCineraIndex(topic string) string {
|
2021-08-28 10:40:13 +00:00
|
|
|
|
defer CatchPanic()
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(fmt.Sprintf("/%s.index", topic), nil)
|
2021-08-28 10:40:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-16 04:40:56 +00:00
|
|
|
|
/*
|
|
|
|
|
* Discord OAuth
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexDiscordOAuthCallback = regexp.MustCompile("^/_discord_callback$")
|
|
|
|
|
|
|
|
|
|
func BuildDiscordOAuthCallback() string {
|
|
|
|
|
return Url("/_discord_callback", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-16 05:07:17 +00:00
|
|
|
|
var RegexDiscordUnlink = regexp.MustCompile("^/_discord_unlink$")
|
|
|
|
|
|
|
|
|
|
func BuildDiscordUnlink() string {
|
|
|
|
|
return Url("/_discord_unlink", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-27 17:58:52 +00:00
|
|
|
|
var RegexDiscordShowcaseBacklog = regexp.MustCompile("^/discord_showcase_backlog$")
|
|
|
|
|
|
|
|
|
|
func BuildDiscordShowcaseBacklog() string {
|
|
|
|
|
return Url("/discord_showcase_backlog", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-25 03:59:51 +00:00
|
|
|
|
/*
|
|
|
|
|
* API
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexAPICheckUsername = regexp.MustCompile("^/api/check_username$")
|
|
|
|
|
|
|
|
|
|
func BuildAPICheckUsername() string {
|
|
|
|
|
return Url("/api/check_username", nil)
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-22 18:07:43 +00:00
|
|
|
|
/*
|
|
|
|
|
* Twitch stuff
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexTwitchEventSubCallback = regexp.MustCompile("^/twitch_eventsub$")
|
|
|
|
|
|
|
|
|
|
func BuildTwitchEventSubCallback() string {
|
|
|
|
|
return Url("/twitch_eventsub", nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var RegexTwitchDebugPage = regexp.MustCompile("^/twitch_debug$")
|
|
|
|
|
|
2021-09-21 23:13:11 +00:00
|
|
|
|
/*
|
|
|
|
|
* User assets
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
var RegexAssetUpload = regexp.MustCompile("^/upload_asset$")
|
|
|
|
|
|
|
|
|
|
// NOTE(asaf): Providing the projectSlug avoids any CORS problems.
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildAssetUpload() string {
|
|
|
|
|
return c.Url("/upload_asset", nil)
|
2021-09-21 23:13:11 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* Assets
|
|
|
|
|
*/
|
|
|
|
|
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexProjectCSS = regexp.MustCompile("^/assets/project.css$")
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
|
|
|
|
func BuildProjectCSS(color string) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-06 04:04:58 +00:00
|
|
|
|
return Url("/assets/project.css", []Q{{"color", color}})
|
2021-05-05 20:34:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-12-07 05:20:12 +00:00
|
|
|
|
var RegexMarkdownWorkerJS = regexp.MustCompile("^/assets/markdown_worker.js$")
|
2021-07-30 22:32:19 +00:00
|
|
|
|
|
2021-12-07 05:20:12 +00:00
|
|
|
|
func BuildMarkdownWorkerJS() string {
|
2021-07-30 22:32:19 +00:00
|
|
|
|
defer CatchPanic()
|
2021-12-07 05:20:12 +00:00
|
|
|
|
return Url("/assets/markdown_worker.js", nil)
|
2021-07-30 22:32:19 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-22 19:18:39 +00:00
|
|
|
|
var RegexS3Asset *regexp.Regexp
|
|
|
|
|
|
2021-06-22 09:50:40 +00:00
|
|
|
|
func BuildS3Asset(s3key string) string {
|
|
|
|
|
defer CatchPanic()
|
2021-09-22 19:18:39 +00:00
|
|
|
|
res := fmt.Sprintf("%s%s", S3BaseUrl, s3key)
|
|
|
|
|
return res
|
2021-06-22 09:50:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-06 05:57:14 +00:00
|
|
|
|
var RegexPublic = regexp.MustCompile("^/public/.+$")
|
2021-05-05 20:34:32 +00:00
|
|
|
|
|
2021-05-25 13:12:20 +00:00
|
|
|
|
func BuildPublic(filepath string, cachebust bool) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-05 20:34:32 +00:00
|
|
|
|
filepath = strings.Trim(filepath, "/")
|
|
|
|
|
if len(strings.TrimSpace(filepath)) == 0 {
|
|
|
|
|
panic(oops.New(nil, "Attempted to build a /public url with no path"))
|
|
|
|
|
}
|
2021-05-25 13:12:20 +00:00
|
|
|
|
if strings.Contains(filepath, "?") {
|
|
|
|
|
panic(oops.New(nil, "Public url failpath must not contain query params"))
|
|
|
|
|
}
|
2021-05-05 20:34:32 +00:00
|
|
|
|
var builder strings.Builder
|
|
|
|
|
builder.WriteString("/public")
|
|
|
|
|
pathParts := strings.Split(filepath, "/")
|
|
|
|
|
for _, part := range pathParts {
|
|
|
|
|
part = strings.TrimSpace(part)
|
|
|
|
|
if len(part) == 0 {
|
|
|
|
|
panic(oops.New(nil, "Attempted to build a /public url with blank path segments: %s", filepath))
|
|
|
|
|
}
|
|
|
|
|
builder.WriteRune('/')
|
|
|
|
|
builder.WriteString(part)
|
|
|
|
|
}
|
2021-05-25 13:12:20 +00:00
|
|
|
|
var query []Q
|
|
|
|
|
if cachebust {
|
2022-09-10 16:29:57 +00:00
|
|
|
|
query = []Q{{"v", cacheBustVersion}}
|
2021-05-25 13:12:20 +00:00
|
|
|
|
}
|
|
|
|
|
return Url(builder.String(), query)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BuildTheme(filepath string, theme string, cachebust bool) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-05-31 23:23:04 +00:00
|
|
|
|
filepath = strings.Trim(filepath, "/")
|
2021-05-25 13:12:20 +00:00
|
|
|
|
if len(theme) == 0 {
|
|
|
|
|
panic(oops.New(nil, "Theme can't be blank"))
|
|
|
|
|
}
|
2021-05-31 23:23:04 +00:00
|
|
|
|
return BuildPublic(fmt.Sprintf("themes/%s/%s", theme, filepath), cachebust)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BuildUserFile(filepath string) string {
|
2021-11-12 00:23:24 +00:00
|
|
|
|
if filepath == "" {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 23:23:04 +00:00
|
|
|
|
filepath = strings.Trim(filepath, "/")
|
|
|
|
|
return BuildPublic(fmt.Sprintf("media/%s", filepath), false)
|
2021-05-05 20:34:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-11 22:53:23 +00:00
|
|
|
|
/*
|
|
|
|
|
* Other
|
|
|
|
|
*/
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
var RegexForumMarkRead = regexp.MustCompile(`^/markread/(?P<sfid>\d+)$`)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
// NOTE(asaf): subforumId == 0 means ALL SUBFORUMS
|
2021-11-10 04:11:39 +00:00
|
|
|
|
func (c *UrlContext) BuildForumMarkRead(subforumId int) string {
|
2021-05-25 13:48:57 +00:00
|
|
|
|
defer CatchPanic()
|
2021-07-30 03:40:47 +00:00
|
|
|
|
if subforumId < 0 {
|
|
|
|
|
panic(oops.New(nil, "Invalid subforum ID (%d), must be >= 0", subforumId))
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var builder strings.Builder
|
2021-07-23 19:00:37 +00:00
|
|
|
|
builder.WriteString("/markread/")
|
2021-07-30 03:40:47 +00:00
|
|
|
|
builder.WriteString(strconv.Itoa(subforumId))
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
2021-11-10 04:11:39 +00:00
|
|
|
|
return c.Url(builder.String(), nil)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-09 19:14:38 +00:00
|
|
|
|
var RegexCatchAll = regexp.MustCompile("^")
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Helper functions
|
|
|
|
|
*/
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
func buildSubforumPath(subforums []string) *strings.Builder {
|
2021-05-11 22:53:23 +00:00
|
|
|
|
for _, subforum := range subforums {
|
|
|
|
|
if strings.Contains(subforum, "/") {
|
|
|
|
|
panic(oops.New(nil, "Tried building forum url with / in subforum name"))
|
|
|
|
|
}
|
|
|
|
|
subforum = strings.TrimSpace(subforum)
|
|
|
|
|
if len(subforum) == 0 {
|
|
|
|
|
panic(oops.New(nil, "Tried building forum url with blank subforum"))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var builder strings.Builder
|
|
|
|
|
builder.WriteString("/forums")
|
|
|
|
|
for _, subforum := range subforums {
|
|
|
|
|
builder.WriteRune('/')
|
|
|
|
|
builder.WriteString(subforum)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &builder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func buildForumThreadPath(subforums []string, threadId int, title string, page int) *strings.Builder {
|
|
|
|
|
if page < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid forum thread page (%d), must be >= 1", page))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if threadId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid forum thread ID (%d), must be >= 1", threadId))
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
builder := buildSubforumPath(subforums)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
|
|
|
|
builder.WriteString("/t/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(threadId))
|
|
|
|
|
if len(title) > 0 {
|
|
|
|
|
builder.WriteRune('-')
|
|
|
|
|
builder.WriteString(PathSafeTitle(title))
|
|
|
|
|
}
|
|
|
|
|
if page > 1 {
|
|
|
|
|
builder.WriteRune('/')
|
|
|
|
|
builder.WriteString(strconv.Itoa(page))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return builder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func buildForumPostPath(subforums []string, threadId int, postId int) *strings.Builder {
|
|
|
|
|
if threadId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid forum thread ID (%d), must be >= 1", threadId))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if postId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid forum post ID (%d), must be >= 1", postId))
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 03:40:47 +00:00
|
|
|
|
builder := buildSubforumPath(subforums)
|
2021-05-11 22:53:23 +00:00
|
|
|
|
|
|
|
|
|
builder.WriteString("/t/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(threadId))
|
|
|
|
|
builder.WriteString("/p/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(postId))
|
|
|
|
|
|
|
|
|
|
return builder
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-30 22:32:19 +00:00
|
|
|
|
func buildBlogThreadPath(threadId int, title string) *strings.Builder {
|
2021-05-11 22:53:23 +00:00
|
|
|
|
if threadId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid blog thread ID (%d), must be >= 1", threadId))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var builder strings.Builder
|
|
|
|
|
|
|
|
|
|
builder.WriteString("/blog/p/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(threadId))
|
|
|
|
|
if len(title) > 0 {
|
|
|
|
|
builder.WriteRune('-')
|
|
|
|
|
builder.WriteString(PathSafeTitle(title))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &builder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func buildBlogPostPath(threadId int, postId int) *strings.Builder {
|
|
|
|
|
if threadId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid blog thread ID (%d), must be >= 1", threadId))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if postId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid blog post ID (%d), must be >= 1", postId))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var builder strings.Builder
|
|
|
|
|
|
|
|
|
|
builder.WriteString("/blog/p/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(threadId))
|
|
|
|
|
builder.WriteString("/e/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(postId))
|
|
|
|
|
|
|
|
|
|
return &builder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func buildLibraryResourcePath(resourceId int) *strings.Builder {
|
|
|
|
|
if resourceId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid library resource ID (%d), must be >= 1", resourceId))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var builder strings.Builder
|
|
|
|
|
builder.WriteString("/library/resource/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(resourceId))
|
|
|
|
|
|
|
|
|
|
return &builder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func buildLibraryDiscussionPath(resourceId int, threadId int, page int) *strings.Builder {
|
|
|
|
|
if page < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid page number (%d), must be >= 1", page))
|
|
|
|
|
}
|
|
|
|
|
if threadId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid library thread ID (%d), must be >= 1", threadId))
|
|
|
|
|
}
|
|
|
|
|
builder := buildLibraryResourcePath(resourceId)
|
|
|
|
|
builder.WriteString("/d/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(threadId))
|
|
|
|
|
if page > 1 {
|
|
|
|
|
builder.WriteRune('/')
|
|
|
|
|
builder.WriteString(strconv.Itoa(page))
|
|
|
|
|
}
|
|
|
|
|
return builder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func buildLibraryPostPath(resourceId int, threadId int, postId int) *strings.Builder {
|
|
|
|
|
if threadId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid library thread ID (%d), must be >= 1", threadId))
|
|
|
|
|
}
|
|
|
|
|
if postId < 1 {
|
|
|
|
|
panic(oops.New(nil, "Invalid library post ID (%d), must be >= 1", postId))
|
|
|
|
|
}
|
|
|
|
|
builder := buildLibraryResourcePath(resourceId)
|
|
|
|
|
builder.WriteString("/d/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(threadId))
|
|
|
|
|
builder.WriteString("/p/")
|
|
|
|
|
builder.WriteString(strconv.Itoa(postId))
|
|
|
|
|
return builder
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var PathCharsToClear = regexp.MustCompile("[$&`<>{}()\\[\\]\"+#%@;=?\\\\^|~‘]")
|
|
|
|
|
var PathCharsToReplace = regexp.MustCompile("[ :/\\\\]")
|
|
|
|
|
|
|
|
|
|
func PathSafeTitle(title string) string {
|
|
|
|
|
title = strings.ToLower(title)
|
|
|
|
|
title = PathCharsToReplace.ReplaceAllLiteralString(title, "_")
|
|
|
|
|
title = PathCharsToClear.ReplaceAllLiteralString(title, "")
|
|
|
|
|
title = url.PathEscape(title)
|
|
|
|
|
return title
|
|
|
|
|
}
|
2021-05-25 13:48:57 +00:00
|
|
|
|
|
2021-05-25 13:51:49 +00:00
|
|
|
|
// TODO(asaf): Find a nicer solution that doesn't require adding a defer to every construction function while also not printing errors in tests.
|
2021-05-25 13:48:57 +00:00
|
|
|
|
func CatchPanic() {
|
|
|
|
|
if !isTest {
|
|
|
|
|
if recovered := recover(); recovered != nil {
|
|
|
|
|
logging.LogPanicValue(nil, recovered, "Url construction failed")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|