Internal server error page

This commit is contained in:
Asaf Gartner 2021-08-28 15:21:03 +03:00
parent a655fe96bc
commit cb5c3c403d
16 changed files with 186 additions and 148 deletions

View File

@ -0,0 +1,16 @@
{{ template "base.html" . }}
{{ define "content" }}
<div class="description">
<p>
<span class="big">Hi there, {{ if .User }}{{ .User.Name }}{{ else }}visitor{{ end }}!</span>
</p>
<p>
<span class="big">
We have encountered an error while processing your request.
<br />
If this keeps happening, please <a href="{{ .ReportIssueMailto }}">let us know</a>.
</span>
</p>
</div>
{{ end }}

View File

@ -6,14 +6,15 @@ import (
)
type BaseData struct {
Title string
CanonicalLink string
OpenGraphItems []OpenGraphItem
BackgroundImage BackgroundImage
Theme string
BodyClasses []string
Breadcrumbs []Breadcrumb
Notices []Notice
Title string
CanonicalLink string
OpenGraphItems []OpenGraphItem
BackgroundImage BackgroundImage
Theme string
BodyClasses []string
Breadcrumbs []Breadcrumb
Notices []Notice
ReportIssueMailto string
CurrentUrl string
LoginPageUrl string

View File

@ -53,7 +53,7 @@ func Login(c *RequestContext) ResponseData {
form, err := c.GetFormValues()
if err != nil {
return ErrorResponse(http.StatusBadRequest, NewSafeError(err, "request must contain form data"))
return c.ErrorResponse(http.StatusBadRequest, NewSafeError(err, "request must contain form data"))
}
redirect := form.Get("redirect")
@ -84,7 +84,7 @@ func Login(c *RequestContext) ResponseData {
if errors.Is(err, db.ErrNoMatchingRows) {
return showLoginWithFailure(c, redirect)
} else {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to look up user by username"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to look up user by username"))
}
}
user := userRow.(*models.User)
@ -92,7 +92,7 @@ func Login(c *RequestContext) ResponseData {
success, err := tryLogin(c, user, password)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if !success {
@ -106,7 +106,7 @@ func Login(c *RequestContext) ResponseData {
res := c.Redirect(redirect, http.StatusSeeOther)
err = loginUser(c, user, &res)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
return res
}
@ -179,7 +179,7 @@ func RegisterNewUserSubmit(c *RequestContext) ResponseData {
if errors.Is(err, db.ErrNoMatchingRows) {
userAlreadyExists = false
} else {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user"))
}
}
@ -200,7 +200,7 @@ func RegisterNewUserSubmit(c *RequestContext) ResponseData {
if errors.Is(err, db.ErrNoMatchingRows) {
emailAlreadyExists = false
} else {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user"))
}
}
c.Perf.EndBlock()
@ -215,7 +215,7 @@ func RegisterNewUserSubmit(c *RequestContext) ResponseData {
c.Perf.StartBlock("SQL", "Create user and one time token")
tx, err := c.Conn.Begin(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to start db transaction"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to start db transaction"))
}
defer tx.Rollback(c.Context())
@ -231,7 +231,7 @@ func RegisterNewUserSubmit(c *RequestContext) ResponseData {
username, emailAddress, hashed.String(), now, displayName, c.GetIP(),
).Scan(&newUserId)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to store user"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to store user"))
}
ott := models.GenerateToken()
@ -247,7 +247,7 @@ func RegisterNewUserSubmit(c *RequestContext) ResponseData {
newUserId,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to store one-time token"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to store one-time token"))
}
c.Perf.EndBlock()
@ -257,13 +257,13 @@ func RegisterNewUserSubmit(c *RequestContext) ResponseData {
}
err = email.SendRegistrationEmail(emailAddress, mailName, username, ott, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to send registration email"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to send registration email"))
}
c.Perf.StartBlock("SQL", "Commit user")
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit user to the db"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit user to the db"))
}
c.Perf.EndBlock()
return c.Redirect(hmnurl.BuildRegistrationSuccess(), http.StatusSeeOther)
@ -349,7 +349,7 @@ func EmailConfirmationSubmit(c *RequestContext) ResponseData {
success, err := tryLogin(c, validationResult.User, password)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
} else if !success {
var res ResponseData
baseData := getBaseData(c)
@ -366,7 +366,7 @@ func EmailConfirmationSubmit(c *RequestContext) ResponseData {
c.Perf.StartBlock("SQL", "Updating user status and deleting token")
tx, err := c.Conn.Begin(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to start db transaction"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to start db transaction"))
}
defer tx.Rollback(c.Context())
@ -380,7 +380,7 @@ func EmailConfirmationSubmit(c *RequestContext) ResponseData {
validationResult.User.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user status"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user status"))
}
_, err = tx.Exec(c.Context(),
@ -390,12 +390,12 @@ func EmailConfirmationSubmit(c *RequestContext) ResponseData {
validationResult.OneTimeToken.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete one time token"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete one time token"))
}
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit transaction"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit transaction"))
}
c.Perf.EndBlock()
@ -403,7 +403,7 @@ func EmailConfirmationSubmit(c *RequestContext) ResponseData {
res.AddFutureNotice("success", "You've completed your registration successfully!")
err = loginUser(c, validationResult.User, &res)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
return res
}
@ -464,7 +464,7 @@ func RequestPasswordResetSubmit(c *RequestContext) ResponseData {
c.Perf.EndBlock()
if err != nil {
if !errors.Is(err, db.ErrNoMatchingRows) {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to look up user by username"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to look up user by username"))
}
}
if userRow != nil {
@ -487,7 +487,7 @@ func RequestPasswordResetSubmit(c *RequestContext) ResponseData {
c.Perf.EndBlock()
if err != nil {
if !errors.Is(err, db.ErrNoMatchingRows) {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch onetimetoken for user"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch onetimetoken for user"))
}
}
var resetToken *models.OneTimeToken
@ -508,7 +508,7 @@ func RequestPasswordResetSubmit(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete onetimetoken"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete onetimetoken"))
}
resetToken = nil
}
@ -530,13 +530,13 @@ func RequestPasswordResetSubmit(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create onetimetoken"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create onetimetoken"))
}
resetToken = tokenRow.(*models.OneTimeToken)
err = email.SendPasswordReset(user.Email, user.BestName(), user.Username, resetToken.Content, resetToken.Expires, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to send email"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to send email"))
}
}
}
@ -624,7 +624,7 @@ func DoPasswordResetSubmit(c *RequestContext) ResponseData {
c.Perf.StartBlock("SQL", "Update user's password and delete reset token")
tx, err := c.Conn.Begin(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to start db transaction"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to start db transaction"))
}
defer tx.Rollback(c.Context())
@ -638,7 +638,7 @@ func DoPasswordResetSubmit(c *RequestContext) ResponseData {
validationResult.User.ID,
)
if err != nil || tag.RowsAffected() == 0 {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user's password"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user's password"))
}
if validationResult.User.Status == models.UserStatusInactive {
@ -652,7 +652,7 @@ func DoPasswordResetSubmit(c *RequestContext) ResponseData {
validationResult.User.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user's status"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user's status"))
}
}
@ -664,12 +664,12 @@ func DoPasswordResetSubmit(c *RequestContext) ResponseData {
validationResult.OneTimeToken.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete onetimetoken"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete onetimetoken"))
}
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit password reset to the db"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit password reset to the db"))
}
c.Perf.EndBlock()
@ -677,7 +677,7 @@ func DoPasswordResetSubmit(c *RequestContext) ResponseData {
res.AddFutureNotice("success", "Password changed successfully.")
err = loginUser(c, validationResult.User, &res)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
return res
}

View File

@ -50,7 +50,7 @@ func BlogIndex(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch total number of blog posts"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch total number of blog posts"))
}
numPages := NumPages(numPosts, postsPerPage)
@ -88,7 +88,7 @@ func BlogIndex(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch blog posts for index"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch blog posts for index"))
}
var entries []blogIndexEntry
@ -112,7 +112,7 @@ func BlogIndex(c *RequestContext) ResponseData {
isProjectOwner := false
owners, err := FetchProjectOwners(c, c.CurrentProject.ID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project owners"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project owners"))
}
for _, owner := range owners {
if owner.ID == c.CurrentUser.ID {
@ -232,7 +232,7 @@ func BlogNewThreadSubmit(c *RequestContext) ResponseData {
err = c.Req.ParseForm()
if err != nil {
return ErrorResponse(http.StatusBadRequest, oops.New(err, "the form data was invalid"))
return c.ErrorResponse(http.StatusBadRequest, oops.New(err, "the form data was invalid"))
}
title := c.Req.Form.Get("title")
unparsed := c.Req.Form.Get("body")
@ -266,7 +266,7 @@ func BlogNewThreadSubmit(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new blog post"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new blog post"))
}
newThreadUrl := hmnurl.BuildBlogThread(c.CurrentProject.Slug, threadId, title)
@ -339,7 +339,7 @@ func BlogPostEditSubmit(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit blog post"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit blog post"))
}
postUrl := hmnurl.BuildBlogThreadWithPostHash(c.CurrentProject.Slug, cd.ThreadID, postData.Thread.Title, cd.PostID)
@ -385,7 +385,7 @@ func BlogPostReplySubmit(c *RequestContext) ResponseData {
err = c.Req.ParseForm()
if err != nil {
return ErrorResponse(http.StatusBadRequest, oops.New(nil, "the form data was invalid"))
return c.ErrorResponse(http.StatusBadRequest, oops.New(nil, "the form data was invalid"))
}
unparsed := c.Req.Form.Get("body")
if unparsed == "" {
@ -396,7 +396,7 @@ func BlogPostReplySubmit(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to blog post"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to blog post"))
}
newPostUrl := hmnurl.BuildBlogPost(c.CurrentProject.Slug, cd.ThreadID, newPostId)
@ -462,7 +462,7 @@ func BlogPostDeleteSubmit(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete post"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete post"))
}
if threadDeleted {

View File

@ -53,19 +53,19 @@ func DiscordOAuthCallback(c *RequestContext) ResponseData {
code := query.Get("code")
res, err := discord.ExchangeOAuthCode(c.Context(), code, hmnurl.BuildDiscordOAuthCallback())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to exchange Discord authorization code"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to exchange Discord authorization code"))
}
expiry := time.Now().Add(time.Duration(res.ExpiresIn) * time.Second)
user, err := discord.GetCurrentUserAsOAuth(c.Context(), res.AccessToken)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch Discord user info"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch Discord user info"))
}
// Add the role on Discord
err = discord.AddGuildMemberRole(c.Context(), user.ID, config.Config.Discord.MemberRoleID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to add member role"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to add member role"))
}
// Add the user to our database
@ -85,7 +85,7 @@ func DiscordOAuthCallback(c *RequestContext) ResponseData {
c.CurrentUser.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to save new Discord user info"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to save new Discord user info"))
}
return c.Redirect(hmnurl.BuildUserSettings("discord"), http.StatusSeeOther)
@ -110,7 +110,7 @@ func DiscordUnlink(c *RequestContext) ResponseData {
if errors.Is(err, db.ErrNoMatchingRows) {
return c.Redirect(hmnurl.BuildUserSettings("discord"), http.StatusSeeOther)
} else {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get Discord user for unlink"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get Discord user for unlink"))
}
}
discordUser := iDiscordUser.(*models.DiscordUser)
@ -123,12 +123,12 @@ func DiscordUnlink(c *RequestContext) ResponseData {
discordUser.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete Discord user"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete Discord user"))
}
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit Discord user delete"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit Discord user delete"))
}
err = discord.RemoveGuildMemberRole(c.Context(), discordUser.UserID, config.Config.Discord.MemberRoleID)
@ -149,13 +149,13 @@ func DiscordShowcaseBacklog(c *RequestContext) ResponseData {
c.Logger.Warn().Msg("could not do showcase backlog because no discord user exists")
return c.Redirect(hmnurl.BuildUserProfile(c.CurrentUser.Username), http.StatusSeeOther)
} else if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get discord user"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get discord user"))
}
duser := iduser.(*models.DiscordUser)
ok, err := discord.AllowedToCreateMessageSnippet(c.Context(), c.Conn, duser.UserID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if !ok {

View File

@ -45,7 +45,7 @@ func Feed(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get count of feed posts"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get count of feed posts"))
}
numPages := int(math.Ceil(float64(numPosts) / postsPerPage))
@ -87,7 +87,7 @@ func Feed(c *RequestContext) ResponseData {
posts, err := fetchAllPosts(c, lineageBuilder, currentUserId, howManyPostsToSkip, postsPerPage)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts"))
}
baseData := getBaseData(c)
@ -165,7 +165,7 @@ func AtomFeed(c *RequestContext) ResponseData {
posts, err := fetchAllPosts(c, lineageBuilder, nil, 0, itemsPerFeed)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed posts"))
}
feedData.Posts = posts
@ -203,7 +203,7 @@ func AtomFeed(c *RequestContext) ResponseData {
itemsPerFeed,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed projects"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed projects"))
}
var projectIds []int
projectMap := make(map[int]int) // map[project id]index in slice
@ -235,7 +235,7 @@ func AtomFeed(c *RequestContext) ResponseData {
projectIds,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed projects owners"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch feed projects owners"))
}
for _, res := range owners.ToSlice() {
owner := res.(*ownerResult)
@ -277,7 +277,7 @@ func AtomFeed(c *RequestContext) ResponseData {
itemsPerFeed,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets"))
}
snippetQuerySlice := snippetQueryResult.ToSlice()
for _, s := range snippetQuerySlice {

View File

@ -330,7 +330,7 @@ func ForumMarkRead(c *RequestContext) ResponseData {
c.CurrentUser.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to mark all posts as read"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to mark all posts as read"))
}
// Delete thread unread info
@ -342,7 +342,7 @@ func ForumMarkRead(c *RequestContext) ResponseData {
c.CurrentUser.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete thread unread info"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete thread unread info"))
}
// Delete subforum unread info
@ -354,7 +354,7 @@ func ForumMarkRead(c *RequestContext) ResponseData {
c.CurrentUser.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete subforum unread info"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete subforum unread info"))
}
} else {
c.Perf.StartBlock("SQL", "Update SLRIs")
@ -373,7 +373,7 @@ func ForumMarkRead(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update forum slris"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update forum slris"))
}
c.Perf.StartBlock("SQL", "Delete TLRIs")
@ -394,13 +394,13 @@ func ForumMarkRead(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete unnecessary tlris"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete unnecessary tlris"))
}
}
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit SLRI/TLRI updates"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to commit SLRI/TLRI updates"))
}
var redirUrl string
@ -503,7 +503,7 @@ func ForumThread(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update forum tlri"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update forum tlri"))
}
}
@ -546,7 +546,7 @@ func ForumPostRedirect(c *RequestContext) ResponseData {
cd.ThreadID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch post ids"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch post ids"))
}
postQuerySlice := postQueryResult.ToSlice()
c.Perf.EndBlock()
@ -574,7 +574,7 @@ func ForumPostRedirect(c *RequestContext) ResponseData {
cd.ThreadID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch thread title"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch thread title"))
}
c.Perf.EndBlock()
threadTitle := threadTitleQueryResult.(*threadTitleQuery).ThreadTitle
@ -625,7 +625,7 @@ func ForumNewThreadSubmit(c *RequestContext) ResponseData {
err = c.Req.ParseForm()
if err != nil {
return ErrorResponse(http.StatusBadRequest, oops.New(err, "the form data was invalid"))
return c.ErrorResponse(http.StatusBadRequest, oops.New(err, "the form data was invalid"))
}
title := c.Req.Form.Get("title")
unparsed := c.Req.Form.Get("body")
@ -665,7 +665,7 @@ func ForumNewThreadSubmit(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new forum thread"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to create new forum thread"))
}
newThreadUrl := hmnurl.BuildForumThread(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), threadId, title, 1)
@ -711,7 +711,7 @@ func ForumPostReplySubmit(c *RequestContext) ResponseData {
err = c.Req.ParseForm()
if err != nil {
return ErrorResponse(http.StatusBadRequest, oops.New(nil, "the form data was invalid"))
return c.ErrorResponse(http.StatusBadRequest, oops.New(nil, "the form data was invalid"))
}
unparsed := c.Req.Form.Get("body")
if unparsed == "" {
@ -722,7 +722,7 @@ func ForumPostReplySubmit(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to forum post"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to reply to forum post"))
}
newPostUrl := hmnurl.BuildForumPost(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, newPostId)
@ -784,7 +784,7 @@ func ForumPostEditSubmit(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit forum post"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to edit forum post"))
}
postUrl := hmnurl.BuildForumPost(c.CurrentProject.Slug, cd.LineageBuilder.GetSubforumLineageSlugs(cd.SubforumID), cd.ThreadID, cd.PostID)
@ -846,7 +846,7 @@ func ForumPostDeleteSubmit(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete post"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to delete post"))
}
if threadDeleted {

View File

@ -67,7 +67,7 @@ func Index(c *RequestContext) ResponseData {
numProjectsToGet*2, // hedge your bets against projects that don't have any content
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get projects for home page"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get projects for home page"))
}
defer iterProjects.Close()
@ -274,7 +274,7 @@ func Index(c *RequestContext) ResponseData {
models.ThreadTypeProjectBlogPost,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch news post"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch news post"))
}
newsPostResult := newsPostRow.(*newsPostQuery)
c.Perf.EndBlock()
@ -299,7 +299,7 @@ func Index(c *RequestContext) ResponseData {
`,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets"))
}
snippetQuerySlice := snippetQueryResult.ToSlice()
showcaseItems := make([]templates.TimelineItem, 0, len(snippetQuerySlice))
@ -343,7 +343,7 @@ func Index(c *RequestContext) ResponseData {
WheelJamUrl: hmnurl.BuildJamIndex(),
}, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render landing page template"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render landing page template"))
}
return res

View File

@ -32,7 +32,7 @@ type PodcastIndexData struct {
func PodcastIndex(c *RequestContext) ResponseData {
podcastResult, err := FetchPodcast(c, c.CurrentProject.ID, true, "")
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if podcastResult.Podcast == nil {
@ -41,7 +41,7 @@ func PodcastIndex(c *RequestContext) ResponseData {
canEdit, err := CanEditProject(c, c.CurrentUser, podcastResult.Podcast.ProjectID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
baseData := getBaseData(c)
@ -63,7 +63,7 @@ func PodcastIndex(c *RequestContext) ResponseData {
var res ResponseData
err = res.WriteTemplate("podcast_index.html", podcastIndexData, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast index page"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast index page"))
}
return res
}
@ -76,12 +76,12 @@ type PodcastEditData struct {
func PodcastEdit(c *RequestContext) ResponseData {
podcastResult, err := FetchPodcast(c, c.CurrentProject.ID, false, "")
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
canEdit, err := CanEditProject(c, c.CurrentUser, podcastResult.Podcast.ProjectID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if podcastResult.Podcast == nil || !canEdit {
@ -99,7 +99,7 @@ func PodcastEdit(c *RequestContext) ResponseData {
var res ResponseData
err = res.WriteTemplate("podcast_edit.html", podcastEditData, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast edit page"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast edit page"))
}
return res
}
@ -107,12 +107,12 @@ func PodcastEdit(c *RequestContext) ResponseData {
func PodcastEditSubmit(c *RequestContext) ResponseData {
podcastResult, err := FetchPodcast(c, c.CurrentProject.ID, false, "")
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
canEdit, err := CanEditProject(c, c.CurrentUser, podcastResult.Podcast.ProjectID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if podcastResult.Podcast == nil || !canEdit {
@ -128,7 +128,7 @@ func PodcastEditSubmit(c *RequestContext) ResponseData {
c.Perf.EndBlock()
if err != nil {
// NOTE(asaf): The error for exceeding the max filesize doesn't have a special type, so we can't easily detect it here.
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to parse form"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to parse form"))
}
title := c.Req.Form.Get("title")
@ -143,7 +143,7 @@ func PodcastEditSubmit(c *RequestContext) ResponseData {
c.Perf.StartBlock("SQL", "Updating podcast")
tx, err := c.Conn.Begin(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to start db transaction"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to start db transaction"))
}
defer tx.Rollback(c.Context())
@ -153,7 +153,7 @@ func PodcastEditSubmit(c *RequestContext) ResponseData {
if errors.As(err, &rejectErr) {
return RejectRequest(c, rejectErr.Error())
} else {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to save podcast image"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to save podcast image"))
}
}
@ -173,7 +173,7 @@ func PodcastEditSubmit(c *RequestContext) ResponseData {
podcastResult.Podcast.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to update podcast"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to update podcast"))
}
} else {
_, err = tx.Exec(c.Context(),
@ -192,7 +192,7 @@ func PodcastEditSubmit(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to commit db transaction"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to commit db transaction"))
}
res := c.Redirect(hmnurl.BuildPodcastEdit(c.CurrentProject.Slug), http.StatusSeeOther)
@ -212,7 +212,7 @@ func PodcastEpisode(c *RequestContext) ResponseData {
podcastResult, err := FetchPodcast(c, c.CurrentProject.ID, true, episodeGUIDStr)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if podcastResult.Podcast == nil || len(podcastResult.Episodes) == 0 {
@ -246,7 +246,7 @@ func PodcastEpisode(c *RequestContext) ResponseData {
var res ResponseData
err = res.WriteTemplate("podcast_episode.html", podcastEpisodeData, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast episode page"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast episode page"))
}
return res
}
@ -264,12 +264,12 @@ type PodcastEpisodeEditData struct {
func PodcastEpisodeNew(c *RequestContext) ResponseData {
podcastResult, err := FetchPodcast(c, c.CurrentProject.ID, false, "")
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
canEdit, err := CanEditProject(c, c.CurrentUser, podcastResult.Podcast.ProjectID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if podcastResult.Podcast == nil || !canEdit {
@ -278,7 +278,7 @@ func PodcastEpisodeNew(c *RequestContext) ResponseData {
episodeFiles, err := GetEpisodeFiles(c.CurrentProject.Slug)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to fetch podcast episode file list"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to fetch podcast episode file list"))
}
podcast := templates.PodcastToTemplate(c.CurrentProject.Slug, podcastResult.Podcast, "")
@ -291,7 +291,7 @@ func PodcastEpisodeNew(c *RequestContext) ResponseData {
EpisodeFiles: episodeFiles,
}, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast episode new page"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast episode new page"))
}
return res
}
@ -304,12 +304,12 @@ func PodcastEpisodeEdit(c *RequestContext) ResponseData {
podcastResult, err := FetchPodcast(c, c.CurrentProject.ID, true, episodeGUIDStr)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
canEdit, err := CanEditProject(c, c.CurrentUser, podcastResult.Podcast.ProjectID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if podcastResult.Podcast == nil || len(podcastResult.Episodes) == 0 || !canEdit {
@ -318,7 +318,7 @@ func PodcastEpisodeEdit(c *RequestContext) ResponseData {
episodeFiles, err := GetEpisodeFiles(c.CurrentProject.Slug)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to fetch podcast episode file list"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to fetch podcast episode file list"))
}
episode := podcastResult.Episodes[0]
@ -339,7 +339,7 @@ func PodcastEpisodeEdit(c *RequestContext) ResponseData {
var res ResponseData
err = res.WriteTemplate("podcast_episode_edit.html", podcastEpisodeEditData, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast episode edit page"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast episode edit page"))
}
return res
}
@ -350,12 +350,12 @@ func PodcastEpisodeSubmit(c *RequestContext) ResponseData {
isEdit := found && episodeGUIDStr != ""
podcastResult, err := FetchPodcast(c, c.CurrentProject.ID, isEdit, episodeGUIDStr)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
canEdit, err := CanEditProject(c, c.CurrentUser, podcastResult.Podcast.ProjectID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if podcastResult.Podcast == nil || (isEdit && len(podcastResult.Episodes) == 0) || !canEdit {
@ -366,7 +366,7 @@ func PodcastEpisodeSubmit(c *RequestContext) ResponseData {
episodeFiles, err := GetEpisodeFiles(c.CurrentProject.Slug)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to fetch podcast episode file list"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to fetch podcast episode file list"))
}
c.Req.ParseForm()
@ -399,7 +399,7 @@ func PodcastEpisodeSubmit(c *RequestContext) ResponseData {
c.Perf.StartBlock("MP3", "Parsing mp3 file for duration")
file, err := os.Open(fmt.Sprintf("public/media/podcast/%s/%s", c.CurrentProject.Slug, episodeFile))
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to open podcast file"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to open podcast file"))
}
mp3Decoder := mp3.NewDecoder(file)
@ -421,7 +421,7 @@ func PodcastEpisodeSubmit(c *RequestContext) ResponseData {
file.Close()
c.Perf.EndBlock()
if decodingError != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to decode mp3 file"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to decode mp3 file"))
}
c.Perf.StartBlock("MARKDOWN", "Parsing description")
@ -455,7 +455,7 @@ func PodcastEpisodeSubmit(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to update podcast episode"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to update podcast episode"))
}
} else {
guid := uuid.New()
@ -480,7 +480,7 @@ func PodcastEpisodeSubmit(c *RequestContext) ResponseData {
)
c.Perf.EndBlock()
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to create podcast episode"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to create podcast episode"))
}
}
@ -504,7 +504,7 @@ type PodcastRSSData struct {
func PodcastRSS(c *RequestContext) ResponseData {
podcastResult, err := FetchPodcast(c, c.CurrentProject.ID, true, "")
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
if podcastResult.Podcast == nil {
@ -529,7 +529,7 @@ func PodcastRSS(c *RequestContext) ResponseData {
var res ResponseData
err = res.WriteTemplate("podcast.xml", podcastRSSData, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast RSS"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render podcast RSS"))
}
return res
}

View File

@ -71,7 +71,7 @@ func ProjectIndex(c *RequestContext) ResponseData {
models.VisibleProjectLifecycles,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch projects"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch projects"))
}
allProjectsSlice := allProjects.ToSlice()
c.Perf.EndBlock()
@ -112,7 +112,7 @@ func ProjectIndex(c *RequestContext) ResponseData {
c.CurrentUser.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user projects"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user projects"))
}
for _, project := range userProjectsResult.ToSlice() {
p := project.(*UserProjectQuery).Project
@ -244,7 +244,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
if errors.Is(err, db.ErrNoMatchingRows) {
return FourOhFour(c)
} else {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project by slug"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project by slug"))
}
}
project = &projectQueryResult.(*projectQuery).Project
@ -262,7 +262,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
owners, err := FetchProjectOwners(c, project.ID)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, err)
return c.ErrorResponse(http.StatusInternalServerError, err)
}
canView := false
@ -312,7 +312,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
project.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch screenshots for project"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch screenshots for project"))
}
c.Perf.EndBlock()
@ -332,7 +332,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
project.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project links"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project links"))
}
c.Perf.EndBlock()
@ -363,7 +363,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
maxRecentActivity,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project posts"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch project posts"))
}
c.Perf.EndBlock()
@ -445,7 +445,7 @@ func ProjectHomepage(c *RequestContext) ResponseData {
var res ResponseData
err = res.WriteTemplate("project_homepage.html", projectHomepageData, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render project homepage template"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render project homepage template"))
}
return res
}

View File

@ -246,6 +246,15 @@ func (c *RequestContext) Redirect(dest string, code int) ResponseData {
return res
}
func (c *RequestContext) ErrorResponse(status int, errs ...error) ResponseData {
res := ResponseData{
StatusCode: status,
Errors: errs,
}
res.MustWriteTemplate("error.html", getBaseData(c), c.Perf)
return res
}
type ResponseData struct {
StatusCode int
Body *bytes.Buffer
@ -304,13 +313,6 @@ func (rd *ResponseData) MustWriteTemplate(name string, data interface{}, rp *per
}
}
func ErrorResponse(status int, errs ...error) ResponseData {
return ResponseData{
StatusCode: status,
Errors: errs,
}
}
func doRequest(rw http.ResponseWriter, c *RequestContext, h Handler) {
defer func() {
/*
@ -320,6 +322,7 @@ func doRequest(rw http.ResponseWriter, c *RequestContext, h Handler) {
if recovered := recover(); recovered != nil {
rw.WriteHeader(http.StatusInternalServerError)
logging.LogPanicValue(c.Logger, recovered, "request panicked and was not handled")
rw.Write([]byte("There was a problem handling your request.\nPlease notify an admin at team@handmade.network"))
}
}()

View File

@ -38,6 +38,7 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
defer logPerf()
defer LogContextErrors(c, &res)
defer MiddlewarePanicCatcher(c, &res)
return h(c)
}
@ -53,6 +54,7 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
defer logPerf()
defer LogContextErrors(c, &res)
defer MiddlewarePanicCatcher(c, &res)
defer storeNoticesInCookie(c, &res)
@ -74,6 +76,7 @@ func NewWebsiteRoutes(longRequestContext context.Context, conn *pgxpool.Pool, pe
defer logPerf()
defer LogContextErrors(c, &res)
defer MiddlewarePanicCatcher(c, &res)
defer storeNoticesInCookie(c, &res)
@ -284,6 +287,8 @@ func getBaseData(c *RequestContext) templates.BaseData {
Session: templateSession,
Notices: notices,
ReportIssueMailto: "team@handmade.network",
OpenGraphItems: buildDefaultOpenGraphItems(c.CurrentProject),
IsProjectPage: !c.CurrentProject.IsHMN(),
@ -355,7 +360,7 @@ func FetchProjectBySlug(ctx context.Context, conn *pgxpool.Pool, slug string) (*
func ProjectCSS(c *RequestContext) ResponseData {
color := c.URL().Query().Get("color")
if color == "" {
return ErrorResponse(http.StatusBadRequest, NewSafeError(nil, "You must provide a 'color' parameter.\n"))
return c.ErrorResponse(http.StatusBadRequest, NewSafeError(nil, "You must provide a 'color' parameter.\n"))
}
baseData := getBaseData(c)
@ -386,7 +391,7 @@ func ProjectCSS(c *RequestContext) ResponseData {
res.Header().Add("Content-Type", "text/css")
err := res.WriteTemplate("project.css", templateData, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to generate project CSS"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to generate project CSS"))
}
return res
@ -423,7 +428,7 @@ func RejectRequest(c *RequestContext, reason string) ResponseData {
RejectReason: reason,
}, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to render reject template"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "Failed to render reject template"))
}
return res
}
@ -439,7 +444,7 @@ func LoadCommonWebsiteData(c *RequestContext) (bool, ResponseData) {
dbProject, err := FetchProjectBySlug(c.Context(), c.Conn, slug)
if err != nil {
return false, ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch current project"))
return false, c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch current project"))
}
if dbProject == nil {
return false, c.Redirect(hmnurl.BuildHomepage(), http.StatusSeeOther)
@ -453,7 +458,7 @@ func LoadCommonWebsiteData(c *RequestContext) (bool, ResponseData) {
if err == nil {
user, session, err := getCurrentUserAndSession(c, sessionCookie.Value)
if err != nil {
return false, ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get current user"))
return false, c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to get current user"))
}
c.CurrentUser = user
@ -539,6 +544,19 @@ func LogContextErrors(c *RequestContext, res *ResponseData) {
}
}
func MiddlewarePanicCatcher(c *RequestContext, res *ResponseData) {
if recovered := recover(); recovered != nil {
maybeError, ok := recovered.(*error)
var err error
if ok {
err = *maybeError
} else {
err = oops.New(nil, fmt.Sprintf("Recovered from panic with value: %v", recovered))
}
*res = c.ErrorResponse(http.StatusInternalServerError, err)
}
}
const NoticesCookieName = "hmn_notices"
func getNoticesFromCookie(c *RequestContext) []templates.Notice {

View File

@ -35,7 +35,7 @@ func TestLogContextErrors(t *testing.T) {
}
routes.GET(regexp.MustCompile("^/test$"), func(c *RequestContext) ResponseData {
return ErrorResponse(http.StatusInternalServerError, err1, err2)
return c.ErrorResponse(http.StatusInternalServerError, err1, err2)
})
srv := httptest.NewServer(router)

View File

@ -36,7 +36,7 @@ func Showcase(c *RequestContext) ResponseData {
`,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets"))
}
snippetQuerySlice := snippetQueryResult.ToSlice()
showcaseItems := make([]templates.TimelineItem, 0, len(snippetQuerySlice))

