diff --git a/backend/cmd/server/main.go b/backend/cmd/server/main.go deleted file mode 100644 index 7905807..0000000 --- a/backend/cmd/server/main.go +++ /dev/null @@ -1,5 +0,0 @@ -package main - -func main() { - -} diff --git a/backend/handler/auth.go b/backend/handler/auth.go deleted file mode 100644 index e69de29..0000000 diff --git a/backend/service/auth.go b/backend/service/auth.go deleted file mode 100644 index c170898..0000000 --- a/backend/service/auth.go +++ /dev/null @@ -1,58 +0,0 @@ -package service - -import ( - "context" - "errors" - - "git.nmcnew.com/nmcnew/bracketeer/db" - "golang.org/x/crypto/bcrypt" -) - -var ( - ErrAuthFailed = errors.New("auth values don't match") -) - -type AuthService interface { - Login(ctx context.Context, username string, authValue string, authType string) (*db.User, error) -} -type authService struct { - q *db.Queries -} - -func NewAuthService(q *db.Queries) AuthService { - return &authService{ - q: q, - } -} - -func (s *authService) Login(ctx context.Context, username, authValue, authType string) (*db.User, error) { - dbValue, err := s.q.GetUserAuthValue(ctx, db.GetUserAuthValueParams{ - Name: username, - Type: db.AuthTypeFromString(authType), - }) - if err != nil { - return nil, err - } - switch authType { - case "password": - err = bcrypt.CompareHashAndPassword([]byte(dbValue.AuthValue), []byte(authValue)) - if err != nil { - return nil, ErrAuthFailed - } - default: - if authValue != dbValue.AuthValue { - return nil, ErrAuthFailed - } - user, err := s.q.GetUserFromId(ctx, dbValue.UserID) - if err != nil { - return nil, err - } - return &user, nil - } - - return nil, ErrAuthFailed -} - -func (s *authService) Register(ctx context.Context, username, email, bio, profileURL, authValue, authType string) (*db.User, error) { - panic("unimplemented") -} diff --git a/db/helpers.go b/db/helpers.go deleted file mode 100644 index 6577d75..0000000 --- a/db/helpers.go +++ /dev/null @@ -1,11 +0,0 @@ -package db - -var authMap = map[string]AuthType{ - string(AuthTypePassword): AuthTypePassword, - string(AuthTypeDiscord): AuthTypeDiscord, - string(AuthTypeGoogle): AuthTypeGoogle, -} - -func AuthTypeFromString(input string) AuthType { - return authMap[input] -} diff --git a/db/migrations/0001_init.sql b/db/migrations/0001_init.sql index 6db1c36..d4aca3b 100644 --- a/db/migrations/0001_init.sql +++ b/db/migrations/0001_init.sql @@ -1,7 +1,7 @@ -- +goose Up -- create initial schema CREATE TABLE users ( - id UUID PRIMARY KEY , + id UUID PRIMARY KEY DEFAULT uuidv7(), name TEXT NOT NULL, email TEXT NOT NULL, bio TEXT NOT NULL default '', diff --git a/db/models.go b/db/models.go index 6b4383b..30f6ee1 100644 --- a/db/models.go +++ b/db/models.go @@ -8,6 +8,7 @@ import ( "database/sql/driver" "fmt" + "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" ) @@ -97,8 +98,8 @@ func (ns NullEntrantType) Value() (driver.Value, error) { } type AuthMethod struct { - ID pgtype.UUID `json:"id"` - UserID pgtype.UUID `json:"user_id"` + ID uuid.UUID `json:"id"` + UserID uuid.UUID `json:"user_id"` Type AuthType `json:"type"` Value string `json:"value"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` @@ -106,63 +107,63 @@ type AuthMethod struct { } type Bracket struct { - ID pgtype.UUID `json:"id"` + ID uuid.UUID `json:"id"` Name string `json:"name"` - EventID pgtype.UUID `json:"event_id"` + EventID uuid.UUID `json:"event_id"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` } type BracketEntrant struct { - ID pgtype.UUID `json:"id"` + ID uuid.UUID `json:"id"` SeedOrder int32 `json:"seed_order"` - EntrantID pgtype.UUID `json:"entrant_id"` + EntrantID uuid.UUID `json:"entrant_id"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` } type Entrant struct { - ID pgtype.UUID `json:"id"` + ID uuid.UUID `json:"id"` Name string `json:"name"` - EventID pgtype.UUID `json:"event_id"` + EventID uuid.UUID `json:"event_id"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` } type Event struct { - ID pgtype.UUID `json:"id"` + ID uuid.UUID `json:"id"` Name string `json:"name"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` } type Match struct { - ID pgtype.UUID `json:"id"` - Player1 pgtype.UUID `json:"player1"` - Player2 pgtype.UUID `json:"player2"` - Player1From pgtype.UUID `json:"player1_from"` - Player2From pgtype.UUID `json:"player2_from"` + ID uuid.UUID `json:"id"` + Player1 uuid.UUID `json:"player1"` + Player2 uuid.UUID `json:"player2"` + Player1From uuid.UUID `json:"player1_from"` + Player2From uuid.UUID `json:"player2_from"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` } type Team struct { - ID pgtype.UUID `json:"id"` + ID uuid.UUID `json:"id"` Name string `json:"name"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` } type TeamEntrant struct { - ID pgtype.UUID `json:"id"` - TeamID pgtype.UUID `json:"team_id"` - EntrantID pgtype.UUID `json:"entrant_id"` + ID uuid.UUID `json:"id"` + TeamID uuid.UUID `json:"team_id"` + EntrantID uuid.UUID `json:"entrant_id"` UpdatedAt pgtype.Timestamptz `json:"updated_at"` CreatedAt pgtype.Timestamptz `json:"created_at"` } type User struct { - ID pgtype.UUID `json:"id"` + ID uuid.UUID `json:"id"` Name string `json:"name"` Email string `json:"email"` Bio string `json:"bio"` diff --git a/db/queries/users.sql b/db/queries/users.sql index 3dcf872..c2b8b6f 100644 --- a/db/queries/users.sql +++ b/db/queries/users.sql @@ -1,7 +1,7 @@ --- name: GetUserFromId :one +-- name: GetUserById :one SELECT * FROM users u -WHERE u.id = $1; +WHERE u.id = @user_id::uuid; -- name: GetUserAuthValue :one SELECT u.ID as user_id, a.value as auth_value @@ -9,5 +9,20 @@ FROM users u JOIN auth_method a ON a.user_id = u.id WHERE - (u.name = $1 OR u.email = $1) - AND a.type = $2; + (u.name = @auth_value::text OR u.email = @auth_value) + AND a.type = @auth_type::auth_type; + +-- name: CreateUser :one +INSERT INTO users (name, email, bio, profile_photo) +VALUES($1, $2, $3, $4) +RETURNING *; + +-- name: UpdateUser :one +UPDATE users +SET name = @name::text, email = @email::text, bio = @bio::text, profile_photo = @photo::text +WHERE id = @id::uuid +RETURNING *; + +-- name: CreateAuthMethod :exec +INSERT INTO auth_method (user_id, type, value) +VALUES ($1, $2, $3); diff --git a/db/users.sql.go b/db/users.sql.go index fa1c6a7..0a921ab 100644 --- a/db/users.sql.go +++ b/db/users.sql.go @@ -8,44 +8,130 @@ package db import ( "context" + "github.com/google/uuid" "github.com/jackc/pgx/v5/pgtype" ) -const getUserAuthValue = `-- name: GetUserAuthValue :one -SELECT u.ID as user_id, a.value as auth_value -FROM users u - JOIN auth_method a - ON a.user_id = u.id -WHERE - (u.name = $1 OR u.email = $1) - AND a.type = $2 +const createAuthMethod = `-- name: CreateAuthMethod :exec +INSERT INTO auth_method (user_id, type, value) +VALUES ($1, $2, $3) ` -type GetUserAuthValueParams struct { - Name string `json:"name"` - Type AuthType `json:"type"` +type CreateAuthMethodParams struct { + UserID uuid.UUID `json:"user_id"` + Type AuthType `json:"type"` + Value string `json:"value"` } -type GetUserAuthValueRow struct { - UserID pgtype.UUID `json:"user_id"` - AuthValue string `json:"auth_value"` +func (q *Queries) CreateAuthMethod(ctx context.Context, arg CreateAuthMethodParams) error { + _, err := q.db.Exec(ctx, createAuthMethod, arg.UserID, arg.Type, arg.Value) + return err } -func (q *Queries) GetUserAuthValue(ctx context.Context, arg GetUserAuthValueParams) (GetUserAuthValueRow, error) { - row := q.db.QueryRow(ctx, getUserAuthValue, arg.Name, arg.Type) - var i GetUserAuthValueRow - err := row.Scan(&i.UserID, &i.AuthValue) - return i, err -} - -const getUserFromId = `-- name: GetUserFromId :one -SELECT id, name, email, bio, profile_photo, updated_at, created_at -FROM users u -WHERE u.id = $1 +const createUser = `-- name: CreateUser :one +INSERT INTO users (name, email, bio, profile_photo) +VALUES($1, $2, $3, $4) +RETURNING id, name, email, bio, profile_photo, updated_at, created_at ` -func (q *Queries) GetUserFromId(ctx context.Context, id pgtype.UUID) (User, error) { - row := q.db.QueryRow(ctx, getUserFromId, id) +type CreateUserParams struct { + Name string `json:"name"` + Email string `json:"email"` + Bio string `json:"bio"` + ProfilePhoto pgtype.Text `json:"profile_photo"` +} + +func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) { + row := q.db.QueryRow(ctx, createUser, + arg.Name, + arg.Email, + arg.Bio, + arg.ProfilePhoto, + ) + var i User + err := row.Scan( + &i.ID, + &i.Name, + &i.Email, + &i.Bio, + &i.ProfilePhoto, + &i.UpdatedAt, + &i.CreatedAt, + ) + return i, err +} + +const getUserAuthValue = `-- name: GetUserAuthValue :one +SELECT u.ID as user_id, a.value as auth_value +FROM users u + JOIN auth_method a + ON a.user_id = u.id +WHERE + (u.name = $1::text OR u.email = $1) + AND a.type = $2::auth_type +` + +type GetUserAuthValueParams struct { + AuthValue string `json:"auth_value"` + AuthType AuthType `json:"auth_type"` +} + +type GetUserAuthValueRow struct { + UserID uuid.UUID `json:"user_id"` + AuthValue string `json:"auth_value"` +} + +func (q *Queries) GetUserAuthValue(ctx context.Context, arg GetUserAuthValueParams) (GetUserAuthValueRow, error) { + row := q.db.QueryRow(ctx, getUserAuthValue, arg.AuthValue, arg.AuthType) + var i GetUserAuthValueRow + err := row.Scan(&i.UserID, &i.AuthValue) + return i, err +} + +const getUserById = `-- name: GetUserById :one +SELECT id, name, email, bio, profile_photo, updated_at, created_at +FROM users u +WHERE u.id = $1::uuid +` + +func (q *Queries) GetUserById(ctx context.Context, userID uuid.UUID) (User, error) { + row := q.db.QueryRow(ctx, getUserById, userID) + var i User + err := row.Scan( + &i.ID, + &i.Name, + &i.Email, + &i.Bio, + &i.ProfilePhoto, + &i.UpdatedAt, + &i.CreatedAt, + ) + return i, err +} + +const updateUser = `-- name: UpdateUser :one +UPDATE users +SET name = $1::text, email = $2::text, bio = $3::text, profile_photo = $4::text +WHERE id = $5::uuid +RETURNING id, name, email, bio, profile_photo, updated_at, created_at +` + +type UpdateUserParams struct { + Name string `json:"name"` + Email string `json:"email"` + Bio string `json:"bio"` + Photo string `json:"photo"` + ID uuid.UUID `json:"id"` +} + +func (q *Queries) UpdateUser(ctx context.Context, arg UpdateUserParams) (User, error) { + row := q.db.QueryRow(ctx, updateUser, + arg.Name, + arg.Email, + arg.Bio, + arg.Photo, + arg.ID, + ) var i User err := row.Scan( &i.ID, diff --git a/go.mod b/go.mod index 71f3a19..cefd653 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/go-chi/chi v4.1.2+incompatible // indirect github.com/go-chi/chi/v5 v5.2.5 // indirect github.com/goccy/go-yaml v1.9.5 // indirect + github.com/google/uuid v1.6.0 // indirect github.com/graphql-go/graphql v0.8.0 // indirect github.com/graphql-go/handler v0.2.3 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect diff --git a/go.sum b/go.sum index bf82c84..42d9207 100644 --- a/go.sum +++ b/go.sum @@ -214,6 +214,8 @@ github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= diff --git a/sqlc.yaml b/sqlc.yaml index 3156b7a..699d227 100644 --- a/sqlc.yaml +++ b/sqlc.yaml @@ -9,3 +9,13 @@ sql: out: "db" sql_package: "pgx/v5" emit_json_tags: true + overrides: + - db_type: "uuid" + go_type: + import: "github.com/google/uuid" + type: "UUID" + - db_type: "uuid" + nullable: true + go_type: + import: "github.com/google/uuid" + type: "UUID"