Add an endpoint to validate and register profiles.
Add a newProfileRequest object that defines the user-specified properties of a
new Profile.
Add a helper that validates a newProfileRequest and modifies it for
sanitization, mostly just removing leading and trailing whitespace.
Add MaxNameLength, MaxUsernameLength, and MaxEmailLength constants to hold the
maximum length for those properties.
Add errors to be returned when a users attempts to log in with a profile that is
compromised or locked.
Add the bare bones of a CreateProfileHandler that validates a profile
registration request adn uses it to create a Profile and at least one Login.
Create a requestError struct that is used for returning API errors, along with
constants for the slugs we'll use to signal those errors.
7 "code.secondbit.org/uuid"
10 var sessionStores = []sessionStore{NewMemstore()}
12 func compareSessions(session1, session2 Session) (success bool, field string, val1, val2 interface{}) {
13 if session1.ID != session2.ID {
14 return false, "ID", session1.ID, session2.ID
16 if session1.IP != session2.IP {
17 return false, "IP", session1.IP, session2.IP
19 if session1.UserAgent != session2.UserAgent {
20 return false, "UserAgent", session1.UserAgent, session2.UserAgent
22 if !session1.ProfileID.Equal(session2.ProfileID) {
23 return false, "ProfileID", session1.ProfileID, session2.ProfileID
25 if !session1.Created.Equal(session2.Created) {
26 return false, "Created", session1.Created, session2.Created
28 if session1.Login != session2.Login {
29 return false, "Login", session1.Login, session2.Login
31 if session1.Active != session2.Active {
32 return false, "Active", session1.Active, session2.Active
34 return true, "", nil, nil
37 func TestSessionStoreSuccess(t *testing.T) {
40 ID: uuid.NewID().String() + uuid.NewID().String(),
42 UserAgent: "TestRunner",
43 ProfileID: uuid.NewID(),
45 Login: "test@example.com",
48 for _, store := range sessionStores {
49 err := store.createSession(session)
51 t.Errorf("Error saving session to %T: %s", store, err)
53 err = store.createSession(session)
54 if err != ErrSessionAlreadyExists {
55 t.Errorf("Expected ErrSessionAlreadyExists from %T, got %s", store, err)
57 retrieved, err := store.getSession(session.ID)
59 t.Errorf("Error retrieving session from %T: %s", store, err)
61 success, field, expectation, result := compareSessions(session, retrieved)
63 t.Errorf("Expected field %s to be %v, but got %v from %T", field, expectation, result, store)
65 retrievedList, err := store.listSessions(session.ProfileID, time.Time{}, 10)
67 t.Errorf("Error retrieving sessions by profile from %T: %s", store, err)
69 if len(retrievedList) != 1 {
70 t.Errorf("Expected 1 session retrieved by profile from %T, got %d", store, len(retrievedList))
72 success, field, expectation, result = compareSessions(session, retrievedList[0])
74 t.Errorf("Expected field %s to be %v, but got %v from %T", field, expectation, result, store)
76 err = store.removeSession(session.ID)
78 t.Errorf("Error removing session from %T: %s", store, err)
80 retrieved, err = store.getSession(session.ID)
81 if err != ErrSessionNotFound {
82 t.Errorf("Expected ErrSessionNotFound from %T, got %s", store, err)
84 retrievedList, err = store.listSessions(session.ProfileID, time.Time{}, 10)
86 t.Errorf("Error retrieving sessions by profile from %T: %s", store, err)
88 if len(retrievedList) != 0 {
89 t.Errorf("Expected 0 sessions retrieved by profile from %T, got %d", store, len(retrievedList))
91 err = store.removeSession(session.ID)
92 if err != ErrSessionNotFound {
93 t.Errorf("Expected ErrSessionNotFound from %T, got %s", store, err)