View File

@ -53,7 +53,7 @@ func Snippet(c *RequestContext) ResponseData {
if errors.Is(err, db.ErrNoMatchingRows) {
return FourOhFour(c)
} else {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippet"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippet"))
}
}
c.Perf.EndBlock()
@ -111,7 +111,7 @@ func Snippet(c *RequestContext) ResponseData {
Snippet: snippet,
}, c.Perf)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render snippet template"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to render snippet template"))
}
return res
}

View File

@ -59,7 +59,7 @@ func UserProfile(c *RequestContext) ResponseData {
if errors.Is(err, db.ErrNoMatchingRows) {
return FourOhFour(c)
} else {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user: %s", username))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user: %s", username))
}
}
profileUser = userResult.(*models.User)
@ -80,7 +80,7 @@ func UserProfile(c *RequestContext) ResponseData {
profileUser.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch links for user: %s", username))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch links for user: %s", username))
}
userLinksSlice := userLinkQueryResult.ToSlice()
profileUserLinks := make([]templates.Link, 0, len(userLinksSlice))
@ -108,7 +108,7 @@ func UserProfile(c *RequestContext) ResponseData {
models.VisibleProjectLifecycles,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch projects for user: %s", username))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch projects for user: %s", username))
}
projectQuerySlice := projectQueryResult.ToSlice()
templateProjects := make([]templates.Project, 0, len(projectQuerySlice))
@ -139,7 +139,7 @@ func UserProfile(c *RequestContext) ResponseData {
models.VisibleProjectLifecycles,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch posts for user: %s", username))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch posts for user: %s", username))
}
postQuerySlice := postQueryResult.ToSlice()
c.Perf.EndBlock()
@ -163,7 +163,7 @@ func UserProfile(c *RequestContext) ResponseData {
profileUser.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets for user: %s", username))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch snippets for user: %s", username))
}
snippetQuerySlice := snippetQueryResult.ToSlice()
c.Perf.EndBlock()
@ -272,7 +272,7 @@ func UserSettings(c *RequestContext) ResponseData {
c.CurrentUser.ID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user links"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user links"))
}
links := ilinks.ToSlice()
@ -295,7 +295,7 @@ func UserSettings(c *RequestContext) ResponseData {
if errors.Is(err, db.ErrNoMatchingRows) {
// this is fine, but don't fetch any more messages
} else if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user's Discord account"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to fetch user's Discord account"))
} else {
duser := iduser.(*models.DiscordUser)
tmp := templates.DiscordUserToTemplate(duser)
@ -316,7 +316,7 @@ func UserSettings(c *RequestContext) ResponseData {
config.Config.Discord.ShowcaseChannelID,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to check for unsaved user messages"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to check for unsaved user messages"))
}
}
@ -402,7 +402,7 @@ func UserSettingsSave(c *RequestContext) ResponseData {
discordDeleteSnippetOnMessageDelete,
)
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update user"))
}
// Process links
@ -460,7 +460,7 @@ func UserSettingsSave(c *RequestContext) ResponseData {
if errors.As(err, &rejectErr) {
return RejectRequest(c, rejectErr.Error())
} else {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to save new avatar"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to save new avatar"))
}
}
@ -468,7 +468,7 @@ func UserSettingsSave(c *RequestContext) ResponseData {
err = tx.Commit(c.Context())
if err != nil {
return ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to save user settings"))
return c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to save user settings"))
}
return c.Redirect(hmnurl.BuildUserSettings(""), http.StatusSeeOther)
@ -489,7 +489,7 @@ func updatePassword(c *RequestContext, tx pgx.Tx, old, new, confirm string) *Res
ok, err := auth.CheckPassword(old, oldHashedPassword)
if err != nil {
res := ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to check user's password"))
res := c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to check user's password"))
return &res
}
@ -501,7 +501,7 @@ func updatePassword(c *RequestContext, tx pgx.Tx, old, new, confirm string) *Res
newHashedPassword := auth.HashPassword(new)
err = auth.UpdatePassword(c.Context(), tx, c.CurrentUser.Username, newHashedPassword)
if err != nil {
res := ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update password"))
res := c.ErrorResponse(http.StatusInternalServerError, oops.New(err, "failed to update password"))
return &res
}