Skip to content

App refactor and dependency update #2

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

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
6 changes: 4 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
sendgrid.env
sendgrid.env
# Environment
*.env
*.pem
*.log
16 changes: 0 additions & 16 deletions .vscode/launch.json

This file was deleted.

24 changes: 0 additions & 24 deletions Dockerfile

This file was deleted.

21 changes: 21 additions & 0 deletions LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2022 caseyrwebb

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
1 change: 0 additions & 1 deletion Procfile

This file was deleted.

9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Go Auth Microservice

## Inspired by the work of:

## d-vignesh's go-jwt-auth -> [d-vignesh/go-jwt-auth](https://github.com/d-vignesh/go-jwt-auth)

## and

## obe711's node-server-boilerplate -> [obe711/node-server-boilerplate](https://github.com/obe711/node-server-boilerplate)
25 changes: 25 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package app

import (
"github.com/caseyrwebb/go-jwt-auth/app/data"
"github.com/caseyrwebb/go-jwt-auth/app/router"
"github.com/caseyrwebb/go-jwt-auth/app/utils"
"github.com/gorilla/mux"
"go.uber.org/zap"
)

type App struct {
Router *mux.Router
DB data.GoDB
}

func New(logger zap.Logger, configs *utils.Configurations) *App {
a := &App{
Router: mux.NewRouter(),
DB: &data.DB{},
}

router.InitRoutes(a.Router, a.DB, logger, configs)

return a
}
73 changes: 73 additions & 0 deletions app/data/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package data

import (
"context"
"fmt"

"github.com/caseyrwebb/go-jwt-auth/app/models"
"github.com/caseyrwebb/go-jwt-auth/app/utils"
"github.com/jmoiron/sqlx"
_ "github.com/lib/pq"
"go.uber.org/zap"
)

type AuthDB interface {
Create(ctx context.Context, user *models.User) error
GetUserByEmail(ctx context.Context, email string) (*models.User, error)
GetUserByID(ctx context.Context, userID string) (*models.User, error)
UpdateUsername(ctx context.Context, user *models.User) error
UpdateUserVerificationStatus(ctx context.Context, email string, status bool) error
StoreVerificationData(ctx context.Context, verificationData *models.VerificationData) error
GetVerificationData(ctx context.Context, email string, verificationDataType models.VerificationDataType) (*models.VerificationData, error)
DeleteVerificationData(ctx context.Context, email string, verificationDataType models.VerificationDataType) error
UpdatePassword(ctx context.Context, userID string, password string, tokenHash string) error
}

type GoDB interface {
AuthDB
Open(config *utils.Configurations) error
Close() error
SetDBLogger(logger *zap.Logger)
}

type DB struct {
db *sqlx.DB
logger *zap.Logger
}

func (d *DB) SetDBLogger(logger *zap.Logger) {
d.logger = logger
}

func (d *DB) Open(config *utils.Configurations) error {
var conn string

if config.DBConn != "" {
conn = config.DBConn
} else {
host := config.DBHost
port := config.DBPort
user := config.DBUser
dbName := config.DBName
password := config.DBPass
conn = fmt.Sprintf("host=%s port=%s user=%s dbname=%s password=%s sslmode=disable", host, port, user, dbName, password)
}
d.logger.Debug(fmt.Sprintf("%s %s", "connection string", conn))

pg, err := sqlx.Open("postgres", conn)
if err != nil {
return err
}
d.logger.Debug("Connected to Database!")

pg.MustExec(createUserTableSchema)
pg.MustExec(createVerificationSchema)

d.db = pg

return nil
}

func (d *DB) Close() error {
return d.db.Close()
}
102 changes: 102 additions & 0 deletions app/data/methods.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
package data

import (
"context"
"fmt"
"time"

"github.com/caseyrwebb/go-jwt-auth/app/models"
uuid "github.com/google/uuid"
)

// Create inserts the given user into the database
func (d *DB) Create(ctx context.Context, user *models.User) error {
user.ID = uuid.New().String()
user.CreatedAt = time.Now()
user.UpdatedAt = time.Now()

d.logger.Info(fmt.Sprintf("%s %v", "creating user", user))
query := "insert into users (id, email, username, password, token, created_at, updated_at) values ($1, $2, $3, $4, $5, $6, $7)"
_, err := d.db.ExecContext(ctx, query, user.ID, user.Email, user.Username, user.Password, user.Token, user.CreatedAt, user.UpdatedAt)
return err
}

// GetUserByEmail retrieves the user object having the given email, else returns error
func (d *DB) GetUserByEmail(ctx context.Context, email string) (*models.User, error) {
d.logger.Debug(fmt.Sprintf("%s %v", "querying for user with email", email))
query := "select * from users where email = $1"
var user models.User
if err := d.db.GetContext(ctx, &user, query, email); err != nil {
return nil, err
}
d.logger.Debug(fmt.Sprintf("%s %v", "read users", user))
return &user, nil
}

// GetUserByID retrieves the user object having the given ID, else returns error
func (d *DB) GetUserByID(ctx context.Context, userID string) (*models.User, error) {
d.logger.Debug(fmt.Sprintf("%s %v", "querying for user with id", userID))
query := "select * from users where id = $1"
var user models.User
if err := d.db.GetContext(ctx, &user, query, userID); err != nil {
return nil, err
}
return &user, nil
}

// UpdateUsername updates the username of the given user
func (d *DB) UpdateUsername(ctx context.Context, user *models.User) error {
user.UpdatedAt = time.Now()

query := "update users set username = $1, updatedat = $2 where id = $3"
if _, err := d.db.ExecContext(ctx, query, user.Username, user.UpdatedAt, user.ID); err != nil {
return err
}
return nil
}

// UpdateUserVerificationStatus updates user verification status to true
func (d *DB) UpdateUserVerificationStatus(ctx context.Context, email string, status bool) error {

query := "update users set isverified = $1 where email = $2"
if _, err := d.db.ExecContext(ctx, query, status, email); err != nil {
return err
}
return nil
}

// StoreMailVerificationData adds a mail verification data to db
func (d *DB) StoreVerificationData(ctx context.Context, verificationData *models.VerificationData) error {

query := "insert into verifications(email, code, expiresat, type) values($1, $2, $3, $4)"
_, err := d.db.ExecContext(ctx, query, verificationData.Email, verificationData.Code, verificationData.ExpiresAt, verificationData.Type)
return err
}

// GetMailVerificationCode retrieves the stored verification code.
func (d *DB) GetVerificationData(ctx context.Context, email string, verificationDataType models.VerificationDataType) (*models.VerificationData, error) {

query := "select * from verifications where email = $1 and type = $2"

var verificationData models.VerificationData
if err := d.db.GetContext(ctx, &verificationData, query, email, verificationDataType); err != nil {
return nil, err
}
return &verificationData, nil
}

// DeleteMailVerificationData deletes a used verification data
func (d *DB) DeleteVerificationData(ctx context.Context, email string, verificationDataType models.VerificationDataType) error {

query := "delete from verifications where email = $1 and type = $2"
_, err := d.db.ExecContext(ctx, query, email, verificationDataType)
return err
}

// UpdatePassword updates the user password
func (d *DB) UpdatePassword(ctx context.Context, userID string, password string, tokenHash string) error {

query := "update users set password = $1, token = $2 where id = $3"
_, err := d.db.ExecContext(ctx, query, password, tokenHash, userID)
return err
}
28 changes: 28 additions & 0 deletions app/data/schemas.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package data

// User table schema
var createUserTableSchema = `
create table if not exists users (
id varchar(36) not null,
email varchar(225) not null unique,
username varchar(225),
password varchar(225) not null,
token varchar(15) not null,
is_verified boolean default false,
created_at timestamp not null,
updated_at timestamp not null,
primary key (id)
);
`

var createVerificationSchema = `
create table if not exists verifications (
email Varchar(100) not null,
code Varchar(10) not null,
expiresat Timestamp not null,
type Varchar(10) not null,
Primary Key (email),
Constraint fk_user_email Foreign Key(email) References users(email)
On Delete Cascade On Update Cascade
)
`
2 changes: 1 addition & 1 deletion data/serialization.go → app/data/serializers.go
Original file line number Diff line number Diff line change
@@ -16,4 +16,4 @@ func ToJSON(i interface{}, w io.Writer) error {
func FromJSON(i interface{}, r io.Reader) error {
d := json.NewDecoder(r)
return d.Decode(i)
}
}
2 changes: 1 addition & 1 deletion data/validation.go → app/data/validation.go
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ func (v *Validation) Validate(i interface{}) ValidationErrors {
var returnErrs ValidationErrors
for _, err := range errs.(validator.ValidationErrors) {
// cast the FieldError into our ValidationError and append to the slice
ve := ValidationError{err.(validator.FieldError)}
ve := ValidationError{err}
returnErrs = append(returnErrs, ve)
}
return returnErrs
Loading