···107107 -- identifiers
108108 id integer primary key autoincrement,
109109 pull_id integer not null,
110110-110110+111111 -- at identifiers
112112 repo_at text not null,
113113 owner_did text not null,
···194194 created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
195195 foreign key (repo_at) references repos(at_uri) on delete cascade,
196196 unique(starred_by_did, repo_at)
197197+ );
198198+199199+ create table if not exists emails (
200200+ id integer primary key autoincrement,
201201+ did text not null,
202202+ email text not null,
203203+ verified integer not null default 0,
204204+ verification_code text not null,
205205+ is_primary integer not null default 0,
206206+ created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
207207+ unique(did, email)
197208 );
198209199210 create table if not exists migrations (
+203
appview/db/email.go
···11+package db
22+33+import "time"
44+55+type Email struct {
66+ ID int64
77+ Did string
88+ Address string
99+ Verified bool
1010+ Primary bool
1111+ VerificationCode string
1212+ CreatedAt time.Time
1313+}
1414+1515+func GetPrimaryEmail(e Execer, did string) (Email, error) {
1616+ query := `
1717+ select id, did, email, verified, is_primary, verification_code, created
1818+ from emails
1919+ where did = ? and is_primary = true
2020+ `
2121+ var email Email
2222+ var createdStr string
2323+ err := e.QueryRow(query, did).Scan(&email.ID, &email.Did, &email.Address, &email.Verified, &email.Primary, &email.VerificationCode, &createdStr)
2424+ if err != nil {
2525+ return Email{}, err
2626+ }
2727+ email.CreatedAt, err = time.Parse(time.RFC3339, createdStr)
2828+ if err != nil {
2929+ return Email{}, err
3030+ }
3131+ return email, nil
3232+}
3333+3434+func GetEmail(e Execer, did string, em string) (Email, error) {
3535+ query := `
3636+ select id, did, email, verified, is_primary, verification_code, created
3737+ from emails
3838+ where did = ? and email = ?
3939+ `
4040+ var email Email
4141+ var createdStr string
4242+ err := e.QueryRow(query, did, em).Scan(&email.ID, &email.Did, &email.Address, &email.Verified, &email.Primary, &email.VerificationCode, &createdStr)
4343+ if err != nil {
4444+ return Email{}, err
4545+ }
4646+ email.CreatedAt, err = time.Parse(time.RFC3339, createdStr)
4747+ if err != nil {
4848+ return Email{}, err
4949+ }
5050+ return email, nil
5151+}
5252+5353+func GetDidForEmail(e Execer, em string) (string, error) {
5454+ query := `
5555+ select did
5656+ from emails
5757+ where email = ?
5858+ `
5959+ var did string
6060+ err := e.QueryRow(query, em).Scan(&did)
6161+ if err != nil {
6262+ return "", err
6363+ }
6464+ return did, nil
6565+}
6666+6767+func GetVerificationCodeForEmail(e Execer, did string, email string) (string, error) {
6868+ query := `
6969+ select verification_code
7070+ from emails
7171+ where did = ? and email = ?
7272+ `
7373+ var code string
7474+ err := e.QueryRow(query, did, email).Scan(&code)
7575+ if err != nil {
7676+ return "", err
7777+ }
7878+ return code, nil
7979+}
8080+8181+func CheckEmailExists(e Execer, did string, email string) (bool, error) {
8282+ query := `
8383+ select count(*)
8484+ from emails
8585+ where did = ? and email = ?
8686+ `
8787+ var count int
8888+ err := e.QueryRow(query, did, email).Scan(&count)
8989+ if err != nil {
9090+ return false, err
9191+ }
9292+ return count > 0, nil
9393+}
9494+9595+func CheckValidVerificationCode(e Execer, did string, email string, code string) (bool, error) {
9696+ query := `
9797+ select count(*)
9898+ from emails
9999+ where did = ? and email = ? and verification_code = ?
100100+ `
101101+ var count int
102102+ err := e.QueryRow(query, did, email, code).Scan(&count)
103103+ if err != nil {
104104+ return false, err
105105+ }
106106+ return count > 0, nil
107107+}
108108+109109+func AddEmail(e Execer, email Email) error {
110110+ // Check if this is the first email for this DID
111111+ countQuery := `
112112+ select count(*)
113113+ from emails
114114+ where did = ?
115115+ `
116116+ var count int
117117+ err := e.QueryRow(countQuery, email.Did).Scan(&count)
118118+ if err != nil {
119119+ return err
120120+ }
121121+122122+ // If this is the first email, mark it as primary
123123+ if count == 0 {
124124+ email.Primary = true
125125+ }
126126+127127+ query := `
128128+ insert into emails (did, email, verified, is_primary, verification_code)
129129+ values (?, ?, ?, ?, ?)
130130+ `
131131+ _, err = e.Exec(query, email.Did, email.Address, email.Verified, email.Primary, email.VerificationCode)
132132+ return err
133133+}
134134+135135+func DeleteEmail(e Execer, did string, email string) error {
136136+ query := `
137137+ delete from emails
138138+ where did = ? and email = ?
139139+ `
140140+ _, err := e.Exec(query, did, email)
141141+ return err
142142+}
143143+144144+func MarkEmailVerified(e Execer, did string, email string) error {
145145+ query := `
146146+ update emails
147147+ set verified = true
148148+ where did = ? and email = ?
149149+ `
150150+ _, err := e.Exec(query, did, email)
151151+ return err
152152+}
153153+154154+func MakeEmailPrimary(e Execer, did string, email string) error {
155155+ // First, unset all primary emails for this DID
156156+ query1 := `
157157+ update emails
158158+ set is_primary = false
159159+ where did = ?
160160+ `
161161+ _, err := e.Exec(query1, did)
162162+ if err != nil {
163163+ return err
164164+ }
165165+166166+ // Then, set the specified email as primary
167167+ query2 := `
168168+ update emails
169169+ set is_primary = true
170170+ where did = ? and email = ?
171171+ `
172172+ _, err = e.Exec(query2, did, email)
173173+ return err
174174+}
175175+176176+func GetAllEmails(e Execer, did string) ([]Email, error) {
177177+ query := `
178178+ select did, email, verified, is_primary, verification_code, created
179179+ from emails
180180+ where did = ?
181181+ `
182182+ rows, err := e.Query(query, did)
183183+ if err != nil {
184184+ return nil, err
185185+ }
186186+ defer rows.Close()
187187+188188+ var emails []Email
189189+ for rows.Next() {
190190+ var email Email
191191+ var createdStr string
192192+ err := rows.Scan(&email.Did, &email.Address, &email.Verified, &email.Primary, &email.VerificationCode, &createdStr)
193193+ if err != nil {
194194+ return nil, err
195195+ }
196196+ email.CreatedAt, err = time.Parse(time.RFC3339, createdStr)
197197+ if err != nil {
198198+ return nil, err
199199+ }
200200+ emails = append(emails, email)
201201+ }
202202+ return emails, nil
203203+}