basic account creation flow created
This commit is contained in:
@@ -2,10 +2,10 @@ package accounts
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/uuid"
|
||||
|
||||
"ruben/inventory2/internal/consts"
|
||||
"ruben/inventory2/internal/domains/accounts"
|
||||
@@ -31,6 +31,8 @@ func Routes(
|
||||
accts: accts,
|
||||
}
|
||||
|
||||
r.POST("", response.Handler(as.createAccount))
|
||||
|
||||
syncGroups := r.Group("/:acctID/inventory/sync-groups")
|
||||
syncGroups.POST("", response.Handler(as.saveNewSyncGroup))
|
||||
|
||||
@@ -41,19 +43,17 @@ func Routes(
|
||||
draftListings.DELETE("/:orderIndex", response.Handler(as.deleteSyncGroupListingDraft))
|
||||
}
|
||||
|
||||
// TODO: test this endpoint again, to make it work.
|
||||
// POST /
|
||||
func (s *accountSubrouter) createAccount(c *gin.Context) (response.Response, error) {
|
||||
r := c.Request
|
||||
ctx := r.Context()
|
||||
email := r.FormValue("email")
|
||||
if email == "" {
|
||||
return nil, response.BadRequest().Msg("no email provided")
|
||||
}
|
||||
|
||||
// TODO: get email from the user's account profile (how?) - will need to flesh out the account creation process later on
|
||||
email := uuid.NewString() + "@example.com"
|
||||
|
||||
userID := auth.GetIdentity(ctx).User.UserID
|
||||
|
||||
acct, err := s.accts.CreateAccount(ctx, userID, email)
|
||||
_, err := s.accts.CreateAccount(ctx, userID, email)
|
||||
if err != nil {
|
||||
if errors.Is(err, consts.ErrConflict) {
|
||||
return nil, response.Conflict().
|
||||
@@ -62,7 +62,10 @@ func (s *accountSubrouter) createAccount(c *gin.Context) (response.Response, err
|
||||
return nil, response.Errorf("failed to create account: %w", err)
|
||||
}
|
||||
|
||||
return response.SeeOther(fmt.Sprintf("/ui/accounts/%d", acct.AccountID)), nil
|
||||
return response.StatusCreated().
|
||||
// force a reload to ensure an sse connection is made.
|
||||
// user should automatically be redirected to the appropriate page based on their current location and/or login/account statuses.
|
||||
HXRefresh("true"), nil
|
||||
}
|
||||
|
||||
// POST /:acctID/inventory/sync-groups/draft/listings
|
||||
|
||||
@@ -59,6 +59,54 @@ func (b bodyRes) Cookie(ck http.Cookie) Response {
|
||||
return Cookie(ck).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXPushURL(v string) Response {
|
||||
return HXPushURL(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXLocation(v string) Response {
|
||||
return HXLocation(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXPushUrl(v string) Response {
|
||||
return HXPushUrl(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXRedirect(v string) Response {
|
||||
return HXRedirect(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXRefresh(v string) Response {
|
||||
return HXRefresh(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXReplaceUrl(v string) Response {
|
||||
return HXReplaceUrl(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXReswap(v string) Response {
|
||||
return HXReswap(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXRetarget(v string) Response {
|
||||
return HXRetarget(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXReselect(v string) Response {
|
||||
return HXReselect(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXTrigger(v string) Response {
|
||||
return HXTrigger(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXTriggerAfterSettle(v string) Response {
|
||||
return HXTriggerAfterSettle(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) HXTriggerAfterSwap(v string) Response {
|
||||
return HXTriggerAfterSwap(v).wrap(b)
|
||||
}
|
||||
|
||||
func (b bodyRes) GetStatus() (int, bool) {
|
||||
if b.res == nil {
|
||||
return 0, false
|
||||
@@ -67,6 +115,13 @@ func (b bodyRes) GetStatus() (int, bool) {
|
||||
return b.res.GetStatus()
|
||||
}
|
||||
|
||||
func (b bodyRes) getHeaders() [][2]string {
|
||||
if b.res != nil {
|
||||
return b.res.getHeaders()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b bodyRes) GetRedirect() (code redirect.Code, to string, ok bool) {
|
||||
if b.res == nil {
|
||||
return 0, "", false
|
||||
|
||||
@@ -58,6 +58,54 @@ func (c cookieRes) Cookie(ck http.Cookie) Response {
|
||||
return Cookie(ck).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXPushURL(v string) Response {
|
||||
return HXPushURL(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXLocation(v string) Response {
|
||||
return HXLocation(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXPushUrl(v string) Response {
|
||||
return HXPushUrl(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXRedirect(v string) Response {
|
||||
return HXRedirect(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXRefresh(v string) Response {
|
||||
return HXRefresh(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXReplaceUrl(v string) Response {
|
||||
return HXReplaceUrl(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXReswap(v string) Response {
|
||||
return HXReswap(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXRetarget(v string) Response {
|
||||
return HXRetarget(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXReselect(v string) Response {
|
||||
return HXReselect(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXTrigger(v string) Response {
|
||||
return HXTrigger(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXTriggerAfterSettle(v string) Response {
|
||||
return HXTriggerAfterSettle(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) HXTriggerAfterSwap(v string) Response {
|
||||
return HXTriggerAfterSwap(v).wrap(c)
|
||||
}
|
||||
|
||||
func (c cookieRes) GetStatus() (int, bool) {
|
||||
if c.res == nil {
|
||||
return 0, false
|
||||
@@ -66,6 +114,13 @@ func (c cookieRes) GetStatus() (int, bool) {
|
||||
return c.res.GetStatus()
|
||||
}
|
||||
|
||||
func (c cookieRes) getHeaders() [][2]string {
|
||||
if c.res != nil {
|
||||
return c.res.getHeaders()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c cookieRes) GetRedirect() (code redirect.Code, to string, ok bool) {
|
||||
if c.res == nil {
|
||||
return 0, "", false
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"ruben/inventory2/internal/server/redirect"
|
||||
)
|
||||
|
||||
type (
|
||||
headerRes struct {
|
||||
name string
|
||||
value string
|
||||
res Response
|
||||
}
|
||||
)
|
||||
|
||||
var _ Response = headerRes{}
|
||||
|
||||
func header(name, value string) Response {
|
||||
return headerRes{
|
||||
name: name,
|
||||
value: value,
|
||||
}
|
||||
}
|
||||
|
||||
func HXPushURL(v string) Response {
|
||||
return header("HX-Push-Url", v)
|
||||
}
|
||||
|
||||
func HXLocation(v string) Response {
|
||||
return header("HX-Location", v)
|
||||
}
|
||||
|
||||
func HXPushUrl(v string) Response {
|
||||
return header("HX-Push-Url", v)
|
||||
}
|
||||
|
||||
func HXRedirect(v string) Response {
|
||||
return header("HX-Redirect", v)
|
||||
}
|
||||
|
||||
func HXRefresh(v string) Response {
|
||||
return header("HX-Refresh", v)
|
||||
}
|
||||
|
||||
func HXReplaceUrl(v string) Response {
|
||||
return header("HX-Replace-Url", v)
|
||||
}
|
||||
|
||||
func HXReswap(v string) Response {
|
||||
return header("HX-Reswap", v)
|
||||
}
|
||||
|
||||
func HXRetarget(v string) Response {
|
||||
return header("HX-Retarget", v)
|
||||
}
|
||||
|
||||
func HXReselect(v string) Response {
|
||||
return header("HX-Reselect", v)
|
||||
}
|
||||
|
||||
func HXTrigger(v string) Response {
|
||||
return header("HX-Trigger", v)
|
||||
}
|
||||
|
||||
func HXTriggerAfterSettle(v string) Response {
|
||||
return header("HX-Trigger-After-Settle", v)
|
||||
}
|
||||
|
||||
func HXTriggerAfterSwap(v string) Response {
|
||||
return header("HX-Trigger-After-Swap", v)
|
||||
}
|
||||
|
||||
func (h headerRes) String() string {
|
||||
if h.res != nil {
|
||||
return fmt.Sprintf(`{"header": {"name": %q, "value": %q}, "nested": %s}`, h.name, h.value, h.res)
|
||||
}
|
||||
return fmt.Sprintf(`{"header": {"name": %q, "value": %q}}`, h.name, h.value)
|
||||
}
|
||||
|
||||
func (h headerRes) wrap(res Response) Response {
|
||||
h.res = res
|
||||
return h
|
||||
}
|
||||
|
||||
func (h headerRes) Status(code int) Response {
|
||||
return Status(code).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) Header(name, value string) Response {
|
||||
h.name = name
|
||||
h.value = value
|
||||
return h
|
||||
}
|
||||
|
||||
func (h headerRes) Redirect(code redirect.Code, to string) Response {
|
||||
return Redirect(code, to).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HTML(body []byte) Response {
|
||||
return HTML(body).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) JSON(body any) Response {
|
||||
return JSON(body).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) Body(body io.ReadCloser) Response {
|
||||
return Body(body).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) Cookie(ck http.Cookie) Response {
|
||||
return Cookie(ck).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXPushURL(v string) Response {
|
||||
return HXPushURL(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXLocation(v string) Response {
|
||||
return HXLocation(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXPushUrl(v string) Response {
|
||||
return HXPushUrl(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXRedirect(v string) Response {
|
||||
return HXRedirect(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXRefresh(v string) Response {
|
||||
return HXRefresh(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXReplaceUrl(v string) Response {
|
||||
return HXReplaceUrl(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXReswap(v string) Response {
|
||||
return HXReswap(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXRetarget(v string) Response {
|
||||
return HXRetarget(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXReselect(v string) Response {
|
||||
return HXReselect(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXTrigger(v string) Response {
|
||||
return HXTrigger(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXTriggerAfterSettle(v string) Response {
|
||||
return HXTriggerAfterSettle(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) HXTriggerAfterSwap(v string) Response {
|
||||
return HXTriggerAfterSwap(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h headerRes) GetStatus() (int, bool) {
|
||||
if h.res == nil {
|
||||
return 0, false
|
||||
}
|
||||
|
||||
return h.res.GetStatus()
|
||||
}
|
||||
|
||||
func (h headerRes) getHeaders() [][2]string {
|
||||
hdr := [2]string{h.name, h.value}
|
||||
if h.res == nil {
|
||||
return [][2]string{hdr}
|
||||
}
|
||||
|
||||
return append(h.res.getHeaders(), hdr)
|
||||
}
|
||||
|
||||
func (h headerRes) GetRedirect() (code redirect.Code, to string, ok bool) {
|
||||
if h.res == nil {
|
||||
return 0, "", false
|
||||
}
|
||||
|
||||
return h.res.GetRedirect()
|
||||
}
|
||||
|
||||
func (h headerRes) getBody() (body io.ReadCloser, ok bool, err error) {
|
||||
if h.res == nil {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
return h.res.getBody()
|
||||
}
|
||||
|
||||
func (h headerRes) getCookies() []http.Cookie {
|
||||
if h.res != nil {
|
||||
return h.res.getCookies()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h headerRes) getContentType() (contentType string, ok bool) {
|
||||
if h.res != nil {
|
||||
return h.res.getContentType()
|
||||
}
|
||||
|
||||
return "", false
|
||||
}
|
||||
@@ -60,6 +60,54 @@ func (h htmlRes) Cookie(ck http.Cookie) Response {
|
||||
return Cookie(ck).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXPushURL(v string) Response {
|
||||
return HXPushURL(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXLocation(v string) Response {
|
||||
return HXLocation(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXPushUrl(v string) Response {
|
||||
return HXPushUrl(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXRedirect(v string) Response {
|
||||
return HXRedirect(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXRefresh(v string) Response {
|
||||
return HXRefresh(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXReplaceUrl(v string) Response {
|
||||
return HXReplaceUrl(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXReswap(v string) Response {
|
||||
return HXReswap(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXRetarget(v string) Response {
|
||||
return HXRetarget(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXReselect(v string) Response {
|
||||
return HXReselect(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXTrigger(v string) Response {
|
||||
return HXTrigger(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXTriggerAfterSettle(v string) Response {
|
||||
return HXTriggerAfterSettle(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) HXTriggerAfterSwap(v string) Response {
|
||||
return HXTriggerAfterSwap(v).wrap(h)
|
||||
}
|
||||
|
||||
func (h htmlRes) GetStatus() (int, bool) {
|
||||
if h.res == nil {
|
||||
return 0, false
|
||||
@@ -68,6 +116,13 @@ func (h htmlRes) GetStatus() (int, bool) {
|
||||
return h.res.GetStatus()
|
||||
}
|
||||
|
||||
func (h htmlRes) getHeaders() [][2]string {
|
||||
if h.res != nil {
|
||||
return h.res.getHeaders()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h htmlRes) GetRedirect() (code redirect.Code, to string, ok bool) {
|
||||
if h.res == nil {
|
||||
return 0, "", false
|
||||
|
||||
@@ -61,6 +61,54 @@ func (j jsonRes) Cookie(ck http.Cookie) Response {
|
||||
return Cookie(ck).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXPushURL(v string) Response {
|
||||
return HXPushURL(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXLocation(v string) Response {
|
||||
return HXLocation(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXPushUrl(v string) Response {
|
||||
return HXPushUrl(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXRedirect(v string) Response {
|
||||
return HXRedirect(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXRefresh(v string) Response {
|
||||
return HXRefresh(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXReplaceUrl(v string) Response {
|
||||
return HXReplaceUrl(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXReswap(v string) Response {
|
||||
return HXReswap(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXRetarget(v string) Response {
|
||||
return HXRetarget(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXReselect(v string) Response {
|
||||
return HXReselect(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXTrigger(v string) Response {
|
||||
return HXTrigger(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXTriggerAfterSettle(v string) Response {
|
||||
return HXTriggerAfterSettle(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) HXTriggerAfterSwap(v string) Response {
|
||||
return HXTriggerAfterSwap(v).wrap(j)
|
||||
}
|
||||
|
||||
func (j jsonRes) GetStatus() (int, bool) {
|
||||
if j.res == nil {
|
||||
return 0, false
|
||||
@@ -69,6 +117,13 @@ func (j jsonRes) GetStatus() (int, bool) {
|
||||
return j.res.GetStatus()
|
||||
}
|
||||
|
||||
func (j jsonRes) getHeaders() [][2]string {
|
||||
if j.res != nil {
|
||||
return j.res.getHeaders()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j jsonRes) GetRedirect() (code redirect.Code, to string, ok bool) {
|
||||
if j.res == nil {
|
||||
return 0, "", false
|
||||
|
||||
@@ -99,6 +99,54 @@ func (r redirectRes) Cookie(ck http.Cookie) Response {
|
||||
return Cookie(ck).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXPushURL(v string) Response {
|
||||
return HXPushURL(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXLocation(v string) Response {
|
||||
return HXLocation(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXPushUrl(v string) Response {
|
||||
return HXPushUrl(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXRedirect(v string) Response {
|
||||
return HXRedirect(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXRefresh(v string) Response {
|
||||
return HXRefresh(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXReplaceUrl(v string) Response {
|
||||
return HXReplaceUrl(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXReswap(v string) Response {
|
||||
return HXReswap(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXRetarget(v string) Response {
|
||||
return HXRetarget(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXReselect(v string) Response {
|
||||
return HXReselect(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXTrigger(v string) Response {
|
||||
return HXTrigger(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXTriggerAfterSettle(v string) Response {
|
||||
return HXTriggerAfterSettle(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) HXTriggerAfterSwap(v string) Response {
|
||||
return HXTriggerAfterSwap(v).wrap(r)
|
||||
}
|
||||
|
||||
func (r redirectRes) GetStatus() (int, bool) {
|
||||
if r.res == nil {
|
||||
return 0, false
|
||||
@@ -107,6 +155,13 @@ func (r redirectRes) GetStatus() (int, bool) {
|
||||
return r.res.GetStatus()
|
||||
}
|
||||
|
||||
func (r redirectRes) getHeaders() [][2]string {
|
||||
if r.res != nil {
|
||||
return r.res.getHeaders()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r redirectRes) GetRedirect() (code redirect.Code, to string, ok bool) {
|
||||
return r.code, r.to, true
|
||||
}
|
||||
|
||||
@@ -10,6 +10,18 @@ import (
|
||||
type (
|
||||
Response interface {
|
||||
Status(int) Response
|
||||
HXPushURL(string) Response
|
||||
HXLocation(string) Response
|
||||
HXPushUrl(string) Response
|
||||
HXRedirect(string) Response
|
||||
HXRefresh(string) Response
|
||||
HXReplaceUrl(string) Response
|
||||
HXReswap(string) Response
|
||||
HXRetarget(string) Response
|
||||
HXReselect(string) Response
|
||||
HXTrigger(string) Response
|
||||
HXTriggerAfterSettle(string) Response
|
||||
HXTriggerAfterSwap(string) Response
|
||||
Redirect(code redirect.Code, to string) Response
|
||||
Body(io.ReadCloser) Response
|
||||
HTML([]byte) Response
|
||||
@@ -21,6 +33,7 @@ type (
|
||||
GetRedirect() (code redirect.Code, to string, ok bool)
|
||||
getCookies() []http.Cookie
|
||||
getContentType() (contentType string, ok bool)
|
||||
getHeaders() [][2]string
|
||||
|
||||
wrap(Response) Response
|
||||
}
|
||||
|
||||
@@ -76,10 +76,65 @@ func (s statusRes) Cookie(ck http.Cookie) Response {
|
||||
return Cookie(ck).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXPushURL(v string) Response {
|
||||
return HXPushURL(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXLocation(v string) Response {
|
||||
return HXLocation(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXPushUrl(v string) Response {
|
||||
return HXPushUrl(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXRedirect(v string) Response {
|
||||
return HXRedirect(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXRefresh(v string) Response {
|
||||
return HXRefresh(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXReplaceUrl(v string) Response {
|
||||
return HXReplaceUrl(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXReswap(v string) Response {
|
||||
return HXReswap(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXRetarget(v string) Response {
|
||||
return HXRetarget(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXReselect(v string) Response {
|
||||
return HXReselect(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXTrigger(v string) Response {
|
||||
return HXTrigger(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXTriggerAfterSettle(v string) Response {
|
||||
return HXTriggerAfterSettle(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) HXTriggerAfterSwap(v string) Response {
|
||||
return HXTriggerAfterSwap(v).wrap(s)
|
||||
}
|
||||
|
||||
func (s statusRes) GetStatus() (int, bool) {
|
||||
return s.code, true
|
||||
}
|
||||
|
||||
func (s statusRes) getHeaders() [][2]string {
|
||||
if s.res != nil {
|
||||
return s.res.getHeaders()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s statusRes) GetRedirect() (code redirect.Code, to string, ok bool) {
|
||||
if s.res == nil {
|
||||
return 0, "", false
|
||||
|
||||
@@ -72,12 +72,16 @@ func writeResponse(c *gin.Context, res Response) {
|
||||
// w.Header() must be set before ResponseWriter.WriteHeader is called
|
||||
// or redirect is attempted
|
||||
hdrs := w.Header()
|
||||
for _, hdr := range res.getHeaders() {
|
||||
hdrs.Add(hdr[0], hdr[1])
|
||||
}
|
||||
|
||||
for _, ck := range res.getCookies() {
|
||||
hdrs.Add("Set-Cookie", ck.String())
|
||||
}
|
||||
|
||||
if ct, ok := res.getContentType(); ok {
|
||||
hdrs.Add("Content-Type", ct)
|
||||
hdrs.Set("Content-Type", ct)
|
||||
}
|
||||
|
||||
if code, to, ok := res.GetRedirect(); ok {
|
||||
|
||||
@@ -93,10 +93,19 @@ func Routes(
|
||||
etsy: etsy,
|
||||
}
|
||||
|
||||
r.GET("", response.Handler(s.serveTemplate))
|
||||
r.GET("", response.Handler(s.redirectToAccountsIfLoggedInWithAnAccount), response.Handler(s.serveTemplate))
|
||||
r.GET("/*rest", authenticate, response.Handler(s.serveTemplate))
|
||||
}
|
||||
|
||||
func (s *webpageRouter) redirectToAccountsIfLoggedInWithAnAccount(c *gin.Context) (response.Response, error) {
|
||||
id := auth.GetIdentity(c)
|
||||
if id.Account == nil || id.Account.AccountID == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return response.TemporaryRedirect(fmt.Sprintf("%s/accounts/%d", s.uiPath, id.Account.AccountID)), nil
|
||||
}
|
||||
|
||||
// GET /
|
||||
// compiles the page template or component template matching the url
|
||||
func (s *webpageRouter) serveTemplate(c *gin.Context) (response.Response, error) {
|
||||
@@ -221,7 +230,33 @@ func authorizeByMatchingAccountID(r *http.Request, acctIDPathPosition int) error
|
||||
id := auth.GetIdentity(r.Context())
|
||||
if id.Account == nil || id.Account.AccountID != acctID {
|
||||
return response.Unauthorized().
|
||||
Msgf("user does not have access to account %d", acctID)
|
||||
HTML([]byte(fmt.Sprintf(`
|
||||
<section class="text-center">
|
||||
<header class="m-[1em]">
|
||||
<h2>
|
||||
Access Not Granted
|
||||
</h2>
|
||||
|
||||
<a href="/ui%s" class="block m-[1em]">
|
||||
<code>
|
||||
/ui%s
|
||||
</code>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<div class="m-[2em]">
|
||||
<p class="italic font-bold">
|
||||
Sorry, you don't have access to the given page.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="text-center">
|
||||
<a href="/">
|
||||
Return to app
|
||||
</a>
|
||||
</section>
|
||||
`, r.URL, r.URL)))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
{{- $loggedIn := and (and .Identity .Identity.AccessToken) true -}}
|
||||
{{- $hasAccount := and (and .Identity .Identity.Account) true -}}
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html class="min-h-full flex flex-col items-stretch">
|
||||
<head>
|
||||
@@ -36,7 +40,7 @@
|
||||
hx-boost="true"
|
||||
|
||||
{{/* subscribe to sse (if logged in) */}}
|
||||
{{- if and .Identity .Identity.AccessToken }}
|
||||
{{- if and $loggedIn $hasAccount }}
|
||||
sse-connect="/api/events/"
|
||||
sse-close="close"
|
||||
{{- end }}
|
||||
@@ -69,29 +73,16 @@
|
||||
style="
|
||||
"
|
||||
>
|
||||
<li class="pt-[1em] pb-[1em]">
|
||||
<a href="/ui" class="p-[1em] font-display {{ if eq $path "/" }}selected{{ end }}">
|
||||
Home
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{/* */}}
|
||||
{{- $userID := .Identity.User.UserID }}
|
||||
{{- $acct := .Identity.Account }}
|
||||
{{- $acctID := 0 }}
|
||||
{{- if $acct }}
|
||||
{{- $acctID = $acct.AccountID }}
|
||||
{{- end }}
|
||||
|
||||
{{- if not $userID }}
|
||||
{{- if not $loggedIn }}
|
||||
|
||||
<li class="pt-[1em] pb-[1em]">
|
||||
<a href="/api/auth/login" hx-boost="false" class="p-[1em] font-display {{ if eq $path "/auth/login" }}selected{{ end }}">
|
||||
Log In / Sign Up
|
||||
Log In
|
||||
</a>
|
||||
</li>
|
||||
|
||||
{{- else if $acctID }}
|
||||
{{- else if $hasAccount }}
|
||||
{{- $acctID := .Identity.Account.AccountID }}
|
||||
|
||||
<li class="pt-[1em] pb-[1em]">
|
||||
<a href="/ui/accounts/{{$acctID}}" class="p-[1em] font-display {{ if eq $path (printf "/accounts/%d" $acctID) }}selected{{ end }}">
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
{{- $loggedIn := and (and .Identity .Identity.AccessToken) true -}}
|
||||
|
||||
|
||||
<section class="flex justify-center max-w-full mt-[3em] mb-[3em]">
|
||||
<h1 class="
|
||||
min-[400px]:px-[calc(10vw-0.5em)]
|
||||
@@ -12,20 +15,21 @@
|
||||
|
||||
</section>
|
||||
|
||||
{{- if and .Identity.User.UserID (not .Identity.Account) }}
|
||||
{{/* TODO: make account creation automatic as part of the user creation process */}}
|
||||
<h2><a href="/ui/account-creation">New Account</a></h2>
|
||||
{{- end }}
|
||||
|
||||
<section class="flex flex-col items-center max-w-full mt-[1em] mb-[1em] gap-y-[2em]">
|
||||
<p class="text-lg text-center max-w-[50%]">
|
||||
Synchronize inventory automatically!
|
||||
</p>
|
||||
|
||||
<div class="border-button border-sidebar-border bg-card text-lg text-center max-w-[50%]">
|
||||
<a href="/api/auth/login" hx-boost="false" class="block p-[1em] font-bold">
|
||||
{{- if $loggedIn }}
|
||||
<a hx-post="/api/accounts" hx-target="body" class="block p-[1em] font-bold">
|
||||
Create an Account
|
||||
</a>
|
||||
{{- else }}
|
||||
<a href="/api/auth/login" hx-boost="false" class="block p-[1em] font-bold">
|
||||
New Login
|
||||
</a>
|
||||
{{- end }}
|
||||
</div>
|
||||
|
||||
<p class="text-lg text-center max-w-[50%]">
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<section class="text-center">
|
||||
<header class="m-[1em]">
|
||||
<h2>
|
||||
Access Not Granted
|
||||
</h2>
|
||||
|
||||
{{ $link := printf "/ui%s" .Request.URL }}
|
||||
<a href="{{ $link }}" class="block m-[1em]">
|
||||
<code>
|
||||
{{ $link }}
|
||||
</code>
|
||||
</a>
|
||||
</header>
|
||||
|
||||
<div class="m-[2em]">
|
||||
<p class="italic font-bold">
|
||||
Sorry, you don't have access to the page you were looking for.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
Reference in New Issue
Block a user