Weekly digest option.

This commit is contained in:
Mihai Parparita 2014-09-27 15:52:57 -07:00
parent 71ef392cfa
commit 40540fd91f
5 changed files with 122 additions and 31 deletions

View file

@ -23,6 +23,8 @@ type Account struct {
TimezoneLocation *time.Location `datastore:"-,"`
ExcludedRepoIds []int `datastore:",noindex"`
DigestEmailAddress string
Frequency string
WeeklyDay time.Weekday
}
func getAccount(c appengine.Context, githubUserId int) (*Account, error) {
@ -49,6 +51,9 @@ func initAccount(account *Account) error {
if len(account.TimezoneName) == 0 {
account.TimezoneName = "America/Los_Angeles"
}
if len(account.Frequency) == 0 {
account.Frequency = "daily"
}
account.TimezoneLocation, err = time.LoadLocation(account.TimezoneName)
if err != nil {
return err
@ -56,18 +61,20 @@ func initAccount(account *Account) error {
return nil
}
func getAllAccountGithubUserIds(c appengine.Context) ([]int, error) {
func getAllAccounts(c appengine.Context) ([]Account, error) {
q := datastore.NewQuery("Account")
var accounts []Account
_, err := q.GetAll(c, &accounts)
if err != nil {
return nil, err
}
result := make([]int, len(accounts))
for i := range accounts {
result[i] = accounts[i].GitHubUserId
err = initAccount(&accounts[i])
if err != nil {
return nil, err
}
}
return result, nil
return accounts, nil
}
func (account *Account) IsRepoIdExcluded(repoId int) bool {

View file

@ -12,10 +12,11 @@ import (
)
const (
CommitDisplayDateFormat = "3:04pm"
CommitDisplayDateTooltipFormat = "Monday January 2 3:04pm"
DigestDisplayDateFormat = "January 2, 2006"
DigestDisplayDayOfWeekFormat = "Monday"
CommitDisplayDateFormat = "3:04pm"
CommitDisplayDateFullFormat = "Monday January 2 3:04pm"
DigestDisplayDateFormat = "January 2, 2006"
DigestDisplayShortDateFormat = "January 2"
DigestDisplayDayOfWeekFormat = "Monday"
)
type DigestCommit struct {
@ -52,12 +53,16 @@ func (commit DigestCommit) DisplayDate() string {
return commit.PushDate.Format(CommitDisplayDateFormat)
}
func (commit DigestCommit) WeeklyDisplayDate() string {
return commit.PushDate.Format(CommitDisplayDateFullFormat)
}
func (commit DigestCommit) DisplayDateTooltip() string {
// But show the full details in a tooltip
return fmt.Sprintf(
"Pushed at %s\nCommited at %s",
commit.PushDate.Format(CommitDisplayDateTooltipFormat),
commit.CommitDate.Format(CommitDisplayDateTooltipFormat))
commit.PushDate.Format(CommitDisplayDateFullFormat),
commit.CommitDate.Format(CommitDisplayDateFullFormat))
}
type RepoDigest struct {
@ -76,6 +81,7 @@ type IntervalDigest struct {
yearDelta int
StartTime time.Time
EndTime time.Time
Weekly bool
RepoDigests []*RepoDigest
repos []*Repo
}
@ -116,15 +122,33 @@ func (digest *IntervalDigest) Description() string {
} else {
formattedRepoCount = fmt.Sprintf("%d repositories", repoCount)
}
dayOfWeek := digest.StartTime.Format(DigestDisplayDayOfWeekFormat)
// Insert a zero-width space inside the day of the week so that Gmail's
// event detection doesn't pick it up.
dayOfWeek = fmt.Sprintf("%s\u200B%s", dayOfWeek[:1], dayOfWeek[1:])
return fmt.Sprintf("%s was a %s. You had %s in %s that day.",
digest.StartTime.Format(DigestDisplayDateFormat),
dayOfWeek,
if !digest.Weekly {
dayOfWeek := digest.StartTime.Format(DigestDisplayDayOfWeekFormat)
// Insert a zero-width space inside the day of the week so that Gmail's
// event detection doesn't pick it up.
dayOfWeek = fmt.Sprintf("%s\u200B%s", dayOfWeek[:1], dayOfWeek[1:])
return fmt.Sprintf("%s was a %s. You had %s in %s that day.",
digest.StartTime.Format(DigestDisplayDateFormat),
dayOfWeek,
formattedCommitCount,
formattedRepoCount)
}
formattedEndTime := digest.EndTime.Format(DigestDisplayDateFormat)
var formattedStartTime string
if digest.StartTime.Year() == digest.EndTime.Year() {
formattedStartTime = digest.StartTime.Format(DigestDisplayShortDateFormat)
} else {
formattedStartTime = digest.StartTime.Format(DigestDisplayDateFormat)
}
formattedStartTime = fmt.Sprintf("%s\u200B%s", formattedStartTime[:1], formattedStartTime[1:])
formattedEndTime = fmt.Sprintf("%s\u200B%s", formattedEndTime[:1], formattedEndTime[1:])
return fmt.Sprintf("You had %s in %s the week of %s to %s.",
formattedCommitCount,
formattedRepoCount)
formattedRepoCount,
formattedStartTime,
formattedEndTime)
}
type Digest struct {
@ -152,7 +176,11 @@ func newDigest(c appengine.Context, githubClient *github.Client, account *Accoun
if digestStartTime.Before(oldestDigestTime) {
break
}
digestEndTime := digestStartTime.AddDate(0, 0, 1)
daysInDigest := 1
if account.Frequency == "weekly" {
daysInDigest = 7
}
digestEndTime := digestStartTime.AddDate(0, 0, daysInDigest)
// Only look at repos that may have activity in the digest interval.
var intervalRepos []*Repo
@ -169,6 +197,7 @@ func newDigest(c appengine.Context, githubClient *github.Client, account *Accoun
RepoDigests: make([]*RepoDigest, 0, len(intervalRepos)),
StartTime: digestStartTime,
EndTime: digestEndTime,
Weekly: account.Frequency == "weekly",
})
}

View file

@ -238,15 +238,23 @@ func sendDigestHandler(w http.ResponseWriter, r *http.Request) {
func digestCronHandler(w http.ResponseWriter, r *http.Request) {
c := appengine.NewContext(r)
githubUserIds, err := getAllAccountGithubUserIds(c)
accounts, err := getAllAccounts(c)
if err != nil {
c.Errorf("Error looking up accounts: %s", err.Error())
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
for _, githubUserId := range githubUserIds {
c.Infof("Enqueing task for %d...", githubUserId)
sendDigestForAccountFunc.Call(c, githubUserId)
for _, account := range accounts {
if account.Frequency == "weekly" {
now := time.Now().In(account.TimezoneLocation)
if now.Weekday() != account.WeeklyDay {
c.Infof("Skipping %d, since it wants weekly digests on %ss and today is a %s.",
account.GitHubUserId, account.WeeklyDay, now.Weekday())
continue
}
}
c.Infof("Enqueing task for %d...", account.GitHubUserId)
sendDigestForAccountFunc.Call(c, account.GitHubUserId)
}
fmt.Fprint(w, "Done")
}
@ -421,6 +429,14 @@ func saveSettingsHandler(w http.ResponseWriter, r *http.Request) {
return
}
account.Frequency = r.FormValue("frequency")
weeklyDay, err := strconv.Atoi(r.FormValue("weekly_day"))
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
account.WeeklyDay = time.Weekday(weeklyDay)
timezoneName := r.FormValue("timezone_name")
_, err = time.LoadLocation(timezoneName)
if err != nil {

View file

@ -15,18 +15,43 @@
<form method="POST" action="{{routeUrl "save-settings"}}">
<div class="setting">
<label>
Frequency:
<select name="frequency" id="frequency" onchange="updateWeeklyDayContainer()">
<option value="daily" {{if eq "daily" .Account.Frequency}}selected{{end}}>Daily</option>
<option value="weekly" {{if eq "weekly" .Account.Frequency}}selected{{end}}>Weekly</option>
</select>
<span id="weekly-day-container">
on
<select name="weekly_day">
<option value="0" {{if eq 0 .Account.WeeklyDay}}selected{{end}}>Sundays</option>
<option value="1" {{if eq 1 .Account.WeeklyDay}}selected{{end}}>Mondays</option>
<option value="2" {{if eq 2 .Account.WeeklyDay}}selected{{end}}>Tuesdays</option>
<option value="3" {{if eq 3 .Account.WeeklyDay}}selected{{end}}>Wednesdays</option>
<option value="4" {{if eq 4 .Account.WeeklyDay}}selected{{end}}>Thursdays</option>
<option value="5" {{if eq 5 .Account.WeeklyDay}}selected{{end}}>Fridays</option>
<option value="6" {{if eq 6 .Account.WeeklyDay}}selected{{end}}>Saturdays</option>
</select>
</span>
<div class="explanation">
How often you'd like to get digests. If there is no activity on that day or week, then no email will be sent.
</div>
</label>
</div>
<div class="setting">
<label>
Timezone:
<select name="timezone_name">
{{$accountTimezoneName := .Account.TimezoneName}}
{{range .Timezones}}
{{if .LocationName}}
<option value="{{.LocationName}}" {{if eq .LocationName $accountTimezoneName}}selected{{end}}>{{.LocationName}} (GMT {{.DisplayUTCOffset}})</option>
{{else}}
<option disabled></option>
{{end}}
{{$accountTimezoneName := .Account.TimezoneName}}
{{range .Timezones}}
{{if .LocationName}}
<option value="{{.LocationName}}" {{if eq .LocationName $accountTimezoneName}}selected{{end}}>{{.LocationName}} (GMT {{.DisplayUTCOffset}})</option>
{{else}}
<option disabled></option>
{{end}}
{{end}}
</select>
<div class="explanation">
Used for determining day boundaries and timestamps in emails.
@ -96,5 +121,18 @@
<input type="submit" value="Save Settings">
</form>
<script>
function updateWeeklyDayContainer() {
var frequencyNode = document.getElementById("frequency");
var weeklyDayContainerNode = document.getElementById("weekly-day-container");
if (frequencyNode.value == "weekly") {
weeklyDayContainerNode.style.display = "inline";
} else {
weeklyDayContainerNode.style.display = "none";
}
}
updateWeeklyDayContainer();
</script>
{{end}}

View file

@ -16,6 +16,7 @@
</p>
{{range .IntervalDigests }}
{{$interval := .}}
<h1 style="{{style "interval-header"}}">{{.Header}}</h1>
<p>{{.Description}}</p>
@ -36,7 +37,7 @@
<a href="{{.URL}}"
style="{{style "link" "commit.footer.link"}}">{{.DisplaySHA}}</a>
<i title={{.DisplayDateTooltip}}
style="{{style "commit.footer.date"}}">{{.DisplayDate}}</i>
style="{{style "commit.footer.date"}}">{{if $interval.Weekly}}{{.WeeklyDisplayDate}}{{else}}{{.DisplayDate}}{{end}}</i>
</div>
</div>
{{end}}