Commit 900cfcf7 authored by Lee Brown's avatar Lee Brown

fixed redirects to handle saving the session when set

parent 7909dc4c
...@@ -209,13 +209,8 @@ func (h *Account) Update(ctx context.Context, w http.ResponseWriter, r *http.Req ...@@ -209,13 +209,8 @@ func (h *Account) Update(ctx context.Context, w http.ResponseWriter, r *http.Req
webcontext.SessionFlashSuccess(ctx, webcontext.SessionFlashSuccess(ctx,
"Account Updated", "Account Updated",
"Account profile successfully updated.") "Account profile successfully updated.")
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
http.Redirect(w, r, "/account", http.StatusFound) return true, web.Redirect(ctx, w, r, "/account", http.StatusFound)
return true, nil
} }
acc, err := account.ReadByID(ctx, claims, h.MasterDB, claims.Audience) acc, err := account.ReadByID(ctx, claims, h.MasterDB, claims.Audience)
......
...@@ -203,13 +203,8 @@ func (h *Projects) Create(ctx context.Context, w http.ResponseWriter, r *http.Re ...@@ -203,13 +203,8 @@ func (h *Projects) Create(ctx context.Context, w http.ResponseWriter, r *http.Re
webcontext.SessionFlashSuccess(ctx, webcontext.SessionFlashSuccess(ctx,
"Project Created", "Project Created",
"Project successfully created.") "Project successfully created.")
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
http.Redirect(w, r, urlProjectsView(usr.ID), http.StatusFound) return true, web.Redirect(ctx, w, r, urlProjectsView(usr.ID), http.StatusFound)
return true, nil
} }
return false, nil return false, nil
...@@ -266,13 +261,8 @@ func (h *Projects) View(ctx context.Context, w http.ResponseWriter, r *http.Requ ...@@ -266,13 +261,8 @@ func (h *Projects) View(ctx context.Context, w http.ResponseWriter, r *http.Requ
webcontext.SessionFlashSuccess(ctx, webcontext.SessionFlashSuccess(ctx,
"Project Archive", "Project Archive",
"Project successfully archive.") "Project successfully archive.")
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
http.Redirect(w, r, urlProjectsIndex(), http.StatusFound) return true, web.Redirect(ctx, w, r, urlProjectsIndex(), http.StatusFound)
return true, nil
} }
} }
...@@ -347,13 +337,8 @@ func (h *Projects) Update(ctx context.Context, w http.ResponseWriter, r *http.Re ...@@ -347,13 +337,8 @@ func (h *Projects) Update(ctx context.Context, w http.ResponseWriter, r *http.Re
webcontext.SessionFlashSuccess(ctx, webcontext.SessionFlashSuccess(ctx,
"Project Updated", "Project Updated",
"Project successfully updated.") "Project successfully updated.")
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
http.Redirect(w, r, urlProjectsView(req.ID), http.StatusFound) return true, web.Redirect(ctx, w, r, urlProjectsView(req.ID), http.StatusFound)
return true, nil
} }
return false, nil return false, nil
......
...@@ -40,12 +40,10 @@ func (h *Root) indexDashboard(ctx context.Context, w http.ResponseWriter, r *htt ...@@ -40,12 +40,10 @@ func (h *Root) indexDashboard(ctx context.Context, w http.ResponseWriter, r *htt
// indexDefault loads the root index page when a user has no authentication. // indexDefault loads the root index page when a user has no authentication.
func (u *Root) indexDefault(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error { func (u *Root) indexDefault(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
return u.Renderer.Render(ctx, w, r, tmplLayoutSite, "site-index.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, nil) return u.Renderer.Render(ctx, w, r, tmplLayoutSite, "site-index.gohtml", web.MIMETextHTMLCharsetUTF8, http.StatusOK, nil)
} }
// indexDefault loads the root index page when a user has no authentication. // SitePage loads the page with the layout for site instead of the app base.
func (u *Root) SitePage(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error { func (u *Root) SitePage(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
var tmpName string var tmpName string
...@@ -63,18 +61,15 @@ func (u *Root) SitePage(ctx context.Context, w http.ResponseWriter, r *http.Requ ...@@ -63,18 +61,15 @@ func (u *Root) SitePage(ctx context.Context, w http.ResponseWriter, r *http.Requ
case "/legal/terms": case "/legal/terms":
tmpName = "legal-terms.gohtml" tmpName = "legal-terms.gohtml"
default: default:
http.Redirect(w, r, "/", http.StatusFound) return web.Redirect(ctx, w, r, "/", http.StatusFound)
return nil
} }
return u.Renderer.Render(ctx, w, r, tmplLayoutSite, tmpName, web.MIMETextHTMLCharsetUTF8, http.StatusOK, nil) return u.Renderer.Render(ctx, w, r, tmplLayoutSite, tmpName, web.MIMETextHTMLCharsetUTF8, http.StatusOK, nil)
} }
// IndexHtml redirects /index.html to the website root page. // IndexHtml redirects /index.html to the website root page.
func (u *Root) IndexHtml(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error { func (u *Root) IndexHtml(ctx context.Context, w http.ResponseWriter, r *http.Request, params map[string]string) error {
http.Redirect(w, r, "/", http.StatusMovedPermanently) return web.Redirect(ctx, w, r, "/", http.StatusMovedPermanently)
return nil
} }
// RobotHandler returns a robots.txt response. // RobotHandler returns a robots.txt response.
......
...@@ -86,14 +86,9 @@ func (h *Signup) Step1(ctx context.Context, w http.ResponseWriter, r *http.Reque ...@@ -86,14 +86,9 @@ func (h *Signup) Step1(ctx context.Context, w http.ResponseWriter, r *http.Reque
webcontext.SessionFlashSuccess(ctx, webcontext.SessionFlashSuccess(ctx,
"Thank you for Joining", "Thank you for Joining",
"You workflow will be a breeze starting today.") "You workflow will be a breeze starting today.")
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
// Redirect the user to the dashboard. // Redirect the user to the dashboard.
http.Redirect(w, r, "/", http.StatusFound) return true, web.Redirect(ctx, w, r, "/", http.StatusFound)
return true, nil
} }
return false, nil return false, nil
...@@ -103,6 +98,10 @@ func (h *Signup) Step1(ctx context.Context, w http.ResponseWriter, r *http.Reque ...@@ -103,6 +98,10 @@ func (h *Signup) Step1(ctx context.Context, w http.ResponseWriter, r *http.Reque
if err != nil { if err != nil {
return web.RenderError(ctx, w, r, err, h.Renderer, TmplLayoutBase, TmplContentErrorGeneric, web.MIMETextHTMLCharsetUTF8) return web.RenderError(ctx, w, r, err, h.Renderer, TmplLayoutBase, TmplContentErrorGeneric, web.MIMETextHTMLCharsetUTF8)
} else if end { } else if end {
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return err
}
return nil return nil
} }
......
...@@ -112,8 +112,7 @@ func (h *User) Login(ctx context.Context, w http.ResponseWriter, r *http.Request ...@@ -112,8 +112,7 @@ func (h *User) Login(ctx context.Context, w http.ResponseWriter, r *http.Request
} }
// Redirect the user to the dashboard. // Redirect the user to the dashboard.
http.Redirect(w, r, redirectUri, http.StatusFound) return true, web.Redirect(ctx, w, r, redirectUri, http.StatusFound)
return true, nil
} }
return false, nil return false, nil
...@@ -148,9 +147,7 @@ func (h *User) Logout(ctx context.Context, w http.ResponseWriter, r *http.Reques ...@@ -148,9 +147,7 @@ func (h *User) Logout(ctx context.Context, w http.ResponseWriter, r *http.Reques
} }
// Redirect the user to the root page. // Redirect the user to the root page.
http.Redirect(w, r, "/", http.StatusFound) return web.Redirect(ctx, w, r, "/", http.StatusFound)
return nil
} }
// ResetPassword allows a user to perform forgot password. // ResetPassword allows a user to perform forgot password.
...@@ -281,8 +278,7 @@ func (h *User) ResetConfirm(ctx context.Context, w http.ResponseWriter, r *http. ...@@ -281,8 +278,7 @@ func (h *User) ResetConfirm(ctx context.Context, w http.ResponseWriter, r *http.
} }
// Redirect the user to the dashboard. // Redirect the user to the dashboard.
http.Redirect(w, r, "/", http.StatusFound) return true, web.Redirect(ctx, w, r, "/", http.StatusFound)
return true, nil
} }
_, err = user.ParseResetHash(ctx, h.SecretKey, resetHash, ctxValues.Now) _, err = user.ParseResetHash(ctx, h.SecretKey, resetHash, ctxValues.Now)
...@@ -432,13 +428,8 @@ func (h *User) Update(ctx context.Context, w http.ResponseWriter, r *http.Reques ...@@ -432,13 +428,8 @@ func (h *User) Update(ctx context.Context, w http.ResponseWriter, r *http.Reques
webcontext.SessionFlashSuccess(ctx, webcontext.SessionFlashSuccess(ctx,
"Profile Updated", "Profile Updated",
"User profile successfully updated.") "User profile successfully updated.")
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
http.Redirect(w, r, "/user", http.StatusFound) return true, web.Redirect(ctx, w, r, "/user", http.StatusFound)
return true, nil
} }
return false, nil return false, nil
...@@ -584,16 +575,8 @@ func (h *User) VirtualLogin(ctx context.Context, w http.ResponseWriter, r *http. ...@@ -584,16 +575,8 @@ func (h *User) VirtualLogin(ctx context.Context, w http.ResponseWriter, r *http.
fmt.Sprintf("You are now virtually logged into user %s.", fmt.Sprintf("You are now virtually logged into user %s.",
usr.Response(ctx).Name)) usr.Response(ctx).Name))
// Write the session to the client.
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
// Redirect the user to the dashboard with the new credentials. // Redirect the user to the dashboard with the new credentials.
http.Redirect(w, r, "/", http.StatusFound) return true, web.Redirect(ctx, w, r, "/", http.StatusFound)
return true, nil
} }
return false, nil return false, nil
...@@ -724,9 +707,7 @@ func (h *User) VirtualLogout(ctx context.Context, w http.ResponseWriter, r *http ...@@ -724,9 +707,7 @@ func (h *User) VirtualLogout(ctx context.Context, w http.ResponseWriter, r *http
} }
// Redirect the user to the dashboard with the new credentials. // Redirect the user to the dashboard with the new credentials.
http.Redirect(w, r, "/", http.StatusFound) return web.Redirect(ctx, w, r, "/", http.StatusFound)
return nil
} }
// VirtualLogin handles switching the scope of the context to another user. // VirtualLogin handles switching the scope of the context to another user.
...@@ -800,16 +781,8 @@ func (h *User) SwitchAccount(ctx context.Context, w http.ResponseWriter, r *http ...@@ -800,16 +781,8 @@ func (h *User) SwitchAccount(ctx context.Context, w http.ResponseWriter, r *http
fmt.Sprintf("You are now logged into account %s.", fmt.Sprintf("You are now logged into account %s.",
acc.Response(ctx).Name)) acc.Response(ctx).Name))
// Write the session to the client.
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
// Redirect the user to the dashboard with the new credentials. // Redirect the user to the dashboard with the new credentials.
http.Redirect(w, r, "/", http.StatusFound) return true, web.Redirect(ctx, w, r, "/", http.StatusFound)
return true, nil
} }
return false, nil return false, nil
......
...@@ -259,13 +259,8 @@ func (h *Users) Create(ctx context.Context, w http.ResponseWriter, r *http.Reque ...@@ -259,13 +259,8 @@ func (h *Users) Create(ctx context.Context, w http.ResponseWriter, r *http.Reque
webcontext.SessionFlashSuccess(ctx, webcontext.SessionFlashSuccess(ctx,
"User Created", "User Created",
"User successfully created.") "User successfully created.")
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
http.Redirect(w, r, urlUsersView(usr.ID), http.StatusFound) return true, web.Redirect(ctx, w, r, urlUsersView(usr.ID), http.StatusFound)
return true, nil
} }
return false, nil return false, nil
...@@ -333,13 +328,8 @@ func (h *Users) View(ctx context.Context, w http.ResponseWriter, r *http.Request ...@@ -333,13 +328,8 @@ func (h *Users) View(ctx context.Context, w http.ResponseWriter, r *http.Request
webcontext.SessionFlashSuccess(ctx, webcontext.SessionFlashSuccess(ctx,
"User Archive", "User Archive",
"User successfully archive.") "User successfully archive.")
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
http.Redirect(w, r, urlUsersIndex(), http.StatusFound) return true, web.Redirect(ctx, w, r, urlUsersIndex(), http.StatusFound)
return true, nil
} }
} }
...@@ -483,13 +473,8 @@ func (h *Users) Update(ctx context.Context, w http.ResponseWriter, r *http.Reque ...@@ -483,13 +473,8 @@ func (h *Users) Update(ctx context.Context, w http.ResponseWriter, r *http.Reque
webcontext.SessionFlashSuccess(ctx, webcontext.SessionFlashSuccess(ctx,
"User Updated", "User Updated",
"User successfully updated.") "User successfully updated.")
err = webcontext.ContextSession(ctx).Save(r, w)
if err != nil {
return false, err
}
http.Redirect(w, r, urlUsersView(req.ID), http.StatusFound) return true, web.Redirect(ctx, w, r, urlUsersView(req.ID), http.StatusFound)
return true, nil
} }
return false, nil return false, nil
...@@ -607,13 +592,7 @@ func (h *Users) Invite(ctx context.Context, w http.ResponseWriter, r *http.Reque ...@@ -607,13 +592,7 @@ func (h *Users) Invite(ctx context.Context, w http.ResponseWriter, r *http.Reque
"No users were invited.") "No users were invited.")
} }
err = webcontext.ContextSession(ctx).Save(r, w) return true, web.Redirect(ctx, w, r, urlUsersIndex(), http.StatusFound)
if err != nil {
return false, err
}
http.Redirect(w, r, urlUsersIndex(), http.StatusFound)
return true, nil
} }
return false, nil return false, nil
...@@ -652,7 +631,7 @@ func (h *Users) InviteAccept(ctx context.Context, w http.ResponseWriter, r *http ...@@ -652,7 +631,7 @@ func (h *Users) InviteAccept(ctx context.Context, w http.ResponseWriter, r *http
} }
// //
req := new(invite.AcceptInviteRequest) req := new(invite.AcceptInviteUserRequest)
data := make(map[string]interface{}) data := make(map[string]interface{})
f := func() (bool, error) { f := func() (bool, error) {
...@@ -670,30 +649,33 @@ func (h *Users) InviteAccept(ctx context.Context, w http.ResponseWriter, r *http ...@@ -670,30 +649,33 @@ func (h *Users) InviteAccept(ctx context.Context, w http.ResponseWriter, r *http
// Append the query param value to the request. // Append the query param value to the request.
req.InviteHash = inviteHash req.InviteHash = inviteHash
hash, err := invite.AcceptInvite(ctx, h.MasterDB, *req, h.SecretKey, ctxValues.Now) hash, err := invite.AcceptInviteUser(ctx, h.MasterDB, *req, h.SecretKey, ctxValues.Now)
if err != nil { if err != nil {
switch errors.Cause(err) { switch errors.Cause(err) {
case invite.ErrInviteExpired: case invite.ErrInviteExpired:
webcontext.SessionFlashError(ctx, webcontext.SessionFlashError(ctx,
"Invite Expired", "Invite Expired",
"The invite has expired.") "The invite has expired.")
return false, nil return false, nil
case invite.ErrUserAccountActive: case invite.ErrUserAccountActive:
webcontext.SessionFlashError(ctx, webcontext.SessionFlashError(ctx,
"User already Active", "User already Active",
"The user already is already active for the account. Try to login or use forgot password.") "The user is already is already active for the account. Try to login or use forgot password.")
http.Redirect(w, r, "/user/login", http.StatusFound)
return true, nil return true, web.Redirect(ctx, w, r, "/user/login", http.StatusFound)
case invite.ErrInviteUserPasswordSet:
case invite.ErrNoPendingInvite:
webcontext.SessionFlashError(ctx, webcontext.SessionFlashError(ctx,
"Invite already Accepted", "Invite Accepted",
"The invite has already been accepted. Try to login or use forgot password.") "The invite has already been accepted. Try to login or use forgot password.")
http.Redirect(w, r, "/user/login", http.StatusFound)
return true, nil return true, web.Redirect(ctx, w, r, "/user/login", http.StatusFound)
case user_account.ErrNotFound: case user_account.ErrNotFound:
return false, err return false, err
case invite.ErrNoPendingInvite:
return false, err
default: default:
if verr, ok := weberror.NewValidationError(ctx, err); ok { if verr, ok := weberror.NewValidationError(ctx, err); ok {
data["validationErrors"] = verr.(*weberror.Error) data["validationErrors"] = verr.(*weberror.Error)
...@@ -732,36 +714,57 @@ func (h *Users) InviteAccept(ctx context.Context, w http.ResponseWriter, r *http ...@@ -732,36 +714,57 @@ func (h *Users) InviteAccept(ctx context.Context, w http.ResponseWriter, r *http
} }
// Redirect the user to the dashboard. // Redirect the user to the dashboard.
http.Redirect(w, r, "/", http.StatusFound) return true, web.Redirect(ctx, w, r, "/", http.StatusFound)
return true, nil
} }
hash, err := invite.ParseInviteHash(ctx, h.SecretKey, inviteHash, ctxValues.Now) usrAcc, err := invite.AcceptInvite(ctx, h.MasterDB, invite.AcceptInviteRequest{
InviteHash: inviteHash,
}, h.SecretKey, ctxValues.Now)
if err != nil { if err != nil {
switch errors.Cause(err) { switch errors.Cause(err) {
case invite.ErrInviteExpired: case invite.ErrInviteExpired:
webcontext.SessionFlashError(ctx, webcontext.SessionFlashError(ctx,
"Invite Expired", "Invite Expired",
"The invite has expired.") "The invite has expired.")
return false, nil
case invite.ErrInviteUserPasswordSet: return true, web.Redirect(ctx, w, r, "/user/login", http.StatusFound)
case invite.ErrUserAccountActive:
webcontext.SessionFlashError(ctx, webcontext.SessionFlashError(ctx,
"Invite already Accepted", "User already Active",
"The user is already is already active for the account. Try to login or use forgot password.")
return true, web.Redirect(ctx, w, r, "/user/login", http.StatusFound)
case invite.ErrNoPendingInvite:
webcontext.SessionFlashError(ctx,
"Invite Accepted",
"The invite has already been accepted. Try to login or use forgot password.") "The invite has already been accepted. Try to login or use forgot password.")
http.Redirect(w, r, "/user/login", http.StatusFound)
return true, nil return true, web.Redirect(ctx, w, r, "/user/login", http.StatusFound)
case user_account.ErrNotFound:
return false, err
default: default:
if verr, ok := weberror.NewValidationError(ctx, err); ok { if verr, ok := weberror.NewValidationError(ctx, err); ok {
data["validationErrors"] = verr.(*weberror.Error) data["validationErrors"] = verr.(*weberror.Error)
return false, nil return false, nil
} else { } else {
return false, err return false, err
} }
} }
} else if usrAcc.Status == user_account.UserAccountStatus_Active {
webcontext.SessionFlashError(ctx,
"Invite Accepted",
"The invite has been accepted. Login to continue.")
return true, web.Redirect(ctx, w, r, "/user/login", http.StatusFound)
} }
// Read user by ID with no claims. // Read user by ID with no claims.
usr, err := user.ReadByID(ctx, auth.Claims{}, h.MasterDB, hash.UserID) usr, err := user.ReadByID(ctx, auth.Claims{}, h.MasterDB, usrAcc.UserID)
if err != nil { if err != nil {
return false, err return false, err
} }
...@@ -791,7 +794,7 @@ func (h *Users) InviteAccept(ctx context.Context, w http.ResponseWriter, r *http ...@@ -791,7 +794,7 @@ func (h *Users) InviteAccept(ctx context.Context, w http.ResponseWriter, r *http
data["form"] = req data["form"] = req
if verr, ok := weberror.NewValidationError(ctx, webcontext.Validator().Struct(invite.AcceptInviteRequest{})); ok { if verr, ok := weberror.NewValidationError(ctx, webcontext.Validator().Struct(invite.AcceptInviteUserRequest{})); ok {
data["validationDefaults"] = verr.(*weberror.Error) data["validationDefaults"] = verr.(*weberror.Error)
} }
......
...@@ -55,13 +55,13 @@ ...@@ -55,13 +55,13 @@
<small>Role</small><br/> <small>Role</small><br/>
{{ if .userAccount }} {{ if .userAccount }}
<b> <b>
{{ range $r := .userAccount.Roles }} {{ range $r := .userAccount.Roles.Options }}{{ if $r.Selected }}
{{ if eq $r "admin" }} {{ if eq $r.Value "admin" }}
<span class="text-pink"><i class="far fa-kiss-wink-heart mr-1"></i>{{ $r }}</span> <span class="text-pink"><i class="far fa-kiss-wink-heart mr-1"></i>{{ $r.Title }}</span>
{{else}} {{else}}
<span class="text-purple"><i class="far fa-user-circle mr-1"></i>{{ $r }}</span> <span class="text-purple"><i class="far fa-user-circle mr-1"></i>{{ $r.Title }}</span>
{{end}} {{end}}
{{ end }} {{ end }}{{ end }}
</b> </b>
{{ end }} {{ end }}
</p> </p>
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
<label for="selectRoles">Roles</label> <label for="selectRoles">Roles</label>
<select class="form-control {{ ValidationFieldClass $.validationErrors "Roles" }}" <select class="form-control {{ ValidationFieldClass $.validationErrors "Roles" }}"
id="selectRoles" name="Roles" multiple="multiple"> id="selectRoles" name="Roles" multiple="multiple">
{{ range $t := .roles }} {{ range $t := .roles.Options }}
<option value="{{ $t.Value }}" {{ if $t.Selected }}selected="selected"{{ end }}>{{ $t.Title }}</option> <option value="{{ $t.Value }}" {{ if $t.Selected }}selected="selected"{{ end }}>{{ $t.Title }}</option>
{{ end }} {{ end }}
</select> </select>
......
...@@ -67,7 +67,7 @@ ...@@ -67,7 +67,7 @@
<small>Role</small><br/> <small>Role</small><br/>
{{ if .userAccount }} {{ if .userAccount }}
<b> <b>
{{ range $r := .userAccount.Roles }}{{ if $r.Selected }} {{ range $r := .userAccount.Roles.Options }}{{ if $r.Selected }}
{{ if eq $r.Value "admin" }} {{ if eq $r.Value "admin" }}
<span class="text-pink"><i class="far fa-kiss-wink-heart mr-1"></i>{{ $r.Title }}</span> <span class="text-pink"><i class="far fa-kiss-wink-heart mr-1"></i>{{ $r.Title }}</span>
{{else}} {{else}}
......
...@@ -117,12 +117,20 @@ func NewEnumResponse(ctx context.Context, value interface{}, options ...interfac ...@@ -117,12 +117,20 @@ func NewEnumResponse(ctx context.Context, value interface{}, options ...interfac
} }
// EnumResponse is a response friendly format for displaying a multi select enum. // EnumResponse is a response friendly format for displaying a multi select enum.
type EnumMultiResponse []EnumOption type EnumMultiResponse struct {
Values []string `json:"values" example:"active_etc"`
Options []EnumOption `json:"options,omitempty"`
}
// NewEnumMultiResponse returns a display friendly format for a multi enum field. // NewEnumMultiResponse returns a display friendly format for a multi enum field.
func NewEnumMultiResponse(ctx context.Context, selected []interface{}, options ...interface{}) EnumMultiResponse { func NewEnumMultiResponse(ctx context.Context, selected []interface{}, options ...interface{}) EnumMultiResponse {
var er EnumMultiResponse var er EnumMultiResponse
for _, s := range selected {
selStr := fmt.Sprintf("%s", s)
er.Values = append(er.Values, selStr)
}
for _, opt := range options { for _, opt := range options {
optStr := fmt.Sprintf("%s", opt) optStr := fmt.Sprintf("%s", opt)
opt := EnumOption{ opt := EnumOption{
...@@ -137,7 +145,7 @@ func NewEnumMultiResponse(ctx context.Context, selected []interface{}, options . ...@@ -137,7 +145,7 @@ func NewEnumMultiResponse(ctx context.Context, selected []interface{}, options .
} }
} }
er = append(er, opt) er.Options = append(er.Options, opt)
} }
return er return er
......
...@@ -256,3 +256,16 @@ func StaticHandler(ctx context.Context, w http.ResponseWriter, r *http.Request, ...@@ -256,3 +256,16 @@ func StaticHandler(ctx context.Context, w http.ResponseWriter, r *http.Request,
return nil return nil
} }
// Redirect ensures the session is flushed to the browser before the redirect is issued.
func Redirect(ctx context.Context, w http.ResponseWriter, r *http.Request, url string, code int) error {
if sess := webcontext.ContextSession(ctx); sess != nil {
if err := sess.Save(r, w); err != nil {
return err
}
}
http.Redirect(w, r, url, code)
return nil
}
...@@ -26,9 +26,6 @@ var ( ...@@ -26,9 +26,6 @@ var (
// ErrUserAccountActive occurs when the user already has an active user_account entry. // ErrUserAccountActive occurs when the user already has an active user_account entry.
ErrUserAccountActive = errors.New("User already active.") ErrUserAccountActive = errors.New("User already active.")
// ErrInviteUserPasswordSet occurs when the the reset hash exceeds the expiration.
ErrInviteUserPasswordSet = errors.New("User password set")
) )
// SendUserInvites sends emails to the users inviting them to join an account. // SendUserInvites sends emails to the users inviting them to join an account.
...@@ -181,7 +178,7 @@ func SendUserInvites(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, r ...@@ -181,7 +178,7 @@ func SendUserInvites(ctx context.Context, claims auth.Claims, dbConn *sqlx.DB, r
} }
// AcceptInvite updates the user using the provided invite hash. // AcceptInvite updates the user using the provided invite hash.
func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest, secretKey string, now time.Time) (*InviteHash, error) { func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest, secretKey string, now time.Time) (*user_account.UserAccount, error) {
span, ctx := tracer.StartSpanFromContext(ctx, "internal.user_account.invite.AcceptInvite") span, ctx := tracer.StartSpanFromContext(ctx, "internal.user_account.invite.AcceptInvite")
defer span.Finish() defer span.Finish()
...@@ -193,7 +190,7 @@ func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest, ...@@ -193,7 +190,7 @@ func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest,
return nil, err return nil, err
} }
hash, err := ParseInviteHash(ctx, secretKey, req.InviteHash, now) hash, err := ParseInviteHash(ctx, req.InviteHash, secretKey, now)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -216,24 +213,86 @@ func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest, ...@@ -216,24 +213,86 @@ func AcceptInvite(ctx context.Context, dbConn *sqlx.DB, req AcceptInviteRequest,
AccountID: hash.AccountID, AccountID: hash.AccountID,
}) })
if err != nil { if err != nil {
return nil, nil return nil, err
} }