1
0
mirror of https://github.com/raseels-repos/golang-saas-starter-kit.git synced 2025-06-27 00:51:13 +02:00

fix signup validation

This commit is contained in:
Lee Brown
2019-08-04 23:27:02 -08:00
parent ed6147260a
commit 6680064cd5
5 changed files with 179 additions and 3 deletions

View File

@ -40,6 +40,7 @@ func APP(shutdown chan os.Signal, log *log.Logger, env webcontext.Env, staticDir
// Construct the web.App which holds all routes as well as common Middleware.
app := web.NewApp(shutdown, log, env, middlewares...)
// Register project management pages.
p := Projects{
MasterDB: masterDB,
@ -63,6 +64,7 @@ func APP(shutdown chan os.Signal, log *log.Logger, env webcontext.Env, staticDir
app.Handle("GET", "/users/:user_id/update", us.Update, mid.AuthenticateSessionRequired(authenticator), mid.HasRole(auth.RoleAdmin))
app.Handle("GET", "/users/:user_id", us.View, mid.AuthenticateSessionRequired(authenticator), mid.HasRole(auth.RoleAdmin))
// Register user management and authentication endpoints.
u := User{
MasterDB: masterDB,
@ -92,6 +94,7 @@ func APP(shutdown chan os.Signal, log *log.Logger, env webcontext.Env, staticDir
app.Handle("POST", "/user", u.View, mid.AuthenticateSessionRequired(authenticator), mid.HasAuth())
app.Handle("GET", "/user", u.View, mid.AuthenticateSessionRequired(authenticator), mid.HasAuth())
// Register account management endpoints.
acc := Account{
MasterDB: masterDB,
@ -103,6 +106,7 @@ func APP(shutdown chan os.Signal, log *log.Logger, env webcontext.Env, staticDir
app.Handle("POST", "/account", acc.View, mid.AuthenticateSessionRequired(authenticator), mid.HasRole(auth.RoleAdmin))
app.Handle("GET", "/account", acc.View, mid.AuthenticateSessionRequired(authenticator), mid.HasRole(auth.RoleAdmin))
// Register user management and authentication endpoints.
s := Signup{
MasterDB: masterDB,
@ -121,6 +125,7 @@ func APP(shutdown chan os.Signal, log *log.Logger, env webcontext.Env, staticDir
app.Handle("GET", "/examples/flash-messages", ex.FlashMessages)
app.Handle("GET", "/examples/images", ex.Images)
// Register geo
g := Geo{
MasterDB: masterDB,
@ -131,6 +136,7 @@ func APP(shutdown chan os.Signal, log *log.Logger, env webcontext.Env, staticDir
app.Handle("GET", "/geo/geonames/postal_code/:postalCode", g.GeonameByPostalCode)
app.Handle("GET", "/geo/country/:countryCode/timezones", g.CountryTimezones)
// Register root
r := Root{
MasterDB: masterDB,
@ -146,6 +152,7 @@ func APP(shutdown chan os.Signal, log *log.Logger, env webcontext.Env, staticDir
app.Handle("GET", "/index.html", r.IndexHtml)
app.Handle("GET", "/robots.txt", r.RobotTxt)
// Register health check endpoint. This route is not authenticated.
check := Check{
MasterDB: masterDB,
@ -154,6 +161,7 @@ func APP(shutdown chan os.Signal, log *log.Logger, env webcontext.Env, staticDir
}
app.Handle("GET", "/v1/health", check.Health)
// Handle static files/pages. Render a custom 404 page when file not found.
static := func(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
err := web.StaticHandler(ctx, w, r, params, staticDir, "")

View File

@ -112,7 +112,7 @@ func (h *Signup) Step1(ctx context.Context, w http.ResponseWriter, r *http.Reque
data["form"] = req
if verr, ok := weberror.NewValidationError(ctx, webcontext.Validator().Struct(signup.SignupRequest{})); ok {
if verr, ok := weberror.NewValidationError(ctx, signup.Validator().Struct(signup.SignupRequest{})); ok {
data["validationDefaults"] = verr.(*weberror.Error)
}

View File

@ -0,0 +1,83 @@
{{define "title"}}Update Profile{{end}}
{{define "style"}}
{{end}}
{{define "content"}}
<form class="user" method="post" novalidate>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="inputFirstName">First Name</label>
<input type="text" class="form-control {{ ValidationFieldClass $.validationErrors "FirstName" }}" placeholder="enter first name" name="FirstName" value="{{ .form.FirstName }}" required>
{{template "invalid-feedback" dict "validationDefaults" $.userValidationDefaults "validationErrors" $.validationErrors "fieldName" "FirstName" }}
</div>
<div class="form-group">
<label for="inputLastName">Last Name</label>
<input type="text" class="form-control {{ ValidationFieldClass $.validationErrors "LastName" }}" placeholder="enter last name" name="LastName" value="{{ .form.LastName }}" required>
{{template "invalid-feedback" dict "validationDefaults" $.userValidationDefaults "validationErrors" $.validationErrors "fieldName" "LastName" }}
</div>
<div class="form-group">
<label for="inputEmail">Email</label>
<input type="text" class="form-control {{ ValidationFieldClass $.validationErrors "Email" }}" placeholder="enter email" name="Email" value="{{ .form.Email }}" required>
{{template "invalid-feedback" dict "validationDefaults" $.userValidationDefaults "validationErrors" $.validationErrors "fieldName" "Email" }}
</div>
<div class="form-group">
<label for="inputTimezone">Timezone</label>
<select class="form-control {{ ValidationFieldClass $.validationErrors "Timezone" }}" name="Timezone">
<option value="">Not set</option>
{{ range $idx, $t := .timezones }}
<option value="{{ $t }}" {{ if CmpString $t $.form.Timezone }}selected="selected"{{ end }}>{{ $t }}</option>
{{ end }}
</select>
{{template "invalid-feedback" dict "validationDefaults" $.validationDefaults "validationErrors" $.validationErrors "fieldName" "Timezone" }}
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<h4 class="card-title">Change Password</h4>
<p><small><b>Optional</b>. You can change your password by specifying a new one below. Otherwise leave the fields empty.</small></p>
<div class="form-group">
<label for="inputPassword">Password</label>
<input type="password" class="form-control" id="inputPassword" placeholder="" name="Password" value="">
<span class="help-block "><small><a a href="javascript:void(0)" id="btnGeneratePassword"><i class="fal fa-random"></i>Generate random password </a></small></span>
{{template "invalid-feedback" dict "validationDefaults" $.passwordValidationDefaults "validationErrors" $.validationErrors "fieldName" "Password" }}
</div>
<div class="form-group">
<label for="inputPasswordConfirm">Confirm Password</label>
<input type="password" class="form-control" id="inputPasswordConfirm" placeholder="" name="PasswordConfirm" value="">
{{template "invalid-feedback" dict "validationDefaults" $.passwordValidationDefaults "validationErrors" $.validationErrors "fieldName" "PasswordConfirm" }}
</div>
</div>
</div>
<div class="spacer-30"></div>
<div class="row">
<div class="col">
<input id="btnSubmit" type="submit" name="action" value="Save" class="btn btn-primary"/>
</div>
</div>
</form>
{{end}}
{{define "js"}}
<script>
function randomPassword(length) {
var chars = "abcdefghijklmnopqrstuvwxyz!@#&*()-+<>ABCDEFGHIJKLMNOP1234567890";
var pass = "";
for (var x = 0; x < length; x++) {
var i = Math.floor(Math.random() * chars.length);
pass += chars.charAt(i);
}
return pass;
}
$(document).ready(function(){
$("#btnGeneratePassword").on("click", function() {
pwd = randomPassword(12);
$("#inputPassword").attr('type', 'text').val(pwd)
$("#inputPasswordConfirm").attr('type', 'text').val(pwd)
return false;
});
});
</script>
{{end}}

View File

@ -0,0 +1,85 @@
{{define "title"}}Profile{{end}}
{{define "style"}}
{{end}}
{{define "content"}}
<div class="row">
<div class="col">
<div class="row">
<div class="col-auto">
<img src="{{ .user.Gravatar.Medium }}" alt="gravatar image" class="rounded">
</div>
<div class="col">
<h4>Name</h4>
<p class="font-14">
{{ .user.Name }}
</p>
</div>
</div>
<div class="spacer-10"></div>
<p class="font-10"><a href="https://gravatar.com" target="_blank">Update Avatar</a></p>
</div>
<div class="col-auto">
<a href="/user/update" class="btn btn-outline-success"><i class="fal fa-edit"></i>Edit Details</a>
</div>
</div>
<div class="spacer-30"></div>
<div class="row">
<div class="col-md-6">
<p>
<small>Name</small><br/>
<b>{{ .user.Name }}</b>
</p>
<p>
<small>Email</small><br/>
<b>{{ .user.Email }}</b>
</p>
{{if .user.Timezone }}
<p>
<small>Timezone</small><br/>
<b>{{.user.Timezone }}</b>
</p>
{{end}}
<div class="spacer-15"></div>
</div>
<div class="col-md-6">
<p>
<small>Role</small><br/>
{{ if .userAccount }}
<b>
{{ range $r := .userAccount.Roles }}
{{ if eq $r "admin" }}
<span class="text-pink-dark"><i class="far fa-user-astronaut"></i>{{ $r }}</span>
{{else}}
<span class="text-purple-dark"><i class="fal fa-user"></i>{{ $r }}</span>
{{end}}
{{ end }}
</b>
{{ end }}
</p>
<p>
<small>Status</small><br/>
{{ if .userAccount }}
<b>
{{ if eq .userAccount.Status.Value "active" }}
<span class="text-green"><i class="fas fa-circle"></i>{{ .userAccount.Status.Title }}</span>
{{ else if eq .userAccount.Status.Value "invited" }}
<span class="text-blue"><i class="fas fa-unicorn"></i>{{ .userAccount.Status.Title }}</span>
{{else}}
<span class="text-orange"><i class="far fa-circle"></i>{{.userAccount.Status.Title }}</span>
{{end}}
</b>
{{ end }}
</p>
<p>
<small>ID</small><br/>
<b>{{ .user.ID }}</b>
</p>
</div>
</div>
{{end}}
{{define "js"}}
{{end}}

View File

@ -2,8 +2,8 @@ package user_account
import (
"context"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
"github.com/jmoiron/sqlx"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
@ -11,7 +11,7 @@ import (
// UserFindByAccount lists all the users for a given account ID.
func UserFindByAccount(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, req UserFindByAccountRequest) (Users, error) {
span, ctx := tracer.StartSpanFromContext(ctx, "internal.user_account.UserFind")
span, ctx := tracer.StartSpanFromContext(ctx, "internal.user_account.UserFindByAccount")
defer span.Finish()
v := webcontext.Validator()