Skip to content

Commit

Permalink
restrict login to employers with verified emails (#149)
Browse files Browse the repository at this point in the history
  • Loading branch information
Adam Gulczyński committed Aug 23, 2023
1 parent 408331a commit db6695e
Show file tree
Hide file tree
Showing 7 changed files with 174 additions and 73 deletions.
24 changes: 20 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ Search functionality is implemented both with Postgres and Elasticsearch (depend
### The app uses:
- Postgres
- Docker
- [Gin](https://github.com/gin-gonic/gin)
- Redis
- [Elasticsearch](https://github.com/elastic/go-elasticsearch)
- [Gin](https://github.com/gin-gonic/gin)
- [golang-migrate](https://github.com/golang-migrate/migrate)
- [sqlc](https://github.com/kyleconroy/sqlc)
- [asynq](https://github.com/hibiken/asynq)
- [testify](https://github.com/stretchr/testify)
- [PASETO Security Tokens](https://github.com/o1egl/paseto)
- [Viper](https://github.com/spf13/viper)
- [jordan-wright/email](https://github.com/jordan-wright/email)
- [gin-swagger](https://github.com/swaggo/gin-swagger)

<hr>
Expand Down Expand Up @@ -55,7 +56,7 @@ This API provides a set of endpoints for managing:
- jobs
- job applications

(and indirectly: user skills and job skills)
(and indirectly: user skills, job skills and verify emails table)


After running the server, the Swagger documentation is available at http://localhost:8080/swagger/index.html.
Expand All @@ -77,12 +78,19 @@ in JSON format. On success, the response has a `201 Created` status code and ret
user in JSON format. If the request body is invalid, a `400 Bad Request` status code is returned.
If a user with the given email already exists, a `403 Forbidden` status code is returned. In case
of any other error, a `500 Internal Server Error` status code is returned.
After registering, a verification email is sent to the provided email address.

+ `GET /users/verify-email`: This endpoint verifies a user’s email by providing a verify email ID and
secret code that should be sent to the user in the verification email. The request body must contain the verify
email ID and secret code as query parameters. On success, the response has a `200 OK` status code and returns the
verification result in JSON format. If the request query is invalid, a `400 Bad Request` status code is returned.
In case of any other error, a `500 Internal Server Error` status code is returned.

+ `POST /users/login`: This endpoint logs in a user. The request body must contain the user credentials
(email, password) in JSON format. On success, the response has a `200 OK` status code and returns
an access token and the authenticated user in JSON format. If the request body is invalid, a
`400 Bad Request` status code is returned. If the password is incorrect, a `401 Unauthorized`
status code is returned. If a user with the given email does not exist, a `404 Not Found` status
status code is returned. If user has not verified email, `403 Forbidden` is returned. If a user with the given email does not exist, a `404 Not Found` status
code is returned. In case of any other error, a `500 Internal Server Error` status code is returned.

+ `GET /users`: This endpoint retrieves the details of the logged-in user. On success, the response
Expand Down Expand Up @@ -126,12 +134,20 @@ the created employer in JSON format. If the request body is invalid,
a `400` status code is returned. If a company with the given name or an
employer with the given email already exists, a `403 Forbidden` status
code is returned. In case of any other error, a 500 Internal Error status code is returned.
After registering, a verification email is sent to the provided email address.

+ `GET /employers/verify-email`: This endpoint verifies an employer’s email by providing a verify email ID and
secret code that should be sent to the user in the verification email. The request body must contain the verify
email ID and secret code as query parameters. On success, the response has a `200 OK` status code and returns the
verification result in JSON format. If the request query is invalid, a `400 Bad Request` status code is returned.
In case of any other error, a `500 Internal Server Error` status code is returned.

+ `POST /employers/login`: This endpoint logs in an employer. The request body
must contain the employer credentials (email, password) in JSON format. On success,
the response has a `200 OK` status code and returns an access token and the authenticated employer
in JSON format. If the request body is invalid, a `400 Bad Request` status code is returned.
If the password is incorrect, a `401 Unauthorized` status code is returned.
If the emails is not verified, a `403 Forbidden` is returned.
If an employer with the given email or a company with the given id does not
exist, a `404 Not Found` status code is returned. In case of any other error,
a `500 Internal Server Error` status code is returned.
Expand Down
67 changes: 43 additions & 24 deletions docs/docs.go

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

67 changes: 43 additions & 24 deletions docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,12 @@
"$ref": "#/definitions/api.ErrorResponse"
}
},
"403": {
"description": "Email not verified",
"schema": {
"$ref": "#/definitions/api.ErrorResponse"
}
},
"404": {
"description": "Employer with given email or company with given id does not exist",
"schema": {
Expand Down Expand Up @@ -355,13 +361,18 @@
"summary": "Verify employer email",
"parameters": [
{
"description": "Verify email ID and secret code from the email.",
"name": "VerifyEmployerEmailRequest",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/api.verifyEmployerEmailRequest"
}
"minLength": 32,
"type": "string",
"name": "code",
"in": "query",
"required": true
},
{
"minimum": 1,
"type": "integer",
"name": "id",
"in": "query",
"required": true
}
],
"responses": {
Expand Down Expand Up @@ -1743,6 +1754,12 @@
"$ref": "#/definitions/api.ErrorResponse"
}
},
"403": {
"description": "Email not verified",
"schema": {
"$ref": "#/definitions/api.ErrorResponse"
}
},
"404": {
"description": "User with given email does not exist",
"schema": {
Expand Down Expand Up @@ -1818,10 +1835,29 @@
"/users/verify-email": {
"get": {
"description": "Verify user email by providing verify email ID and secret code that should be sent to the user in the verification email.",
"produces": [
"application/json"
],
"tags": [
"users"
],
"summary": "Verify user email",
"parameters": [
{
"minLength": 32,
"type": "string",
"name": "code",
"in": "query",
"required": true
},
{
"minimum": 1,
"type": "integer",
"name": "id",
"in": "query",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
Expand Down Expand Up @@ -2430,23 +2466,6 @@
}
}
},
"api.verifyEmployerEmailRequest": {
"type": "object",
"required": [
"code",
"id"
],
"properties": {
"code": {
"type": "string",
"minLength": 32
},
"id": {
"type": "integer",
"minimum": 1
}
}
},
"api.verifyEmployerEmailResponse": {
"type": "object",
"properties": {
Expand Down
47 changes: 30 additions & 17 deletions docs/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -391,18 +391,6 @@ definitions:
skills_description:
type: string
type: object
api.verifyEmployerEmailRequest:
properties:
code:
minLength: 32
type: string
id:
minimum: 1
type: integer
required:
- code
- id
type: object
api.verifyEmployerEmailResponse:
properties:
message:
Expand Down Expand Up @@ -747,6 +735,10 @@ paths:
description: Incorrect password
schema:
$ref: '#/definitions/api.ErrorResponse'
"403":
description: Email not verified
schema:
$ref: '#/definitions/api.ErrorResponse'
"404":
description: Employer with given email or company with given id does not
exist
Expand Down Expand Up @@ -830,12 +822,16 @@ paths:
description: Verify employer email by providing verify email ID and secret code
that should be sent to the user in the verification email.
parameters:
- description: Verify email ID and secret code from the email.
in: body
name: VerifyEmployerEmailRequest
- in: query
minLength: 32
name: code
required: true
schema:
$ref: '#/definitions/api.verifyEmployerEmailRequest'
type: string
- in: query
minimum: 1
name: id
required: true
type: integer
produces:
- application/json
responses:
Expand Down Expand Up @@ -1755,6 +1751,10 @@ paths:
description: Incorrect password
schema:
$ref: '#/definitions/api.ErrorResponse'
"403":
description: Email not verified
schema:
$ref: '#/definitions/api.ErrorResponse'
"404":
description: User with given email does not exist
schema:
Expand Down Expand Up @@ -1807,6 +1807,19 @@ paths:
get:
description: Verify user email by providing verify email ID and secret code
that should be sent to the user in the verification email.
parameters:
- in: query
minLength: 32
name: code
required: true
type: string
- in: query
minimum: 1
name: id
required: true
type: integer
produces:
- application/json
responses:
"200":
description: OK
Expand Down
11 changes: 9 additions & 2 deletions internal/api/employer.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,9 @@ type loginEmployerResponse struct {
// @param LoginEmployerRequest body loginEmployerRequest true "Employer credentials"
// @Success 200 {object} loginEmployerResponse
// @Failure 400 {object} ErrorResponse "Invalid request body"
// @Failure 404 {object} ErrorResponse "Employer with given email or company with given id does not exist"
// @Failure 401 {object} ErrorResponse "Incorrect password"
// @Failure 403 {object} ErrorResponse "Email not verified"
// @Failure 404 {object} ErrorResponse "Employer with given email or company with given id does not exist"
// @Failure 500 {object} ErrorResponse "Any other error"
// @Router /employers/login [post]
// loginEmployer handles login of an employer
Expand All @@ -182,6 +183,12 @@ func (server *Server) loginEmployer(ctx *gin.Context) {
return
}

// check if the user has verified email
if !employer.IsEmailVerified {
ctx.JSON(http.StatusForbidden, errorResponse(emailNotVerifiedErr))
return
}

// check password
err = utils.CheckPassword(request.Password, employer.HashedPassword)
if err != nil {
Expand Down Expand Up @@ -587,7 +594,7 @@ type verifyEmployerEmailResponse struct {
// @Description Verify employer email by providing verify email ID and secret code that should be sent to the user in the verification email.
// @Tags employers
// @Produce json
// @param VerifyEmployerEmailRequest body verifyEmployerEmailRequest true "Verify email ID and secret code from the email."
// @param VerifyEmployerEmailRequest query verifyEmployerEmailRequest true "Verify email ID and secret code from the email."
// @Success 200 {object} verifyEmployerEmailResponse
// @Failure 400 {object} ErrorResponse "Invalid request body."
// @Failure 500 {object} ErrorResponse "Any other error."
Expand Down
Loading

0 comments on commit db6695e

Please sign in to comment.