Prompt families to refresh photos and facts that have aged (#7)

This commit is contained in:
Ian Gulliver
2026-08-23 16:59:45 -07:00
parent c38084a7a4
commit e747510e11
11 changed files with 435 additions and 42 deletions
+36 -3
View File
@@ -72,6 +72,19 @@ var overrideColumns = []string{
"Is Student", "Is Parent", "Is Staff", "New to Helios", "Pronouns", "Facts",
"Grade", "Classroom", "Crew", "Phone", "Job Title", "Department", "Grade Band", "Room Parent",
"Address", "Family Phone", "Family Photo Caption", "Opted Out",
"Photo Updated", "Facts Updated", "Family Photo Updated",
}
const updatedFormat = "2006-01-02"
func checkUpdated(email, column, cell string) error {
if cell == "" || cell == "-" {
return nil
}
if _, err := time.Parse(updatedFormat, cell); err != nil {
return fmt.Errorf("overrides row %s has invalid %s %q", email, column, cell)
}
return nil
}
type BlobChecker interface {
@@ -115,8 +128,8 @@ type household struct {
}
type familyCells struct {
address, phone, caption string
hasAddress, hasPhone, hasCaption bool
address, phone, caption, photoUpdated string
hasAddress, hasPhone, hasCaption, hasPhotoUpdated bool
}
func exactColumns(table string, header, wanted []string) error {
@@ -447,6 +460,14 @@ func (l *loader) applyOverrides() error {
}
apply(row["Pronouns"], &p.Pronouns)
apply(row["Facts"], &p.Facts)
if err := checkUpdated(email, "Facts Updated", row["Facts Updated"]); err != nil {
return err
}
apply(row["Facts Updated"], &p.FactsUpdated)
if err := checkUpdated(email, "Photo Updated", row["Photo Updated"]); err != nil {
return err
}
apply(row["Photo Updated"], &p.PhotoUpdated)
if cell := row["Grade"]; cell != "" && cell != "-" && !added && gradeBands[cell] == "" {
return fmt.Errorf("overrides row %s has unknown grade %q", email, cell)
}
@@ -486,7 +507,16 @@ func (l *loader) applyOverrides() error {
cells.caption = cell
}
}
if cells.hasAddress || cells.hasPhone || cells.hasCaption {
if cell := row["Family Photo Updated"]; cell != "" {
if err := checkUpdated(email, "Family Photo Updated", cell); err != nil {
return err
}
cells.hasPhotoUpdated = true
if cell != "-" {
cells.photoUpdated = cell
}
}
if cells.hasAddress || cells.hasPhone || cells.hasCaption || cells.hasPhotoUpdated {
l.familyOverrides[email] = cells
}
@@ -558,6 +588,9 @@ func (l *loader) buildFamilies() error {
if cells.hasCaption {
family.PhotoCaption = cells.caption
}
if cells.hasPhotoUpdated {
family.PhotoUpdated = cells.photoUpdated
}
l.model.Families[key] = family
}
return nil
+3
View File
@@ -19,8 +19,10 @@ type Person struct {
IsNew bool `json:"isNew,omitempty"`
Pronouns string `json:"pronouns,omitempty"`
Facts string `json:"facts,omitempty"`
FactsUpdated string `json:"factsUpdated,omitempty"`
PronunciationURL string `json:"pronunciationUrl,omitempty"`
PhotoURL string `json:"photoUrl,omitempty"`
PhotoUpdated string `json:"photoUpdated,omitempty"`
Grade string `json:"grade,omitempty"`
Classroom string `json:"classroom,omitempty"`
Crew string `json:"crew,omitempty"`
@@ -45,6 +47,7 @@ type Family struct {
Lng float64 `json:"lng,omitempty"`
PhotoURL string `json:"photoUrl,omitempty"`
PhotoCaption string `json:"photoCaption,omitempty"`
PhotoUpdated string `json:"photoUpdated,omitempty"`
PronunciationURL string `json:"pronunciationUrl,omitempty"`
AdultEmails []string `json:"adultEmails,omitempty"`
KidEmails []string `json:"kidEmails,omitempty"`
+19 -4
View File
@@ -66,6 +66,10 @@ func RegisterUpload(mux *http.ServeMux, cache *Cache, sheet *data.Sheet, store *
mux.HandleFunc("POST /api/directory/edit", u.edit)
}
func today() string {
return time.Now().UTC().Format(updatedFormat)
}
func clearable(value string) string {
if value == "" {
return "-"
@@ -197,11 +201,13 @@ func (u uploader) facts(w http.ResponseWriter, r *http.Request) {
http.Error(w, "not allowed to edit this record", http.StatusForbidden)
return
}
old := ""
old, oldUpdated := "", ""
if p := model.Person(key); p != nil {
old = p.Facts
old, oldUpdated = p.Facts, p.FactsUpdated
}
if !u.applyOverride(w, me, key, "facts update", map[string]string{"Facts": facts}, map[string]string{"Facts": old}) {
cells := map[string]string{"Facts": facts, "Facts Updated": today()}
previous := map[string]string{"Facts": old, "Facts Updated": oldUpdated}
if !u.applyOverride(w, me, key, "facts update", cells, previous) {
return
}
log.Printf("facts: %s set %s (%d chars)", me, key, len(facts))
@@ -260,7 +266,16 @@ func (u uploader) upload(w http.ResponseWriter, r *http.Request) {
serverError(w, err)
return
}
if err := u.cache.Refresh(); err != nil {
if kind == "photo" {
row, column, previous := key, "Photo Updated", model.Person(key).PhotoUpdated
if target == "family" {
row, column, previous = strings.ToLower(me), "Family Photo Updated", model.Families[key].PhotoUpdated
}
if !u.applyOverride(w, me, row, "photo upload",
map[string]string{column: today()}, map[string]string{column: previous}) {
return
}
} else if err := u.cache.Refresh(); err != nil {
serverError(w, fmt.Errorf("refresh model after upload: %w", err))
return
}