// HandleUpdate responds to POST /comments/update func HandleUpdate(context router.Context) error { // Find the comment comment, err := comments.Find(context.ParamInt("id")) if err != nil { return router.NotFoundError(err) } // Authorise update comment, check auth token err = authorise.ResourceAndAuthenticity(context, comment) if err != nil { return router.NotAuthorizedError(err) } // Update the comment from params params, err := context.Params() if err != nil { return router.InternalError(err) } // Clean params according to role accepted := comments.AllowedParams() if authorise.CurrentUser(context).Admin() { accepted = comments.AllowedParamsAdmin() } cleanedParams := params.Clean(accepted) err = comment.Update(cleanedParams) if err != nil { return router.InternalError(err) } // Redirect to comment return router.Redirect(context, comment.URLShow()) }
// HandleUpvoted displays a list of stories the user has upvoted in the past func HandleUpvoted(context router.Context) error { // Build a query q := stories.Query().Limit(listLimit) // Select only above 0 points, Order by rank, then points, then name q.Where("points > 0").Order("rank desc, points desc, id desc") // Select only stories which the user has upvoted user := authorise.CurrentUser(context) if !user.Anon() { // Can we use a join instead? v := query.New("votes", "story_id").Select("select story_id as id from votes").Where("user_id=? AND story_id IS NOT NULL AND points > 0", user.Id) storyIDs := v.ResultIDs() if len(storyIDs) > 0 { q.WhereIn("id", storyIDs) } } // Set the offset in pages if we have one page := int(context.ParamInt("page")) if page > 0 { q.Offset(listLimit * page) } // Fetch the stories results, err := stories.FindAll(q) if err != nil { return router.InternalError(err) } // Render the template view := view.New(context) setStoriesMetadata(view, context.Request()) view.AddKey("page", page) view.AddKey("stories", results) view.Template("stories/views/index.html.got") if context.Param("format") == ".xml" { view.Layout("") view.Template("stories/views/index.xml.got") } return view.Render() }
// HandleDownvote handles POST to /stories/123/downvote func HandleDownvote(context router.Context) error { // Prevent CSRF err := authorise.AuthenticityToken(context) if err != nil { return router.NotAuthorizedError(err, "Vote Failed", "CSRF failure") } // Find the story story, err := stories.Find(context.ParamInt("id")) if err != nil { return router.NotFoundError(err) } user := authorise.CurrentUser(context) ip := getUserIP(context) if !user.Admin() { // Check we have no votes already from this user, if we do fail if storyHasUserVote(story, user) { return router.NotAuthorizedError(err, "Vote Failed", "Sorry you are not allowed to vote twice, nice try!") } } // Authorise upvote on story for this user - our rules are: if !user.CanDownvote() { return router.NotAuthorizedError(err, "Vote Failed", "Sorry, you can't downvote yet") } err = authorise.Resource(context, story) if err != nil { return router.NotAuthorizedError(err, "Vote Failed", "Sorry you are not allowed to vote") } err = adjustUserPoints(user, -1) if err != nil { return err } // Adjust points on story and add to the vote table err = addStoryVote(story, user, ip, -1) if err != nil { return err } return updateStoriesRank() }
// HandleFlag handles POST to /stories/123/flag func HandleFlag(context router.Context) error { // Protect against CSRF err := authorise.AuthenticityToken(context) if err != nil { return router.NotAuthorizedError(err, "Flag Failed", "CSRF failure") } // Find the story story, err := stories.Find(context.ParamInt("id")) if err != nil { return router.NotFoundError(err) } user := authorise.CurrentUser(context) ip := getUserIP(context) // Check we have no votes already from this user, if we do fail if storyHasUserFlag(story, user) { return router.NotAuthorizedError(err, "Flag Failed", "Sorry you are not allowed to flag twice, nice try!") } // Authorise upvote on story for this user if !user.CanFlag() { return router.NotAuthorizedError(err, "Flag Failed", "Sorry, you can't flag yet") } err = authorise.Resource(context, story) if err != nil { return router.NotAuthorizedError(err, "Flag Failed", "Sorry you are not allowed to flag") } err = adjustUserPoints(user, -1) if err != nil { return err } err = addStoryVote(story, user, ip, -5) if err != nil { return err } return updateStoriesRank() }
// HandleDownvote handles POST to /comments/123/downvote func HandleDownvote(context router.Context) error { // Prevent CSRF err := authorise.AuthenticityToken(context) if err != nil { return router.NotAuthorizedError(err, "Vote Failed", "CSRF failure") } // Find the comment comment, err := comments.Find(context.ParamInt("id")) if err != nil { return router.NotFoundError(err) } user := authorise.CurrentUser(context) ip := getUserIP(context) if !user.Admin() { // Check we have no votes already from this user, if we do fail if commentHasUserVote(comment, user) { return router.NotAuthorizedError(err, "Vote Failed", "Sorry you are not allowed to vote twice, nice try!") } } // Authorise upvote on comment for this user - our rules are: if !user.CanDownvote() { return router.NotAuthorizedError(err, "Vote Failed", "Sorry, you can't downvote yet") } // CURRENT User burns points for downvoting err = adjustUserPoints(user, -1) if err != nil { return err } // Adjust points on comment and add to the vote table err = addCommentVote(comment, user, ip, -1) if err != nil { return err } return updateCommentsRank(comment.StoryId) }
// HandleLoginShow shows the page at /users/login func HandleLoginShow(context router.Context) error { // Setup context for template view := view.New(context) // Check we're not already logged in, if so redirect with a message // we could alternatively display an error here? if !authorise.CurrentUser(context).Anon() { return router.Redirect(context, "/?warn=already_logged_in") } switch context.Param("error") { case "failed_email": view.AddKey("warning", "Sorry, we couldn't find a user with that email.") case "failed_password": view.AddKey("warning", "Sorry, the password was incorrect, please try again.") } // Serve return view.Render() }
// HandleUpdate handles the POST of the form to update a story func HandleUpdate(context router.Context) error { // Find the story story, err := stories.Find(context.ParamInt("id")) if err != nil { return router.NotFoundError(err) } // Authorise update story err = authorise.ResourceAndAuthenticity(context, story) if err != nil { return router.NotAuthorizedError(err) } // Update the story from params params, err := context.Params() if err != nil { return router.InternalError(err) } // Clean params according to role accepted := stories.AllowedParams() if authorise.CurrentUser(context).Admin() { accepted = stories.AllowedParamsAdmin() } cleanedParams := params.Clean(accepted) err = story.Update(cleanedParams) if err != nil { return err // Create returns a router.Error } err = updateStoriesRank() if err != nil { return router.InternalError(err) } // Redirect to story return router.Redirect(context, story.URLShow()) }
// HandleUpdate or PUT /users/1/update func HandleUpdate(context router.Context) error { // Find the user id := context.ParamInt("id") user, err := users.Find(id) if err != nil { context.Logf("#error Error finding user %s", err) return router.NotFoundError(err) } // Authorise err = authorise.ResourceAndAuthenticity(context, user) if err != nil { return router.NotAuthorizedError(err) } // Get the params params, err := context.Params() if err != nil { return router.InternalError(err) } // Clean params according to role accepted := users.AllowedParams() if authorise.CurrentUser(context).Admin() { accepted = users.AllowedParamsAdmin() } allowedParams := params.Clean(accepted) err = user.Update(allowedParams) if err != nil { return router.InternalError(err) } // Redirect to user return router.Redirect(context, user.URLShow()) }
// HandleCreate handles the POST of the create form for comments func HandleCreate(context router.Context) error { // Authorise csrf token err := authorise.AuthenticityToken(context) if err != nil { return router.NotAuthorizedError(err) } // Check permissions - if not logged in and above 0 points, redirect if !authorise.CurrentUser(context).CanComment() { return router.NotAuthorizedError(nil, "Sorry", "You need to be registered and have more than 0 points to comment.") } // Setup context params, err := context.Params() if err != nil { return router.InternalError(err) } // Find parent story - this must exist story, err := stories.Find(params.GetInt("story_id")) if err != nil { return router.NotFoundError(err) } params.SetInt("story_id", story.Id) params.Set("story_name", story.Name) // Set a few params user := authorise.CurrentUser(context) params.SetInt("user_id", user.Id) params.Set("user_name", user.Name) params.SetInt("points", 1) // Find the parent and set dotted id // these are of the form xx.xx. with a trailing dot // this saves us from saving twice on create parentID := context.ParamInt("parent_id") if parentID > 0 { parent, err := comments.Find(parentID) if err != nil { return router.NotFoundError(err) } context.Logf("PARENT:%d - %s", parent.Id, parent.DottedIds) params.Set("dotted_ids", fmt.Sprintf(parent.DottedIds+".")) } // Clean params allowing all through (since we have manually reset them above) accepted := comments.AllowedParamsAdmin() cleanedParams := params.Clean(accepted) id, err := comments.Create(cleanedParams) if err != nil { return router.InternalError(err) } // Log creation context.Logf("#info Created comment id,%d", id) // Update the story comment count storyParams := map[string]string{"comment_count": fmt.Sprintf("%d", story.CommentCount+1)} err = story.Update(storyParams) if err != nil { return router.InternalError(err, "Error", "Could not update story.") } // Redirect to the new comment m, err := comments.Find(id) if err != nil { return router.InternalError(err) } // Re-rank comments on this story err = updateCommentsRank(m.StoryId) if err != nil { return err } return router.Redirect(context, m.URLStory()) }
// HandleCreate handles the POST of the create form for stories func HandleCreate(context router.Context) error { // Check csrf token err := authorise.AuthenticityToken(context) if err != nil { return router.NotAuthorizedError(err) } // Check permissions - if not logged in and above 1 points, redirect to error if !authorise.CurrentUser(context).CanSubmit() { return router.NotAuthorizedError(nil, "Sorry", "You need to be registered and have more than 1 points to submit stories.") } // Get params params, err := context.Params() if err != nil { return router.InternalError(err) } // Get user details user := authorise.CurrentUser(context) ip := getUserIP(context) // Process urls url := params.Get("url") // Strip trailing slashes on url before comparisons if strings.HasSuffix(url, "/") { url = strings.Trim(url, "/") } // Strip ?utm_source etc - remove all after ?utm_source if strings.Contains(url, "?utm_") { url = strings.Split(url, "?utm_")[0] } // Strip url fragments (For example trailing # on medium urls) if strings.Contains(url, "#") { url = strings.Split(url, "#")[0] } // Rewrite mobile youtube links if strings.HasPrefix(url, "https://m.youtube.com") { url = strings.Replace(url, "https://m.youtube.com", "https://www.youtube.com", 1) } params.Set("url", url) // Check that no story with this url already exists q := stories.Where("url=?", url) duplicates, err := stories.FindAll(q) if err != nil { return router.InternalError(err) } if len(duplicates) > 0 { story := duplicates[0] // Check we have no votes already from this user, if we do fail if storyHasUserVote(story, user) { return router.NotAuthorizedError(err, "Vote Failed", "Sorry you are not allowed to vote twice, nice try!") } // Add a point to dupe and return addStoryVote(story, user, ip, 1) return router.Redirect(context, story.URLShow()) } // Clean params according to role accepted := stories.AllowedParams() if authorise.CurrentUser(context).Admin() { accepted = stories.AllowedParamsAdmin() } cleanedParams := params.Clean(accepted) // Set a few params cleanedParams["points"] = "1" cleanedParams["user_id"] = fmt.Sprintf("%d", user.Id) cleanedParams["user_name"] = user.Name id, err := stories.Create(cleanedParams) if err != nil { return err // Create returns a router.Error } // Log creation context.Logf("#info Created story id,%d", id) // Redirect to the new story story, err := stories.Find(id) if err != nil { return router.InternalError(err) } // We need to add a vote to the story here too by adding a join to the new id err = recordStoryVote(story, user, ip, +1) if err != nil { return err } // Re-rank stories err = updateStoriesRank() if err != nil { return err } return router.Redirect(context, story.URLIndex()) }