Partial implementation of the SQL version of the user storage interface
Signed-off-by: Ethan Wellenreiter <ewellenreiter@gmail.com>
This commit is contained in:
parent
fc11937b07
commit
970cf0274e
@ -3,6 +3,7 @@ package storage
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -11,21 +12,175 @@ type SQLUsersStore struct {
|
||||
}
|
||||
|
||||
func (s *SQLUsersStore) GetByID(ctx context.Context, id int64) (*User, error) {
|
||||
return nil, nil
|
||||
query := `SELECT users.id, users.username, users.email, users.password, users.created_at, roles.*
|
||||
FROM users
|
||||
JOIN roles ON (users.role_id = roles.id)
|
||||
WHERE users.id = $1 AND is_active = true`
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, QueryTimeoutDuration)
|
||||
defer cancel()
|
||||
|
||||
user := &User{}
|
||||
err := s.db.QueryRowContext(
|
||||
ctx,
|
||||
query,
|
||||
id,
|
||||
).Scan(
|
||||
&user.ID,
|
||||
&user.Username,
|
||||
&user.Email,
|
||||
&user.Password.hash,
|
||||
&user.CreatedAt,
|
||||
&user.Role.ID,
|
||||
&user.Role.Name,
|
||||
&user.Role.Level,
|
||||
&user.Role.Description,
|
||||
)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case sql.ErrNoRows:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (s *SQLUsersStore) GetByEmail(context.Context, string) (*User, error) {
|
||||
return nil, nil
|
||||
func (s *SQLUsersStore) GetByEmail(ctx context.Context, email string) (*User, error) {
|
||||
query := `SELECT users.id, users.username, users.email, users.password, users.created_at, roles.*
|
||||
FROM users
|
||||
JOIN roles ON (users.role_id = roles.id)
|
||||
WHERE users.email = $1 AND is_active = true`
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, QueryTimeoutDuration)
|
||||
defer cancel()
|
||||
|
||||
user := &User{}
|
||||
err := s.db.QueryRowContext(
|
||||
ctx,
|
||||
query,
|
||||
email,
|
||||
).Scan(
|
||||
&user.ID,
|
||||
&user.Username,
|
||||
&user.Email,
|
||||
&user.Password.hash,
|
||||
&user.CreatedAt,
|
||||
&user.Role.ID,
|
||||
&user.Role.Name,
|
||||
&user.Role.Level,
|
||||
&user.Role.Description,
|
||||
)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case sql.ErrNoRows:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (s *SQLUsersStore) GetByUsername(context.Context, string) (*User, error) {
|
||||
return nil, nil
|
||||
func (s *SQLUsersStore) GetByUsername(ctx context.Context, username string) (*User, error) {
|
||||
query := `SELECT users.id, users.username, users.email, users.password, users.created_at, roles.*
|
||||
FROM users
|
||||
JOIN roles ON (users.role_id = roles.id)
|
||||
WHERE users.username = $1 AND is_active = true`
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, QueryTimeoutDuration)
|
||||
defer cancel()
|
||||
|
||||
user := &User{}
|
||||
err := s.db.QueryRowContext(
|
||||
ctx,
|
||||
query,
|
||||
username,
|
||||
).Scan(
|
||||
&user.ID,
|
||||
&user.Username,
|
||||
&user.Email,
|
||||
&user.Password.hash,
|
||||
&user.CreatedAt,
|
||||
&user.Role.ID,
|
||||
&user.Role.Name,
|
||||
&user.Role.Level,
|
||||
&user.Role.Description,
|
||||
)
|
||||
if err != nil {
|
||||
switch err {
|
||||
case sql.ErrNoRows:
|
||||
return nil, ErrNotFound
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (s *SQLUsersStore) Create(context.Context, *User) error { // create a non-exported create function which does take in the tx
|
||||
func (s *SQLUsersStore) create(ctx context.Context, user *User, tx *sql.Tx) error { // creates the personal group and binds them
|
||||
ctx, cancel := context.WithTimeout(ctx, QueryTimeoutDuration)
|
||||
defer cancel()
|
||||
|
||||
query := `INSERT INTO groups (name, owner) VALUES ($1, $2) RETURNING id`
|
||||
|
||||
err := tx.QueryRowContext(ctx, query, fmt.Sprintf("User-%d-Personal-Group", user.ID), user.ID).Scan(&user.PersonalGroup)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query = `INSERT INTO users (username, password, email, role_id, personalgroup) VALUES
|
||||
($1, $2, $3, (SELECT id FROM roles WHERE name = $4), $5)
|
||||
RETURNING id, created_at`
|
||||
|
||||
role := user.Role.Name
|
||||
if role == "" {
|
||||
role = "user"
|
||||
}
|
||||
|
||||
err = tx.QueryRowContext(
|
||||
ctx,
|
||||
query,
|
||||
user.Username,
|
||||
user.Password,
|
||||
user.Email,
|
||||
role,
|
||||
user.PersonalGroup,
|
||||
).Scan(
|
||||
&user.ID,
|
||||
&user.CreatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
switch {
|
||||
case err.Error() == `pq: duplicate key value violates unique constraint "users_email_key"`:
|
||||
return ErrDuplicateEmail
|
||||
case err.Error() == `pq: duplicate key value violates unique constraint "users_username_key"`:
|
||||
return ErrDuplicateUsername
|
||||
default:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
query = `INSERT INTO groupMembership (groupid, userid, moderator) VALUES ($1, $2, $3)`
|
||||
|
||||
_, err = tx.ExecContext(ctx, query, user.PersonalGroup, user.ID, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLUsersStore) Create(ctx context.Context, user *User) error { // create a non-exported create function which does take in the tx
|
||||
return withTx(s.db, ctx, func(tx *sql.Tx) error {
|
||||
return s.create(ctx, user, tx)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SQLUsersStore) CreateAndInvite(ctx context.Context, user *User, token string, exp time.Duration) error { // figure this out
|
||||
return nil
|
||||
}
|
||||
@ -34,10 +189,35 @@ func (s *SQLUsersStore) Activate(context.Context, string) error { // what does t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLUsersStore) Delete(ctx context.Context, id int64) error {
|
||||
func (s *SQLUsersStore) delete(ctx context.Context, id int64, tx *sql.Tx) error {
|
||||
query := `DELETE FROM users WHERE id = $1`
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, QueryTimeoutDuration)
|
||||
defer cancel()
|
||||
|
||||
res, err := s.db.ExecContext(ctx, query, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rows, err := res.RowsAffected()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if rows == 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLUsersStore) Delete(ctx context.Context, id int64) error {
|
||||
return withTx(s.db, ctx, func(tx *sql.Tx) error {
|
||||
return s.delete(ctx, id, tx)
|
||||
})
|
||||
}
|
||||
|
||||
func (s *SQLUsersStore) UpdateUserPass(ctx context.Context, user string, oldPassword string, newPass string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user