// DailyEmail sends a daily email to subscribed users with top stories - change this to WeeklyEmail // before putting it into production // We should probably only do this for kenny at present func DailyEmail(context schedule.Context) { context.Log("Sending daily email") // First fetch our stories over 5 points q := stories.Popular() // Must be within 7 days q.Where("created_at > current_timestamp - interval '7 day'") // Order by rank q.Order("rank desc, points desc, id desc") // Don't fetch stories that have already been mailed q.Where("newsletter_at IS NULL") // Fetch the stories topStories, err := stories.FindAll(q) if err != nil { context.Logf("#error getting top story tweet %s", err) return } if len(topStories) == 0 { context.Logf("#warn no stories found for newsletter") return } // Now fetch our recipient (initially just Kenny as this is in testing) recipient, err := users.Find(1) if err != nil { context.Logf("#error getting email reciipents %s", err) return } var jobStories []*stories.Story // Email recipients the stories in question - we should perhaps save in db so that we can // have an issue number and always reproduce the digests? mailContext := map[string]interface{}{ "stories": topStories, "jobs": jobStories, } err = mail.SendOne(recipient.Email, "Go News Digest", "users/views/mail/digest.html.got", mailContext) if err != nil { context.Logf("#error sending email %s", err) return } // Record that these stories have been mailed in db params := map[string]string{"newsletter_at": query.TimeString(time.Now().UTC())} err = q.Order("").UpdateAll(params) if err != nil { context.Logf("#error updating top story newsletter_at %s", err) return } }
// HandleUpdateShow serves a get request at /users/1/update (show form to update) func HandleUpdateShow(context router.Context) error { // Setup context for template view := view.New(context) user, err := users.Find(context.ParamInt("id")) if err != nil { context.Logf("#error Error finding user %s", err) return router.NotFoundError(err) } // Authorise err = authorise.Resource(context, user) if err != nil { return router.NotAuthorizedError(err) } view.AddKey("user", user) return view.Render() }
// HandleDestroy responds to POST /users/1/destroy func HandleDestroy(context router.Context) error { // Set the user on the context for checking user, err := users.Find(context.ParamInt("id")) if err != nil { return router.NotFoundError(err) } // Authorise err = authorise.ResourceAndAuthenticity(context, user) if err != nil { return router.NotAuthorizedError(err) } // Destroy the user user.Destroy() // Redirect to users root return router.Redirect(context, user.URLIndex()) }
// CurrentUser returns the saved user (or an empty anon user) for the current session cookie // Strictly speaking this should be authenticate.User func CurrentUser(context router.Context) *users.User { // First check if the user has already been set on context, if so return it if context.Get("current_user") != nil { return context.Get("current_user").(*users.User) } // Start with an anon user by default (role 0, id 0) user := &users.User{} // Build the session from the secure cookie, or create a new one session, err := auth.Session(context.Writer(), context.Request()) if err != nil { context.Logf("#error problem retrieving session") return user } // Fetch the current user record if we have one recorded in the session var id int64 ids := session.Get(auth.SessionUserKey) if len(ids) > 0 { id, err = strconv.ParseInt(ids, 10, 64) if err != nil { context.Logf("#error Error decoding session user key:%s\n", err) return user } } if id != 0 { u, err := users.Find(id) if err != nil { context.Logf("#info User not found from session id:%d\n", id) return user } user = u } return user }
// addStoryVote adjusts the story points, and adds a vote record for this user func addStoryVote(story *stories.Story, user *users.User, ip string, delta int64) error { if story.Points < -5 && delta < 0 { return router.InternalError(nil, "Vote Failed", "Story is already hidden") } // Update the story points by delta err := story.Update(map[string]string{"points": fmt.Sprintf("%d", story.Points+delta)}) if err != nil { return router.InternalError(err, "Vote Failed", "Sorry your adjust vote points") } // Update the *story* posting user points by delta storyUser, err := users.Find(story.UserId) if err != nil { return err } err = adjustUserPoints(storyUser, delta) if err != nil { return err } return recordStoryVote(story, user, ip, delta) }
// HandleShow serve a get request at /users/1 func HandleShow(context router.Context) error { // No auth - this is public // Find the user user, err := users.Find(context.ParamInt("id")) if err != nil { context.Logf("#error parsing user id: %s", err) return router.NotFoundError(err) } // Get the user comments q := comments.Where("user_id=?", user.Id).Limit(10).Order("created_at desc") userComments, err := comments.FindAll(q) if err != nil { return router.InternalError(err) } // Get the user stories q = stories.Where("user_id=?", user.Id).Limit(50).Order("created_at desc") userStories, err := stories.FindAll(q) if err != nil { return router.InternalError(err) } // Render the Template view := view.New(context) view.AddKey("user", user) view.AddKey("comments", userComments) view.AddKey("stories", userStories) view.AddKey("meta_title", user.Name) view.AddKey("meta_desc", user.Name) return view.Render() }
// 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()) }
// addCommentVote adjusts the comment points, and adds a vote record for this user func addCommentVote(comment *comments.Comment, user *users.User, ip string, delta int64) error { if comment.Points < -5 && delta < 0 { return router.InternalError(nil, "Vote Failed", "Comment is already hidden") } // Update the comment points by delta err := comment.Update(map[string]string{"points": fmt.Sprintf("%d", comment.Points+delta)}) if err != nil { return router.InternalError(err, "Vote Failed", "Sorry your adjust vote points") } // Update the *comment* user points by delta commentUser, err := users.Find(comment.UserId) if err != nil { return err } err = adjustUserPoints(commentUser, delta) if err != nil { return err } return recordCommentVote(comment, user, ip, delta) }
// HandleCreate handles POST /users/create from the register page func HandleCreate(context router.Context) error { // Check csrf token err := authorise.AuthenticityToken(context) if err != nil { return router.NotAuthorizedError(err) } // Setup context params, err := context.Params() if err != nil { return router.InternalError(err) } // Check for email duplicates email := params.Get("email") if len(email) > 0 { if len(email) < 3 || !strings.Contains(email, "@") { return router.InternalError(err, "Invalid email", "Please just miss out the email field, or use a valid email.") } count, err := users.Query().Where("email=?", email).Count() if err != nil { return router.InternalError(err) } if count > 0 { return router.NotAuthorizedError(err, "User already exists", "Sorry, a user already exists with that email.") } } // Check for invalid or duplicate names name := params.Get("name") if len(name) < 2 { return router.InternalError(err, "Name too short", "Please choose a username longer than 2 characters") } count, err := users.Query().Where("name=?", name).Count() if err != nil { return router.InternalError(err) } if count > 0 { return router.NotAuthorizedError(err, "User already exists", "Sorry, a user already exists with that name, please choose another.") } // Set some defaults for the new user params.SetInt("status", status.Published) params.SetInt("role", users.RoleReader) params.SetInt("points", 1) // Now try to create the user - NB AllowedParamsAdmin, we allow points etc on create as we explicitly set them id, err := users.Create(params.Clean(users.AllowedParamsAdmin())) if err != nil { return router.InternalError(err, "Error", "Sorry, an error occurred creating the user record.") } context.Logf("#info Created user id,%d", id) // Find the user again so we can save login user, err := users.Find(id) if err != nil { context.Logf("#error parsing user id: %s", err) return router.NotFoundError(err) } // Save the fact user is logged in to session cookie err = loginUser(context, user) if err != nil { return router.InternalError(err) } // Redirect to root return router.Redirect(context, "/?message=welcome") }