1
0
mirror of https://github.com/raseels-repos/golang-saas-starter-kit.git synced 2025-06-10 23:57:45 +02:00

Fix unittests

This commit is contained in:
Lee Brown 2019-08-01 16:17:47 -08:00
parent b3d30a019e
commit 1d69ea88a3
32 changed files with 919 additions and 722 deletions

View File

@ -2,6 +2,9 @@ package handlers
import (
"context"
"fmt"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"net/http"
"strconv"
@ -45,7 +48,7 @@ func (a *Account) Read(ctx context.Context, w http.ResponseWriter, r *http.Reque
b, err := strconv.ParseBool(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as boolean for included-archived param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
includeArchived = b
}
@ -55,7 +58,10 @@ func (a *Account) Read(ctx context.Context, w http.ResponseWriter, r *http.Reque
cause := errors.Cause(err)
switch cause {
case account.ErrNotFound:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
fmt.Println("HERE!!!!! account.ErrNotFound")
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusNotFound))
default:
return errors.Wrapf(err, "ID: %s", params["id"])
}
@ -78,9 +84,10 @@ func (a *Account) Read(ctx context.Context, w http.ResponseWriter, r *http.Reque
// @Failure 500 {object} web.ErrorResponse
// @Router /accounts [patch]
func (a *Account) Update(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
@ -89,23 +96,23 @@ func (a *Account) Update(ctx context.Context, w http.ResponseWriter, r *http.Req
}
var req account.AccountUpdateRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
err := account.Update(ctx, claims, a.MasterDB, req, v.Now)
err = account.Update(ctx, claims, a.MasterDB, req, v.Now)
if err != nil {
cause := errors.Cause(err)
switch cause {
case account.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "Id: %s Account: %+v", req.ID, &req)

View File

@ -2,6 +2,8 @@ package handlers
import (
"context"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"net/http"
"strconv"
"strings"
@ -51,7 +53,7 @@ func (p *Project) Find(ctx context.Context, w http.ResponseWriter, r *http.Reque
if v := r.URL.Query().Get("where"); v != "" {
where, args, err := web.ExtractWhereArgs(v)
if err != nil {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
req.Where = &where
req.Args = args
@ -72,7 +74,7 @@ func (p *Project) Find(ctx context.Context, w http.ResponseWriter, r *http.Reque
l, err := strconv.Atoi(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as int for limit param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
ul := uint(l)
req.Limit = &ul
@ -83,7 +85,7 @@ func (p *Project) Find(ctx context.Context, w http.ResponseWriter, r *http.Reque
l, err := strconv.Atoi(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as int for offset param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
ul := uint(l)
req.Limit = &ul
@ -94,14 +96,14 @@ func (p *Project) Find(ctx context.Context, w http.ResponseWriter, r *http.Reque
b, err := strconv.ParseBool(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as boolean for included-archived param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
req.IncludedArchived = b
}
//if err := web.Decode(r, &req); err != nil {
// if _, ok := errors.Cause(err).(*web.Error); !ok {
// err = web.NewRequestError(err, http.StatusBadRequest)
// err = weberror.NewError(ctx, err, http.StatusBadRequest)
// }
// return web.RespondJsonError(ctx, w, err)
//}
@ -144,7 +146,7 @@ func (p *Project) Read(ctx context.Context, w http.ResponseWriter, r *http.Reque
b, err := strconv.ParseBool(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as boolean for included-archived param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
includeArchived = b
}
@ -154,7 +156,7 @@ func (p *Project) Read(ctx context.Context, w http.ResponseWriter, r *http.Reque
cause := errors.Cause(err)
switch cause {
case project.ErrNotFound:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusNotFound))
default:
return errors.Wrapf(err, "ID: %s", params["id"])
}
@ -178,20 +180,20 @@ func (p *Project) Read(ctx context.Context, w http.ResponseWriter, r *http.Reque
// @Failure 500 {object} web.ErrorResponse
// @Router /projects [post]
func (p *Project) Create(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req project.ProjectCreateRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
@ -201,11 +203,11 @@ func (p *Project) Create(ctx context.Context, w http.ResponseWriter, r *http.Req
cause := errors.Cause(err)
switch cause {
case project.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "Project: %+v", &req)
}
@ -228,34 +230,34 @@ func (p *Project) Create(ctx context.Context, w http.ResponseWriter, r *http.Req
// @Failure 500 {object} web.ErrorResponse
// @Router /projects [patch]
func (p *Project) Update(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req project.ProjectUpdateRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
err := project.Update(ctx, claims, p.MasterDB, req, v.Now)
err = project.Update(ctx, claims, p.MasterDB, req, v.Now)
if err != nil {
cause := errors.Cause(err)
switch cause {
case project.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "ID: %s Update: %+v", req.ID, req)
@ -279,34 +281,34 @@ func (p *Project) Update(ctx context.Context, w http.ResponseWriter, r *http.Req
// @Failure 500 {object} web.ErrorResponse
// @Router /projects/archive [patch]
func (p *Project) Archive(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req project.ProjectArchiveRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
err := project.Archive(ctx, claims, p.MasterDB, req, v.Now)
err = project.Archive(ctx, claims, p.MasterDB, req, v.Now)
if err != nil {
cause := errors.Cause(err)
switch cause {
case project.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "Id: %s", req.ID)
@ -330,21 +332,21 @@ func (p *Project) Archive(ctx context.Context, w http.ResponseWriter, r *http.Re
// @Failure 500 {object} web.ErrorResponse
// @Router /projects/{id} [delete]
func (p *Project) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
err := project.Delete(ctx, claims, p.MasterDB, params["id"])
err = project.Delete(ctx, claims, p.MasterDB, params["id"])
if err != nil {
cause := errors.Cause(err)
switch cause {
case project.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "Id: %s", params["id"])

View File

@ -2,6 +2,8 @@ package handlers
import (
"context"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"net/http"
"geeks-accelerator/oss/saas-starter-kit/internal/account"
@ -32,18 +34,18 @@ type Signup struct {
// @Failure 500 {object} web.ErrorResponse
// @Router /signup [post]
func (c *Signup) Signup(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
// Claims are optional as authentication is not required ATM for this method.
claims, _ := ctx.Value(auth.Key).(auth.Claims)
claims, _ := auth.ClaimsFromContext(ctx)
var req signup.SignupRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
@ -52,11 +54,11 @@ func (c *Signup) Signup(ctx context.Context, w http.ResponseWriter, r *http.Requ
if err != nil {
switch errors.Cause(err) {
case account.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := err.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "Signup: %+v", &req)

View File

@ -2,6 +2,8 @@ package handlers
import (
"context"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"net/http"
"strconv"
"strings"
@ -55,7 +57,7 @@ func (u *User) Find(ctx context.Context, w http.ResponseWriter, r *http.Request,
if v := r.URL.Query().Get("where"); v != "" {
where, args, err := web.ExtractWhereArgs(v)
if err != nil {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
req.Where = &where
req.Args = args
@ -76,7 +78,7 @@ func (u *User) Find(ctx context.Context, w http.ResponseWriter, r *http.Request,
l, err := strconv.Atoi(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as int for limit param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
ul := uint(l)
req.Limit = &ul
@ -87,7 +89,7 @@ func (u *User) Find(ctx context.Context, w http.ResponseWriter, r *http.Request,
l, err := strconv.Atoi(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as int for offset param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
ul := uint(l)
req.Limit = &ul
@ -98,14 +100,14 @@ func (u *User) Find(ctx context.Context, w http.ResponseWriter, r *http.Request,
b, err := strconv.ParseBool(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as boolean for included-archived param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
req.IncludedArchived = b
}
//if err := web.Decode(r, &req); err != nil {
// if _, ok := errors.Cause(err).(*web.Error); !ok {
// err = web.NewRequestError(err, http.StatusBadRequest)
// err = weberror.NewError(ctx, err, http.StatusBadRequest)
// }
// return web.RespondJsonError(ctx, w, err)
//}
@ -148,7 +150,7 @@ func (u *User) Read(ctx context.Context, w http.ResponseWriter, r *http.Request,
b, err := strconv.ParseBool(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as boolean for included-archived param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
includeArchived = b
}
@ -158,7 +160,7 @@ func (u *User) Read(ctx context.Context, w http.ResponseWriter, r *http.Request,
cause := errors.Cause(err)
switch cause {
case user.ErrNotFound:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusNotFound))
default:
return errors.Wrapf(err, "ID: %s", params["id"])
}
@ -181,20 +183,20 @@ func (u *User) Read(ctx context.Context, w http.ResponseWriter, r *http.Request,
// @Failure 500 {object} web.ErrorResponse
// @Router /users [post]
func (u *User) Create(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req user.UserCreateRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
@ -204,11 +206,11 @@ func (u *User) Create(ctx context.Context, w http.ResponseWriter, r *http.Reques
cause := errors.Cause(err)
switch cause {
case user.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "User: %+v", &req)
@ -232,34 +234,34 @@ func (u *User) Create(ctx context.Context, w http.ResponseWriter, r *http.Reques
// @Failure 500 {object} web.ErrorResponse
// @Router /users [patch]
func (u *User) Update(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req user.UserUpdateRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
err := user.Update(ctx, claims, u.MasterDB, req, v.Now)
err = user.Update(ctx, claims, u.MasterDB, req, v.Now)
if err != nil {
cause := errors.Cause(err)
switch cause {
case user.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "Id: %s User: %+v", req.ID, &req)
@ -283,36 +285,36 @@ func (u *User) Update(ctx context.Context, w http.ResponseWriter, r *http.Reques
// @Failure 500 {object} web.ErrorResponse
// @Router /users/password [patch]
func (u *User) UpdatePassword(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req user.UserUpdatePasswordRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
err := user.UpdatePassword(ctx, claims, u.MasterDB, req, v.Now)
err = user.UpdatePassword(ctx, claims, u.MasterDB, req, v.Now)
if err != nil {
cause := errors.Cause(err)
switch cause {
case user.ErrNotFound:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusNotFound))
case user.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "Id: %s User: %+v", req.ID, &req)
@ -336,34 +338,34 @@ func (u *User) UpdatePassword(ctx context.Context, w http.ResponseWriter, r *htt
// @Failure 500 {object} web.ErrorResponse
// @Router /users/archive [patch]
func (u *User) Archive(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req user.UserArchiveRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
err := user.Archive(ctx, claims, u.MasterDB, req, v.Now)
err = user.Archive(ctx, claims, u.MasterDB, req, v.Now)
if err != nil {
cause := errors.Cause(err)
switch cause {
case user.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "Id: %s", req.ID)
@ -387,21 +389,21 @@ func (u *User) Archive(ctx context.Context, w http.ResponseWriter, r *http.Reque
// @Failure 500 {object} web.ErrorResponse
// @Router /users/{id} [delete]
func (u *User) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
err := user.Delete(ctx, claims, u.MasterDB, params["id"])
err = user.Delete(ctx, claims, u.MasterDB, params["id"])
if err != nil {
cause := errors.Cause(err)
switch cause {
case user.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "Id: %s", params["id"])
@ -425,14 +427,14 @@ func (u *User) Delete(ctx context.Context, w http.ResponseWriter, r *http.Reques
// @Failure 500 {object} web.ErrorResponse
// @Router /users/switch-account/{account_id} [patch]
func (u *User) SwitchAccount(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
tkn, err := user.SwitchAccount(ctx, u.MasterDB, u.TokenGenerator, claims, params["account_id"], sessionTtl, v.Now)
@ -440,11 +442,11 @@ func (u *User) SwitchAccount(ctx context.Context, w http.ResponseWriter, r *http
cause := errors.Cause(err)
switch cause {
case user.ErrAuthenticationFailure:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusUnauthorized))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusUnauthorized))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrap(err, "switch account")
@ -468,15 +470,15 @@ func (u *User) SwitchAccount(ctx context.Context, w http.ResponseWriter, r *http
// @Failure 500 {object} web.ErrorResponse
// @Router /oauth/token [post]
func (u *User) Token(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
email, pass, ok := r.BasicAuth()
if !ok {
err := errors.New("must provide email and password in Basic auth")
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusUnauthorized))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusUnauthorized))
}
// Optional to include scope.
@ -487,11 +489,11 @@ func (u *User) Token(ctx context.Context, w http.ResponseWriter, r *http.Request
cause := errors.Cause(err)
switch cause {
case user.ErrAuthenticationFailure:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusUnauthorized))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusUnauthorized))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrap(err, "authenticating")

View File

@ -4,6 +4,8 @@ import (
"context"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"geeks-accelerator/oss/saas-starter-kit/internal/user_account"
"github.com/jmoiron/sqlx"
"github.com/pkg/errors"
@ -50,7 +52,7 @@ func (u *UserAccount) Find(ctx context.Context, w http.ResponseWriter, r *http.R
if v := r.URL.Query().Get("where"); v != "" {
where, args, err := web.ExtractWhereArgs(v)
if err != nil {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
req.Where = &where
req.Args = args
@ -71,7 +73,7 @@ func (u *UserAccount) Find(ctx context.Context, w http.ResponseWriter, r *http.R
l, err := strconv.Atoi(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as int for limit param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
ul := uint(l)
req.Limit = &ul
@ -82,7 +84,7 @@ func (u *UserAccount) Find(ctx context.Context, w http.ResponseWriter, r *http.R
l, err := strconv.Atoi(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as int for offset param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
ul := uint(l)
req.Limit = &ul
@ -93,14 +95,14 @@ func (u *UserAccount) Find(ctx context.Context, w http.ResponseWriter, r *http.R
b, err := strconv.ParseBool(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as boolean for included-archived param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
req.IncludedArchived = b
}
//if err := web.Decode(r, &req); err != nil {
// if _, ok := errors.Cause(err).(*web.Error); !ok {
// err = web.NewRequestError(err, http.StatusBadRequest)
// err = weberror.NewError(ctx, err, http.StatusBadRequest)
// }
// return web.RespondJsonError(ctx, w, err)
//}
@ -143,7 +145,7 @@ func (u *UserAccount) Read(ctx context.Context, w http.ResponseWriter, r *http.R
b, err := strconv.ParseBool(v)
if err != nil {
err = errors.WithMessagef(err, "unable to parse %s as boolean for included-archived param", v)
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
includeArchived = b
}
@ -153,7 +155,7 @@ func (u *UserAccount) Read(ctx context.Context, w http.ResponseWriter, r *http.R
cause := errors.Cause(err)
switch cause {
case user_account.ErrNotFound:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusNotFound))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusNotFound))
default:
return errors.Wrapf(err, "ID: %s", params["id"])
}
@ -177,20 +179,20 @@ func (u *UserAccount) Read(ctx context.Context, w http.ResponseWriter, r *http.R
// @Failure 500 {object} web.ErrorResponse
// @Router /user_accounts [post]
func (u *UserAccount) Create(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req user_account.UserAccountCreateRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
@ -200,11 +202,11 @@ func (u *UserAccount) Create(ctx context.Context, w http.ResponseWriter, r *http
cause := errors.Cause(err)
switch cause {
case user_account.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "User Account: %+v", &req)
@ -228,34 +230,34 @@ func (u *UserAccount) Create(ctx context.Context, w http.ResponseWriter, r *http
// @Failure 500 {object} web.ErrorResponse
// @Router /user_accounts [patch]
func (u *UserAccount) Update(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req user_account.UserAccountUpdateRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
err := user_account.Update(ctx, claims, u.MasterDB, req, v.Now)
err = user_account.Update(ctx, claims, u.MasterDB, req, v.Now)
if err != nil {
cause := errors.Cause(err)
switch cause {
case user_account.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "UserID: %s AccountID: %s User Account: %+v", req.UserID, req.AccountID, &req)
@ -279,34 +281,34 @@ func (u *UserAccount) Update(ctx context.Context, w http.ResponseWriter, r *http
// @Failure 500 {object} web.ErrorResponse
// @Router /user_accounts/archive [patch]
func (u *UserAccount) Archive(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
v, ok := ctx.Value(web.KeyValues).(*web.Values)
if !ok {
return web.NewShutdownError("web value missing from context")
v, err := webcontext.ContextValues(ctx)
if err != nil {
return err
}
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req user_account.UserAccountArchiveRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
err := user_account.Archive(ctx, claims, u.MasterDB, req, v.Now)
err = user_account.Archive(ctx, claims, u.MasterDB, req, v.Now)
if err != nil {
cause := errors.Cause(err)
switch cause {
case user_account.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "UserID: %s AccountID: %s User Account: %+v", req.UserID, req.AccountID, &req)
@ -330,29 +332,29 @@ func (u *UserAccount) Archive(ctx context.Context, w http.ResponseWriter, r *htt
// @Failure 500 {object} web.ErrorResponse
// @Router /user_accounts [delete]
func (u *UserAccount) Delete(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
claims, ok := ctx.Value(auth.Key).(auth.Claims)
if !ok {
return errors.New("claims missing from context")
claims, err := auth.ClaimsFromContext(ctx)
if err != nil {
return err
}
var req user_account.UserAccountDeleteRequest
if err := web.Decode(r, &req); err != nil {
if _, ok := errors.Cause(err).(*web.Error); !ok {
err = web.NewRequestError(err, http.StatusBadRequest)
if err := web.Decode(ctx, r, &req); err != nil {
if _, ok := errors.Cause(err).(*weberror.Error); !ok {
err = weberror.NewError(ctx, err, http.StatusBadRequest)
}
return web.RespondJsonError(ctx, w, err)
}
err := user_account.Delete(ctx, claims, u.MasterDB, req)
err = user_account.Delete(ctx, claims, u.MasterDB, req)
if err != nil {
cause := errors.Cause(err)
switch cause {
case user_account.ErrForbidden:
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusForbidden))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusForbidden))
default:
_, ok := cause.(validator.ValidationErrors)
if ok {
return web.RespondJsonError(ctx, w, web.NewRequestError(err, http.StatusBadRequest))
return web.RespondJsonError(ctx, w, weberror.NewError(ctx, err, http.StatusBadRequest))
}
return errors.Wrapf(err, "UserID: %s, AccountID: %s", req.UserID, req.AccountID)

View File

@ -443,7 +443,7 @@ func main() {
if cfg.HTTP.Host != "" {
api := http.Server{
Addr: cfg.HTTP.Host,
Handler: handlers.API(shutdown, log, masterDb, redisClient, authenticator, serviceMiddlewares...),
Handler: handlers.API(shutdown, log, cfg.Env, masterDb, redisClient, authenticator, serviceMiddlewares...),
ReadTimeout: cfg.HTTP.ReadTimeout,
WriteTimeout: cfg.HTTP.WriteTimeout,
MaxHeaderBytes: 1 << 20,
@ -460,7 +460,7 @@ func main() {
if cfg.HTTPS.Host != "" {
api := http.Server{
Addr: cfg.HTTPS.Host,
Handler: handlers.API(shutdown, log, masterDb, redisClient, authenticator, serviceMiddlewares...),
Handler: handlers.API(shutdown, log, cfg.Env, masterDb, redisClient, authenticator, serviceMiddlewares...),
ReadTimeout: cfg.HTTPS.ReadTimeout,
WriteTimeout: cfg.HTTPS.WriteTimeout,
MaxHeaderBytes: 1 << 20,

View File

@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"net/http"
"testing"
@ -115,7 +116,7 @@ func TestAccountCRUDAdmin(t *testing.T) {
t.Fatalf("\t%s\tDecode expected failed.", tests.Failed)
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
}
t.Logf("\t%s\tReceived expected result.", tests.Success)
@ -144,17 +145,17 @@ func TestAccountCRUDAdmin(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("account %s not found: Entity not found", randID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -182,17 +183,17 @@ func TestAccountCRUDAdmin(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("account %s not found: Entity not found", tr.ForbiddenAccount.ID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -329,7 +330,7 @@ func TestAccountCRUDUser(t *testing.T) {
t.Fatalf("\t%s\tDecode expected failed.", tests.Failed)
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected result.", tests.Failed)
}
t.Logf("\t%s\tReceived expected result.", tests.Success)
@ -358,17 +359,17 @@ func TestAccountCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("account %s not found: Entity not found", randID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -396,17 +397,17 @@ func TestAccountCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("account %s not found: Entity not found", tr.ForbiddenAccount.ID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -438,17 +439,14 @@ func TestAccountCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
if diff := cmpDiff(t, actual, expected); diff {
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -490,20 +488,27 @@ func TestAccountUpdate(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "status", Error: "Key: 'AccountUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "status", Error: "Key: 'AccountUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
{
Field: "status",
Value: invalidStatus.String(),
Tag: "oneof",
Error: "status must be one of [active pending disabled]",
Display: "status must be one of [active pending disabled]",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)

View File

@ -12,6 +12,7 @@ import (
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/tests"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"geeks-accelerator/oss/saas-starter-kit/internal/project"
"github.com/pborman/uuid"
)
@ -90,7 +91,7 @@ func TestProjectCRUDAdmin(t *testing.T) {
t.Fatalf("\t%s\tDecode expected failed.", tests.Failed)
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
if len(expectedMap) == 0 {
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
}
@ -156,17 +157,17 @@ func TestProjectCRUDAdmin(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("project %s not found: Entity not found", randID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -195,17 +196,17 @@ func TestProjectCRUDAdmin(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("project %s not found: Entity not found", forbiddenProject.ID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -340,17 +341,15 @@ func TestProjectCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -416,17 +415,17 @@ func TestProjectCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("project %s not found: Entity not found", randID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -455,17 +454,17 @@ func TestProjectCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("project %s not found: Entity not found", forbiddenProject.ID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -497,17 +496,15 @@ func TestProjectCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -537,17 +534,15 @@ func TestProjectCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -575,17 +570,15 @@ func TestProjectCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -626,20 +619,27 @@ func TestProjectCreate(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "status", Error: "Key: 'ProjectCreateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "status", Error: "Key: 'ProjectCreateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
{
Field: "status",
Value: invalidStatus.String(),
Tag: "oneof",
Error: "status must be one of [active disabled]",
Display: "status must be one of [active disabled]",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -681,20 +681,27 @@ func TestProjectUpdate(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "status", Error: "Key: 'ProjectUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "status", Error: "Key: 'ProjectUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
{
Field: "status",
Value: invalidStatus.String(),
Tag: "oneof",
Error: "status must be one of [active disabled]",
Display: "status must be one of [active disabled]",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -716,12 +723,14 @@ func TestProjectArchive(t *testing.T) {
{
expectedStatus := http.StatusBadRequest
invalidId := "a"
rt := requestTest{
fmt.Sprintf("Archive %d w/role %s using invalid data", expectedStatus, tr.Role),
http.MethodPatch,
"/v1/projects/archive",
project.ProjectArchiveRequest{
ID: "a",
ID: invalidId,
},
tr.Token,
tr.Claims,
@ -736,20 +745,27 @@ func TestProjectArchive(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "id", Error: "Key: 'ProjectArchiveRequest.id' Error:Field validation for 'id' failed on the 'uuid' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "id", Error: "Key: 'ProjectArchiveRequest.id' Error:Field validation for 'id' failed on the 'uuid' tag"},
{
Field: "id",
Value: invalidId,
Tag: "uuid",
Error: "id must be a valid UUID",
Display: "id must be a valid UUID",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -779,17 +795,17 @@ func TestProjectArchive(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: project.ErrForbidden.Error(),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -811,10 +827,12 @@ func TestProjectDelete(t *testing.T) {
{
expectedStatus := http.StatusBadRequest
invalidId := "a"
rt := requestTest{
fmt.Sprintf("Delete %d w/role %s using invalid data", expectedStatus, tr.Role),
http.MethodDelete,
"/v1/projects/a",
"/v1/projects/" + invalidId,
nil,
tr.Token,
tr.Claims,
@ -829,20 +847,27 @@ func TestProjectDelete(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "id", Error: "Key: 'id' Error:Field validation for 'id' failed on the 'uuid' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "id", Error: "Key: 'id' Error:Field validation for 'id' failed on the 'uuid' tag"},
{
Field: "id",
Value: invalidId,
Tag: "uuid",
Error: "id must be a valid UUID",
Display: "id must be a valid UUID",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -870,17 +895,17 @@ func TestProjectDelete(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: project.ErrForbidden.Error(),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)

View File

@ -12,6 +12,7 @@ import (
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/tests"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"geeks-accelerator/oss/saas-starter-kit/internal/signup"
"geeks-accelerator/oss/saas-starter-kit/internal/user"
"github.com/pborman/uuid"
@ -37,7 +38,8 @@ func mockSignupRequest() signup.SignupRequest {
Zipcode: "99686",
},
User: signup.SignupUser{
Name: "Lee Brown",
FirstName: "Lee",
LastName: "Brown",
Email: uuid.NewRandom().String() + "@geeksinthewoods.com",
Password: "akTechFr0n!ier",
PasswordConfirm: "akTechFr0n!ier",
@ -114,7 +116,8 @@ func TestSignup(t *testing.T) {
expectedMap := map[string]interface{}{
"user": map[string]interface{}{
"id": actual.User.ID,
"name": req.User.Name,
"first_name": req.User.FirstName,
"last_name": req.User.LastName,
"email": req.User.Email,
"timezone": actual.User.Timezone,
"created_at": web.NewTimeResponse(ctx, actual.User.CreatedAt.Value),
@ -149,7 +152,7 @@ func TestSignup(t *testing.T) {
t.Fatalf("\t%s\tDecode expected failed.", tests.Failed)
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
if len(expectedMap) == 0 {
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
}
@ -180,17 +183,17 @@ func TestSignup(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "decode request body failed: EOF",
expected := weberror.ErrorResponse{
Error: "decode request body failed",
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -221,21 +224,36 @@ func TestSignup(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "name", Error: "Key: 'SignupRequest.account.name' Error:Field validation for 'name' failed on the 'required' tag"},
{Field: "email", Error: "Key: 'SignupRequest.user.email' Error:Field validation for 'email' failed on the 'required' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "name", Error: "Key: 'SignupRequest.account.name' Error:Field validation for 'name' failed on the 'required' tag"},
//{Field: "email", Error: "Key: 'SignupRequest.user.email' Error:Field validation for 'email' failed on the 'required' tag"},
{
Field: "name",
Value: "",
Tag: "required",
Error: "Name is a required field",
Display: "Name is a required field",
},
{
Field: "email",
Value: "",
Tag: "required",
Error: "email is a required field",
Display: "email is a required field",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)

View File

@ -5,6 +5,7 @@ import (
"context"
"encoding/json"
"fmt"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"io"
"io/ioutil"
"net/http"
@ -19,6 +20,7 @@ import (
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/tests"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"geeks-accelerator/oss/saas-starter-kit/internal/signup"
"geeks-accelerator/oss/saas-starter-kit/internal/user"
"geeks-accelerator/oss/saas-starter-kit/internal/user_account"
@ -81,7 +83,7 @@ func testMain(m *testing.M) int {
log := test.Log
log.SetOutput(ioutil.Discard)
a = handlers.API(shutdown, log, test.MasterDB, nil, authenticator)
a = handlers.API(shutdown, log, webcontext.Env_Dev, test.MasterDB, nil, authenticator)
// Create a new account directly business logic. This creates an
// initial account and user that we will use for admin validated endpoints.
@ -122,7 +124,8 @@ func testMain(m *testing.M) int {
// Create a regular user to use when calling regular validated endpoints.
userReq := user.UserCreateRequest{
Name: "Lucas Brown",
FirstName: "Lucas",
LastName: "Brown",
Email: uuid.NewRandom().String() + "@geeksinthewoods.com",
Password: "akTechFr0n!ier",
PasswordConfirm: "akTechFr0n!ier",
@ -204,7 +207,7 @@ func executeRequestTest(t *testing.T, tt requestTest, ctx context.Context) (*htt
}
if tt.error != nil {
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tBody : %s\n", w.Body.String())
t.Logf("\t\tGot error : %+v", err)

View File

@ -13,6 +13,7 @@ import (
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/tests"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"geeks-accelerator/oss/saas-starter-kit/internal/user"
"geeks-accelerator/oss/saas-starter-kit/internal/user_account"
"github.com/pborman/uuid"
@ -105,7 +106,7 @@ func TestUserAccountCRUDAdmin(t *testing.T) {
t.Fatalf("\t%s\tDecode expected failed.", tests.Failed)
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
if len(expectedMap) == 0 {
printResultMap(ctx, w.Body.Bytes()) // used to help format expectedMap
}
@ -171,17 +172,17 @@ func TestUserAccountCRUDAdmin(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("user account %s not found: Entity not found", randID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -210,17 +211,17 @@ func TestUserAccountCRUDAdmin(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("user account %s not found: Entity not found", forbiddenUserAccount.ID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -363,17 +364,15 @@ func TestUserAccountCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -439,17 +438,17 @@ func TestUserAccountCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("user account %s not found: Entity not found", randID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -478,17 +477,17 @@ func TestUserAccountCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("user account %s not found: Entity not found", forbiddenUserAccount.ID),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -521,17 +520,17 @@ func TestUserAccountCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: account.ErrForbidden.Error(),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -562,17 +561,15 @@ func TestUserAccountCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -603,17 +600,15 @@ func TestUserAccountCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -657,20 +652,27 @@ func TestUserAccountCreate(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "status", Error: "Key: 'UserAccountCreateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "status", Error: "Key: 'UserAccountCreateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
{
Field: "status",
Value: invalidStatus.String(),
Tag: "oneof",
Error: "status must be one of [active invited disabled]",
Display: "status must be one of [active invited disabled]",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -713,20 +715,27 @@ func TestUserAccountUpdate(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "status", Error: "Key: 'UserAccountUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "status", Error: "Key: 'UserAccountUpdateRequest.status' Error:Field validation for 'status' failed on the 'oneof' tag"},
{
Field: "status",
Value: invalidStatus.String(),
Tag: "oneof",
Error: "status must be one of [active invited disabled]",
Display: "status must be one of [active invited disabled]",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -745,15 +754,15 @@ func TestUserAccountArchive(t *testing.T) {
// Test archive with invalid data.
{
expectedStatus := http.StatusBadRequest
req := user_account.UserAccountArchiveRequest{
UserID: "foo",
AccountID: "bar",
}
rt := requestTest{
fmt.Sprintf("Archive %d w/role %s using invalid data", expectedStatus, tr.Role),
http.MethodPatch,
"/v1/user_accounts/archive",
user_account.UserAccountArchiveRequest{
UserID: "foo",
AccountID: "bar",
},
req,
tr.Token,
tr.Claims,
expectedStatus,
@ -767,21 +776,35 @@ func TestUserAccountArchive(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "user_id", Error: "Key: 'UserAccountArchiveRequest.user_id' Error:Field validation for 'user_id' failed on the 'uuid' tag"},
{Field: "account_id", Error: "Key: 'UserAccountArchiveRequest.account_id' Error:Field validation for 'account_id' failed on the 'uuid' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "user_id", Error: "Key: 'UserAccountArchiveRequest.user_id' Error:Field validation for 'user_id' failed on the 'uuid' tag"},
//{Field: "account_id", Error: "Key: 'UserAccountArchiveRequest.account_id' Error:Field validation for 'account_id' failed on the 'uuid' tag"},
{
Field: "user_id",
Value: req.UserID,
Tag: "uuid",
Error: "user_id must be a valid UUID",
Display: "user_id must be a valid UUID",
},
{
Field: "account_id",
Value: req.AccountID,
Tag: "uuid",
Error: "account_id must be a valid UUID",
Display: "account_id must be a valid UUID",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -813,17 +836,17 @@ func TestUserAccountArchive(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: user_account.ErrForbidden.Error(),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -866,21 +889,35 @@ func TestUserAccountDelete(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "user_id", Error: "Key: 'UserAccountDeleteRequest.user_id' Error:Field validation for 'user_id' failed on the 'uuid' tag"},
{Field: "account_id", Error: "Key: 'UserAccountDeleteRequest.account_id' Error:Field validation for 'account_id' failed on the 'uuid' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "user_id", Error: "Key: 'UserAccountDeleteRequest.user_id' Error:Field validation for 'user_id' failed on the 'uuid' tag"},
//{Field: "account_id", Error: "Key: 'UserAccountDeleteRequest.account_id' Error:Field validation for 'account_id' failed on the 'uuid' tag"},
{
Field: "user_id",
Value: req.UserID,
Tag: "uuid",
Error: "user_id must be a valid UUID",
Display: "user_id must be a valid UUID",
},
{
Field: "account_id",
Value: req.AccountID,
Tag: "uuid",
Error: "account_id must be a valid UUID",
Display: "account_id must be a valid UUID",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -912,17 +949,17 @@ func TestUserAccountDelete(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: user_account.ErrForbidden.Error(),
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)

View File

@ -13,6 +13,7 @@ import (
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/tests"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"geeks-accelerator/oss/saas-starter-kit/internal/user"
"geeks-accelerator/oss/saas-starter-kit/internal/user_account"
"github.com/pborman/uuid"
@ -25,7 +26,8 @@ type mockUser struct {
func mockUserCreateRequest() user.UserCreateRequest {
return user.UserCreateRequest{
Name: "Lee Brown",
FirstName: "Lee",
LastName: "Brown",
Email: uuid.NewRandom().String() + "@geeksinthewoods.com",
Password: "akTechFr0n!ier",
PasswordConfirm: "akTechFr0n!ier",
@ -101,7 +103,8 @@ func TestUserCRUDAdmin(t *testing.T) {
"email": req.Email,
"timezone": actual.Timezone,
"created_at": web.NewTimeResponse(ctx, actual.CreatedAt.Value),
"name": req.Name,
"first_name": req.FirstName,
"last_name": req.LastName,
}
var expected user.UserResponse
@ -187,13 +190,13 @@ func TestUserCRUDAdmin(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("user %s not found: Entity not found", randID),
}
@ -225,13 +228,13 @@ func TestUserCRUDAdmin(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("user %s not found: Entity not found", tr.ForbiddenUser.ID),
}
@ -251,8 +254,8 @@ func TestUserCRUDAdmin(t *testing.T) {
http.MethodPatch,
"/v1/users",
user.UserUpdateRequest{
ID: created.ID,
Name: &newName,
ID: created.ID,
FirstName: &newName,
},
tr.Token,
tr.Claims,
@ -415,6 +418,7 @@ func TestUserCRUDAdmin(t *testing.T) {
"access_token": actual["access_token"],
"token_type": actual["token_type"],
"expiry": actual["expiry"],
"ttl": actual["ttl"],
}
if diff := cmpDiff(t, actual, expected); diff {
@ -471,15 +475,13 @@ func TestUserCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
@ -547,13 +549,13 @@ func TestUserCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("user %s not found: Entity not found", randID),
}
@ -585,13 +587,13 @@ func TestUserCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: fmt.Sprintf("user %s not found: Entity not found", tr.ForbiddenUser.ID),
}
@ -611,8 +613,8 @@ func TestUserCRUDUser(t *testing.T) {
http.MethodPatch,
"/v1/users",
user.UserUpdateRequest{
ID: created.ID,
Name: &newName,
ID: created.ID,
FirstName: &newName,
},
tr.Token,
tr.Claims,
@ -627,13 +629,13 @@ func TestUserCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: user.ErrForbidden.Error(),
}
@ -670,13 +672,13 @@ func TestUserCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: user.ErrForbidden.Error(),
}
@ -710,15 +712,13 @@ func TestUserCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
@ -748,15 +748,13 @@ func TestUserCRUDUser(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: mid.ErrForbidden.Error(),
}
expected := mid.ErrorForbidden(ctx).(*weberror.Error).Display(ctx)
if diff := cmpDiff(t, actual, expected); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
@ -807,6 +805,7 @@ func TestUserCRUDUser(t *testing.T) {
"access_token": actual["access_token"],
"token_type": actual["token_type"],
"expiry": actual["expiry"],
"ttl": actual["ttl"],
}
if diff := cmpDiff(t, actual, expected); diff {
@ -864,16 +863,23 @@ func TestUserCreate(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "email", Error: "Key: 'UserCreateRequest.email' Error:Field validation for 'email' failed on the 'email' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "email", Error: "Key: 'UserCreateRequest.email' Error:Field validation for 'email' failed on the 'email' tag"},
{
Field: "email",
Value: req.Email,
Tag: "email",
Error: "email must be a valid email address",
Display: "email must be a valid email address",
},
},
}
@ -919,16 +925,23 @@ func TestUserUpdate(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "email", Error: "Key: 'UserUpdateRequest.email' Error:Field validation for 'email' failed on the 'email' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "email", Error: "Key: 'UserUpdateRequest.email' Error:Field validation for 'email' failed on the 'email' tag"},
{
Field: "email",
Value: invalidEmail,
Tag: "email",
Error: "email must be a valid email address",
Display: "email must be a valid email address",
},
},
}
@ -956,6 +969,8 @@ func TestUserUpdatePassword(t *testing.T) {
expectedStatus := http.StatusBadRequest
newPass := uuid.NewRandom().String()
diffPass := "different"
rt := requestTest{
fmt.Sprintf("Update password %d w/role %s using invalid data", expectedStatus, tr.Role),
http.MethodPatch,
@ -963,7 +978,7 @@ func TestUserUpdatePassword(t *testing.T) {
user.UserUpdatePasswordRequest{
ID: created.ID,
Password: newPass,
PasswordConfirm: "different",
PasswordConfirm: diffPass,
},
tr.Token,
tr.Claims,
@ -978,16 +993,23 @@ func TestUserUpdatePassword(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "password_confirm", Error: "Key: 'UserUpdatePasswordRequest.password_confirm' Error:Field validation for 'password_confirm' failed on the 'eqfield' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "password_confirm", Error: "Key: 'UserUpdatePasswordRequest.password_confirm' Error:Field validation for 'password_confirm' failed on the 'eqfield' tag"},
{
Field: "password_confirm",
Value: diffPass,
Tag: "eqfield",
Error: "password_confirm must be equal to Password",
Display: "password_confirm must be equal to Password",
},
},
}
@ -1011,12 +1033,14 @@ func TestUserArchive(t *testing.T) {
{
expectedStatus := http.StatusBadRequest
invalidId := "a"
rt := requestTest{
fmt.Sprintf("Archive %d w/role %s using invalid data", expectedStatus, tr.Role),
http.MethodPatch,
"/v1/users/archive",
user.UserArchiveRequest{
ID: "a",
ID: invalidId,
},
tr.Token,
tr.Claims,
@ -1031,16 +1055,23 @@ func TestUserArchive(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "id", Error: "Key: 'UserArchiveRequest.id' Error:Field validation for 'id' failed on the 'uuid' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "id", Error: "Key: 'UserArchiveRequest.id' Error:Field validation for 'id' failed on the 'uuid' tag"},
{
Field: "id",
Value: invalidId,
Tag: "uuid",
Error: "id must be a valid UUID",
Display: "id must be a valid UUID",
},
},
}
@ -1074,13 +1105,13 @@ func TestUserArchive(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: user.ErrForbidden.Error(),
}
@ -1104,10 +1135,12 @@ func TestUserDelete(t *testing.T) {
{
expectedStatus := http.StatusBadRequest
invalidId := "345345"
rt := requestTest{
fmt.Sprintf("Delete %d w/role %s using invalid data", expectedStatus, tr.Role),
http.MethodDelete,
"/v1/users/345345",
fmt.Sprintf("/v1/users/%s", invalidId),
nil,
tr.Token,
tr.Claims,
@ -1122,16 +1155,23 @@ func TestUserDelete(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "id", Error: "Key: 'id' Error:Field validation for 'id' failed on the 'uuid' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
//{Field: "id", Error: "Key: 'id' Error:Field validation for 'id' failed on the 'uuid' tag"},
{
Field: "id",
Value: invalidId,
Tag: "uuid",
Error: "id must be a valid UUID",
Display: "id must be a valid UUID",
},
},
}
@ -1163,13 +1203,13 @@ func TestUserDelete(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: user.ErrForbidden.Error(),
}
@ -1193,10 +1233,12 @@ func TestUserSwitchAccount(t *testing.T) {
{
expectedStatus := http.StatusBadRequest
invalidAccountId := "sf"
rt := requestTest{
fmt.Sprintf("Switch account %d w/role %s using invalid data", expectedStatus, tr.Role),
http.MethodPatch,
"/v1/users/switch-account/sf",
"/v1/users/switch-account/" + invalidAccountId,
nil,
tr.Token,
tr.Claims,
@ -1211,20 +1253,26 @@ func TestUserSwitchAccount(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
Error: "field validation error",
Fields: []web.FieldError{
{Field: "account_id", Error: "Key: 'account_id' Error:Field validation for 'account_id' failed on the 'uuid' tag"},
expected := weberror.ErrorResponse{
Error: "Field validation error",
Fields: []weberror.FieldError{
{
Field: "account_id",
Value: invalidAccountId,
Tag: "uuid",
Error: "account_id must be a valid UUID",
Display: "account_id must be a valid UUID",
},
},
}
if diff := cmpDiff(t, actual, expected); diff {
if diff := cmpDiff(t, expected, actual); diff {
t.Fatalf("\t%s\tReceived expected error.", tests.Failed)
}
t.Logf("\t%s\tReceived expected error.", tests.Success)
@ -1252,13 +1300,13 @@ func TestUserSwitchAccount(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: user.ErrAuthenticationFailure.Error(),
}
@ -1295,13 +1343,13 @@ func TestUserToken(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: "must provide email and password in Basic auth",
}
@ -1342,13 +1390,13 @@ func TestUserToken(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: user.ErrAuthenticationFailure.Error(),
}
@ -1390,13 +1438,13 @@ func TestUserToken(t *testing.T) {
}
t.Logf("\t%s\tReceived valid status code of %d.", tests.Success, w.Code)
var actual web.ErrorResponse
var actual weberror.ErrorResponse
if err := json.Unmarshal(w.Body.Bytes(), &actual); err != nil {
t.Logf("\t\tGot error : %+v", err)
t.Fatalf("\t%s\tDecode response body failed.", tests.Failed)
}
expected := web.ErrorResponse{
expected := weberror.ErrorResponse{
Error: user.ErrAuthenticationFailure.Error(),
}
@ -1450,6 +1498,7 @@ func TestUserToken(t *testing.T) {
"access_token": actual["access_token"],
"token_type": actual["token_type"],
"expiry": actual["expiry"],
"ttl": actual["ttl"],
}
if diff := cmpDiff(t, actual, expected); diff {

View File

@ -18,7 +18,7 @@ import (
)
const (
tmplLayoutBase = "base.tmpl"
tmplLayoutBase = "base.gohtml"
tmplContentErrorGeneric = "error-generic.gohtml"
)

View File

@ -2,11 +2,11 @@ package handlers
import (
"context"
"geeks-accelerator/oss/saas-starter-kit/internal/geonames"
"net/http"
"time"
"geeks-accelerator/oss/saas-starter-kit/internal/account"
"geeks-accelerator/oss/saas-starter-kit/internal/geonames"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/auth"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
@ -104,5 +104,5 @@ func (h *Signup) Step1(ctx context.Context, w http.ResponseWriter, r *http.Reque
data["validationDefaults"] = verr.(*weberror.Error)
}
return h.Renderer.Render(ctx, w, r, tmplLayoutBase, "signup-step1.tmpl", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
return h.Renderer.Render(ctx, w, r, tmplLayoutBase, "signup-step1.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
}

View File

@ -107,7 +107,7 @@ func (h *User) Login(ctx context.Context, w http.ResponseWriter, r *http.Request
data["validationDefaults"] = verr.(*weberror.Error)
}
return h.Renderer.Render(ctx, w, r, tmplLayoutBase, "user-login.tmpl", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
return h.Renderer.Render(ctx, w, r, tmplLayoutBase, "user-login.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, data)
}
// handleSessionToken persists the access token to the session for request authentication.

View File

@ -12,7 +12,6 @@ import (
"github.com/pborman/uuid"
"github.com/pkg/errors"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
"gopkg.in/go-playground/validator.v9"
)
const (
@ -262,23 +261,17 @@ func Create(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, req Accoun
span, ctx := tracer.StartSpanFromContext(ctx, "internal.account.Create")
defer span.Finish()
// Validation email address is unique in the database.
v := webcontext.Validator()
// Validation account name is unique in the database.
uniq, err := UniqueName(ctx, dbConn, req.Name, "")
if err != nil {
return nil, err
}
f := func(fl validator.FieldLevel) bool {
if fl.Field().String() == "invalid" {
return false
}
return uniq
}
v := webcontext.Validator()
v.RegisterValidation("unique", f)
ctx = context.WithValue(ctx, webcontext.KeyTagUnique, uniq)
// Validate the request.
err = v.Struct(req)
err = v.StructCtx(ctx, req)
if err != nil {
return nil, err
}
@ -371,24 +364,19 @@ func Update(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, req Accoun
v := webcontext.Validator()
// Validation name is unique in the database.
if req.Name != nil {
// Validation account name is unique in the database.
uniq, err := UniqueName(ctx, dbConn, *req.Name, req.ID)
if err != nil {
return err
}
f := func(fl validator.FieldLevel) bool {
if fl.Field().String() == "invalid" {
return false
}
return uniq
}
v.RegisterValidation("unique", f)
ctx = context.WithValue(ctx, webcontext.KeyTagUnique, uniq)
} else {
ctx = context.WithValue(ctx, webcontext.KeyTagUnique, true)
}
// Validate the request.
err := v.Struct(req)
err := v.StructCtx(ctx, req)
if err != nil {
return err
}

View File

@ -32,7 +32,7 @@ func testMain(m *testing.M) int {
// TestFindRequestQuery validates findRequestQuery
func TestFindRequestQuery(t *testing.T) {
where := "name = ? or address1 = ?"
where := "first_name = ? or address1 = ?"
var (
limit uint = 12
offset uint = 34
@ -41,7 +41,7 @@ func TestFindRequestQuery(t *testing.T) {
req := AccountFindRequest{
Where: &where,
Args: []interface{}{
"lee brown",
"lee",
"103 East Main St.",
},
Order: []string{
@ -51,7 +51,7 @@ func TestFindRequestQuery(t *testing.T) {
Limit: &limit,
Offset: &offset,
}
expected := "SELECT " + accountMapColumns + " FROM " + accountTableName + " WHERE (name = ? or address1 = ?) ORDER BY id asc, created_at desc LIMIT 12 OFFSET 34"
expected := "SELECT " + accountMapColumns + " FROM " + accountTableName + " WHERE (first_name = ? or address1 = ?) ORDER BY id asc, created_at desc LIMIT 12 OFFSET 34"
res, args := findRequestQuery(req)
@ -223,7 +223,8 @@ func TestCreateValidation(t *testing.T) {
// of type interface validator.ValidationErrorsTranslations
var errStr string
if err != nil {
errStr = err.Error()
errStr = strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
}
var expectStr string
if tt.error != nil {
@ -293,8 +294,11 @@ func TestCreateValidationNameUnique(t *testing.T) {
t.Fatalf("\t%s\tCreate failed.", tests.Failed)
}
if err.Error() != expectedErr.Error() {
t.Logf("\t\tGot : %+v", err)
errStr := strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
if errStr != expectedErr.Error() {
t.Logf("\t\tGot : %+v", errStr)
t.Logf("\t\tWant: %+v", expectedErr)
t.Fatalf("\t%s\tCreate failed.", tests.Failed)
}
@ -431,7 +435,8 @@ func TestUpdateValidation(t *testing.T) {
// of type interface validator.ValidationErrorsTranslations
var errStr string
if err != nil {
errStr = err.Error()
errStr = strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
}
var expectStr string
if tt.error != nil {
@ -501,8 +506,11 @@ func TestUpdateValidationNameUnique(t *testing.T) {
t.Fatalf("\t%s\tUpdate failed.", tests.Failed)
}
if err.Error() != expectedErr.Error() {
t.Logf("\t\tGot : %+v", err)
errStr := strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
if errStr != expectedErr.Error() {
t.Logf("\t\tGot : %+v", errStr)
t.Logf("\t\tWant: %+v", expectedErr)
t.Fatalf("\t%s\tUpdate failed.", tests.Failed)
}

View File

@ -3,6 +3,7 @@ package saasSwagger
import (
"context"
"fmt"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/weberror"
"github.com/pborman/uuid"
"html/template"
"net/http"
@ -74,7 +75,7 @@ func SaasWrapHandler(confs ...func(c *Config)) web.Handler {
prefix = matches[1]
} else if len(matches) > 0 {
err := errors.WithMessagef(ErrNotFound, "page %s not found", r.RequestURI)
return web.NewRequestError(err, http.StatusNotFound)
return weberror.NewError(ctx, err, http.StatusNotFound)
}
// Default to index page.
@ -92,7 +93,7 @@ func SaasWrapHandler(confs ...func(c *Config)) web.Handler {
case "doc.json":
doc, err := swag.ReadDoc()
if err != nil {
return web.NewRequestError(err, http.StatusInternalServerError)
return weberror.NewError(ctx, err, http.StatusInternalServerError)
}
// Replace the dynamic placeholder {RANDOM_UUID}

View File

@ -3,6 +3,7 @@ package tests
import (
"context"
"fmt"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web/webcontext"
"io"
"log"
"os"
@ -12,7 +13,6 @@ import (
"time"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/docker"
"geeks-accelerator/oss/saas-starter-kit/internal/platform/web"
"geeks-accelerator/oss/saas-starter-kit/internal/schema"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/jmoiron/sqlx"
@ -94,7 +94,7 @@ func New() *Test {
}
// Execute the migrations
if err = schema.Migrate(masterDB, log); err != nil {
if err = schema.Migrate(masterDB, log, true); err != nil {
log.Fatalf("main : Migrate : %v", err)
}
log.Printf("main : Migrate : Completed")
@ -126,10 +126,10 @@ func Recover(t *testing.T) {
// Context returns an app level context for testing.
func Context() context.Context {
values := web.Values{
values := webcontext.Values{
TraceID: uint64(time.Now().UnixNano()),
Now: time.Now(),
}
return context.WithValue(context.Background(), web.KeyValues, &values)
return context.WithValue(context.Background(), webcontext.KeyValues, &values)
}

View File

@ -31,7 +31,7 @@ const (
)
// RespondJsonError sends an error formatted as JSON response back to the client.
func RespondJsonError(ctx context.Context, w http.ResponseWriter, err error) error {
func RespondJsonError(ctx context.Context, w http.ResponseWriter, er error) error {
// Set the status code for the request logger middleware.
// If the context is missing this value, request the service
@ -41,9 +41,13 @@ func RespondJsonError(ctx context.Context, w http.ResponseWriter, err error) err
return err
}
// If the error was of the type *Error, the handler has
// a specific status code and error to return.
webErr := weberror.NewError(ctx, err, v.StatusCode).(*weberror.Error)
webErr, ok := er.(*weberror.Error)
if !ok {
// If the error was of the type *Error, the handler has
// a specific status code and error to return.
webErr = weberror.NewError(ctx, er, v.StatusCode).(*weberror.Error)
}
v.StatusCode = webErr.Status
return RespondJson(ctx, w, webErr.Display(ctx), webErr.Status)

View File

@ -34,7 +34,10 @@ func ContextWithTranslator(ctx context.Context, translator ut.Translator) contex
// ContextTranslator returns the universal context from a context.
func ContextTranslator(ctx context.Context) ut.Translator {
return ctx.Value(KeyTranslate).(ut.Translator)
if t, ok := ctx.Value(KeyTranslate).(ut.Translator); ok {
return t
}
return uniTrans.GetFallback()
}
// validate holds the settings and caches for validating request struct values.
@ -122,6 +125,10 @@ func init() {
}
type ctxKeyTagUnique int
const KeyTagUnique ctxKeyTagUnique = 1
// newValidator inits a new validator with custom settings.
func newValidator() *validator.Validate {
var v = validator.New()
@ -139,10 +146,18 @@ func newValidator() *validator.Validate {
// Empty method that can be overwritten in business logic packages to prevent web.Decode from failing.
f := func(fl validator.FieldLevel) bool {
return true
return false
}
v.RegisterValidation("unique", f)
fctx := func(ctx context.Context, fl validator.FieldLevel) bool {
if fl.Field().String() == "invalid" {
return false
}
return ctx.Value(KeyTagUnique).(bool)
}
v.RegisterValidationCtx("unique", fctx)
return v
}

View File

@ -2,7 +2,6 @@ package weberror
import (
"context"
"fmt"
"net/http"
"strings"
@ -44,7 +43,7 @@ func NewValidationError(ctx context.Context, err error) (error, bool) {
fieldErr = strings.Replace(fieldErr, "}}", "", -1)
field := FieldError{
Field: verror.Field(),
Field: fieldName,
Value: verror.Value(),
Tag: verror.Tag(),
Error: fieldErr,
@ -52,12 +51,12 @@ func NewValidationError(ctx context.Context, err error) (error, bool) {
Display: fieldErr,
}
switch verror.Tag() {
case "required":
field.Display = fmt.Sprintf("%s is required.", localName)
case "unique":
field.Display = fmt.Sprintf("%s must be unique.", localName)
}
//switch verror.Tag() {
//case "required":
// field.Display = fmt.Sprintf("%s is required.", localName)
//case "unique":
// field.Display = fmt.Sprintf("%s must be unique.", localName)
//}
/*
fmt.Println("field", field.Error)

View File

@ -8,7 +8,7 @@ import (
// initSchema runs before any migrations are executed. This happens when no other migrations
// have previously been executed.
func initSchema(db *sqlx.DB, log *log.Logger) func(*sqlx.DB) error {
func initSchema(db *sqlx.DB, log *log.Logger, isUnittest bool) func(*sqlx.DB) error {
f := func(db *sqlx.DB) error {
return nil
}

View File

@ -18,7 +18,7 @@ import (
// migrationList returns a list of migrations to be executed. If the id of the
// migration already exists in the migrations table it will be skipped.
func migrationList(db *sqlx.DB, log *log.Logger) []*sqlxmigrate.Migration {
func migrationList(db *sqlx.DB, log *log.Logger, isUnittest bool) []*sqlxmigrate.Migration {
return []*sqlxmigrate.Migration{
// Create table users.
{
@ -249,18 +249,22 @@ func migrationList(db *sqlx.DB, log *log.Logger) []*sqlxmigrate.Migration {
return errors.WithMessagef(err, "Failed to prepare sql query '%s'", q)
}
resChan := make(chan interface{})
go geonames.LoadGeonames(context.Background(), resChan)
if isUnittest {
for r := range resChan {
switch v := r.(type) {
case geonames.Geoname:
_, err = stmt.Exec(v.CountryCode, v.PostalCode, v.PlaceName, v.StateName, v.StateCode, v.CountyName, v.CountyCode, v.CommunityName, v.CommunityCode, v.Latitude, v.Longitude, v.Accuracy)
if err != nil {
return errors.WithStack(err)
} else {
resChan := make(chan interface{})
go geonames.LoadGeonames(context.Background(), resChan)
for r := range resChan {
switch v := r.(type) {
case geonames.Geoname:
_, err = stmt.Exec(v.CountryCode, v.PostalCode, v.PlaceName, v.StateName, v.StateCode, v.CountyName, v.CountyCode, v.CommunityName, v.CommunityCode, v.Latitude, v.Longitude, v.Accuracy)
if err != nil {
return errors.WithStack(err)
}
case error:
return v
}
case error:
return v
}
}
@ -287,9 +291,35 @@ func migrationList(db *sqlx.DB, log *log.Logger) []*sqlxmigrate.Migration {
ID: "20190731-02d",
Migrate: func(tx *sql.Tx) error {
prep := []string{
`DROP TABLE IF EXISTS countryinfo`,
`CREATE TABLE countryinfo (
schemas := []string{
// Countries...
`DROP TABLE IF EXISTS countries`,
`CREATE TABLE countries(
code char(2) not null constraint countries_pkey primary key,
iso_alpha3 char(3),
name character varying(50),
capital character varying(50),
currency_code char(3),
currency_name CHAR(20),
phone character varying(20),
postal_code_format character varying(200),
postal_code_regex character varying(200))`,
}
for _, q := range schemas {
_, err := db.Exec(q)
if err != nil {
return errors.WithMessagef(err, "Failed to execute sql query '%s'", q)
}
}
if isUnittest {
// `insert into countries(code, iso_alpha3, name, capital, currency_code, currency_name, phone, postal_code_format, postal_code_regex)
} else {
prep := []string{
`DROP TABLE IF EXISTS countryinfo`,
`CREATE TABLE countryinfo (
iso_alpha2 char(2),
iso_alpha3 char(3),
iso_numeric integer,
@ -309,38 +339,108 @@ func migrationList(db *sqlx.DB, log *log.Logger) []*sqlxmigrate.Migration {
geonameId int,
neighbours character varying(50),
equivalent_fips_code character varying(3))`,
}
}
for _, q := range prep {
_, err := db.Exec(q)
for _, q := range prep {
_, err := db.Exec(q)
if err != nil {
return errors.WithMessagef(err, "Failed to execute sql query '%s'", q)
}
}
u := "http://download.geonames.org/export/dump/countryInfo.txt"
resp, err := pester.Get(u)
if err != nil {
return errors.WithMessagef(err, "Failed to execute sql query '%s'", q)
return errors.WithMessagef(err, "Failed to read country info from '%s'", u)
}
}
defer resp.Body.Close()
u := "http://download.geonames.org/export/dump/countryInfo.txt"
resp, err := pester.Get(u)
if err != nil {
return errors.WithMessagef(err, "Failed to read country info from '%s'", u)
}
defer resp.Body.Close()
scanner := bufio.NewScanner(resp.Body)
var prevLine string
var stmt *sql.Stmt
for scanner.Scan() {
line := scanner.Text()
scanner := bufio.NewScanner(resp.Body)
var prevLine string
var stmt *sql.Stmt
for scanner.Scan() {
line := scanner.Text()
// Skip comments.
if strings.HasPrefix(line, "#") {
prevLine = line
continue
}
// Skip comments.
if strings.HasPrefix(line, "#") {
prevLine = line
continue
}
// Pull the last comment to load the fields.
if stmt == nil {
prevLine = strings.TrimPrefix(prevLine, "#")
r := csv.NewReader(strings.NewReader(prevLine))
r.Comma = '\t' // Use tab-delimited instead of comma <---- here!
r.FieldsPerRecord = -1
// Pull the last comment to load the fields.
if stmt == nil {
prevLine = strings.TrimPrefix(prevLine, "#")
r := csv.NewReader(strings.NewReader(prevLine))
lines, err := r.ReadAll()
if err != nil {
return errors.WithStack(err)
}
var columns []string
for _, fn := range lines[0] {
var cn string
switch fn {
case "ISO":
cn = "iso_alpha2"
case "ISO3":
cn = "iso_alpha3"
case "ISO-Numeric":
cn = "iso_numeric"
case "fips":
cn = "fips_code"
case "Country":
cn = "country"
case "Capital":
cn = "capital"
case "Area(in sq km)":
cn = "areainsqkm"
case "Population":
cn = "population"
case "Continent":
cn = "continent"
case "tld":
cn = "tld"
case "CurrencyCode":
cn = "currency_code"
case "CurrencyName":
cn = "currency_name"
case "Phone":
cn = "phone"
case "Postal Code Format":
cn = "postal_format"
case "Postal Code Regex":
cn = "postal_regex"
case "Languages":
cn = "languages"
case "geonameid":
cn = "geonameId"
case "neighbours":
cn = "neighbours"
case "EquivalentFipsCode":
cn = "equivalent_fips_code"
default:
return errors.Errorf("Failed to map column %s", fn)
}
columns = append(columns, cn)
}
placeholders := []string{}
for i := 0; i < len(columns); i++ {
placeholders = append(placeholders, "?")
}
q := "insert into countryinfo (" + strings.Join(columns, ",") + ") values(" + strings.Join(placeholders, ",") + ")"
q = db.Rebind(q)
stmt, err = db.Prepare(q)
if err != nil {
return errors.WithMessagef(err, "Failed to prepare sql query '%s'", q)
}
}
r := csv.NewReader(strings.NewReader(line))
r.Comma = '\t' // Use tab-delimited instead of comma <---- here!
r.FieldsPerRecord = -1
@ -348,117 +448,36 @@ func migrationList(db *sqlx.DB, log *log.Logger) []*sqlxmigrate.Migration {
if err != nil {
return errors.WithStack(err)
}
var columns []string
for _, fn := range lines[0] {
var cn string
switch fn {
case "ISO":
cn = "iso_alpha2"
case "ISO3":
cn = "iso_alpha3"
case "ISO-Numeric":
cn = "iso_numeric"
case "fips":
cn = "fips_code"
case "Country":
cn = "country"
case "Capital":
cn = "capital"
case "Area(in sq km)":
cn = "areainsqkm"
case "Population":
cn = "population"
case "Continent":
cn = "continent"
case "tld":
cn = "tld"
case "CurrencyCode":
cn = "currency_code"
case "CurrencyName":
cn = "currency_name"
case "Phone":
cn = "phone"
case "Postal Code Format":
cn = "postal_format"
case "Postal Code Regex":
cn = "postal_regex"
case "Languages":
cn = "languages"
case "geonameid":
cn = "geonameId"
case "neighbours":
cn = "neighbours"
case "EquivalentFipsCode":
cn = "equivalent_fips_code"
default:
return errors.Errorf("Failed to map column %s", fn)
for _, row := range lines {
var args []interface{}
for _, v := range row {
args = append(args, v)
}
columns = append(columns, cn)
}
placeholders := []string{}
for i := 0; i < len(columns); i++ {
placeholders = append(placeholders, "?")
}
q := "insert into countryinfo (" + strings.Join(columns, ",") + ") values(" + strings.Join(placeholders, ",") + ")"
q = db.Rebind(q)
stmt, err = db.Prepare(q)
if err != nil {
return errors.WithMessagef(err, "Failed to prepare sql query '%s'", q)
_, err = stmt.Exec(args...)
if err != nil {
return errors.WithStack(err)
}
}
}
r := csv.NewReader(strings.NewReader(line))
r.Comma = '\t' // Use tab-delimited instead of comma <---- here!
r.FieldsPerRecord = -1
lines, err := r.ReadAll()
if err != nil {
if err := scanner.Err(); err != nil {
return errors.WithStack(err)
}
for _, row := range lines {
var args []interface{}
for _, v := range row {
args = append(args, v)
}
_, err = stmt.Exec(args...)
if err != nil {
return errors.WithStack(err)
}
}
}
if err := scanner.Err(); err != nil {
return errors.WithStack(err)
}
queries := []string{
// Countries...
`DROP TABLE IF EXISTS countries`,
`CREATE TABLE countries(
code char(2) not null constraint countries_pkey primary key,
iso_alpha3 char(3),
name character varying(50),
capital character varying(50),
currency_code char(3),
currency_name CHAR(20),
phone character varying(20),
postal_code_format character varying(200),
postal_code_regex character varying(200))`,
`insert into countries(code, iso_alpha3, name, capital, currency_code, currency_name, phone, postal_code_format, postal_code_regex)
queries := []string{
`insert into countries(code, iso_alpha3, name, capital, currency_code, currency_name, phone, postal_code_format, postal_code_regex)
select iso_alpha2, iso_alpha3, country, capital, currency_code, currency_name, phone, postal_format, postal_regex
from countryinfo`,
`DROP TABLE IF EXISTS countryinfo`,
}
`DROP TABLE IF EXISTS countryinfo`,
}
for _, q := range queries {
_, err := db.Exec(q)
if err != nil {
return errors.WithMessagef(err, "Failed to execute sql query '%s'", q)
for _, q := range queries {
_, err := db.Exec(q)
if err != nil {
return errors.WithMessagef(err, "Failed to execute sql query '%s'", q)
}
}
}
@ -488,48 +507,52 @@ func migrationList(db *sqlx.DB, log *log.Logger) []*sqlxmigrate.Migration {
}
}
u := "http://download.geonames.org/export/dump/timeZones.txt"
resp, err := pester.Get(u)
if err != nil {
return errors.WithMessagef(err, "Failed to read timezones info from '%s'", u)
}
defer resp.Body.Close()
if isUnittest {
q := "insert into country_timezones (country_code,timezone_id) values(?, ?)"
q = db.Rebind(q)
stmt, err := db.Prepare(q)
if err != nil {
return errors.WithMessagef(err, "Failed to prepare sql query '%s'", q)
}
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
line := scanner.Text()
// Skip comments.
if strings.HasPrefix(line, "CountryCode") {
continue
}
r := csv.NewReader(strings.NewReader(line))
r.Comma = '\t' // Use tab-delimited instead of comma <---- here!
r.FieldsPerRecord = -1
lines, err := r.ReadAll()
} else {
u := "http://download.geonames.org/export/dump/timeZones.txt"
resp, err := pester.Get(u)
if err != nil {
return errors.WithStack(err)
return errors.WithMessagef(err, "Failed to read timezones info from '%s'", u)
}
defer resp.Body.Close()
q := "insert into country_timezones (country_code,timezone_id) values(?, ?)"
q = db.Rebind(q)
stmt, err := db.Prepare(q)
if err != nil {
return errors.WithMessagef(err, "Failed to prepare sql query '%s'", q)
}
for _, row := range lines {
_, err = stmt.Exec(row[0], row[1])
scanner := bufio.NewScanner(resp.Body)
for scanner.Scan() {
line := scanner.Text()
// Skip comments.
if strings.HasPrefix(line, "CountryCode") {
continue
}
r := csv.NewReader(strings.NewReader(line))
r.Comma = '\t' // Use tab-delimited instead of comma <---- here!
r.FieldsPerRecord = -1
lines, err := r.ReadAll()
if err != nil {
return errors.WithStack(err)
}
}
}
if err := scanner.Err(); err != nil {
return errors.WithStack(err)
for _, row := range lines {
_, err = stmt.Exec(row[0], row[1])
if err != nil {
return errors.WithStack(err)
}
}
}
if err := scanner.Err(); err != nil {
return errors.WithStack(err)
}
}
return nil

View File

@ -7,15 +7,15 @@ import (
"github.com/jmoiron/sqlx"
)
func Migrate(masterDb *sqlx.DB, log *log.Logger) error {
func Migrate(masterDb *sqlx.DB, log *log.Logger, isUnittest bool) error {
// Load list of Schema migrations and init new sqlxmigrate client
migrations := migrationList(masterDb, log)
migrations := migrationList(masterDb, log, isUnittest)
m := sqlxmigrate.New(masterDb, sqlxmigrate.DefaultOptions, migrations)
m.SetLogger(log)
// Append any schema that need to be applied if this is a fresh migration
// ie. the migrations database table does not exist.
m.InitSchema(initSchema(masterDb, log))
m.InitSchema(initSchema(masterDb, log, isUnittest))
// Execute the migrations
return m.Migrate()

View File

@ -13,7 +13,6 @@ import (
"github.com/pkg/errors"
"golang.org/x/crypto/bcrypt"
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
"gopkg.in/go-playground/validator.v9"
)
const (
@ -278,23 +277,17 @@ func Create(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, req UserCr
span, ctx := tracer.StartSpanFromContext(ctx, "internal.user.Create")
defer span.Finish()
v := webcontext.Validator()
// Validation email address is unique in the database.
uniq, err := UniqueEmail(ctx, dbConn, req.Email, "")
if err != nil {
return nil, err
}
f := func(fl validator.FieldLevel) bool {
if fl.Field().String() == "invalid" {
return false
}
return uniq
}
v := webcontext.Validator()
v.RegisterValidation("unique", f)
ctx = context.WithValue(ctx, webcontext.KeyTagUnique, uniq)
// Validate the request.
err = v.Struct(req)
err = v.StructCtx(ctx, req)
if err != nil {
return nil, err
}
@ -394,21 +387,18 @@ func Update(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, req UserUp
// Validation email address is unique in the database.
if req.Email != nil {
// Validation email address is unique in the database.
uniq, err := UniqueEmail(ctx, dbConn, *req.Email, req.ID)
if err != nil {
return err
}
f := func(fl validator.FieldLevel) bool {
if fl.Field().String() == "invalid" {
return false
}
return uniq
}
v.RegisterValidation("unique", f)
ctx = context.WithValue(ctx, webcontext.KeyTagUnique, uniq)
} else {
ctx = context.WithValue(ctx, webcontext.KeyTagUnique, true)
}
// Validate the request.
err := v.Struct(req)
err := v.StructCtx(ctx, req)
if err != nil {
return err
}
@ -437,10 +427,10 @@ func Update(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, req UserUp
var fields []string
if req.FirstName != nil {
fields = append(fields, query.Assign("name", req.FirstName))
fields = append(fields, query.Assign("first_name", req.FirstName))
}
if req.LastName != nil {
fields = append(fields, query.Assign("name", req.LastName))
fields = append(fields, query.Assign("last_name", req.LastName))
}
if req.Email != nil {
fields = append(fields, query.Assign("email", req.Email))

View File

@ -152,7 +152,8 @@ func TestCreateValidation(t *testing.T) {
errors.New("Key: 'UserCreateRequest.first_name' Error:Field validation for 'first_name' failed on the 'required' tag\n" +
"Key: 'UserCreateRequest.last_name' Error:Field validation for 'last_name' failed on the 'required' tag\n" +
"Key: 'UserCreateRequest.email' Error:Field validation for 'email' failed on the 'required' tag\n" +
"Key: 'UserCreateRequest.password' Error:Field validation for 'password' failed on the 'required' tag"),
"Key: 'UserCreateRequest.password' Error:Field validation for 'password' failed on the 'required' tag\n" +
"Key: 'UserCreateRequest.password_confirm' Error:Field validation for 'password_confirm' failed on the 'required' tag"),
},
{"Valid Email",
UserCreateRequest{
@ -224,15 +225,16 @@ func TestCreateValidation(t *testing.T) {
// of type interface validator.ValidationErrorsTranslations
var errStr string
if err != nil {
errStr = err.Error()
errStr = strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
}
var expectStr string
if tt.error != nil {
expectStr = tt.error.Error()
}
if errStr != expectStr {
t.Logf("\t\tGot : %+v", err)
t.Logf("\t\tWant: %+v", tt.error)
t.Logf("\t\tGot : %+v", errStr)
t.Logf("\t\tWant: %+v", expectStr)
t.Fatalf("\t%s\tCreate failed.", tests.Failed)
}
}
@ -290,8 +292,11 @@ func TestCreateValidationEmailUnique(t *testing.T) {
t.Fatalf("\t%s\tCreate failed.", tests.Failed)
}
if err.Error() != expectedErr.Error() {
t.Logf("\t\tGot : %+v", err)
errStr := strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
if errStr != expectedErr.Error() {
t.Logf("\t\tGot : %+v", errStr)
t.Logf("\t\tWant: %+v", expectedErr)
t.Fatalf("\t%s\tCreate failed.", tests.Failed)
}
@ -422,15 +427,16 @@ func TestUpdateValidation(t *testing.T) {
// of type interface validator.ValidationErrorsTranslations
var errStr string
if err != nil {
errStr = err.Error()
errStr = strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
}
var expectStr string
if tt.error != nil {
expectStr = tt.error.Error()
}
if errStr != expectStr {
t.Logf("\t\tGot : %+v", err)
t.Logf("\t\tWant: %+v", tt.error)
t.Logf("\t\tGot : %+v", errStr)
t.Logf("\t\tWant: %+v", expectStr)
t.Fatalf("\t%s\tUpdate failed.", tests.Failed)
}
}
@ -488,8 +494,11 @@ func TestUpdateValidationEmailUnique(t *testing.T) {
t.Fatalf("\t%s\tUpdate failed.", tests.Failed)
}
if err.Error() != expectedErr.Error() {
t.Logf("\t\tGot : %+v", err)
errStr := strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
if errStr != expectedErr.Error() {
t.Logf("\t\tGot : %+v", errStr)
t.Logf("\t\tWant: %+v", expectedErr)
t.Fatalf("\t%s\tUpdate failed.", tests.Failed)
}
@ -547,13 +556,19 @@ func TestUpdatePassword(t *testing.T) {
// Ensure validation is working by trying UpdatePassword with an empty request.
expectedErr := errors.New("Key: 'UserUpdatePasswordRequest.id' Error:Field validation for 'id' failed on the 'required' tag\n" +
"Key: 'UserUpdatePasswordRequest.password' Error:Field validation for 'password' failed on the 'required' tag")
"Key: 'UserUpdatePasswordRequest.password' Error:Field validation for 'password' failed on the 'required' tag\n" +
"Key: 'UserUpdatePasswordRequest.password_confirm' Error:Field validation for 'password_confirm' failed on the 'required' tag")
err = UpdatePassword(ctx, auth.Claims{}, test.MasterDB, UserUpdatePasswordRequest{}, now)
if err == nil {
t.Logf("\t\tWant: %+v", expectedErr)
t.Fatalf("\t%s\tUpdate failed.", tests.Failed)
} else if err.Error() != expectedErr.Error() {
t.Logf("\t\tGot : %+v", err)
}
errStr := strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
if errStr != expectedErr.Error() {
t.Logf("\t\tGot : %+v", errStr)
t.Logf("\t\tWant: %+v", expectedErr)
t.Fatalf("\t%s\tValidation failed.", tests.Failed)
}

View File

@ -232,15 +232,16 @@ func TestCreateValidation(t *testing.T) {
// of type interface validator.ValidationErrorsTranslations
var errStr string
if err != nil {
errStr = err.Error()
errStr = strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
}
var expectStr string
if tt.error != nil {
expectStr = tt.error.Error()
}
if errStr != expectStr {
t.Logf("\t\tGot : %+v", err)
t.Logf("\t\tWant: %+v", tt.error)
t.Logf("\t\tGot : %+v", errStr)
t.Logf("\t\tWant: %+v", expectStr)
t.Fatalf("\t%s\tCreate user account failed.", tests.Failed)
}
}
@ -411,15 +412,16 @@ func TestUpdateValidation(t *testing.T) {
// of type interface validator.ValidationErrorsTranslations
var errStr string
if err != nil {
errStr = err.Error()
errStr = strings.Replace(err.Error(), "{{", "", -1)
errStr = strings.Replace(errStr, "}}", "", -1)
}
var expectStr string
if tt.error != nil {
expectStr = tt.error.Error()
}
if errStr != expectStr {
t.Logf("\t\tGot : %+v", err)
t.Logf("\t\tWant: %+v", tt.error)
t.Logf("\t\tGot : %+v", errStr)
t.Logf("\t\tWant: %+v", expectStr)
t.Fatalf("\t%s\tUpdate user account failed.", tests.Failed)
}
}

View File

@ -126,7 +126,7 @@ func main() {
// Start Migrations
// Execute the migrations
if err = schema.Migrate(masterDb, log); err != nil {
if err = schema.Migrate(masterDb, log, false); err != nil {
log.Fatalf("main : Migrate : %v", err)
}
log.Printf("main : Migrate : Completed")