Skip to content

Commit

Permalink
Added Email Verifier using gmail smtp + new tests
Browse files Browse the repository at this point in the history
  • Loading branch information
the-eduardo committed Jul 26, 2024
1 parent 0460eea commit 828c748
Show file tree
Hide file tree
Showing 36 changed files with 1,436 additions and 73 deletions.
11 changes: 8 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,27 @@ migratedown:
migratedown1:
migrate -path db/migration -database "$(DB_URL)" -verbose down 1

new_migration:
migrate create -ext sql -dir db/migration -seq $(name)

dbdocs:
dbdocs build .\doc\db.dbml

dbschema:
dbml2sql $(DB_URL)--postgres -o doc/gobankschema.sql doc/db.dbml
dbml2sql --postgres -o doc/gobankschema.sql doc/db.dbml

sqlc:
sqlc generate

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

server:
go run main.go

mock:
mockgen -destination db/mock/store.go github.com/the-eduardo/Go-Bank/db/sqlc Store
mockgen -package mockwk -destination worker/mock/distributor.go github.com/the-eduardo/Go-Bank/worker TaskDistributor
# mockery is deprecated, use mock instead
mockery:
mockery --config=.mockery.yaml
Expand All @@ -59,4 +64,4 @@ dockerbuild:
redis:
docker run --name gobank_redis --network bank-network -p 6379:6379 -d redis:7.4-rc2-alpine

.PHONY: postgres createdb dropdb migrateup migrateup1 migratedown migratedown1 sqlc test server mock mockery dockerbuild dbdocs dbschema proto evans redis
.PHONY: postgres createdb dropdb migrateup migrateup1 migratedown migratedown1 sqlc test server mock mockery dockerbuild dbdocs dbschema proto evans redis new_migration
6 changes: 5 additions & 1 deletion app.env
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,8 @@ GRPC_SERVER_ADDRESS=0.0.0.0:9090
TOKEN_SYMMETRIC_KEY=12345678901234567890123456789012
ACCESS_TOKEN_DURATION=20m
REFRESH_TOKEN_DURATION=24h
REDIS_ADDRESS=0.0.0.0:6379
REDIS_ADDRESS=0.0.0.0:6379
SECRET_CODE_LENGTH=32
EMAIL_SENDER_NAME=EduardoGoBank
EMAIL_SENDER_ADDRESS=
EMAIL_SENDER_PASSWORD=
2 changes: 2 additions & 0 deletions db/migration/000004_add_verify_emails.down.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
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" boolean NOT NULL DEFAULT false,
"created_at" timestamptz NOT NULL DEFAULT (now()),
"expires_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" boolean 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 @@ -20,7 +20,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 *;
16 changes: 16 additions & 0 deletions db/query/verify_email.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
-- 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 expires_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 @@ -12,6 +12,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
40 changes: 40 additions & 0 deletions db/sqlc/tx_verify_email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package db

import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)

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 {
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: pgtype.Bool{
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.

70 changes: 70 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.

11 changes: 11 additions & 0 deletions doc/db.dbml
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,21 @@ Table users as U {
hashed_password varchar [not null]
full_name varchar [not null]
email varchar [unique, not null]
is_email_verified boolean [not null, default: false]
password_changed_at timestamptz [not null, default: '0001-01-01 00:00:00Z']
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 boolean [not null, default: false]
created_at timestamptz [not null, default: `now()`]
expires_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

0 comments on commit 828c748

Please sign in to comment.