Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add email verification #32

Merged
merged 3 commits into from
Apr 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ sqlc:
docker run --rm -v $(makeFileDir):/src -w /src sqlc/sqlc generate

test:
go test -v -cover ./...
go test -v -cover -short ./...

db_docs:
dbdocs build docs/db.dbml
Expand Down
5 changes: 4 additions & 1 deletion app.env
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ GRPC_SERVER_ADDRESS=127.0.0.1:9090
TOKEN_SYMMETRIC_KEY=12345678901234567890123456789012
ACCESS_TOKEN_DURATION=15m
REFRESH_TOKEN_DURATION=24h
REDIS_ADDRESS=127.0.0.1:6379
REDIS_ADDRESS=127.0.0.1:6379
EMAIL_SENDER_NAME=Simple simple_bank
[email protected]
EMAIL_SENDER_PASSWORD=xkuqqowogfpaqtuo
3 changes: 3 additions & 0 deletions db/migration/000004_add_verify_emails.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DROP TABLE IF EXISTS "verify_emails" CASCADE;

ALTER TABLE "users" DROP COLUMN "is_email_verified";
13 changes: 13 additions & 0 deletions db/migration/000004_add_verify_emails.up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CREATE TABLE "verify_emails" (
"id" bigserial PRIMARY KEY,
"username" varchar NOT NULL,
"email" varchar NOT NULL,
"secret_code" varchar NOT NULL,
"is_used" bool NOT NULL DEFAULT false,
"created_at" timestamptz NOT NULL DEFAULT (now()),
"expired_at" timestamptz NOT NULL DEFAULT (now() + interval '15 minutes')
);

ALTER TABLE "verify_emails" ADD FOREIGN KEY ("username") REFERENCES "users" ("username");

ALTER TABLE "users" ADD COLUMN "is_email_verified" bool NOT NULL DEFAULT false;
45 changes: 45 additions & 0 deletions db/mock/store.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion db/query/user.sql
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ SET
hashed_password = coalesce(sqlc.narg(hashed_password), hashed_password),
password_changed_at = coalesce(sqlc.narg(password_changed_at), password_changed_at),
full_name = coalesce(sqlc.narg(full_name), full_name),
email = coalesce(sqlc.narg(email), email)
email = coalesce(sqlc.narg(email), email),
is_email_verified = coalesce(sqlc.narg(is_email_verified), is_email_verified)
WHERE
username = sqlc.arg(username)
RETURNING *;
20 changes: 20 additions & 0 deletions db/query/verify_email.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- name: CreateVerifyEmail :one
INSERT INTO verify_emails (
username,
email,
secret_code
) VALUES (
$1, $2, $3
) RETURNING *;


-- name: UpdateVerifyEmail :one
UPDATE verify_emails
SET
is_used = TRUE
WHERE
id = @id
AND secret_code = @secret_code
AND is_used = FALSE
AND expired_at > now()
RETURNING *;
11 changes: 11 additions & 0 deletions db/sqlc/models.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions db/sqlc/querier.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions db/sqlc/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type Store interface {
Querier
TransferTx(ctx context.Context, arg TransferTxParams) (TransferTxResult, error)
CreateUserTx(ctx context.Context, arg CreateUserTxParams) (CreateUserTxResult, error)
VerifyEmailTx(ctx context.Context, arg VerifyEmailTxParams) (VerifyEmailTxResult, error)
}

// SQLStore provides all functions to execute SQL queries and transactions
Expand Down
42 changes: 42 additions & 0 deletions db/sqlc/tx_verify_email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package db

import (
"context"
"database/sql"
)

type VerifyEmailTxParams struct {
EmailId int64
SecretCode string
}

type VerifyEmailTxResult struct {
User User
VerifyEmail VerifyEmail
}

func (store *SQLStore) VerifyEmailTx(ctx context.Context, arg VerifyEmailTxParams) (VerifyEmailTxResult, error) {
var result VerifyEmailTxResult
err := store.execTx(ctx, func(q *Queries) error {
// closure is often used when we want to get the result from a callback function
var err error
result.VerifyEmail, err = q.UpdateVerifyEmail(ctx, UpdateVerifyEmailParams{
ID: arg.EmailId,
SecretCode: arg.SecretCode,
})
if err != nil {
return err
}

result.User, err = q.UpdateUser(ctx, UpdateUserParams{
Username: result.VerifyEmail.Username,
IsEmailVerified: sql.NullBool{
Bool: true,
Valid: true,
},
})
return err
})

return result, err
}
16 changes: 11 additions & 5 deletions db/sqlc/user.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 73 additions & 0 deletions db/sqlc/verify_email.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions docs/db.dbml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ Table users as U {
created_at timestamptz [not null, default: `now()`]
}

Table verify_emails {
id bigserial [pk]
username varchar [ref: > U.username, not null]
email varchar [not null]
secret_code varchar [not null]
is_used bool [not null, default: false]
created_at timestamptz [not null, default: `now()`]
expired_at timestamptz [not null, default: `now() + interval '15 minutes'`]
}

Table accounts as A {
id bigserial [pk]
owner varchar [ref: > U.username, not null]
Expand Down
Loading
Loading