Add self-service person-level opt-out with full removal at load
This commit is contained in:
@@ -47,7 +47,7 @@ var overrideColumns = []string{
|
||||
"Email", "Added", "Full Name", "Legal Name", "Preferred Name",
|
||||
"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",
|
||||
"Address", "Family Phone", "Family Photo Caption", "Opted Out",
|
||||
}
|
||||
|
||||
type BlobChecker interface {
|
||||
@@ -282,6 +282,7 @@ func LoadModel(source data.Source, blobs BlobChecker) (*Model, error) {
|
||||
bandSet[band] = true
|
||||
}
|
||||
roomParents := map[string][]string{}
|
||||
optedOut := map[string]bool{}
|
||||
|
||||
seenOverride := map[string]bool{}
|
||||
for _, row := range overrideRows {
|
||||
@@ -383,6 +384,14 @@ func LoadModel(source data.Source, blobs BlobChecker) (*Model, error) {
|
||||
familyOverrides[email] = cells
|
||||
}
|
||||
|
||||
switch row["Opted Out"] {
|
||||
case "", "-", "FALSE":
|
||||
case "TRUE":
|
||||
optedOut[email] = true
|
||||
default:
|
||||
return nil, fmt.Errorf("overrides row %s has invalid Opted Out %q", email, row["Opted Out"])
|
||||
}
|
||||
|
||||
if added {
|
||||
if p.FullName == "" {
|
||||
return nil, fmt.Errorf("added row %s has no full name", email)
|
||||
@@ -401,15 +410,13 @@ func LoadModel(source data.Source, blobs BlobChecker) (*Model, error) {
|
||||
members := append(append([]string{}, hh.adults...), hh.kids...)
|
||||
key := familyHash(members)
|
||||
familyKeys[setKey] = key
|
||||
family := Family{
|
||||
model.Families[key] = Family{
|
||||
Key: key,
|
||||
Address: hh.address,
|
||||
Phone: hh.phone,
|
||||
AdultEmails: hh.adults,
|
||||
KidEmails: hh.kids,
|
||||
}
|
||||
family.Name = familyNameFor(family, people)
|
||||
model.Families[key] = family
|
||||
}
|
||||
for email, sets := range personHouseholds {
|
||||
if p := people[email]; p.FamilyKey == "" {
|
||||
@@ -439,6 +446,33 @@ func LoadModel(source data.Source, blobs BlobChecker) (*Model, error) {
|
||||
model.Families[key] = family
|
||||
}
|
||||
|
||||
for email := range optedOut {
|
||||
delete(people, email)
|
||||
}
|
||||
kept := []string{}
|
||||
for _, email := range order {
|
||||
if !optedOut[email] {
|
||||
kept = append(kept, email)
|
||||
}
|
||||
}
|
||||
order = kept
|
||||
for key, family := range model.Families {
|
||||
family.AdultEmails = without(family.AdultEmails, optedOut)
|
||||
family.KidEmails = without(family.KidEmails, optedOut)
|
||||
if len(family.AdultEmails)+len(family.KidEmails) == 0 {
|
||||
delete(model.Families, key)
|
||||
continue
|
||||
}
|
||||
family.Name = familyNameFor(family, people)
|
||||
model.Families[key] = family
|
||||
}
|
||||
for _, p := range people {
|
||||
p.ParentContactEmails = without(p.ParentContactEmails, optedOut)
|
||||
}
|
||||
for band, emails := range roomParents {
|
||||
roomParents[band] = without(emails, optedOut)
|
||||
}
|
||||
|
||||
if blobs != nil {
|
||||
for _, p := range people {
|
||||
local, _, _ := strings.Cut(p.Email, "@")
|
||||
@@ -603,6 +637,16 @@ func bandLabel(band string) string {
|
||||
return strings.Join(labels, " / ")
|
||||
}
|
||||
|
||||
func without(list []string, drop map[string]bool) []string {
|
||||
kept := []string{}
|
||||
for _, item := range list {
|
||||
if !drop[item] {
|
||||
kept = append(kept, item)
|
||||
}
|
||||
}
|
||||
return kept
|
||||
}
|
||||
|
||||
func surname(fullName string) string {
|
||||
fields := strings.Fields(fullName)
|
||||
if len(fields) == 0 {
|
||||
|
||||
@@ -62,6 +62,26 @@ func RegisterUpload(mux *http.ServeMux, cache *Cache, sheet *data.Sheet, store *
|
||||
u := uploader{cache: cache, sheet: sheet, store: store}
|
||||
mux.HandleFunc("POST /api/directory/upload", u.upload)
|
||||
mux.HandleFunc("POST /api/directory/facts", u.facts)
|
||||
mux.HandleFunc("POST /api/directory/optout", u.optOut)
|
||||
}
|
||||
|
||||
func (u uploader) optOut(w http.ResponseWriter, r *http.Request) {
|
||||
me := strings.ToLower(auth.Email(r))
|
||||
if err := u.sheet.Upsert(appName, "Overrides", "Email", me, "Opted Out", "TRUE"); err != nil {
|
||||
serverError(w, fmt.Errorf("opt out %s: %w", me, err))
|
||||
return
|
||||
}
|
||||
logRow := changeLogRow(me, me, map[string]string{"Opted Out": ""})
|
||||
if err := u.sheet.Append(appName, changeLogTable, changeLogHeader, logRow); err != nil {
|
||||
serverError(w, fmt.Errorf("append change log after opt out of %s: %w", me, err))
|
||||
return
|
||||
}
|
||||
if err := u.cache.Refresh(); err != nil {
|
||||
serverError(w, fmt.Errorf("refresh model after opt out: %w", err))
|
||||
return
|
||||
}
|
||||
log.Printf("optout: %s removed themselves from the directory", me)
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
func (u uploader) facts(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user