diff --git a/users.go b/users.go index a20fc2a..aa5894f 100644 --- a/users.go +++ b/users.go @@ -1,6 +1,8 @@ package users import ( + "fmt" + "github.com/jmoiron/sqlx" "gitlab.quimbo.fr/odwrtw/canape-sql/random" ) @@ -11,7 +13,7 @@ CREATE TABLE users ( name text NOT NULL UNIQUE ); -CREATE TABLE token ( +CREATE TABLE tokens ( id SERIAL, value text NOT NULL UNIQUE, users_id integer REFERENCES users (id) ON DELETE CASCADE @@ -23,8 +25,10 @@ const ( updateUserQuery = `UPDATE users SET (name)=(:name);` deleteUseQuery = `DELETE FROM users WHERE id=:id;` - addTokenQuery = `INSERT INTO token (value, users_id) VALUES ($1, $2) RETURNING id;` - getTokensQuery = `SELECT id, value FROM token WHERE users_id=$1;` + addTokenQuery = `INSERT INTO tokens (value, users_id) VALUES ($1, $2) RETURNING id;` + getTokensQuery = `SELECT id, value FROM tokens WHERE users_id=$1;` + checkTokenQuery = `SELECT count(*) FROM tokens WHERE users_id=$1 AND value=$2;` + deleteTokenQuery = `DELETE FROM tokens WHERE users_id=$1 AND value=$2;` ) // User represents an user @@ -33,6 +37,7 @@ type User struct { Name string } +// Token represents a token type Token struct { ID int Value string @@ -77,6 +82,7 @@ func (u *User) Delete(ex *sqlx.DB) error { return nil } +// GetTokens returns all tokens owned by the user func (u *User) GetTokens(ex *sqlx.DB) ([]*Token, error) { tokens := []*Token{} err := ex.Select(&tokens, getTokensQuery, u.ID) @@ -86,6 +92,7 @@ func (u *User) GetTokens(ex *sqlx.DB) ([]*Token, error) { return tokens, nil } +// NewToken generates a new token for the user func (u *User) NewToken(ex *sqlx.DB) (*Token, error) { t := &Token{ Value: random.String(50), @@ -100,10 +107,28 @@ func (u *User) NewToken(ex *sqlx.DB) (*Token, error) { return t, nil } -func (u *User) CheckToken(ex *sqlx.DB, value string) error { - return nil +// CheckToken checks if specified value exists in token's values for the user +func (u *User) CheckToken(ex *sqlx.DB, value string) (bool, error) { + var count int + err := ex.QueryRowx(checkTokenQuery, u.ID, value).Scan(&count) + if err != nil { + return false, err + } + if count != 1 { + return false, nil + } + return true, nil } +// DeleteToken delete token by value func (u *User) DeleteToken(ex *sqlx.DB, value string) error { + r, err := ex.Exec(deleteTokenQuery, u.ID, value) + if err != nil { + return err + } + count, _ := r.RowsAffected() + if count != 1 { + return fmt.Errorf("Unexpected number of row deleted: %d", count) + } return nil } diff --git a/users_test.go b/users_test.go index f38043e..700bfcf 100644 --- a/users_test.go +++ b/users_test.go @@ -12,7 +12,7 @@ import ( ) const drop = ` -DROP TABLE token; +DROP TABLE tokens; DROP TABLE users;` var db *sqlx.DB @@ -109,6 +109,7 @@ func TestTokenAddDelete(t *testing.T) { // Add many token _, err = u.NewToken(db) _, err = u.NewToken(db) + token, err := u.NewToken(db) if err != nil { t.Fatal(err) } @@ -118,13 +119,32 @@ func TestTokenAddDelete(t *testing.T) { if err != nil { t.Fatal(err) } + if len(tokens) != 3 { + t.Fatalf("Unexpected number of token: %q", len(tokens)) + } + + // Delete token + err = u.DeleteToken(db, token.Value) + if err != nil { + t.Fatal(err) + } + tokens, _ = u.GetTokens(db) if len(tokens) != 2 { t.Fatalf("Unexpected number of token: %q", len(tokens)) } + // Delete a fake token + err = u.DeleteToken(db, "plop") + if err == nil { + t.Fatalf("We expect an error when try to delete a fake token") + } + if err.Error() != "Unexpected number of row deleted: 0" { + t.Fatalf("Unexpected error: %q", err) + } + // Remove user and test auto delete token u.Delete(db) - q := `SELECT count(*) FROM token WHERE users_id=$1;` + q := `SELECT count(*) FROM tokens WHERE users_id=$1;` var count int err = db.QueryRowx(q, u.ID).Scan(&count) if err != nil { @@ -136,3 +156,29 @@ func TestTokenAddDelete(t *testing.T) { }) } + +func TestTokenCheck(t *testing.T) { + sqltest.RunWithSchema(db, usersCreate, drop, t, func(db *sqlx.DB, t *testing.T) { + u := &User{Name: "plop"} + u.Add(db) + token, err := u.NewToken(db) + + ok, err := u.CheckToken(db, token.Value) + if err != nil { + t.Fatal(err) + } + if !ok { + t.Fatalf("Token not found") + } + + // test fake token + ok, err = u.CheckToken(db, "plop") + if err != nil { + t.Fatal(err) + } + if ok { + t.Fatalf("Token found otherwise we don't expect") + } + + }) +}