diff --git a/.vscode/project.code-snippets b/.vscode/project.code-snippets index bdea364..852bba9 100644 --- a/.vscode/project.code-snippets +++ b/.vscode/project.code-snippets @@ -15,5 +15,12 @@ "ctx := c.Request().Context()" ], "description": "Get's the request from echo context" - } + }, + "Get All Context": { + "prefix": "gac", + "body": [ + "allCtx := reqctx.GetAllCtx(c)" + ], + "description": "Inserts code to get all contexts from a request" + }, } \ No newline at end of file diff --git a/internal/view/reqctx/README.md b/internal/view/reqctx/README.md new file mode 100644 index 0000000..03d0605 --- /dev/null +++ b/internal/view/reqctx/README.md @@ -0,0 +1,5 @@ +# reqctx + +This package provides a helper functions and types for echo request context. + +Can be used to store request-scoped data like user data, etc. diff --git a/internal/view/reqctx/all_ctx.go b/internal/view/reqctx/all_ctx.go new file mode 100644 index 0000000..3db2fee --- /dev/null +++ b/internal/view/reqctx/all_ctx.go @@ -0,0 +1,20 @@ +package reqctx + +import ( + "github.com/labstack/echo/v4" +) + +// GetAllCtx returns ALL the values from an +// echo request context. +// +// It includes AuthCtx, TenantCtx, etc. +func GetAllCtx(c echo.Context) AllCtx { + authCtx := GetAuthCtx(c) + + return AllCtx{ + Auth: authCtx, + + IsAuthed: authCtx.IsAuthed, + UserID: authCtx.User.ID, + } +} diff --git a/internal/view/reqctx/all_ctx_test.go b/internal/view/reqctx/all_ctx_test.go new file mode 100644 index 0000000..bdb790f --- /dev/null +++ b/internal/view/reqctx/all_ctx_test.go @@ -0,0 +1,40 @@ +package reqctx + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/eduardolat/pgbackweb/internal/database/dbgen" + "github.com/google/uuid" + "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" +) + +func TestAllCtxFuncs(t *testing.T) { + testUser := dbgen.User{ + ID: uuid.New(), + Email: "user@example.com", + Name: "John", + } + + e := echo.New() + req := httptest.NewRequest(http.MethodGet, "/", nil) + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + + t.Run("Create authentication values in context", func(t *testing.T) { + SetAuthCtx(c, AuthCtx{ + IsAuthed: true, + User: testUser, + }) + + ctx := GetAllCtx(c) + + assert.True(t, ctx.Auth.IsAuthed) + assert.Equal(t, testUser, ctx.Auth.User) + assert.Equal(t, testUser.Email, ctx.Auth.User.Email) + assert.Equal(t, testUser.ID, ctx.UserID) + assert.Equal(t, testUser.ID, ctx.Auth.User.ID) + }) +} diff --git a/internal/view/reqctx/auth_ctx.go b/internal/view/reqctx/auth_ctx.go new file mode 100644 index 0000000..2627d71 --- /dev/null +++ b/internal/view/reqctx/auth_ctx.go @@ -0,0 +1,32 @@ +package reqctx + +import ( + "github.com/eduardolat/pgbackweb/internal/database/dbgen" + "github.com/labstack/echo/v4" +) + +// SetAuthCtx inserts the authentication values of +// a user into a echo request context. +func SetAuthCtx(c echo.Context, auth AuthCtx) { + c.Set("isAuthed", auth.IsAuthed) + c.Set("user", auth.User) +} + +// GetAuthCtx returns the authentication values of +// a user from a echo request context. +func GetAuthCtx(c echo.Context) AuthCtx { + var isAuthed bool + var user dbgen.User + + if ia, ok := c.Get("isAuthed").(bool); ok { + isAuthed = ia + } + if au, ok := c.Get("user").(dbgen.User); ok { + user = au + } + + return AuthCtx{ + IsAuthed: isAuthed, + User: user, + } +} diff --git a/internal/view/reqctx/auth_ctx_test.go b/internal/view/reqctx/auth_ctx_test.go new file mode 100644 index 0000000..762248f --- /dev/null +++ b/internal/view/reqctx/auth_ctx_test.go @@ -0,0 +1,51 @@ +package reqctx + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/eduardolat/pgbackweb/internal/database/dbgen" + "github.com/google/uuid" + "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" +) + +func TestAuthCtxFuncs(t *testing.T) { + testUser := dbgen.User{ + ID: uuid.New(), + Email: "user@example.com", + Name: "John", + } + + e := echo.New() + req := httptest.NewRequest(http.MethodGet, "/", nil) + rec := httptest.NewRecorder() + c := e.NewContext(req, rec) + + t.Run("Create authentication values in context", func(t *testing.T) { + authData := AuthCtx{ + IsAuthed: true, + User: testUser, + } + + SetAuthCtx(c, authData) + auth := GetAuthCtx(c) + + assert.True(t, auth.IsAuthed) + assert.Equal(t, testUser, auth.User) + assert.Equal(t, testUser.Email, auth.User.Email) + }) + + t.Run("Create authentication values in context with only IsAuthed", func(t *testing.T) { + authData := AuthCtx{ + IsAuthed: true, + } + + SetAuthCtx(c, authData) + auth := GetAuthCtx(c) + + assert.True(t, auth.IsAuthed) + assert.Empty(t, auth.User) + }) +} diff --git a/internal/view/reqctx/reqctx.go b/internal/view/reqctx/reqctx.go new file mode 100644 index 0000000..b1e1370 --- /dev/null +++ b/internal/view/reqctx/reqctx.go @@ -0,0 +1,23 @@ +package reqctx + +import ( + "github.com/eduardolat/pgbackweb/internal/database/dbgen" + "github.com/google/uuid" +) + +// AllCtx represents the full context of a request. +// +// ⚠️ SHOULD have with all the other *Ctx structs. +type AllCtx struct { + Auth AuthCtx + + IsAuthed bool + UserID uuid.UUID +} + +// AuthCtx represents the authentication values of a user +// in the context of a request. +type AuthCtx struct { + IsAuthed bool + User dbgen.User +}