B: getting closer to a login system
This commit is contained in:
parent
ce0a301449
commit
f7dc37fb02
|
@ -5,9 +5,9 @@ tmp_dir = "tmp"
|
||||||
[build]
|
[build]
|
||||||
args_bin = []
|
args_bin = []
|
||||||
bin = "./tmp/main"
|
bin = "./tmp/main"
|
||||||
cmd = "rm **/*_templ.go && templ generate && go build -o ./tmp/main ."
|
cmd = "rm **/*_templ.go; templ generate --path ./templates && go build -o ./tmp/main ."
|
||||||
delay = 1000
|
delay = 1000
|
||||||
exclude_dir = ["assets", "tmp", "vendor", "testdata", "dist"]
|
exclude_dir = ["assets", "tmp", "vendor", "testdata", "dist", "docker"]
|
||||||
exclude_file = []
|
exclude_file = []
|
||||||
exclude_regex = ["_test.go", "_templ.go"]
|
exclude_regex = ["_test.go", "_templ.go"]
|
||||||
exclude_unchanged = false
|
exclude_unchanged = false
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
dist/*
|
dist/*
|
||||||
tmp/*
|
tmp/*
|
||||||
**/*_templ.go
|
**/*_templ.go
|
||||||
|
docker/tmp/*
|
||||||
|
|
|
@ -5,26 +5,23 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type config struct {
|
type config struct {
|
||||||
Mongo *MongoConfig `json:"mogno"`
|
Mongo *MongoConfig `mapstructure:"mongo"`
|
||||||
JwtSecret string `json:"jwt_secret"`
|
JwtSecret string `mapstructure:"jwt_secret"`
|
||||||
Env string `json:"env"`
|
Env string `mapstructure:"env"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MongoConfig struct {
|
type MongoConfig struct {
|
||||||
Host string `json:"host"`
|
Uri string `mapstructure:"uri"`
|
||||||
Port string `json:"port"`
|
EntDb string `mapstructure:"ent_db"`
|
||||||
User string `json:"user"`
|
EntCol string `mapstructure:"ent_col"`
|
||||||
Password string `json:"password"`
|
|
||||||
EntDb string `json:"entity_db"`
|
|
||||||
EntCol string `json:"entity_col"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var cfg *config
|
var cfg *config
|
||||||
|
|
||||||
func init() {
|
func Init() {
|
||||||
viper.SetConfigName("config") // name of config file (without extension)
|
viper.SetConfigName("config") // name of config file (without extension)
|
||||||
viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
|
viper.SetConfigType("yaml") // REQUIRED if the config file does not have the extension in the name
|
||||||
viper.AddConfigPath("/etc/capstone/") // path to look for the config file in
|
viper.AddConfigPath("/etc/capstone") // path to look for the config file in
|
||||||
|
|
||||||
err := viper.ReadInConfig()
|
err := viper.ReadInConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -0,0 +1,160 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config"
|
||||||
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db/models"
|
||||||
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/templates"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/golang-jwt/jwt/v5"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LoginPostBody struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignUpHandler (c *gin.Context) {
|
||||||
|
//get uname and password.
|
||||||
|
conf := config.Config()
|
||||||
|
reqBody := &LoginPostBody{}
|
||||||
|
c.Request.ParseForm()
|
||||||
|
reqBody.Email = c.Request.FormValue("email")
|
||||||
|
reqBody.Password = c.Request.FormValue("password")
|
||||||
|
|
||||||
|
if reqBody.Email == "" {
|
||||||
|
renderTempl(c, templates.SignupPage("Please provide an email"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if reqBody.Password == "" {
|
||||||
|
renderTempl(c, templates.SignupPage("Please provide a password"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Verify username and password
|
||||||
|
user, err := mongo.FindUserByEmail(reqBody.Email)
|
||||||
|
if err != nil {
|
||||||
|
renderTempl(c, templates.SignupPage("Error occured. Please try again later"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user != nil {
|
||||||
|
renderTempl(c, templates.SignupPage(fmt.Sprintf("user already exists for %s", reqBody.Email)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user = &models.User{}
|
||||||
|
|
||||||
|
passHash, err := bcrypt.GenerateFromPassword([]byte(reqBody.Password), 10)
|
||||||
|
if err != nil {
|
||||||
|
renderTempl(c, templates.SignupPage("Signup failed. Please try again later"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
user.PassowrdHash = string(passHash)
|
||||||
|
user.Email = reqBody.Email
|
||||||
|
|
||||||
|
err = mongo.SaveModel(user)
|
||||||
|
if err != nil {
|
||||||
|
renderTempl(c, templates.SignupPage("Signup failed. Please try again later"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//build jwt
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256,
|
||||||
|
jwt.MapClaims{
|
||||||
|
"sub": user.UserId,
|
||||||
|
"exp": time.Now().Add(12 * time.Hour).Unix(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
jwtStr, err := token.SignedString(conf.JwtSecret)
|
||||||
|
if err != nil {
|
||||||
|
renderTempl(c, templates.SignupPage("Signup failed. Please try again later"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//store jwt as cookie
|
||||||
|
//TODO: Make sure set secure for prd deployment
|
||||||
|
c.SetCookie("authorization", jwtStr, 3600 * 24, "", "", false, true)
|
||||||
|
|
||||||
|
c.Redirect(302, "/dashboard")
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoginHandler(c *gin.Context) {
|
||||||
|
//get uname and password.
|
||||||
|
conf := config.Config()
|
||||||
|
reqBody := &LoginPostBody{}
|
||||||
|
c.Request.ParseForm()
|
||||||
|
reqBody.Email = c.Request.FormValue("email")
|
||||||
|
reqBody.Password = c.Request.FormValue("password")
|
||||||
|
|
||||||
|
if reqBody.Email == "" {
|
||||||
|
renderTempl(c, templates.LoginPage("Please provide an email"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if reqBody.Password == "" {
|
||||||
|
renderTempl(c, templates.LoginPage("Please provide a password"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//Verify username and password
|
||||||
|
user, err := mongo.FindUserByEmail(reqBody.Email)
|
||||||
|
if err != nil {
|
||||||
|
renderTempl(c, templates.LoginPage(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if user == nil {
|
||||||
|
renderTempl(c, templates.LoginPage(fmt.Sprintf("No user found for %s", reqBody.Email)))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bcrypt.CompareHashAndPassword([]byte(user.PassowrdHash), []byte(reqBody.Password)); err != nil {
|
||||||
|
renderTempl(c, templates.LoginPage("Email and password are incorrect"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//build jwt
|
||||||
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256,
|
||||||
|
jwt.MapClaims{
|
||||||
|
"sub": user.UserId,
|
||||||
|
"exp": time.Now().Add(12 * time.Hour).Unix(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
jwtStr, err := token.SignedString(conf.JwtSecret)
|
||||||
|
if err != nil {
|
||||||
|
renderTempl(c, templates.LoginPage("An error occured. Please try again later"))
|
||||||
|
}
|
||||||
|
|
||||||
|
//store jwt as cookie
|
||||||
|
var secure bool
|
||||||
|
if conf.Env == "dev" {
|
||||||
|
secure = false
|
||||||
|
} else {
|
||||||
|
secure = true
|
||||||
|
}
|
||||||
|
c.SetCookie("authorization", jwtStr, 3600 * 24, "", "", secure, true)
|
||||||
|
|
||||||
|
c.Redirect(302, "/dashboard")
|
||||||
|
}
|
||||||
|
|
||||||
|
func LogoutHandler(c *gin.Context) {
|
||||||
|
conf := config.Config()
|
||||||
|
|
||||||
|
var secure bool
|
||||||
|
if conf.Env == "dev" {
|
||||||
|
secure = false
|
||||||
|
} else {
|
||||||
|
secure = true
|
||||||
|
}
|
||||||
|
c.SetCookie("authorization", "", 3600 * 24, "", "", secure, true)
|
||||||
|
|
||||||
|
c.Redirect(302, "/login")
|
||||||
|
}
|
|
@ -1,21 +1,37 @@
|
||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config"
|
||||||
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db"
|
||||||
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/middleware"
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/middleware"
|
||||||
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/templates"
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var mongo *db.DB
|
||||||
|
var log *logrus.Logger
|
||||||
|
|
||||||
func BuildRouter(r *gin.Engine) {
|
func BuildRouter(r *gin.Engine) {
|
||||||
|
conf := config.Config()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
mongo, err = db.NewClient(conf.Mongo.Uri)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
r.GET("/", middleware.AuthMiddleware(false) ,LandingPage)
|
r.GET("/", middleware.AuthMiddleware(false) ,LandingPage)
|
||||||
r.GET("/login", middleware.AuthMiddleware(false), LoginPage)
|
r.GET("/login", middleware.AuthMiddleware(false), LoginPage)
|
||||||
|
r.GET("/signup", middleware.AuthMiddleware(false), SignUpPage)
|
||||||
|
|
||||||
|
r.POST("/login", LoginHandler)
|
||||||
|
r.POST("/signup", SignUpHandler)
|
||||||
|
r.POST("/logout", LogoutHandler)
|
||||||
|
|
||||||
|
dashboard := r.Group("/dashboard")
|
||||||
|
dashboard.Use(middleware.AuthMiddleware(true))
|
||||||
|
dashboard.GET("/", DashboardPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LandingPage(c *gin.Context) {
|
|
||||||
renderTempl(c, templates.LandingPage(false))
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoginPage(c *gin.Context) {
|
|
||||||
renderTempl(c, templates.LoginPage())
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/templates"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func LandingPage(c *gin.Context) {
|
||||||
|
renderTempl(c, templates.LandingPage(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
func LoginPage(c *gin.Context) {
|
||||||
|
renderTempl(c, templates.LoginPage(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
func SignUpPage(c *gin.Context) {
|
||||||
|
renderTempl(c, templates.SignupPage(""))
|
||||||
|
}
|
||||||
|
|
||||||
|
func DashboardPage(c *gin.Context) {
|
||||||
|
c.JSON(200, gin.H{"response": "dashboard"})
|
||||||
|
}
|
|
@ -14,3 +14,20 @@ func renderTempl(c *gin.Context, tmpl templ.Component) {
|
||||||
|
|
||||||
c.Data(200, "text/html", buf.Bytes())
|
c.Data(200, "text/html", buf.Bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func badRequest(c *gin.Context, reason string) {
|
||||||
|
c.JSON(400, map[string]string{"error": reason})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func serverError(c *gin.Context, reason string) {
|
||||||
|
c.JSON(504, map[string]string{"error": reason})
|
||||||
|
}
|
||||||
|
|
||||||
|
func notFound(c *gin.Context, reason string) {
|
||||||
|
c.JSON(404, map[string]string{"error": reason})
|
||||||
|
}
|
||||||
|
|
||||||
|
func unauthorized(c *gin.Context, reason string) {
|
||||||
|
c.JSON(403, map[string]string{"error": reason})
|
||||||
|
}
|
||||||
|
|
|
@ -24,3 +24,7 @@ func NewClient(uri string) (*DB, error) {
|
||||||
|
|
||||||
return &DB{client: client}, nil
|
return &DB{client: client}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DB) SaveModel(m Model) error {
|
||||||
|
return m.Save(db.client)
|
||||||
|
}
|
||||||
|
|
|
@ -28,9 +28,11 @@ func (user *User) Save(client *mongo.Client) error {
|
||||||
|
|
||||||
if user.mongoId.IsZero() {
|
if user.mongoId.IsZero() {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
user.EntityType = USER_TYPE
|
user.model = &model{
|
||||||
user.CreatedAt = now
|
EntityType: USER_TYPE,
|
||||||
user.UpdatedAt = now
|
CreatedAt: now,
|
||||||
|
UpdatedAt: now,
|
||||||
|
}
|
||||||
user.UserId = uuid.New().String()
|
user.UserId = uuid.New().String()
|
||||||
user.mongoId = primitive.NewObjectIDFromTimestamp(now)
|
user.mongoId = primitive.NewObjectIDFromTimestamp(now)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config"
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config"
|
||||||
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db/models"
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/db/models"
|
||||||
"go.mongodb.org/mongo-driver/bson"
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,6 +17,9 @@ func (db *DB) FindUserByEmail(email string) (*models.User, error) {
|
||||||
res := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).FindOne(context.Background(), bson.M{"email": email}, opts)
|
res := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).FindOne(context.Background(), bson.M{"email": email}, opts)
|
||||||
|
|
||||||
if res.Err() != nil {
|
if res.Err() != nil {
|
||||||
|
if res.Err() == mongo.ErrNoDocuments {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, res.Err()
|
return nil, res.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +39,9 @@ func (db *DB) FindUserById(id string) (*models.User, error) {
|
||||||
res := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).FindOne(context.Background(), bson.M{"user_id": id}, opts)
|
res := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).FindOne(context.Background(), bson.M{"user_id": id}, opts)
|
||||||
|
|
||||||
if res.Err() != nil {
|
if res.Err() != nil {
|
||||||
|
if res.Err() == mongo.ErrNoDocuments {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, res.Err()
|
return nil, res.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,6 +61,9 @@ func (db *DB) FindAllUsers() ([]models.User, error) {
|
||||||
res, err := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).Find(context.Background(), bson.M{"ent": models.USER_TYPE}, opts)
|
res, err := db.client.Database(conf.Mongo.EntDb).Collection(conf.Mongo.EntCol).Find(context.Background(), bson.M{"ent": models.USER_TYPE}, opts)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if err == mongo.ErrNoDocuments {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
return nil, res.Err()
|
return nil, res.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
mongodb:
|
||||||
|
image: mongo:7
|
||||||
|
ports:
|
||||||
|
- '27017:27017'
|
||||||
|
volumes:
|
||||||
|
- ./tmp/mongo:/data/db
|
|
@ -5,8 +5,11 @@ go 1.19
|
||||||
require (
|
require (
|
||||||
github.com/a-h/templ v0.2.408
|
github.com/a-h/templ v0.2.408
|
||||||
github.com/gin-gonic/gin v1.9.1
|
github.com/gin-gonic/gin v1.9.1
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.0.0
|
||||||
|
github.com/google/uuid v1.1.2
|
||||||
github.com/spf13/viper v1.17.0
|
github.com/spf13/viper v1.17.0
|
||||||
go.mongodb.org/mongo-driver v1.12.1
|
go.mongodb.org/mongo-driver v1.12.1
|
||||||
|
golang.org/x/crypto v0.13.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
@ -34,6 +37,7 @@ require (
|
||||||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||||
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
github.com/spf13/afero v1.10.0 // indirect
|
github.com/spf13/afero v1.10.0 // indirect
|
||||||
github.com/spf13/cast v1.5.1 // indirect
|
github.com/spf13/cast v1.5.1 // indirect
|
||||||
|
@ -48,11 +52,10 @@ require (
|
||||||
go.uber.org/atomic v1.10.0 // indirect
|
go.uber.org/atomic v1.10.0 // indirect
|
||||||
go.uber.org/multierr v1.9.0 // indirect
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/crypto v0.13.0 // indirect
|
|
||||||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||||
golang.org/x/net v0.15.0 // indirect
|
golang.org/x/net v0.15.0 // indirect
|
||||||
golang.org/x/sync v0.3.0 // indirect
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
golang.org/x/sys v0.12.0 // indirect
|
golang.org/x/sys v0.13.0 // indirect
|
||||||
golang.org/x/text v0.13.0 // indirect
|
golang.org/x/text v0.13.0 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/protobuf v1.31.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
|
|
@ -84,6 +84,8 @@ github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg
|
||||||
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.0.0 h1:1n1XNM9hk7O9mnQoNBGolZvzebBQ7p93ULHRc28XJUE=
|
||||||
|
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
@ -140,6 +142,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe
|
||||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
@ -195,6 +198,8 @@ github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9c
|
||||||
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
|
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||||
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
|
github.com/spf13/afero v1.10.0 h1:EaGW2JJh15aKOejeuJ+wpFSHnbd7GE6Wvp3TsNhb6LY=
|
||||||
|
@ -393,11 +398,14 @@ golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
|
||||||
|
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config"
|
||||||
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/controllers"
|
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/controllers"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
config.Init()
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
|
|
||||||
controllers.BuildRouter(r)
|
controllers.BuildRouter(r)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package templates
|
package templates
|
||||||
|
|
||||||
templ LoginContent() {
|
templ LoginContent(signup bool, errorMsg string) {
|
||||||
<main>
|
<main>
|
||||||
<section class="absolute w-full h-full">
|
<section class="absolute w-full h-full">
|
||||||
<div
|
<div
|
||||||
|
@ -14,10 +14,27 @@ templ LoginContent() {
|
||||||
class="relative flex flex-col min-w-0 break-words w-full mb-6 shadow-lg rounded-lg bg-gray-300 border-0"
|
class="relative flex flex-col min-w-0 break-words w-full mb-6 shadow-lg rounded-lg bg-gray-300 border-0"
|
||||||
>
|
>
|
||||||
<div class="flex-auto px-4 lg:px-10 py-10 pt-10">
|
<div class="flex-auto px-4 lg:px-10 py-10 pt-10">
|
||||||
|
if errorMsg != "" {
|
||||||
|
<div role="alert">
|
||||||
|
<div class="bg-red-500 text-white font-bold rounded-t px-4 py-2">
|
||||||
|
Error
|
||||||
|
</div>
|
||||||
|
<div class="border border-t-0 border-red-400 rounded-b bg-red-100 px-4 py-3 text-red-700">
|
||||||
|
<p>{ errorMsg }</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
<div class="text-gray-500 text-center mb-3 font-bold">
|
<div class="text-gray-500 text-center mb-3 font-bold">
|
||||||
<small>Sign in</small>
|
<small>Sign in</small>
|
||||||
</div>
|
</div>
|
||||||
<form>
|
<form
|
||||||
|
if signup {
|
||||||
|
action="/signup"
|
||||||
|
} else {
|
||||||
|
action="/login"
|
||||||
|
}
|
||||||
|
method="POST"
|
||||||
|
>
|
||||||
<div class="relative w-full mb-3">
|
<div class="relative w-full mb-3">
|
||||||
<label
|
<label
|
||||||
class="block uppercase text-gray-700 text-xs font-bold mb-2"
|
class="block uppercase text-gray-700 text-xs font-bold mb-2"
|
||||||
|
@ -27,6 +44,7 @@ templ LoginContent() {
|
||||||
class="border-0 px-3 py-3 placeholder-gray-400 text-gray-700 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full"
|
class="border-0 px-3 py-3 placeholder-gray-400 text-gray-700 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full"
|
||||||
placeholder="Email"
|
placeholder="Email"
|
||||||
style="transition: all 0.15s ease 0s;"
|
style="transition: all 0.15s ease 0s;"
|
||||||
|
name="email"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative w-full mb-3">
|
<div class="relative w-full mb-3">
|
||||||
|
@ -38,6 +56,7 @@ templ LoginContent() {
|
||||||
class="border-0 px-3 py-3 placeholder-gray-400 text-gray-700 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full"
|
class="border-0 px-3 py-3 placeholder-gray-400 text-gray-700 bg-white rounded text-sm shadow focus:outline-none focus:ring w-full"
|
||||||
placeholder="Password"
|
placeholder="Password"
|
||||||
style="transition: all 0.15s ease 0s;"
|
style="transition: all 0.15s ease 0s;"
|
||||||
|
name="password"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -52,22 +71,35 @@ templ LoginContent() {
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center mt-6">
|
<div class="text-center mt-6">
|
||||||
<button
|
<button
|
||||||
|
type="submit"
|
||||||
class="bg-gray-900 text-white active:bg-gray-700 text-sm font-bold uppercase px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 w-full"
|
class="bg-gray-900 text-white active:bg-gray-700 text-sm font-bold uppercase px-6 py-3 rounded shadow hover:shadow-lg outline-none focus:outline-none mr-1 mb-1 w-full"
|
||||||
type="button"
|
type="button"
|
||||||
style="transition: all 0.15s ease 0s;"
|
style="transition: all 0.15s ease 0s;"
|
||||||
>
|
>
|
||||||
Sign In
|
if signup {
|
||||||
|
{ "Signup" }
|
||||||
|
} else {
|
||||||
|
{ "Login" }
|
||||||
|
}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex flex-wrap mt-2 py-5">
|
||||||
|
if !signup {
|
||||||
|
<div class="w-1/2 text-center">
|
||||||
|
<a href="#pablo" class="text-gray-800"><small>Forgot password?</small></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-wrap mt-6">
|
}
|
||||||
<div class="w-1/2">
|
if signup {
|
||||||
<a href="#pablo" class="text-gray-300"><small>Forgot password?</small></a>
|
<div class="w-full text-center">
|
||||||
|
<a href="/login" class="text-gray-800"><small>Log in instead</small></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-1/2 text-right">
|
} else {
|
||||||
<a href="#pablo" class="text-gray-300"><small>Create new account</small></a>
|
<div class="w-1/2 text-center">
|
||||||
|
<a href="/signup" class="text-gray-800"><small>Create an account</small></a>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,12 +1,25 @@
|
||||||
package templates
|
package templates
|
||||||
|
|
||||||
templ LoginPage() {
|
templ LoginPage(errorMsg string) {
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
@Head()
|
@Head()
|
||||||
<body class="text-gray-800 antialiased">
|
<body class="text-gray-800 antialiased">
|
||||||
@Nav(false)
|
@Nav(false)
|
||||||
@LoginContent()
|
@LoginContent(false, errorMsg)
|
||||||
|
</body>
|
||||||
|
@Footer()
|
||||||
|
@toggleNavBar()
|
||||||
|
</html>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ SignupPage(errorMsg string) {
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
@Head()
|
||||||
|
<body class="text-gray-800 antialiased">
|
||||||
|
@Nav(false)
|
||||||
|
@LoginContent(true, errorMsg)
|
||||||
</body>
|
</body>
|
||||||
@Footer()
|
@Footer()
|
||||||
@toggleNavBar()
|
@toggleNavBar()
|
||||||
|
|
Loading…
Reference in New Issue