Добавил миддлвейр для авторизации. И дописал readme.md
This commit is contained in:
parent
f18f1a1662
commit
2310cfd05b
|
@ -2,5 +2,5 @@ vars {
|
|||
host: http://localhost:8080
|
||||
manufacturerID: 1
|
||||
productID: 6
|
||||
token: npG8pIdPaFSBHdM119QpZtm773KKCoVIGw==
|
||||
token: UFY7FwOZpuac11IXiogxtpfVYt0Ib2Il3w==
|
||||
}
|
|
@ -24,7 +24,7 @@ func main() {
|
|||
panic("failed to connect database")
|
||||
}
|
||||
|
||||
err = db.AutoMigrate(&database.Manufacturer{}, &database.Product{}, &database.User{})
|
||||
err = db.AutoMigrate(&database.Manufacturer{}, &database.Product{}, &database.User{}, &database.Token{})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"golang-test/database"
|
||||
"golang-test/libs"
|
||||
"golang-test/types"
|
||||
|
@ -55,7 +53,7 @@ func RegisterUser(c *gin.Context, register types.RegisterRequest) {
|
|||
}
|
||||
|
||||
// Генерация токена для пользователя
|
||||
token.Token = generateToken()
|
||||
token.Token = libs.GenerateToken()
|
||||
token.UserID = user.ID
|
||||
user.Tokens = append(user.Tokens, token)
|
||||
|
||||
|
@ -98,7 +96,7 @@ func LoginUser(c *gin.Context, login types.LoginRequest) {
|
|||
return
|
||||
}
|
||||
|
||||
token.Token = generateToken()
|
||||
token.Token = libs.GenerateToken()
|
||||
token.UserID = user.ID
|
||||
|
||||
user.Tokens = append(user.Tokens, token)
|
||||
|
@ -108,27 +106,25 @@ func LoginUser(c *gin.Context, login types.LoginRequest) {
|
|||
c.JSON(http.StatusOK, types.TokenResponse{Token: token.Token})
|
||||
}
|
||||
|
||||
func generateToken() string {
|
||||
b := make([]byte, 25)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return ""
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
||||
func GetUser(c *gin.Context) {
|
||||
var products []types.ProductResponse
|
||||
user, err := libs.GetUserFromHeaders(c)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, types.ErrorResponse{Message: err.Error()})
|
||||
userFromMiddleware, ok := c.Get("user")
|
||||
if !ok {
|
||||
c.JSON(http.StatusUnauthorized, types.ErrorResponse{Message: "Authorization Error. Please login"})
|
||||
return
|
||||
}
|
||||
user := userFromMiddleware.(database.User)
|
||||
|
||||
for _, product := range user.Products {
|
||||
products = append(products, types.ProductResponse{
|
||||
ID: product.ID,
|
||||
Name: product.Name,
|
||||
Price: product.Price,
|
||||
ManufacturerID: product.ManufacturerID,
|
||||
Manufacturer: types.ManufacturerResponse{
|
||||
Name: product.Manufacturer.Name,
|
||||
ID: product.Manufacturer.ID,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -152,11 +148,12 @@ func EditUserName(c *gin.Context, userName types.EditUserNameRequest) {
|
|||
return
|
||||
}
|
||||
|
||||
user, err := libs.GetUserFromHeaders(c)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, types.ErrorResponse{Message: err.Error()})
|
||||
userFromMiddleware, ok := c.Get("user")
|
||||
if !ok {
|
||||
c.JSON(http.StatusUnauthorized, types.ErrorResponse{Message: "Authorization Error. Please login"})
|
||||
return
|
||||
}
|
||||
user := userFromMiddleware.(database.User)
|
||||
|
||||
user.Name = userName.Name
|
||||
|
||||
|
@ -201,11 +198,12 @@ func BuyProduct(c *gin.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
user, err := libs.GetUserFromHeaders(c)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, types.ErrorResponse{Message: err.Error()})
|
||||
userFromMiddleware, ok := c.Get("user")
|
||||
if !ok {
|
||||
c.JSON(http.StatusUnauthorized, types.ErrorResponse{Message: "Authorization Error. Please login"})
|
||||
return
|
||||
}
|
||||
user := userFromMiddleware.(database.User)
|
||||
|
||||
if user.Money-product.Price < 0 {
|
||||
c.JSON(http.StatusOK, types.MessageResponse{Message: "Not enough money"})
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
meta {
|
||||
name: Test
|
||||
type: http
|
||||
seq: 2
|
||||
}
|
||||
|
||||
get {
|
||||
url: {{host}}/test
|
||||
body: none
|
||||
auth: none
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package libs
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"golang-test/database"
|
||||
"strings"
|
||||
|
@ -65,3 +66,11 @@ func GetUserFromHeaders(c *gin.Context) (database.User, error) {
|
|||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func GenerateToken() string {
|
||||
b := make([]byte, 25)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return ""
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(b)
|
||||
}
|
||||
|
|
105
main.go
105
main.go
|
@ -1,12 +1,10 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"golang-test/controllers"
|
||||
"golang-test/database"
|
||||
"golang-test/types"
|
||||
"log"
|
||||
"net/http"
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang-test/database"
|
||||
"golang-test/routes"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -14,106 +12,15 @@ func main() {
|
|||
// Создание сервера
|
||||
r := gin.Default()
|
||||
|
||||
r.POST("/product", func(c *gin.Context) {
|
||||
var product database.Product
|
||||
if err := c.ShouldBind(&product); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.CreateProduct(c, product)
|
||||
})
|
||||
|
||||
r.DELETE("/product/:id", func(c *gin.Context) {
|
||||
controllers.DeleteProduct(c)
|
||||
})
|
||||
|
||||
r.GET("/product", func(c *gin.Context) {
|
||||
controllers.GetProducts(c)
|
||||
})
|
||||
|
||||
r.GET("/product/:id", func(c *gin.Context) {
|
||||
controllers.GetProductInfo(c)
|
||||
})
|
||||
|
||||
r.GET("/product/:id/buy", func(c *gin.Context) {
|
||||
controllers.BuyProduct(c)
|
||||
})
|
||||
|
||||
r.POST("/manufacturer", func(c *gin.Context) {
|
||||
var manufacturer database.Manufacturer
|
||||
if err := c.ShouldBind(&manufacturer); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.CreateManufacturer(c, manufacturer)
|
||||
})
|
||||
|
||||
r.DELETE("/manufacturer/:id", func(c *gin.Context) {
|
||||
controllers.DeleteManufacturer(c)
|
||||
})
|
||||
|
||||
r.GET("/manufacturer", func(c *gin.Context) {
|
||||
controllers.GetManufacturers(c)
|
||||
})
|
||||
|
||||
r.PATCH("/manufacturer/:id", func(c *gin.Context) {
|
||||
var manufacturer types.ManufacturerPatchRequest
|
||||
if err := c.ShouldBind(&manufacturer); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.EditManufacture(c, manufacturer)
|
||||
})
|
||||
|
||||
r.POST("/registration", func(c *gin.Context) {
|
||||
var form types.RegisterRequest
|
||||
if err := c.ShouldBind(&form); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.RegisterUser(c, form)
|
||||
})
|
||||
|
||||
r.POST("/login", func(c *gin.Context) {
|
||||
var register types.LoginRequest
|
||||
if err := c.ShouldBind(®ister); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.LoginUser(c, register)
|
||||
})
|
||||
|
||||
r.GET("/user", func(c *gin.Context) {
|
||||
controllers.GetUser(c)
|
||||
})
|
||||
|
||||
r.PATCH("/user", func(c *gin.Context) {
|
||||
var user types.EditUserNameRequest
|
||||
if err := c.ShouldBind(&user); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.EditUserName(c, user)
|
||||
})
|
||||
|
||||
r.POST("/user/addmoney", func(c *gin.Context) {
|
||||
var moneyRequest types.AddMoneyRequest
|
||||
if err := c.ShouldBind(&moneyRequest); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.AddMoneyToUser(c, moneyRequest)
|
||||
})
|
||||
|
||||
r.GET("/user/products", func(c *gin.Context) {
|
||||
controllers.GetBuyedProducts(c)
|
||||
})
|
||||
//Создание маршрутов
|
||||
routes.ResolveRoutes(r)
|
||||
|
||||
err := r.Run()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
//Отключение от БД при выключении приложения.
|
||||
defer func() {
|
||||
db := database.Connector()
|
||||
sqlDB, err := db.DB()
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package middlewares
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang-test/libs"
|
||||
"golang-test/types"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Middleware для авторизации
|
||||
func AuthMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
user, err := libs.GetUserFromHeaders(c)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusUnauthorized, types.ErrorResponse{Message: err.Error()})
|
||||
c.Abort() // Прерываем обработку запроса
|
||||
return
|
||||
}
|
||||
|
||||
// Если пользователь успешно извлечен, продолжаем обработку запроса
|
||||
c.Set("user", user)
|
||||
c.Next()
|
||||
}
|
||||
}
|
18
readme.md
18
readme.md
|
@ -3,6 +3,24 @@
|
|||
## Обзор
|
||||
Этот проект представляет собой RESTful API для управления товарами, производителями и пользователями. В качестве ORM используется GORM.
|
||||
|
||||
## Структура проекта
|
||||
|
||||
- **cli/migration.go** - Применение автомиграции в БД.
|
||||
- **contollers/** - Вся бизнес логика, обращения к БД.
|
||||
- **database/connect.go** - Подключение к БД.
|
||||
- **database/models.go** - Модели Gorm.
|
||||
- **brunoTest/** - Коллекция Bruno для тестирования API.
|
||||
- **libs/** - Небольшие функции используемые в разных контроллерах.
|
||||
- **middlewares/authMiddleware.go** - Прослойка для авторизации.
|
||||
- **routes.go** - Описание всех маршрутов.
|
||||
- **types/** - Типы для запросов и ответов на сервер.
|
||||
- **validators/** - Кастомные валидаторы.
|
||||
- **docker-compose.yml** - Файл docker-compose для запуска в контейнере вместе в БД.
|
||||
- **Dockerfile** - Файл для сборки докер контейнера.
|
||||
- **entrypoint.sh** - Входная точка для докер контейнера. Нужна чтобы запустить миграцию в бд перед запуском сервера.
|
||||
- **main.go** - Основной файл. Используется для запуска сервера.
|
||||
|
||||
|
||||
## Endpoints
|
||||
|
||||
### Товары
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
package routes
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"golang-test/controllers"
|
||||
"golang-test/database"
|
||||
"golang-test/middlewares"
|
||||
"golang-test/types"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ResolveRoutes настраивает конечные точки API
|
||||
func ResolveRoutes(r *gin.Engine) {
|
||||
|
||||
// Создать новый продукт
|
||||
r.POST("/product", func(c *gin.Context) {
|
||||
var product database.Product
|
||||
if err := c.ShouldBind(&product); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.CreateProduct(c, product)
|
||||
})
|
||||
|
||||
// Удалить продукт по ID
|
||||
r.DELETE("/product/:id", func(c *gin.Context) {
|
||||
controllers.DeleteProduct(c)
|
||||
})
|
||||
|
||||
// Получить все продукты
|
||||
r.GET("/product", func(c *gin.Context) {
|
||||
controllers.GetProducts(c)
|
||||
})
|
||||
|
||||
// Получить информацию о продукте по ID
|
||||
r.GET("/product/:id", func(c *gin.Context) {
|
||||
controllers.GetProductInfo(c)
|
||||
})
|
||||
|
||||
// Купить продукт по ID
|
||||
r.GET("/product/:id/buy", middlewares.AuthMiddleware(), func(c *gin.Context) {
|
||||
controllers.BuyProduct(c)
|
||||
})
|
||||
|
||||
// Создать нового производителя
|
||||
r.POST("/manufacturer", func(c *gin.Context) {
|
||||
var manufacturer database.Manufacturer
|
||||
if err := c.ShouldBind(&manufacturer); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.CreateManufacturer(c, manufacturer)
|
||||
})
|
||||
|
||||
// Удалить производителя по ID
|
||||
r.DELETE("/manufacturer/:id", func(c *gin.Context) {
|
||||
controllers.DeleteManufacturer(c)
|
||||
})
|
||||
|
||||
// Получить всех производителей
|
||||
r.GET("/manufacturer", func(c *gin.Context) {
|
||||
controllers.GetManufacturers(c)
|
||||
})
|
||||
|
||||
// Редактировать производителя по ID
|
||||
r.PATCH("/manufacturer/:id", func(c *gin.Context) {
|
||||
var manufacturer types.ManufacturerPatchRequest
|
||||
if err := c.ShouldBind(&manufacturer); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.EditManufacture(c, manufacturer)
|
||||
})
|
||||
|
||||
// Зарегистрировать нового пользователя
|
||||
r.POST("/registration", func(c *gin.Context) {
|
||||
var form types.RegisterRequest
|
||||
if err := c.ShouldBind(&form); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.RegisterUser(c, form)
|
||||
})
|
||||
|
||||
// Войти в систему
|
||||
r.POST("/login", func(c *gin.Context) {
|
||||
var register types.LoginRequest
|
||||
if err := c.ShouldBind(®ister); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.LoginUser(c, register)
|
||||
})
|
||||
|
||||
// Получить информацию о пользователе
|
||||
r.GET("/user", middlewares.AuthMiddleware(), func(c *gin.Context) {
|
||||
controllers.GetUser(c)
|
||||
})
|
||||
|
||||
// Редактировать имя пользователя
|
||||
r.PATCH("/user", middlewares.AuthMiddleware(), func(c *gin.Context) {
|
||||
var user types.EditUserNameRequest
|
||||
if err := c.ShouldBind(&user); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.EditUserName(c, user)
|
||||
})
|
||||
|
||||
// Добавить деньги на счет пользователя
|
||||
r.POST("/user/addmoney", func(c *gin.Context) {
|
||||
var moneyRequest types.AddMoneyRequest
|
||||
if err := c.ShouldBind(&moneyRequest); err != nil {
|
||||
c.JSON(http.StatusBadRequest, types.ErrorResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
controllers.AddMoneyToUser(c, moneyRequest)
|
||||
})
|
||||
|
||||
// Получить купленные продукты пользователя
|
||||
r.GET("/user/products", middlewares.AuthMiddleware(), func(c *gin.Context) {
|
||||
controllers.GetBuyedProducts(c)
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue