feat: service/controller prototype
This commit is contained in:
@@ -50,7 +50,25 @@ const docTemplate = `{
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Acquire tokens via login credentials (and 2FA code if needed)",
|
||||
"responses": {}
|
||||
"parameters": [
|
||||
{
|
||||
"description": "desc",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.LoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "desc",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.LoginResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/passwordResetBegin": {
|
||||
@@ -230,7 +248,7 @@ const docTemplate = `{
|
||||
"summary": "Get health status",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "desc",
|
||||
"description": "Says whether it's healthy or not",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.HealthStatus"
|
||||
}
|
||||
@@ -247,6 +265,31 @@ const docTemplate = `{
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LoginRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"totp": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LoginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"access_token": {
|
||||
"type": "string"
|
||||
},
|
||||
"refresh_token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
|
||||
@@ -46,7 +46,25 @@
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Acquire tokens via login credentials (and 2FA code if needed)",
|
||||
"responses": {}
|
||||
"parameters": [
|
||||
{
|
||||
"description": "desc",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.LoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "desc",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/models.LoginResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/passwordResetBegin": {
|
||||
@@ -226,7 +244,7 @@
|
||||
"summary": "Get health status",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "desc",
|
||||
"description": "Says whether it's healthy or not",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/controllers.HealthStatus"
|
||||
}
|
||||
@@ -243,6 +261,31 @@
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LoginRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"totp": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"models.LoginResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"access_token": {
|
||||
"type": "string"
|
||||
},
|
||||
"refresh_token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
|
||||
@@ -5,6 +5,22 @@ definitions:
|
||||
healthy:
|
||||
type: boolean
|
||||
type: object
|
||||
models.LoginRequest:
|
||||
properties:
|
||||
password:
|
||||
type: string
|
||||
totp:
|
||||
type: string
|
||||
username:
|
||||
type: string
|
||||
type: object
|
||||
models.LoginResponse:
|
||||
properties:
|
||||
access_token:
|
||||
type: string
|
||||
refresh_token:
|
||||
type: string
|
||||
type: object
|
||||
info:
|
||||
contact: {}
|
||||
description: Easy and feature-rich wishlist.
|
||||
@@ -29,9 +45,20 @@ paths:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- description: desc
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/models.LoginRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses: {}
|
||||
responses:
|
||||
"200":
|
||||
description: desc
|
||||
schema:
|
||||
$ref: '#/definitions/models.LoginResponse'
|
||||
summary: Acquire tokens via login credentials (and 2FA code if needed)
|
||||
tags:
|
||||
- Auth
|
||||
@@ -148,7 +175,7 @@ paths:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: desc
|
||||
description: Says whether it's healthy or not
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.HealthStatus'
|
||||
summary: Get health status
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"easywish/internal/models"
|
||||
"easywish/internal/services"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -28,9 +30,28 @@ func RegistrationComplete(c *gin.Context) {
|
||||
// @Tags Auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body models.LoginRequest true "desc"
|
||||
// @Success 200 {object} models.LoginResponse "desc"
|
||||
// @Router /auth/login [post]
|
||||
func Login(c *gin.Context) {
|
||||
c.Status(http.StatusNotImplemented)
|
||||
|
||||
var request models.LoginRequest
|
||||
|
||||
if err := c.ShouldBindJSON(&request); err != nil {
|
||||
c.Status(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
auths := services.NewAuthService()
|
||||
|
||||
result, err := auths.Login(request)
|
||||
|
||||
if err != nil {
|
||||
c.Status(http.StatusTeapot)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusFound, result)
|
||||
}
|
||||
|
||||
// @Summary Receive new tokens via refresh token
|
||||
|
||||
@@ -15,7 +15,7 @@ type HealthStatus struct {
|
||||
// @Tags Service
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {object} HealthStatus "desc"
|
||||
// @Success 200 {object} HealthStatus "Says whether it's healthy or not"
|
||||
// @Router /service/health [get]
|
||||
func HealthCheck(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, gin.H{"healthy": true})
|
||||
|
||||
@@ -546,12 +546,12 @@ WHERE
|
||||
users.verified IS TRUE AND -- Verified
|
||||
users.deleted IS FALSE AND -- Not deleted
|
||||
banned.user_id IS NULL AND -- Not banned
|
||||
linfo.password_hash = crypt($2, linfo.password_hash)
|
||||
linfo.password_hash = crypt($2::text, linfo.password_hash)
|
||||
`
|
||||
|
||||
type GetUserByLoginCredentialsParams struct {
|
||||
Username string
|
||||
Crypt string
|
||||
Password string
|
||||
}
|
||||
|
||||
type GetUserByLoginCredentialsRow struct {
|
||||
@@ -562,7 +562,7 @@ type GetUserByLoginCredentialsRow struct {
|
||||
}
|
||||
|
||||
func (q *Queries) GetUserByLoginCredentials(ctx context.Context, arg GetUserByLoginCredentialsParams) (GetUserByLoginCredentialsRow, error) {
|
||||
row := q.db.QueryRow(ctx, getUserByLoginCredentials, arg.Username, arg.Crypt)
|
||||
row := q.db.QueryRow(ctx, getUserByLoginCredentials, arg.Username, arg.Password)
|
||||
var i GetUserByLoginCredentialsRow
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
|
||||
9
backend/internal/errors/auth.go
Normal file
9
backend/internal/errors/auth.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrUnauthorized = errors.New("User is not authorized")
|
||||
)
|
||||
11
backend/internal/errors/general.go
Normal file
11
backend/internal/errors/general.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotImplemented = errors.New("Feature is not implemented")
|
||||
ErrBadRequest = errors.New("Bad request")
|
||||
)
|
||||
|
||||
24
backend/internal/models/auth.go
Normal file
24
backend/internal/models/auth.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package models
|
||||
|
||||
type Tokens struct {
|
||||
AccessToken string `json:"access_token"`
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
||||
type LoginRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
TOTP *string `json:"totp"`
|
||||
}
|
||||
|
||||
type LoginResponse struct {
|
||||
Tokens
|
||||
}
|
||||
|
||||
type RefreshRequest struct {
|
||||
RefreshToken string `json:"refresh_token"`
|
||||
}
|
||||
|
||||
type RefreshResponse struct {
|
||||
Tokens
|
||||
}
|
||||
50
backend/internal/services/auth.go
Normal file
50
backend/internal/services/auth.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"easywish/internal/database"
|
||||
"easywish/internal/errors"
|
||||
errs "easywish/internal/errors"
|
||||
"easywish/internal/models"
|
||||
"easywish/internal/utils"
|
||||
)
|
||||
|
||||
type AuthService interface {
|
||||
Login(request models.LoginRequest) (*models.LoginResponse, error)
|
||||
Refresh(request models.RefreshRequest) (*models.RefreshResponse, error)
|
||||
}
|
||||
|
||||
type authServiceImpl struct {
|
||||
|
||||
}
|
||||
|
||||
func NewAuthService() AuthService {
|
||||
return &authServiceImpl{}
|
||||
}
|
||||
|
||||
func (a *authServiceImpl) Login(request models.LoginRequest) (*models.LoginResponse, error) {
|
||||
conn, ctx, err := utils.GetDbConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close(ctx)
|
||||
|
||||
queries := database.New(conn)
|
||||
|
||||
user, err := queries.GetUserByLoginCredentials(ctx, database.GetUserByLoginCredentialsParams{
|
||||
Username: request.Username,
|
||||
Password: request.Password,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, errs.ErrUnauthorized
|
||||
}
|
||||
|
||||
accessToken, refreshToken, err := utils.GenerateTokens(user.Username)
|
||||
|
||||
return &models.LoginResponse{Tokens: models.Tokens{AccessToken: accessToken, RefreshToken: refreshToken}}, nil
|
||||
}
|
||||
|
||||
|
||||
func (a *authServiceImpl) Refresh(request models.RefreshRequest) (*models.RefreshResponse, error) {
|
||||
return nil, errors.ErrNotImplemented
|
||||
}
|
||||
18
backend/internal/utils/db.go
Normal file
18
backend/internal/utils/db.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"easywish/config"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
)
|
||||
|
||||
func GetDbConn() (*pgx.Conn, context.Context, error) {
|
||||
ctx := context.Background()
|
||||
conn, err := pgx.Connect(ctx, config.GetConfig().DatabaseUrl)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return conn, ctx, nil
|
||||
}
|
||||
Reference in New Issue
Block a user