diff --git a/users.go b/users.go index 0918d04..ba655c2 100644 --- a/users.go +++ b/users.go @@ -34,6 +34,30 @@ func (s *UserService) GetCurrent(ctx context.Context) (*types.User, error) { return &out, nil } +// ListEmails returns all email addresses for the authenticated user. +func (s *UserService) ListEmails(ctx context.Context) ([]types.Email, error) { + return ListAll[types.Email](ctx, s.client, "/api/v1/user/emails", nil) +} + +// IterEmails returns an iterator over all email addresses for the authenticated user. +func (s *UserService) IterEmails(ctx context.Context) iter.Seq2[types.Email, error] { + return ListIter[types.Email](ctx, s.client, "/api/v1/user/emails", nil) +} + +// AddEmails adds email addresses for the authenticated user. +func (s *UserService) AddEmails(ctx context.Context, emails ...string) ([]types.Email, error) { + var out []types.Email + if err := s.client.Post(ctx, "/api/v1/user/emails", types.CreateEmailOption{Emails: emails}, &out); err != nil { + return nil, err + } + return out, nil +} + +// DeleteEmails deletes email addresses for the authenticated user. +func (s *UserService) DeleteEmails(ctx context.Context, emails ...string) error { + return s.client.DeleteWithBody(ctx, "/api/v1/user/emails", types.DeleteEmailOption{Emails: emails}) +} + // ListFollowers returns all followers of a user. func (s *UserService) ListFollowers(ctx context.Context, username string) ([]types.User, error) { path := ResolvePath("/api/v1/users/{username}/followers", pathParams("username", username)) diff --git a/users_test.go b/users_test.go index bfda464..d5a5f0f 100644 --- a/users_test.go +++ b/users_test.go @@ -54,6 +54,96 @@ func TestUserService_GetCurrent_Good(t *testing.T) { } } +func TestUserService_ListEmails_Good(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + t.Errorf("expected GET, got %s", r.Method) + } + if r.URL.Path != "/api/v1/user/emails" { + t.Errorf("wrong path: %s", r.URL.Path) + } + w.Header().Set("X-Total-Count", "2") + json.NewEncoder(w).Encode([]types.Email{ + {Email: "alice@example.com", Primary: true}, + {Email: "alice+alt@example.com", Verified: true}, + }) + })) + defer srv.Close() + + f := NewForge(srv.URL, "tok") + emails, err := f.Users.ListEmails(context.Background()) + if err != nil { + t.Fatal(err) + } + if len(emails) != 2 { + t.Fatalf("got %d emails, want 2", len(emails)) + } + if emails[0].Email != "alice@example.com" || !emails[0].Primary { + t.Errorf("unexpected first email: %+v", emails[0]) + } +} + +func TestUserService_AddEmails_Good(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + t.Errorf("expected POST, got %s", r.Method) + } + if r.URL.Path != "/api/v1/user/emails" { + t.Errorf("wrong path: %s", r.URL.Path) + } + var body types.CreateEmailOption + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + t.Fatal(err) + } + if len(body.Emails) != 2 || body.Emails[0] != "alice@example.com" || body.Emails[1] != "alice+alt@example.com" { + t.Fatalf("unexpected body: %+v", body) + } + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode([]types.Email{ + {Email: "alice@example.com", Primary: true}, + {Email: "alice+alt@example.com", Verified: true}, + }) + })) + defer srv.Close() + + f := NewForge(srv.URL, "tok") + emails, err := f.Users.AddEmails(context.Background(), "alice@example.com", "alice+alt@example.com") + if err != nil { + t.Fatal(err) + } + if len(emails) != 2 { + t.Fatalf("got %d emails, want 2", len(emails)) + } + if emails[1].Email != "alice+alt@example.com" || !emails[1].Verified { + t.Errorf("unexpected second email: %+v", emails[1]) + } +} + +func TestUserService_DeleteEmails_Good(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodDelete { + t.Errorf("expected DELETE, got %s", r.Method) + } + if r.URL.Path != "/api/v1/user/emails" { + t.Errorf("wrong path: %s", r.URL.Path) + } + var body types.DeleteEmailOption + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + t.Fatal(err) + } + if len(body.Emails) != 1 || body.Emails[0] != "alice+alt@example.com" { + t.Fatalf("unexpected body: %+v", body) + } + w.WriteHeader(http.StatusNoContent) + })) + defer srv.Close() + + f := NewForge(srv.URL, "tok") + if err := f.Users.DeleteEmails(context.Background(), "alice+alt@example.com"); err != nil { + t.Fatal(err) + } +} + func TestUserService_ListFollowers_Good(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet {