-
Notifications
You must be signed in to change notification settings - Fork 27
/
main.go
142 lines (115 loc) · 4.17 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package main
import (
"context"
"net/http"
"os"
"os/signal"
"time"
"github.com/d-vignesh/go-jwt-auth/data"
"github.com/d-vignesh/go-jwt-auth/handlers"
"github.com/d-vignesh/go-jwt-auth/service"
"github.com/d-vignesh/go-jwt-auth/utils"
"github.com/gorilla/mux"
"github.com/hashicorp/go-hclog"
)
// schema for user table
const userSchema = `
create table if not exists users (
id Varchar(36) not null,
email Varchar(100) not null unique,
username Varchar(225),
password Varchar(225) not null,
tokenhash Varchar(15) not null,
isverified Boolean default false,
createdat Timestamp not null,
updatedat Timestamp not null,
Primary Key (id)
);
`
const verificationSchema = `
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
)
`
func main() {
logger := utils.NewLogger()
configs := utils.NewConfigurations(logger)
// validator contains all the methods that are need to validate the user json in request
validator := data.NewValidation()
// create a new connection to the postgres db store
db, err := data.NewConnection(configs, logger)
if err != nil {
logger.Error("unable to connect to db", "error", err)
panic(err)
}
defer db.Close()
// creation of user table.
db.MustExec(userSchema)
db.MustExec(verificationSchema)
// repository contains all the methods that interact with DB to perform CURD operations for user.
repository := data.NewPostgresRepository(db, logger)
// authService contains all methods that help in authorizing a user request
authService := service.NewAuthService(logger, configs)
// mailService contains the utility methods to send an email
mailService := service.NewSGMailService(logger, configs)
// UserHandler encapsulates all the services related to user
uh := handlers.NewAuthHandler(logger, configs, validator, repository, authService, mailService)
// create a serve mux
sm := mux.NewRouter()
// register handlers
postR := sm.Methods(http.MethodPost).Subrouter()
mailR := sm.PathPrefix("/verify").Methods(http.MethodPost).Subrouter()
mailR.HandleFunc("/mail", uh.VerifyMail)
mailR.HandleFunc("/password-reset", uh.VerifyPasswordReset)
mailR.Use(uh.MiddlewareValidateVerificationData)
postR.HandleFunc("/signup", uh.Signup)
postR.HandleFunc("/login", uh.Login)
postR.Use(uh.MiddlewareValidateUser)
// used the PathPrefix as workaround for scenarios where all the
// get requests must use the ValidateAccessToken middleware except
// the /refresh-token request which has to use ValidateRefreshToken middleware
refToken := sm.PathPrefix("/refresh-token").Subrouter()
refToken.HandleFunc("", uh.RefreshToken)
refToken.Use(uh.MiddlewareValidateRefreshToken)
getR := sm.Methods(http.MethodGet).Subrouter()
getR.HandleFunc("/greet", uh.Greet)
getR.HandleFunc("/get-password-reset-code", uh.GeneratePassResetCode)
getR.Use(uh.MiddlewareValidateAccessToken)
putR := sm.Methods(http.MethodPut).Subrouter()
putR.HandleFunc("/update-username", uh.UpdateUsername)
putR.HandleFunc("/reset-password", uh.ResetPassword)
putR.Use(uh.MiddlewareValidateAccessToken)
// create a server
svr := http.Server{
Addr: configs.ServerAddress,
Handler: sm,
ErrorLog: logger.StandardLogger(&hclog.StandardLoggerOptions{}),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
IdleTimeout: 120 * time.Second,
}
// start the server
go func() {
logger.Info("starting the server at port", configs.ServerAddress)
err := svr.ListenAndServe()
if err != nil {
logger.Error("could not start the server", "error", err)
os.Exit(1)
}
}()
// look for interrupts for graceful shutdown
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
signal.Notify(c, os.Kill)
sig := <-c
logger.Info("shutting down the server", "received signal", sig)
//gracefully shutdown the server, waiting max 30 seconds for current operations to complete
ctx, _ := context.WithTimeout(context.Background(), 30*time.Second)
svr.Shutdown(ctx)
}