B: getting closer to a login system
This commit is contained in:
parent
ce0a301449
commit
f7dc37fb02
|
@ -5,9 +5,9 @@ tmp_dir = "tmp"
|
|||
[build]
|
||||
args_bin = []
|
||||
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
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata", "dist"]
|
||||
exclude_dir = ["assets", "tmp", "vendor", "testdata", "dist", "docker"]
|
||||
exclude_file = []
|
||||
exclude_regex = ["_test.go", "_templ.go"]
|
||||
exclude_unchanged = false
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
dist/*
|
||||
tmp/*
|
||||
**/*_templ.go
|
||||
docker/tmp/*
|
||||
|
|
|
@ -5,26 +5,23 @@ import (
|
|||
)
|
||||
|
||||
type config struct {
|
||||
Mongo *MongoConfig `json:"mogno"`
|
||||
JwtSecret string `json:"jwt_secret"`
|
||||
Env string `json:"env"`
|
||||
Mongo *MongoConfig `mapstructure:"mongo"`
|
||||
JwtSecret string `mapstructure:"jwt_secret"`
|
||||
Env string `mapstructure:"env"`
|
||||
}
|
||||
|
||||
type MongoConfig struct {
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
EntDb string `json:"entity_db"`
|
||||
EntCol string `json:"entity_col"`
|
||||
Uri string `mapstructure:"uri"`
|
||||
EntDb string `mapstructure:"ent_db"`
|
||||
EntCol string `mapstructure:"ent_col"`
|
||||
}
|
||||
|
||||
var cfg *config
|
||||
|
||||
func init() {
|
||||
func Init() {
|
||||
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.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()
|
||||
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
|
||||
|
||||
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/templates"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var mongo *db.DB
|
||||
var log *logrus.Logger
|
||||
|
||||
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("/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())
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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() {
|
||||
now := time.Now()
|
||||
user.EntityType = USER_TYPE
|
||||
user.CreatedAt = now
|
||||
user.UpdatedAt = now
|
||||
user.model = &model{
|
||||
EntityType: USER_TYPE,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
user.UserId = uuid.New().String()
|
||||
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/db/models"
|
||||
"go.mongodb.org/mongo-driver/bson"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"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)
|
||||
|
||||
if res.Err() != nil {
|
||||
if res.Err() == mongo.ErrNoDocuments {
|
||||
return nil, nil
|
||||
}
|
||||
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)
|
||||
|
||||
if res.Err() != nil {
|
||||
if res.Err() == mongo.ErrNoDocuments {
|
||||
return nil, nil
|
||||
}
|
||||
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)
|
||||
|
||||
if err != nil {
|
||||
if err == mongo.ErrNoDocuments {
|
||||
return nil, nil
|
||||
}
|
||||
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 (
|
||||
github.com/a-h/templ v0.2.408
|
||||
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
|
||||
go.mongodb.org/mongo-driver v1.12.1
|
||||
golang.org/x/crypto v0.13.0
|
||||
)
|
||||
|
||||
require (
|
||||
|
@ -34,6 +37,7 @@ require (
|
|||
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||
github.com/sagikazarmark/locafero v0.3.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/spf13/afero v1.10.0 // 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/multierr v1.9.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/net v0.15.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
|
||||
google.golang.org/protobuf v1.31.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/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
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/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=
|
||||
|
@ -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-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
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/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=
|
||||
|
@ -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/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
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/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
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-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-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-20220908164124-27713097b956/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/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-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/config"
|
||||
"git.preston-baxter.com/Preston_PLB/capstone/frontend-service/controllers"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
config.Init()
|
||||
r := gin.Default()
|
||||
|
||||
controllers.BuildRouter(r)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package templates
|
||||
|
||||
templ LoginContent() {
|
||||
templ LoginContent(signup bool, errorMsg string) {
|
||||
<main>
|
||||
<section class="absolute w-full h-full">
|
||||
<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"
|
||||
>
|
||||
<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">
|
||||
<small>Sign in</small>
|
||||
</div>
|
||||
<form>
|
||||
<form
|
||||
if signup {
|
||||
action="/signup"
|
||||
} else {
|
||||
action="/login"
|
||||
}
|
||||
method="POST"
|
||||
>
|
||||
<div class="relative w-full mb-3">
|
||||
<label
|
||||
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"
|
||||
placeholder="Email"
|
||||
style="transition: all 0.15s ease 0s;"
|
||||
name="email"
|
||||
/>
|
||||
</div>
|
||||
<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"
|
||||
placeholder="Password"
|
||||
style="transition: all 0.15s ease 0s;"
|
||||
name="password"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
|
@ -52,22 +71,35 @@ templ LoginContent() {
|
|||
</div>
|
||||
<div class="text-center mt-6">
|
||||
<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"
|
||||
type="button"
|
||||
style="transition: all 0.15s ease 0s;"
|
||||
>
|
||||
Sign In
|
||||
if signup {
|
||||
{ "Signup" }
|
||||
} else {
|
||||
{ "Login" }
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</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 class="flex flex-wrap mt-6">
|
||||
<div class="w-1/2">
|
||||
<a href="#pablo" class="text-gray-300"><small>Forgot password?</small></a>
|
||||
}
|
||||
if signup {
|
||||
<div class="w-full text-center">
|
||||
<a href="/login" class="text-gray-800"><small>Log in instead</small></a>
|
||||
</div>
|
||||
<div class="w-1/2 text-right">
|
||||
<a href="#pablo" class="text-gray-300"><small>Create new account</small></a>
|
||||
} else {
|
||||
<div class="w-1/2 text-center">
|
||||
<a href="/signup" class="text-gray-800"><small>Create an account</small></a>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,25 @@
|
|||
package templates
|
||||
|
||||
templ LoginPage() {
|
||||
templ LoginPage(errorMsg string) {
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
@Head()
|
||||
<body class="text-gray-800 antialiased">
|
||||
@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>
|
||||
@Footer()
|
||||
@toggleNavBar()
|
||||
|
|
Loading…
Reference in New Issue