ms-auth/internal/users/delivery/rest/handlers.go
2025-02-25 23:02:21 +05:00

254 lines
5.5 KiB
Go

package rest
import (
"encoding/base64"
"errors"
"git.sch9.ru/new_gate/ms-auth/internal/models"
"git.sch9.ru/new_gate/ms-auth/internal/users"
"git.sch9.ru/new_gate/ms-auth/pkg"
userv1 "git.sch9.ru/new_gate/ms-auth/proto/user/v1"
"github.com/gofiber/fiber/v2"
"github.com/golang-jwt/jwt/v4"
"strings"
"time"
)
type UserHandlers struct {
userUC users.UseCase
jwtSecret string
}
func NewUserHandlers(userUC users.UseCase, jwtSecret string) *UserHandlers {
return &UserHandlers{
userUC: userUC,
jwtSecret: jwtSecret,
}
}
func (h *UserHandlers) Login(c *fiber.Ctx) error {
const op = "UserHandlers.Login"
authHeader := c.Get("Authorization", "")
if authHeader == "" {
return c.SendStatus(fiber.StatusUnauthorized)
}
authParts := strings.Split(authHeader, " ")
if len(authParts) != 2 || strings.ToLower(authParts[0]) != "basic" {
return c.SendStatus(fiber.StatusUnauthorized)
}
decodedAuth, err := base64.StdEncoding.DecodeString(authParts[1])
if err != nil {
return c.SendStatus(fiber.StatusUnauthorized)
}
authParts = strings.Split(string(decodedAuth), ":")
if len(authParts) != 2 {
return c.SendStatus(fiber.StatusUnauthorized)
}
ctx := c.Context()
user, err := h.userUC.ReadUserByUsername(ctx, authParts[0])
if err != nil {
if errors.Is(err, pkg.ErrNotFound) {
return c.SendStatus(fiber.StatusUnauthorized)
}
return c.SendStatus(pkg.ToREST(err))
}
if !user.IsSamePwd(authParts[1]) {
return c.SendStatus(fiber.StatusUnauthorized)
}
userAgent := c.Get("User-Agent", "")
ip := c.IP()
session, err := h.userUC.CreateSession(ctx, user.Id, user.Role, userAgent, ip)
if err != nil {
return c.SendStatus(pkg.ToREST(err))
}
claims := jwt.NewWithClaims(jwt.SigningMethodHS256, models.JWT{
SessionId: session.Id,
UserId: user.Id,
Role: user.Role,
ExpiresAt: session.ExpiresAt.Unix(),
IssuedAt: time.Now().Unix(),
NotBefore: time.Now().Unix(),
Permissions: models.Grants[user.Role.String()],
})
token, err := claims.SignedString([]byte(h.jwtSecret))
if err != nil {
return c.SendStatus(fiber.StatusInternalServerError)
}
c.Set("Authorization", "Bearer "+token)
return c.SendStatus(fiber.StatusOK)
}
func (h *UserHandlers) Refresh(c *fiber.Ctx) error {
const op = "UserHandlers.Refresh"
token, ok := c.Locals(TokenKey).(*models.JWT)
if !ok {
return c.SendStatus(fiber.StatusUnauthorized)
}
err := h.userUC.UpdateSession(c.Context(), token.SessionId)
if err != nil {
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusOK)
}
func (h *UserHandlers) Logout(c *fiber.Ctx) error {
const op = "UserHandlers.Logout"
token, ok := c.Locals(TokenKey).(*models.JWT)
if !ok {
return c.SendStatus(fiber.StatusUnauthorized)
}
err := h.userUC.DeleteSession(c.Context(), token.SessionId)
if err != nil {
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusOK)
}
func (h *UserHandlers) CompleteLogout(c *fiber.Ctx) error {
const op = "UserHandlers.CompleteLogout"
token, ok := c.Locals(TokenKey).(*models.JWT)
if !ok {
return c.SendStatus(fiber.StatusUnauthorized)
}
ctx := c.Context()
err := h.userUC.DeleteAllSessions(ctx, token.UserId)
if err != nil {
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusOK)
}
func (h *UserHandlers) Verify(c *fiber.Ctx) error {
const op = "UserHandlers.Verify"
return c.SendStatus(fiber.StatusNotImplemented)
}
func (h *UserHandlers) CreateUser(c *fiber.Ctx) error {
const op = "UserHandlers.CreateUser"
ctx := c.Context()
var req = &userv1.CreateUserRequest{}
err := c.BodyParser(req)
if err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
id, err := h.userUC.CreateUser(
ctx,
req.Username,
req.Password,
models.RoleStudent,
)
if err != nil {
return c.SendStatus(pkg.ToREST(err))
}
return c.JSON(map[string]interface{}{
"id": id,
})
}
func (h *UserHandlers) GetUser(c *fiber.Ctx, id int32) error {
const op = "UserHandlers.GetUser"
user, err := h.userUC.ReadUserById(c.Context(), id)
if err != nil {
return c.SendStatus(pkg.ToREST(err))
}
return c.JSON(map[string]interface{}{
"user": user,
})
}
func (h *UserHandlers) UpdateUser(c *fiber.Ctx, id int32) error {
const op = "UserHandlers.UpdateUser"
var req = &userv1.UpdateUserRequest{}
err := c.BodyParser(req)
if err != nil {
return c.SendStatus(fiber.StatusBadRequest)
}
err = h.userUC.UpdateUser(c.Context(), id, req.Username, int32PtrToRolePtr(req.Role))
if err != nil {
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusOK)
}
func (h *UserHandlers) DeleteUser(c *fiber.Ctx, id int32) error {
const op = "UserHandlers.DeleteUser"
ctx := c.Context()
err := h.userUC.DeleteUser(ctx, id)
if err != nil {
return c.SendStatus(pkg.ToREST(err))
}
return c.SendStatus(fiber.StatusOK)
}
func (h *UserHandlers) ListUsers(c *fiber.Ctx, params userv1.ListUsersParams) error {
const op = "UserHandlers.ListUsers"
usersList, count, err := h.userUC.ListUsers(c.Context(), params.Page, params.PageSize)
if err != nil {
return c.SendStatus(pkg.ToREST(err))
}
return c.JSON(map[string]interface{}{
"users": usersList,
"page": params.Page,
"max_page": func() int32 {
if count%params.PageSize == 0 {
return count / params.PageSize
}
return count/params.PageSize + 1
}(),
})
}
func (h *UserHandlers) ListSessions(c *fiber.Ctx) error {
const op = "UserHandlers.ListSessions"
return c.SendStatus(fiber.StatusNotImplemented)
}
func int32PtrToRolePtr(i *int32) *models.Role {
if i == nil {
return nil
}
ii := models.Role(*i)
return &ii
}