mirror of
https://github.com/samsonjs/retrogit.git
synced 2026-04-27 15:07:43 +00:00
Add digest cron handler.
This commit is contained in:
parent
1bc9d53325
commit
649bbd8fd9
5 changed files with 67 additions and 26 deletions
2
TODO
2
TODO
|
|
@ -1,7 +1,7 @@
|
||||||
TODO
|
TODO
|
||||||
- Break up indexHandler
|
- Break up indexHandler
|
||||||
- Flash message when sending a single email
|
- Flash message when sending a single email
|
||||||
- Loop over registered accounts and send them email
|
- Use task queue for sending out of digests, for better parallelism and retry behavior
|
||||||
- Flash message and sign out when OAuth token has expired/is invalid
|
- Flash message and sign out when OAuth token has expired/is invalid
|
||||||
- Handle pagination for user repository list
|
- Handle pagination for user repository list
|
||||||
- Handle pagination for user organization list
|
- Handle pagination for user organization list
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,22 @@ func getAccount(c appengine.Context, gitHubUserId int) (*Account, error) {
|
||||||
return account, err
|
return account, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAllAccounts(c appengine.Context, accounts *[]Account) error {
|
||||||
|
q := datastore.NewQuery("Account")
|
||||||
|
_, err := q.GetAll(c, accounts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, _ := range *accounts {
|
||||||
|
r := bytes.NewBuffer((*accounts)[i].OAuthTokenSerialized)
|
||||||
|
err = gob.NewDecoder(r).Decode(&(*accounts)[i].OAuthToken)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (account *Account) put(c appengine.Context) error {
|
func (account *Account) put(c appengine.Context) error {
|
||||||
w := new(bytes.Buffer)
|
w := new(bytes.Buffer)
|
||||||
err := gob.NewEncoder(w).Encode(&account.OAuthToken)
|
err := gob.NewEncoder(w).Encode(&account.OAuthToken)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,9 @@ api_version: go1
|
||||||
handlers:
|
handlers:
|
||||||
- url: /static
|
- url: /static
|
||||||
static_dir: static
|
static_dir: static
|
||||||
|
- url: /digest/cron
|
||||||
|
script: _go_app
|
||||||
|
login: admin
|
||||||
- url: /.*
|
- url: /.*
|
||||||
script: _go_app
|
script: _go_app
|
||||||
secure: always
|
secure: always
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ func newDigest(githubClient *github.Client) (*Digest, error) {
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
digestStartTime := time.Date(now.Year()-1, now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
digestStartTime := time.Date(now.Year()-1, now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
|
||||||
digestEndTime := digestStartTime.AddDate(0, 0, 7)
|
digestEndTime := digestStartTime.AddDate(0, 0, 1)
|
||||||
|
|
||||||
// Only look at repos that may have activity in the digest interval.
|
// Only look at repos that may have activity in the digest interval.
|
||||||
var digestRepos []github.Repository
|
var digestRepos []github.Repository
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ package githop
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
|
@ -49,6 +51,7 @@ func init() {
|
||||||
router = mux.NewRouter()
|
router = mux.NewRouter()
|
||||||
router.HandleFunc("/", indexHandler).Name("index")
|
router.HandleFunc("/", indexHandler).Name("index")
|
||||||
router.HandleFunc("/digest/send", sendDigestHandler).Name("send-digest").Methods("POST")
|
router.HandleFunc("/digest/send", sendDigestHandler).Name("send-digest").Methods("POST")
|
||||||
|
router.HandleFunc("/digest/cron", digestCronHandler)
|
||||||
router.HandleFunc("/session/sign-in", signInHandler).Name("sign-in")
|
router.HandleFunc("/session/sign-in", signInHandler).Name("sign-in")
|
||||||
router.HandleFunc("/session/sign-out", signOutHandler).Name("sign-out")
|
router.HandleFunc("/session/sign-out", signOutHandler).Name("sign-out")
|
||||||
router.HandleFunc("/github/callback", githubOAuthCallbackHandler)
|
router.HandleFunc("/github/callback", githubOAuthCallbackHandler)
|
||||||
|
|
@ -82,7 +85,8 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
account, err := getAccount(appengine.NewContext(r), userId)
|
c := appengine.NewContext(r)
|
||||||
|
account, err := getAccount(c, userId)
|
||||||
if account == nil {
|
if account == nil {
|
||||||
// Can't look up the account, session cookie must be invalid, clear it.
|
// Can't look up the account, session cookie must be invalid, clear it.
|
||||||
indexUrl, _ := router.Get("sign-out").URL()
|
indexUrl, _ := router.Get("sign-out").URL()
|
||||||
|
|
@ -94,7 +98,7 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
oauthTransport := githubOAuthTransport(r)
|
oauthTransport := githubOAuthTransport(c)
|
||||||
oauthTransport.Token = &account.OAuthToken
|
oauthTransport.Token = &account.OAuthToken
|
||||||
githubClient := github.NewClient(oauthTransport.Client())
|
githubClient := github.NewClient(oauthTransport.Client())
|
||||||
|
|
||||||
|
|
@ -124,26 +128,50 @@ func sendDigestHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
oauthTransport := githubOAuthTransport(r)
|
err = sendDigestForAccount(account, c)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
indexUrl, _ := router.Get("index").URL()
|
||||||
|
http.Redirect(w, r, indexUrl.String(), http.StatusFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func digestCronHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var accounts []Account
|
||||||
|
c := appengine.NewContext(r)
|
||||||
|
getAllAccounts(c, &accounts)
|
||||||
|
for _, account := range accounts {
|
||||||
|
c.Infof("Sending digest for %d...", account.GitHubUserId)
|
||||||
|
err := sendDigestForAccount(&account, c)
|
||||||
|
if err != nil {
|
||||||
|
c.Errorf(" Error: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
c.Infof(" Sent!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Fprint(w, "Done")
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendDigestForAccount(account *Account, c appengine.Context) error {
|
||||||
|
oauthTransport := githubOAuthTransport(c)
|
||||||
oauthTransport.Token = &account.OAuthToken
|
oauthTransport.Token = &account.OAuthToken
|
||||||
githubClient := github.NewClient(oauthTransport.Client())
|
githubClient := github.NewClient(oauthTransport.Client())
|
||||||
|
|
||||||
digest, err := newDigest(githubClient)
|
digest, err := newDigest(githubClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var digestHtml bytes.Buffer
|
var digestHtml bytes.Buffer
|
||||||
if err := templates.ExecuteTemplate(&digestHtml, "digest", digest); err != nil {
|
if err := templates.ExecuteTemplate(&digestHtml, "digest", digest); err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emails, _, err := githubClient.Users.ListEmails(nil)
|
emails, _, err := githubClient.Users.ListEmails(nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return err
|
||||||
return
|
|
||||||
}
|
}
|
||||||
var primaryVerified *string
|
var primaryVerified *string
|
||||||
for _, email := range emails {
|
for _, email := range emails {
|
||||||
|
|
@ -154,8 +182,7 @@ func sendDigestHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if primaryVerified == nil {
|
if primaryVerified == nil {
|
||||||
http.Error(w, "No verified email addresses found in GitHub account", http.StatusBadRequest)
|
return errors.New("No verified email addresses found in GitHub account")
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
digestMessage := &mail.Message{
|
digestMessage := &mail.Message{
|
||||||
|
|
@ -164,18 +191,14 @@ func sendDigestHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
Subject: "GitHop Digest",
|
Subject: "GitHop Digest",
|
||||||
HTMLBody: digestHtml.String(),
|
HTMLBody: digestHtml.String(),
|
||||||
}
|
}
|
||||||
if err := mail.Send(c, digestMessage); err != nil {
|
err = mail.Send(c, digestMessage)
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
return err
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
indexUrl, _ := router.Get("index").URL()
|
|
||||||
http.Redirect(w, r, indexUrl.String(), http.StatusFound)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func githubOAuthCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
func githubOAuthCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
code := r.FormValue("code")
|
code := r.FormValue("code")
|
||||||
oauthTransport := githubOAuthTransport(r)
|
c := appengine.NewContext(r)
|
||||||
|
oauthTransport := githubOAuthTransport(c)
|
||||||
token, err := oauthTransport.Exchange(code)
|
token, err := oauthTransport.Exchange(code)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
|
|
@ -194,7 +217,7 @@ func githubOAuthCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
GitHubUserId: *user.ID,
|
GitHubUserId: *user.ID,
|
||||||
OAuthToken: *token,
|
OAuthToken: *token,
|
||||||
}
|
}
|
||||||
err = account.put(appengine.NewContext(r))
|
err = account.put(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||||
return
|
return
|
||||||
|
|
@ -207,12 +230,11 @@ func githubOAuthCallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, indexUrl.String(), http.StatusFound)
|
http.Redirect(w, r, indexUrl.String(), http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
func githubOAuthTransport(r *http.Request) *oauth.Transport {
|
func githubOAuthTransport(c appengine.Context) *oauth.Transport {
|
||||||
appengineContext := appengine.NewContext(r)
|
appengineTransport := &urlfetch.Transport{Context: c}
|
||||||
appengineTransport := &urlfetch.Transport{Context: appengineContext}
|
|
||||||
cachingTransport := &CachingTransport{
|
cachingTransport := &CachingTransport{
|
||||||
Transport: appengineTransport,
|
Transport: appengineTransport,
|
||||||
Context: appengineContext,
|
Context: c,
|
||||||
}
|
}
|
||||||
return &oauth.Transport{
|
return &oauth.Transport{
|
||||||
Config: &githubOauthConfig,
|
Config: &githubOauthConfig,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue