From 16f16ae9d9ff979509fcdd8a28c72f1eac35e4cb Mon Sep 17 00:00:00 2001 From: Mihai Parparita Date: Fri, 28 Nov 2014 15:00:39 -0800 Subject: [PATCH] Add helper wrapper for handlers that require signed in state, to reduce boilerplate. --- app/app.go | 68 +++++++++++++++++++++++++++ app/retrogit.go | 121 ++++++++++++------------------------------------ 2 files changed, 98 insertions(+), 91 deletions(-) diff --git a/app/app.go b/app/app.go index 44eb660..a1f9379 100644 --- a/app/app.go +++ b/app/app.go @@ -15,6 +15,7 @@ import ( "appengine" "github.com/google/go-github/github" + "github.com/gorilla/sessions" ) const ( @@ -32,6 +33,36 @@ type AppError struct { Type int } +type AppSignedInState struct { + Account *Account + GitHubClient *github.Client + session *sessions.Session + request *http.Request + responseWriter http.ResponseWriter +} + +func (state *AppSignedInState) AddFlash(value interface{}) { + state.session.AddFlash(value) + state.saveSession() +} + +func (state *AppSignedInState) Flashes() []interface{} { + flashes := state.session.Flashes() + if len(flashes) > 0 { + state.saveSession() + } + return flashes +} + +func (state *AppSignedInState) ClearSession() { + state.session.Options.MaxAge = -1 + state.saveSession() +} + +func (state *AppSignedInState) saveSession() { + state.session.Save(state.request, state.responseWriter) +} + func GitHubFetchError(err error, fetchType string) *AppError { return &AppError{ Error: err, @@ -84,6 +115,10 @@ func RedirectToRoute(routeName string) *AppError { return RedirectToUrl(routeUrl.String()) } +func NotSignedIn() *AppError { + return RedirectToRoute("index") +} + type AppHandler func(http.ResponseWriter, *http.Request) *AppError func (fn AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { @@ -92,6 +127,39 @@ func (fn AppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { } } +type SignedInAppHandler func(http.ResponseWriter, *http.Request, *AppSignedInState) *AppError + +func (fn SignedInAppHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + session, _ := sessionStore.Get(r, sessionConfig.CookieName) + userId, ok := session.Values[sessionConfig.UserIdKey].(int) + if !ok { + handleAppError(NotSignedIn(), w, r) + return + } + c := appengine.NewContext(r) + account, err := getAccount(c, userId) + if account == nil || err != nil { + handleAppError(NotSignedIn(), w, r) + return + } + + oauthTransport := githubOAuthTransport(c) + oauthTransport.Token = &account.OAuthToken + githubClient := github.NewClient(oauthTransport.Client()) + + state := &AppSignedInState{ + Account: account, + GitHubClient: githubClient, + session: session, + responseWriter: w, + request: r, + } + + if e := fn(w, r, state); e != nil { + handleAppError(e, w, r) + } +} + func handleAppError(e *AppError, w http.ResponseWriter, r *http.Request) { c := appengine.NewContext(r) if e.Type == AppErrorTypeGitHubFetch { diff --git a/app/retrogit.go b/app/retrogit.go index 4e6e905..e299a04 100644 --- a/app/retrogit.go +++ b/app/retrogit.go @@ -46,14 +46,14 @@ func init() { router.Handle("/session/sign-out", AppHandler(signOutHandler)).Name("sign-out").Methods("POST") router.Handle("/github/callback", AppHandler(githubOAuthCallbackHandler)) - router.Handle("/digest/view", AppHandler(viewDigestHandler)).Name("view-digest") - router.Handle("/digest/send", AppHandler(sendDigestHandler)).Name("send-digest").Methods("POST") + router.Handle("/digest/view", SignedInAppHandler(viewDigestHandler)).Name("view-digest") + router.Handle("/digest/send", SignedInAppHandler(sendDigestHandler)).Name("send-digest").Methods("POST") router.Handle("/digest/cron", AppHandler(digestCronHandler)) - router.Handle("/account/settings", AppHandler(settingsHandler)).Name("settings").Methods("GET") - router.Handle("/account/settings", AppHandler(saveSettingsHandler)).Name("save-settings").Methods("POST") - router.Handle("/account/set-initial-timezone", AppHandler(setInitialTimezoneHandler)).Name("set-initial-timezone").Methods("POST") - router.Handle("/account/delete", AppHandler(deleteAccountHandler)).Name("delete-account").Methods("POST") + router.Handle("/account/settings", SignedInAppHandler(settingsHandler)).Name("settings").Methods("GET") + router.Handle("/account/settings", SignedInAppHandler(saveSettingsHandler)).Name("save-settings").Methods("POST") + router.Handle("/account/set-initial-timezone", SignedInAppHandler(setInitialTimezoneHandler)).Name("set-initial-timezone").Methods("POST") + router.Handle("/account/delete", SignedInAppHandler(deleteAccountHandler)).Name("delete-account").Methods("POST") router.Handle("/admin/users", AppHandler(usersAdminHandler)) router.Handle("/admin/digest", AppHandler(digestAdminHandler)).Name("digest-admin") @@ -183,20 +183,9 @@ func signOutHandler(w http.ResponseWriter, r *http.Request) *AppError { return RedirectToRoute("index") } -func viewDigestHandler(w http.ResponseWriter, r *http.Request) *AppError { - session, _ := sessionStore.Get(r, sessionConfig.CookieName) - userId := session.Values[sessionConfig.UserIdKey].(int) +func viewDigestHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError { c := appengine.NewContext(r) - account, err := getAccount(c, userId) - if err != nil { - return InternalError(err, "Could not look up account") - } - - oauthTransport := githubOAuthTransport(c) - oauthTransport.Token = &account.OAuthToken - githubClient := github.NewClient(oauthTransport.Client()) - - digest, err := newDigest(c, githubClient, account) + digest, err := newDigest(c, state.GitHubClient, state.Account) if err != nil { return GitHubFetchError(err, "digest") } @@ -206,26 +195,18 @@ func viewDigestHandler(w http.ResponseWriter, r *http.Request) *AppError { return templates["digest-page"].Render(w, data) } -func sendDigestHandler(w http.ResponseWriter, r *http.Request) *AppError { - session, _ := sessionStore.Get(r, sessionConfig.CookieName) - userId := session.Values[sessionConfig.UserIdKey].(int) +func sendDigestHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError { c := appengine.NewContext(r) - account, err := getAccount(c, userId) - if err != nil { - return InternalError(err, "Could not look up account") - } - - sent, err := sendDigestForAccount(account, c) + sent, err := sendDigestForAccount(state.Account, c) if err != nil { return InternalError(err, "Could not send digest") } if sent { - session.AddFlash("Digest emailed!") + state.AddFlash("Digest emailed!") } else { - session.AddFlash("No digest was sent, it was empty or disabled.") + state.AddFlash("No digest was sent, it was empty or disabled.") } - session.Save(r, w) return RedirectToRoute("index") } @@ -346,31 +327,19 @@ func githubOAuthCallbackHandler(w http.ResponseWriter, r *http.Request) *AppErro return RedirectToUrl(continueUrl) } -func settingsHandler(w http.ResponseWriter, r *http.Request) *AppError { - session, _ := sessionStore.Get(r, sessionConfig.CookieName) - userId := session.Values[sessionConfig.UserIdKey].(int) +func settingsHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError { c := appengine.NewContext(r) - account, err := getAccount(c, userId) - if err != nil { - // TODO: redirect to sign in again - return InternalError(err, "Could not look up account") - } - - oauthTransport := githubOAuthTransport(c) - oauthTransport.Token = &account.OAuthToken - githubClient := github.NewClient(oauthTransport.Client()) - - user, _, err := githubClient.Users.Get("") + user, _, err := state.GitHubClient.Users.Get("") if err != nil { return GitHubFetchError(err, "user") } - repos, err := getRepos(c, githubClient, account, user) + repos, err := getRepos(c, state.GitHubClient, state.Account, user) if err != nil { return GitHubFetchError(err, "repositories") } - emails, _, err := githubClient.Users.ListEmails(nil) + emails, _, err := state.GitHubClient.Users.ListEmails(nil) if err != nil { return GitHubFetchError(err, "emails") } @@ -378,18 +347,15 @@ func settingsHandler(w http.ResponseWriter, r *http.Request) *AppError { for i := range emails { emailAddresses[i] = *emails[i].Email } - accountEmailAddress, err := account.GetDigestEmailAddress(githubClient) + accountEmailAddress, err := state.Account.GetDigestEmailAddress(state.GitHubClient) if err != nil { return GitHubFetchError(err, "emails") } - flashes := session.Flashes() - if len(flashes) > 0 { - session.Save(r, w) - } + flashes := state.Flashes() var data = map[string]interface{}{ - "Account": account, + "Account": state.Account, "User": user, "Timezones": timezones, "Repos": repos, @@ -400,25 +366,16 @@ func settingsHandler(w http.ResponseWriter, r *http.Request) *AppError { return templates["settings"].Render(w, data) } -func saveSettingsHandler(w http.ResponseWriter, r *http.Request) *AppError { - session, _ := sessionStore.Get(r, sessionConfig.CookieName) - userId := session.Values[sessionConfig.UserIdKey].(int) +func saveSettingsHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError { c := appengine.NewContext(r) - account, err := getAccount(c, userId) - if err != nil { - // TODO: redirect to sign in again - return InternalError(err, "Could not look up account") - } - oauthTransport := githubOAuthTransport(c) - oauthTransport.Token = &account.OAuthToken - githubClient := github.NewClient(oauthTransport.Client()) + account := state.Account - user, _, err := githubClient.Users.Get("") + user, _, err := state.GitHubClient.Users.Get("") if err != nil { return GitHubFetchError(err, "user") } - repos, err := getRepos(c, githubClient, account, user) + repos, err := getRepos(c, state.GitHubClient, account, user) if err != nil { return GitHubFetchError(err, "repos") } @@ -453,23 +410,16 @@ func saveSettingsHandler(w http.ResponseWriter, r *http.Request) *AppError { return InternalError(err, "Could not save user") } - session.AddFlash("Settings saved.") - session.Save(r, w) + state.AddFlash("Settings saved.") return RedirectToRoute("settings") } -func setInitialTimezoneHandler(w http.ResponseWriter, r *http.Request) *AppError { - session, _ := sessionStore.Get(r, sessionConfig.CookieName) - userId := session.Values[sessionConfig.UserIdKey].(int) +func setInitialTimezoneHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError { c := appengine.NewContext(r) - account, err := getAccount(c, userId) - if err != nil { - // TODO: redirect to sign in again - return InternalError(err, "Could not look up account") - } + account := state.Account timezoneName := r.FormValue("timezone_name") - _, err = time.LoadLocation(timezoneName) + _, err := time.LoadLocation(timezoneName) if err != nil { return BadRequest(err, "Malformed timezone_name value") } @@ -512,21 +462,10 @@ var cacheDigestForAccountFunc = delay.Func( return nil }) -func deleteAccountHandler(w http.ResponseWriter, r *http.Request) *AppError { - session, _ := sessionStore.Get(r, sessionConfig.CookieName) - userId := session.Values[sessionConfig.UserIdKey].(int) +func deleteAccountHandler(w http.ResponseWriter, r *http.Request, state *AppSignedInState) *AppError { c := appengine.NewContext(r) - account, err := getAccount(c, userId) - if err != nil { - // TODO: redirect to sign in again - return InternalError(err, "Could not look up account") - } - - account.Delete(c) - session.Options.MaxAge = -1 - session.Save(r, w) - - // TODO: add a flash message saying that the account was deleted. + state.Account.Delete(c) + state.ClearSession() return RedirectToRoute("index") }