Skip to content

Commit

Permalink
Merge branch 'main' into feat/207/jwt-auth-middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
AmirAgassi committed Dec 18, 2024
2 parents ca69f43 + 7d8b5b3 commit 9d9465f
Show file tree
Hide file tree
Showing 6 changed files with 228 additions and 11 deletions.
48 changes: 48 additions & 0 deletions backend/internal/v1/v1_common/helpers.go
Original file line number Diff line number Diff line change
@@ -1 +1,49 @@
package v1common

import (
"net/http"

"github.com/labstack/echo/v4"
)

/*
Basic helper that response with the basic response json.
To use a default message, pass an empty string.
Example:
func handler(c echo.Context) error
// some code...
return success(c, http.StatusOk, "Something")
}
*/
func success(c echo.Context, code int, message string) error {
if message == "" {
message = http.StatusText(code)
}
return c.JSON(code, basicResponse{Message: message})
}

/*
Helper that sets some of fields for the underlying error handler
to properly log/handle the error response.
If no internal error to pass, use nil. It is recommended to always pass
an error so that the underlying error handler can log the error.
To use a default public message, pass an empty string.
Example:
func handler(c echo.Context) error
// some code...
return fail(c, http.StatusNotFound, "Something not found", err)
}
*/
func fail(c echo.Context, code int, publicErrMsg string, internalErr error) error {
c.Set("request_error", internalErr)
if publicErrMsg == "" {
publicErrMsg = http.StatusText(code)
}
return echo.NewHTTPError(code, publicErrMsg)
}
91 changes: 91 additions & 0 deletions backend/internal/v1/v1_common/helpers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package v1common

import (
"encoding/json"
"errors"
"io"
"net/http"
"net/http/httptest"
"testing"

"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
)

func TestRequestResponders(t *testing.T) {
t.Run("Test success responder", func(t *testing.T) {
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
err := success(c, http.StatusOK, "test")
assert.NoError(t, err)
data, err := io.ReadAll(rec.Body)
assert.NoError(t, err)
var resBody basicResponse
err = json.Unmarshal(data, &resBody)
assert.NoError(t, err)
assert.Equal(t, rec.Code, http.StatusOK)
assert.Equal(t, resBody, basicResponse{Message: "test"})
})

t.Run("Test success responder with empty message", func(t *testing.T) {
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
err := success(c, http.StatusOK, "")
assert.NoError(t, err)
data, err := io.ReadAll(rec.Body)
assert.NoError(t, err)
var resBody basicResponse
err = json.Unmarshal(data, &resBody)
assert.NoError(t, err)
assert.Equal(t, rec.Code, http.StatusOK)
assert.Equal(t, resBody, basicResponse{Message: http.StatusText(http.StatusOK)})
})

t.Run("Test fail responder", func(t *testing.T) {
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
testErr := errors.New("test-error")
err, ok := fail(c, http.StatusBadRequest, "test", testErr).(*echo.HTTPError)
assert.True(t, ok)
assert.Equal(t, err.Code, http.StatusBadRequest)
assert.Equal(t, err.Message, "test")
contextErr, ok := c.Get("request_error").(error)
assert.True(t, ok)
assert.Equal(t, contextErr, testErr)
})

t.Run("Test fail responder with empty message", func(t *testing.T) {
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
testErr := errors.New("test-error")
err, ok := fail(c, http.StatusBadRequest, "", testErr).(*echo.HTTPError)
assert.True(t, ok)
assert.Equal(t, err.Code, http.StatusBadRequest)
assert.Equal(t, err.Message, http.StatusText(http.StatusBadRequest))
contextErr, ok := c.Get("request_error").(error)
assert.True(t, ok)
assert.Equal(t, contextErr, testErr)
})

t.Run("Test fail responder with nil error", func(t *testing.T) {
e := echo.New()
req := httptest.NewRequest(http.MethodGet, "/", nil)
rec := httptest.NewRecorder()
c := e.NewContext(req, rec)
err, ok := fail(c, http.StatusBadRequest, "", nil).(*echo.HTTPError)
assert.True(t, ok)
assert.Equal(t, err.Code, http.StatusBadRequest)
assert.Equal(t, err.Message, http.StatusText(http.StatusBadRequest))
contextErr, ok := c.Get("request_error").(error)
assert.False(t, ok)
assert.Equal(t, contextErr, nil)
})
}
1 change: 1 addition & 0 deletions backend/internal/v1/v1_common/request.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package v1common
16 changes: 16 additions & 0 deletions backend/internal/v1/v1_common/response.go
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
package v1common

/*
Use this for any json response that just needs a simple message field.
*/
type basicResponse struct {
Message string `json:"message"`
}

/*
Use this for any request that resulted in a failure state.
This includes any response that was not a 200 or 300 level codes.
*/
type basicErrResponse struct {
Message string `json:"message"`
RequestId string `json:"request_id"`
}
64 changes: 56 additions & 8 deletions backend/internal/views/verification_email.templ
Original file line number Diff line number Diff line change
@@ -1,12 +1,60 @@
package views

templ VerificationEmail(url string) {
<div>
<h1>SPUR x Konfer</h1>
<div>
<h1>Let's Verify Your Email</h1>
<p>Please click the link below and we will verify your email.</p>
<a href={ templ.URL(url) }>Verify now</a>
</div>
</div>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Verify Your Email</title>
<style>
body {
font-family: Arial, sans-serif;
line-height: 1.6;
color: #000000 !important;
margin: 0;
padding: 0;
}
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.header {
background-color: #f8f9fa;
padding: 20px;
text-align: center;
}
.content {
padding: 20px;
}
.button, .button:visited {
display: inline-block;
padding: 10px 20px;
background-color: #007bff;
color: #ffffff !important;
text-decoration: none;
border-radius: 5px;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Verify Your Email</h1>
</div>
<div class="content">
<p>Hello,</p>
<p>Thank you for signing up! To complete your registration, please verify your email address by clicking the button below:</p>
<p style="text-align: center;">
<a href={ templ.SafeURL(url) } class="button">Verify Email</a>
</p>
<p>If the button above doesn't work, you can also copy and paste the following link into your browser:</p>
<p>{ url }</p>
<p>This link will expire in 30 minutes for security reasons.</p>
<p>If you didn't create an account with us, please ignore this email.</p>
<p>Best regards,<br/>SPUR x KONFER</p>
</div>
</div>
</body>
</html>
}
19 changes: 16 additions & 3 deletions backend/internal/views/verification_email_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 9d9465f

Please sign in to comment.