Implement token add and get
This commit is contained in:
parent
4e9072c28a
commit
a173f15a57
37
random/random.go
Normal file
37
random/random.go
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
package random
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
}
|
||||||
|
|
||||||
|
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
const (
|
||||||
|
letterIdxBits = 6 // 6 bits to represent a letter index
|
||||||
|
letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
|
||||||
|
letterIdxMax = 63 / letterIdxBits // # of letter indices fitting in 63 bits
|
||||||
|
)
|
||||||
|
|
||||||
|
var src = rand.NewSource(time.Now().UnixNano())
|
||||||
|
|
||||||
|
func String(n int) string {
|
||||||
|
b := make([]byte, n)
|
||||||
|
// A src.Int63() generates 63 random bits, enough for letterIdxMax characters!
|
||||||
|
for i, cache, remain := n-1, src.Int63(), letterIdxMax; i >= 0; {
|
||||||
|
if remain == 0 {
|
||||||
|
cache, remain = src.Int63(), letterIdxMax
|
||||||
|
}
|
||||||
|
if idx := int(cache & letterIdxMask); idx < len(letterBytes) {
|
||||||
|
b[i] = letterBytes[idx]
|
||||||
|
i--
|
||||||
|
}
|
||||||
|
cache >>= letterIdxBits
|
||||||
|
remain--
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(b)
|
||||||
|
}
|
52
users.go
52
users.go
@ -1,18 +1,30 @@
|
|||||||
package users
|
package users
|
||||||
|
|
||||||
import "github.com/jmoiron/sqlx"
|
import (
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"gitlab.quimbo.fr/odwrtw/canape-sql/random"
|
||||||
|
)
|
||||||
|
|
||||||
const usersCreate = `
|
const usersCreate = `
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id SERIAL,
|
id SERIAL PRIMARY KEY,
|
||||||
name text NOT NULL UNIQUE
|
name text NOT NULL UNIQUE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE token (
|
||||||
|
id SERIAL,
|
||||||
|
value text NOT NULL UNIQUE,
|
||||||
|
users_id integer REFERENCES users (id) ON DELETE CASCADE
|
||||||
|
);
|
||||||
`
|
`
|
||||||
const (
|
const (
|
||||||
addUserQuery = `INSERT INTO users (name) VALUES ($1) RETURNING id;`
|
addUserQuery = `INSERT INTO users (name) VALUES ($1) RETURNING id;`
|
||||||
getUserQuery = `SELECT * FROM users WHERE name=$1;`
|
getUserQuery = `SELECT * FROM users WHERE name=$1;`
|
||||||
updateUserQuery = `UPDATE users SET (name)=(:name);`
|
updateUserQuery = `UPDATE users SET (name)=(:name);`
|
||||||
deleteUseQuery = `DELETE FROM users WHERE id=:id;`
|
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;`
|
||||||
)
|
)
|
||||||
|
|
||||||
// User represents an user
|
// User represents an user
|
||||||
@ -21,6 +33,11 @@ type User struct {
|
|||||||
Name string
|
Name string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Token struct {
|
||||||
|
ID int
|
||||||
|
Value string
|
||||||
|
}
|
||||||
|
|
||||||
// Get returns user with specified name
|
// Get returns user with specified name
|
||||||
func Get(q sqlx.Queryer, name string) (*User, error) {
|
func Get(q sqlx.Queryer, name string) (*User, error) {
|
||||||
u := &User{}
|
u := &User{}
|
||||||
@ -59,3 +76,34 @@ func (u *User) Delete(ex *sqlx.DB) error {
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *User) GetTokens(ex *sqlx.DB) ([]*Token, error) {
|
||||||
|
tokens := []*Token{}
|
||||||
|
err := ex.Select(&tokens, getTokensQuery, u.ID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return tokens, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) NewToken(ex *sqlx.DB) (*Token, error) {
|
||||||
|
t := &Token{
|
||||||
|
Value: random.String(50),
|
||||||
|
}
|
||||||
|
|
||||||
|
var id int
|
||||||
|
err := ex.QueryRowx(addTokenQuery, t.Value, u.ID).Scan(&id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
t.ID = id
|
||||||
|
return t, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) CheckToken(ex *sqlx.DB, value string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) DeleteToken(ex *sqlx.DB, value string) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -11,7 +11,9 @@ import (
|
|||||||
"github.com/lib/pq"
|
"github.com/lib/pq"
|
||||||
)
|
)
|
||||||
|
|
||||||
const drop = `DROP TABLE users;`
|
const drop = `
|
||||||
|
DROP TABLE token;
|
||||||
|
DROP TABLE users;`
|
||||||
|
|
||||||
var db *sqlx.DB
|
var db *sqlx.DB
|
||||||
|
|
||||||
@ -94,3 +96,43 @@ func TestUser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTokenAddDelete(t *testing.T) {
|
||||||
|
sqltest.RunWithSchema(db, usersCreate, drop, t, func(db *sqlx.DB, t *testing.T) {
|
||||||
|
// Add a new user
|
||||||
|
u := &User{Name: "plop"}
|
||||||
|
err := u.Add(db)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add many token
|
||||||
|
_, err = u.NewToken(db)
|
||||||
|
_, err = u.NewToken(db)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get token
|
||||||
|
tokens, err := u.GetTokens(db)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(tokens) != 2 {
|
||||||
|
t.Fatalf("Unexpected number of token: %q", len(tokens))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove user and test auto delete token
|
||||||
|
u.Delete(db)
|
||||||
|
q := `SELECT count(*) FROM token WHERE users_id=$1;`
|
||||||
|
var count int
|
||||||
|
err = db.QueryRowx(q, u.ID).Scan(&count)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if count != 0 {
|
||||||
|
t.Fatalf("Unexpected number of token: %d", count)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user