added a bunch of customer columns
This commit is contained in:
parent
f380dfe58d
commit
173c01b01b
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
|||||||
.envrc
|
.env
|
||||||
|
|||||||
5
.vscode/launch.json
vendored
5
.vscode/launch.json
vendored
@ -6,11 +6,12 @@
|
|||||||
"configurations": [
|
"configurations": [
|
||||||
|
|
||||||
{
|
{
|
||||||
"name": "Launch Package",
|
"name": "Launch API",
|
||||||
"type": "go",
|
"type": "go",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
"program": "${workspaceFolder}/cmd/api"
|
"program": "${workspaceFolder}/cmd/api",
|
||||||
|
"envFile": "${workspaceFolder}/.env"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
2
Makefile
2
Makefile
@ -24,7 +24,7 @@ build/api:
|
|||||||
.PHONY: run/api
|
.PHONY: run/api
|
||||||
run/api:
|
run/api:
|
||||||
@echo "Running the API"
|
@echo "Running the API"
|
||||||
go run ./cmd/api
|
go run ./cmd/api -db-dsn=${PARTY_DB_DSN}
|
||||||
|
|
||||||
.PHONY: db/psql
|
.PHONY: db/psql
|
||||||
db/psql:
|
db/psql:
|
||||||
|
|||||||
@ -80,6 +80,8 @@ var upgrader = websocket.Upgrader{
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
fmt.Printf("Full Args: %v\n", os.Args)
|
||||||
|
|
||||||
var cfg config
|
var cfg config
|
||||||
|
|
||||||
flag.IntVar(&cfg.port, "port", 4000, "API server port")
|
flag.IntVar(&cfg.port, "port", 4000, "API server port")
|
||||||
|
|||||||
@ -14,10 +14,14 @@ func (app *application) createUserHandler(w http.ResponseWriter, r *http.Request
|
|||||||
var input struct {
|
var input struct {
|
||||||
ProviderId int64 `json:"provider_id"`
|
ProviderId int64 `json:"provider_id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Country string `json:"country"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
AltName string `json:"alt_name"`
|
AltName string `json:"alt_name"`
|
||||||
|
DateOfBirth time.Time `json:"date_of_birth"`
|
||||||
|
Address string `json:"address"`
|
||||||
}
|
}
|
||||||
|
|
||||||
err := app.readJSON(w, r, &input)
|
err := app.readJSON(w, r, &input)
|
||||||
@ -28,8 +32,12 @@ func (app *application) createUserHandler(w http.ResponseWriter, r *http.Request
|
|||||||
|
|
||||||
user := &data.User{
|
user := &data.User{
|
||||||
Email: input.Email,
|
Email: input.Email,
|
||||||
|
PhoneNumber: input.PhoneNumber,
|
||||||
|
Country: input.Country,
|
||||||
Name: input.Name,
|
Name: input.Name,
|
||||||
AltName: sql.NullString{String: input.AltName, Valid: true},
|
AltName: sql.NullString{String: input.AltName, Valid: true},
|
||||||
|
DateOfBirth: input.DateOfBirth,
|
||||||
|
Address: input.Address,
|
||||||
Activated: false,
|
Activated: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -58,10 +58,10 @@ func ValidatePasswordPlaintext(v *validator.Validator, password string) {
|
|||||||
func ValidateUserIdentity(v *validator.Validator, userIdentity *UserIdentity) {
|
func ValidateUserIdentity(v *validator.Validator, userIdentity *UserIdentity) {
|
||||||
v.Check(userIdentity.ProviderID == int64(ProviderLocal), "provider_id", "must be 1");
|
v.Check(userIdentity.ProviderID == int64(ProviderLocal), "provider_id", "must be 1");
|
||||||
|
|
||||||
if userIdentity.ProviderID == int64(ProviderLocal) {
|
// if userIdentity.ProviderID == int64(ProviderLocal) {
|
||||||
v.Check(userIdentity.ProviderUserID != "", "username", "must be provided")
|
// v.Check(userIdentity.ProviderUserID != "", "username", "must be provided")
|
||||||
v.Check(len(userIdentity.ProviderUserID) <= 500, "username", "must not be more than 500 bytes long")
|
// v.Check(len(userIdentity.ProviderUserID) <= 500, "username", "must not be more than 500 bytes long")
|
||||||
}
|
// }
|
||||||
|
|
||||||
if userIdentity.Password.plaintext != nil {
|
if userIdentity.Password.plaintext != nil {
|
||||||
ValidatePasswordPlaintext(v,
|
ValidatePasswordPlaintext(v,
|
||||||
|
|||||||
@ -20,8 +20,12 @@ var AnonymousUser = &User{}
|
|||||||
type User struct {
|
type User struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
Country string `json:"country"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
AltName sql.NullString `json:"alt_name"`
|
AltName sql.NullString `json:"alt_name"`
|
||||||
|
DateOfBirth time.Time `json:"date_of_birth"`
|
||||||
|
Address string `json:"address"`
|
||||||
Created time.Time `json:"created"`
|
Created time.Time `json:"created"`
|
||||||
LastLogin time.Time `json:"last_login"`
|
LastLogin time.Time `json:"last_login"`
|
||||||
Activated bool `json:"activated"`
|
Activated bool `json:"activated"`
|
||||||
@ -56,14 +60,18 @@ func (m UserModel) ExecuteRegistrationTx(user *User, userIdentity *UserIdentity)
|
|||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
query := `
|
query := `
|
||||||
INSERT INTO users (email, name, alt_name)
|
INSERT INTO users (email, phone_number, country, name, alt_name, date_of_birth, address)
|
||||||
VALUES ($1, $2, $3)
|
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||||
RETURNING id, created, last_login, version`
|
RETURNING id, created, last_login, version`
|
||||||
|
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
user.Email,
|
user.Email,
|
||||||
|
user.PhoneNumber,
|
||||||
|
user.Country,
|
||||||
user.Name,
|
user.Name,
|
||||||
user.AltName,
|
user.AltName,
|
||||||
|
user.DateOfBirth,
|
||||||
|
user.Address,
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tx.QueryRowContext(ctx, query, args...).Scan(&user.ID, &user.Created, &user.LastLogin, &user.Version)
|
err = tx.QueryRowContext(ctx, query, args...).Scan(&user.ID, &user.Created, &user.LastLogin, &user.Version)
|
||||||
@ -113,36 +121,6 @@ RETURNING id, version`
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (m UserModel) Insert(user *User) error {
|
|
||||||
// query := `
|
|
||||||
// INSERT INTO users (email, name, alt_name, activated)
|
|
||||||
// VALUES ($1, $2, $3, $4)
|
|
||||||
// RETURNING id, created, last_login, version`
|
|
||||||
|
|
||||||
// args := []interface{}{
|
|
||||||
// user.Email,
|
|
||||||
// user.Name,
|
|
||||||
// user.AltName,
|
|
||||||
// user.Activated,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
||||||
// defer cancel()
|
|
||||||
|
|
||||||
// err := m.DB.QueryRowContext(ctx, query, args...).Scan(&user.ID, &user.Created, &user.LastLogin, &user.Version)
|
|
||||||
// if err != nil {
|
|
||||||
// switch {
|
|
||||||
// case err.Error() ==
|
|
||||||
// `pq: duplicate key value violates unique constraint "users_email_key"`:
|
|
||||||
// return ErrDuplicateEmail
|
|
||||||
// default:
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return nil
|
|
||||||
// }
|
|
||||||
|
|
||||||
func (m UserModel) Get(id int64) (*User, error) {
|
func (m UserModel) Get(id int64) (*User, error) {
|
||||||
if id < 1 {
|
if id < 1 {
|
||||||
return nil, ErrRecordNotFound
|
return nil, ErrRecordNotFound
|
||||||
@ -150,7 +128,7 @@ func (m UserModel) Get(id int64) (*User, error) {
|
|||||||
|
|
||||||
// Define the SQL query for retrieving the issue data.
|
// Define the SQL query for retrieving the issue data.
|
||||||
query :=`
|
query :=`
|
||||||
SELECT id, email, name, alt_name, created, last_login, activated, version
|
SELECT id, email, phone_number, country, name, alt_name, date_of_birth, address, created, last_login, activated, version
|
||||||
FROM users
|
FROM users
|
||||||
WHERE id = $1`
|
WHERE id = $1`
|
||||||
|
|
||||||
@ -160,8 +138,12 @@ WHERE id = $1`
|
|||||||
err := m.DB.QueryRow(query, id).Scan(
|
err := m.DB.QueryRow(query, id).Scan(
|
||||||
&user.ID,
|
&user.ID,
|
||||||
&user.Email,
|
&user.Email,
|
||||||
|
&user.PhoneNumber,
|
||||||
|
&user.Country,
|
||||||
&user.Name,
|
&user.Name,
|
||||||
&user.AltName,
|
&user.AltName,
|
||||||
|
&user.DateOfBirth,
|
||||||
|
&user.Address,
|
||||||
&user.Created,
|
&user.Created,
|
||||||
&user.LastLogin,
|
&user.LastLogin,
|
||||||
&user.Activated,
|
&user.Activated,
|
||||||
@ -181,7 +163,7 @@ WHERE id = $1`
|
|||||||
|
|
||||||
func (m UserModel) GetByEmail(email string) (*User, error) {
|
func (m UserModel) GetByEmail(email string) (*User, error) {
|
||||||
query :=`
|
query :=`
|
||||||
SELECT id, email, name, alt_name, created, last_login, activated, version
|
SELECT id, email, phone, country, name, alt_name, date_of_birth, address, created, last_login, activated, version
|
||||||
FROM users
|
FROM users
|
||||||
WHERE email = $1`
|
WHERE email = $1`
|
||||||
|
|
||||||
@ -192,8 +174,12 @@ WHERE email = $1`
|
|||||||
err := m.DB.QueryRowContext(ctx, query, email).Scan(
|
err := m.DB.QueryRowContext(ctx, query, email).Scan(
|
||||||
&user.ID,
|
&user.ID,
|
||||||
&user.Email,
|
&user.Email,
|
||||||
|
&user.PhoneNumber,
|
||||||
|
&user.Country,
|
||||||
&user.Name,
|
&user.Name,
|
||||||
&user.AltName,
|
&user.AltName,
|
||||||
|
&user.DateOfBirth,
|
||||||
|
&user.Address,
|
||||||
&user.Created,
|
&user.Created,
|
||||||
&user.LastLogin,
|
&user.LastLogin,
|
||||||
&user.Activated,
|
&user.Activated,
|
||||||
@ -219,7 +205,7 @@ func (m UserModel) GetForToken(tokenScope, tokenPlaintext string) (*User, error)
|
|||||||
|
|
||||||
// Set up the SQL query.
|
// Set up the SQL query.
|
||||||
query :=`
|
query :=`
|
||||||
SELECT users.id, users.created, users.name, users.email, users.activated, users.version
|
SELECT users.id, users.email, user.phone_number, user.country, users.name, users.date_of_birth, users.address, users.created, users.activated, users.version
|
||||||
FROM users
|
FROM users
|
||||||
INNER JOIN tokens ON users.id = tokens.user_id
|
INNER JOIN tokens ON users.id = tokens.user_id
|
||||||
WHERE tokens.hash = $1
|
WHERE tokens.hash = $1
|
||||||
@ -239,9 +225,13 @@ AND tokens.expiry > $3`
|
|||||||
// record is found we return an ErrRecordNotFound error.
|
// record is found we return an ErrRecordNotFound error.
|
||||||
err := m.DB.QueryRowContext(ctx, query, args...).Scan(
|
err := m.DB.QueryRowContext(ctx, query, args...).Scan(
|
||||||
&user.ID,
|
&user.ID,
|
||||||
&user.Created,
|
|
||||||
&user.Name,
|
|
||||||
&user.Email,
|
&user.Email,
|
||||||
|
&user.PhoneNumber,
|
||||||
|
&user.Country,
|
||||||
|
&user.Name,
|
||||||
|
&user.DateOfBirth,
|
||||||
|
&user.Address,
|
||||||
|
&user.Created,
|
||||||
&user.Activated,
|
&user.Activated,
|
||||||
&user.Version,
|
&user.Version,
|
||||||
)
|
)
|
||||||
@ -261,15 +251,19 @@ AND tokens.expiry > $3`
|
|||||||
func (m UserModel) Update(user *User) error {
|
func (m UserModel) Update(user *User) error {
|
||||||
query := `
|
query := `
|
||||||
UPDATE users
|
UPDATE users
|
||||||
SET email = $1, name = $2, alt_name = $3, activated = $4, version = version + 1
|
SET email = $1, phone_number = $2, country = $3, name = $4, alt_name = $5, date_of_birth = $6, address = $7, activated = $8, version = version + 1
|
||||||
WHERE id = $5 AND version = $6
|
WHERE id = $9 AND version = $10
|
||||||
RETURNING version`
|
RETURNING version`
|
||||||
|
|
||||||
// Create an args slice containing the values for the placeholder parameters.
|
// Create an args slice containing the values for the placeholder parameters.
|
||||||
args := []interface{}{
|
args := []interface{}{
|
||||||
user.Email,
|
user.Email,
|
||||||
|
user.PhoneNumber,
|
||||||
|
user.Country,
|
||||||
user.Name,
|
user.Name,
|
||||||
user.AltName,
|
user.AltName,
|
||||||
|
user.DateOfBirth,
|
||||||
|
user.Address,
|
||||||
user.Activated,
|
user.Activated,
|
||||||
user.ID,
|
user.ID,
|
||||||
user.Version,
|
user.Version,
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
email citext UNIQUE NOT NULL,
|
email citext UNIQUE NOT NULL,
|
||||||
|
phone_number TEXT,
|
||||||
|
country CHAR(2),
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
alt_name TEXT,
|
alt_name TEXT,
|
||||||
|
date_of_birth DATE,
|
||||||
|
address TEXT,
|
||||||
created TIMESTAMPTZ NOT NULL DEFAULT now(),
|
created TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||||
last_login TIMESTAMPTZ NOT NULL DEFAULT '1970-01-01 00:00:00+00',
|
last_login TIMESTAMPTZ NOT NULL DEFAULT '1970-01-01 00:00:00+00',
|
||||||
activated BOOL NOT NULL DEFAULT false,
|
activated BOOL NOT NULL DEFAULT false,
|
||||||
@ -24,7 +28,7 @@ CREATE TABLE IF NOT EXISTS user_identities (
|
|||||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
-- For local: the username. For OIDC: the 'sub' (Subject ID)
|
-- For local: the username. For OIDC: the 'sub' (Subject ID)
|
||||||
provider_user_id TEXT NOT NULL,
|
provider_user_id TEXT,
|
||||||
|
|
||||||
-- Nullable because OIDC users won't have a password in your DB
|
-- Nullable because OIDC users won't have a password in your DB
|
||||||
password bytea,
|
password bytea,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user