Refactor authentication module: Introduce AuthController and endpoints, implement login, registration, password reset, and token management functionalities. Update routes and services to utilize new structures and improve code organization. Enhance user management with detailed error handling and session management. Update API response types and ensure consistent naming conventions across the application.

This commit is contained in:
fabio 2026-04-05 17:09:01 +02:00
parent 6920d7ae95
commit 36fca2af6c
21 changed files with 651 additions and 648 deletions

View File

@ -1,3 +1,11 @@
# go-quasar-partial-ssr
bakend in GO frontend quasar framework con generazione delle pagine statiche per la parte public
internal
auth
model
controller
service
endpoint

View File

@ -4,7 +4,7 @@
//
// This file was generated by github.com/millevolte/ts-rpc
//
// Mar 17, 2026 18:16:42 UTC
// Apr 05, 2026 17:08:11 UTC
//
export interface ApiRestResponse {
@ -280,17 +280,74 @@ export type Nullable<T> = T | null;
export type Record<K extends string | number | symbol, T> = { [P in K]: T };
//
// package model
//
export interface RefreshRequest {
refresh_token: string;
}
export interface TokenPair {
access_token: string;
refresh_token: string;
}
export interface ForgotPasswordRequest {
email: string;
}
export interface LoginRequest {
username: string;
password: string;
}
export interface ResetPasswordRequest {
token: string;
password: string;
}
//
// package controllers
//
export interface BlockUserRequest {
action: string;
}
export interface ListUsersRequest {
page: number;
pageSize: number;
}
export interface SimpleResponse {
message: string;
}
export interface UpdateUserRequest {
name: string;
email: string;
password: string;
roles: models.UserRoles;
status: models.UserStatus;
types: models.UserTypes;
avatar: Nullable<string>;
details: Nullable<models.UserDetailsShort>;
preferences: Nullable<models.UserPreferencesShort>;
}
//
// package routes
//
// Typescript: TSEndpoint= path=/users/:uuid; name=getUser; method=GET; response=models.UserProfile
// internal/http/routes/user_routes.go Line: 13
export const getUser = async (
uuid: string,
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.GET(`/users/${uuid}`)) as {
data: UserProfile;
// Typescript: TSEndpoint= path=/metrics; name=metrics; method=GET; response=string
// internal/http/routes/system_routes.go Line: 37
export const metrics = async (): Promise<{
data: string;
error: Nullable<string>;
}> => {
return (await api.GET("/metrics")) as {
data: string;
error: Nullable<string>;
};
};
@ -307,38 +364,13 @@ export const mailDebug = async (): Promise<{
};
};
// Typescript: TSEndpoint= path=/auth/login; name=login; method=POST; request=controllers.LoginRequest; response=auth.TokenPair
// internal/http/routes/auth_routes.go Line: 22
export const login = async (
data: LoginRequest,
): Promise<{ data: TokenPair; error: Nullable<string> }> => {
return (await api.POST("/auth/login", data)) as {
data: TokenPair;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/register; name=register; method=POST; request=models.UserCreateInput; response=models.UserShort
// internal/http/routes/auth_routes.go Line: 31
export const register = async (
data: UserCreateInput,
): Promise<{ data: UserShort; error: Nullable<string> }> => {
return (await api.POST("/auth/register", data)) as {
data: UserShort;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/metrics; name=metrics; method=GET; response=string
// internal/http/routes/system_routes.go Line: 37
export const metrics = async (): Promise<{
data: string;
error: Nullable<string>;
}> => {
return (await api.GET("/metrics")) as {
data: string;
// Typescript: TSEndpoint= path=/users/:uuid; name=getUser; method=GET; response=models.UserProfile
// internal/http/routes/user_routes.go Line: 13
export const getUser = async (
uuid: string,
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.GET(`/users/${uuid}`)) as {
data: UserProfile;
error: Nullable<string>;
};
};
@ -355,90 +387,6 @@ export const updateUser = async (
};
};
// Typescript: TSEndpoint= path=/auth/password/valid; name=validToken; method=POST; request=string; response=controllers.SimpleResponse
// internal/http/routes/auth_routes.go Line: 40
export const validToken = async (
data: string,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/valid", data)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/health; name=health; method=GET; response=string
// internal/http/routes/system_routes.go Line: 34
export const health = async (): Promise<{
data: string;
error: Nullable<string>;
}> => {
return (await api.GET("/health")) as {
data: string;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/users/:uuid; name=deleteUser; method=DELETE; response=controllers.SimpleResponse
// internal/http/routes/user_routes.go Line: 22
export const deleteUser = async (
uuid: string,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.DELETE(`/users/${uuid}`)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/password/reset; name=resetPassword; method=POST; request=controllers.ResetPasswordRequest; response=controllers.SimpleResponse
// internal/http/routes/auth_routes.go Line: 37
export const resetPassword = async (
data: ResetPasswordRequest,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/reset", data)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/users; name=createUser; method=POST; request=models.UserCreateInput; response=models.UserProfile
// internal/http/routes/user_routes.go Line: 16
export const createUser = async (
data: UserCreateInput,
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.POST("/users", data)) as {
data: UserProfile;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/refresh; name=refresh; method=POST; request=controllers.RefreshRequest; response=auth.TokenPair
// internal/http/routes/auth_routes.go Line: 25
export const refresh = async (
data: RefreshRequest,
): Promise<{ data: TokenPair; error: Nullable<string> }> => {
return (await api.POST("/auth/refresh", data)) as {
data: TokenPair;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/me; name=me; method=GET; response=models.UserShort
// internal/http/routes/auth_routes.go Line: 28
export const me = async (): Promise<{
data: UserShort;
error: Nullable<string>;
}> => {
return (await api.GET("/auth/me")) as {
data: UserShort;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/admin/users; name=listUsers; method=POST; request=controllers.ListUsersRequest; response=models.[]UserShort
// internal/http/routes/admin_routes.go Line: 12
@ -463,18 +411,42 @@ export const blockUser = async (
};
};
// Typescript: TSEndpoint= path=/auth/password/forgot; name=forgotPassword; method=POST; request=controllers.ForgotPasswordRequest; response=controllers.SimpleResponse
// internal/http/routes/auth_routes.go Line: 34
// Typescript: TSEndpoint= path=/users; name=createUser; method=POST; request=models.UserCreateInput; response=models.UserProfile
// internal/http/routes/user_routes.go Line: 16
export const forgotPassword = async (
data: ForgotPasswordRequest,
export const createUser = async (
data: UserCreateInput,
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.POST("/users", data)) as {
data: UserProfile;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/users/:uuid; name=deleteUser; method=DELETE; response=controllers.SimpleResponse
// internal/http/routes/user_routes.go Line: 22
export const deleteUser = async (
uuid: string,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/forgot", data)) as {
return (await api.DELETE(`/users/${uuid}`)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/health; name=health; method=GET; response=string
// internal/http/routes/system_routes.go Line: 34
export const health = async (): Promise<{
data: string;
error: Nullable<string>;
}> => {
return (await api.GET("/health")) as {
data: string;
error: Nullable<string>;
};
};
export interface FormRequest {
req: string;
count: number;
@ -489,6 +461,94 @@ export interface MailDebugItem {
content: string;
}
//
// package endpoint
//
// Typescript: TSEndpoint= path=/auth/password/forgot; name=forgotPassword; method=POST; request=model.ForgotPasswordRequest; response=controllers.SimpleResponse
// internal/auth/endpoint/routes.go Line: 34
export const forgotPassword = async (
data: ForgotPasswordRequest,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/forgot", data)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/password/reset; name=resetPassword; method=POST; request=model.ResetPasswordRequest; response=controllers.SimpleResponse
// internal/auth/endpoint/routes.go Line: 37
export const resetPassword = async (
data: ResetPasswordRequest,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/reset", data)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/password/valid; name=validToken; method=POST; request=string; response=controllers.SimpleResponse
// internal/auth/endpoint/routes.go Line: 40
export const validToken = async (
data: string,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/valid", data)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/login; name=login; method=POST; request=model.LoginRequest; response=model.TokenPair
// internal/auth/endpoint/routes.go Line: 22
export const login = async (
data: LoginRequest,
): Promise<{ data: TokenPair; error: Nullable<string> }> => {
return (await api.POST("/auth/login", data)) as {
data: TokenPair;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/refresh; name=refresh; method=POST; request=model.RefreshRequest; response=model.TokenPair
// internal/auth/endpoint/routes.go Line: 25
export const refresh = async (
data: RefreshRequest,
): Promise<{ data: TokenPair; error: Nullable<string> }> => {
return (await api.POST("/auth/refresh", data)) as {
data: TokenPair;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/me; name=me; method=GET; response=models.UserShort
// internal/auth/endpoint/routes.go Line: 28
export const me = async (): Promise<{
data: UserShort;
error: Nullable<string>;
}> => {
return (await api.GET("/auth/me")) as {
data: UserShort;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/register; name=register; method=POST; request=models.UserCreateInput; response=models.UserShort
// internal/auth/endpoint/routes.go Line: 31
export const register = async (
data: UserCreateInput,
): Promise<{ data: UserShort; error: Nullable<string> }> => {
return (await api.POST("/auth/register", data)) as {
data: UserShort;
error: Nullable<string>;
};
};
//
// package models
//
@ -516,17 +576,6 @@ export interface UserDetailsShort {
phone: string;
}
export interface UserShort {
email: string;
name: string;
roles: UserRoles;
status: UserStatus;
uuid: string;
details: Nullable<UserDetailsShort>;
preferences: Nullable<UserPreferencesShort>;
avatar: Nullable<string>;
}
export interface UserPreferencesShort {
useIdle: boolean;
idleTimeout: number;
@ -538,7 +587,16 @@ export interface UserPreferencesShort {
language: string;
}
export type UsersShort = UserShort[];
export interface UserShort {
email: string;
name: string;
roles: UserRoles;
status: UserStatus;
uuid: string;
details: Nullable<UserDetailsShort>;
preferences: Nullable<UserPreferencesShort>;
avatar: Nullable<string>;
}
export type UserRoles = string[];
@ -546,64 +604,10 @@ export type UserStatus = (typeof EnumUserStatus)[keyof typeof EnumUserStatus];
export type UserTypes = string[];
export type UsersShort = UserShort[];
export const EnumUserStatus = {
UserStatusPending: "pending",
UserStatusActive: "active",
UserStatusDisabled: "disabled",
} as const;
//
// package controllers
//
export interface ResetPasswordRequest {
token: string;
password: string;
}
export interface RefreshRequest {
refresh_token: string;
}
export interface SimpleResponse {
message: string;
}
export interface UpdateUserRequest {
name: string;
email: string;
password: string;
roles: models.UserRoles;
status: models.UserStatus;
types: models.UserTypes;
avatar: Nullable<string>;
details: Nullable<models.UserDetailsShort>;
preferences: Nullable<models.UserPreferencesShort>;
}
export interface BlockUserRequest {
action: string;
}
export interface ForgotPasswordRequest {
email: string;
}
export interface ListUsersRequest {
page: number;
pageSize: number;
}
export interface LoginRequest {
username: string;
password: string;
}
//
// package auth
//
export interface TokenPair {
access_token: string;
refresh_token: string;
}

View File

@ -11,7 +11,8 @@ import (
"syscall"
"time"
"server/internal/auth"
authmodel "server/internal/auth/model"
authservice "server/internal/auth/service"
"server/internal/config"
"server/internal/db"
"server/internal/http/controllers"
@ -54,7 +55,7 @@ func main() {
log.Fatalf("init db: %v", err)
}
authService, err := auth.New(auth.Config{
authService, err := authservice.New(authmodel.Config{
Secret: cfg.Auth.Secret,
Issuer: cfg.Auth.Issuer,
AccessTokenExpiry: time.Duration(cfg.Auth.AccessTokenExpiryMinutes) * time.Minute,

View File

@ -1,4 +1,4 @@
package controllers
package controller
import (
"crypto/rand"
@ -10,65 +10,39 @@ import (
"time"
"github.com/gofiber/fiber/v3"
"github.com/google/uuid"
"gorm.io/gorm"
"server/internal/auth"
authmodel "server/internal/auth/model"
authservice "server/internal/auth/service"
"server/internal/http/controllers"
"server/internal/mail"
"server/internal/models"
"github.com/google/uuid"
)
type AuthController struct {
authService *auth.Service
authService *authservice.Service
mailService *mail.Service
}
// Typescript: interface
type SimpleResponse struct {
Message string `json:"message"`
}
func NewAuthController(authService *auth.Service, mailService *mail.Service) *AuthController {
func New(authService *authservice.Service, mailService *mail.Service) *AuthController {
return &AuthController{
authService: authService,
mailService: mailService,
}
}
// Typescript: interface
type LoginRequest struct {
Username string `json:"username" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,max=128"`
}
// Typescript: interface
type RefreshRequest struct {
RefreshToken string `json:"refresh_token"`
}
// Typescript: interface
type ForgotPasswordRequest struct {
Email string `json:"email" validate:"required,email"`
}
// Typescript: interface
type ResetPasswordRequest struct {
Token string `json:"token" validate:"required,min=20,max=255"`
Password string `json:"password" validate:"required,min=8,max=128"`
}
// Login authenticates a user and issues an access/refresh token pair.
func (ac *AuthController) Login(c fiber.Ctx) error {
var req LoginRequest
var req authmodel.LoginRequest
if err := c.Bind().Body(&req); err != nil {
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
}
if err := validateStruct(&req); err != nil {
if err := controllers.ValidateStruct(&req); err != nil {
return err
}
db, err := dbFromCtx(c)
db, err := controllers.DBFromCtx(c)
if err != nil {
return err
}
@ -80,7 +54,7 @@ func (ac *AuthController) Login(c fiber.Ctx) error {
}
return fiber.NewError(fiber.StatusInternalServerError, "failed to fetch user")
}
match, err := auth.VerifyPassword(user.Password, req.Password)
match, err := authservice.VerifyPassword(user.Password, req.Password)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "failed to verify credentials")
}
@ -102,8 +76,8 @@ func (ac *AuthController) Login(c fiber.Ctx) error {
session := models.Session{
UserID: &userID,
Username: user.Email,
AccessTokenHash: hashToken(tokens.AccessToken),
RefreshTokenHash: hashToken(tokens.RefreshToken),
AccessTokenHash: controllers.HashToken(tokens.AccessToken),
RefreshTokenHash: controllers.HashToken(tokens.RefreshToken),
ExpiresAt: now.Add(ac.authService.RefreshExpiry()),
IPAddress: c.IP(),
UserAgent: c.Get("User-Agent"),
@ -113,15 +87,14 @@ func (ac *AuthController) Login(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "failed to record session")
}
//c.Set("Auth-Token", tokens.AccessToken)
c.Response().Header.Set("Auth-Token", tokens.AccessToken)
return c.JSON(success(tokens))
return c.JSON(controllers.Success(tokens))
}
// Refresh renews an access/refresh token pair using a valid refresh token.
func (ac *AuthController) Refresh(c fiber.Ctx) error {
var req RefreshRequest
var req authmodel.RefreshRequest
if err := c.Bind().Body(&req); err != nil {
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
}
@ -133,17 +106,17 @@ func (ac *AuthController) Refresh(c fiber.Ctx) error {
if err != nil {
return fiber.NewError(fiber.StatusUnauthorized, err.Error())
}
return c.JSON(success(tokens))
return c.JSON(controllers.Success(tokens))
}
// Me returns the authenticated user's profile (short format).
func (ac *AuthController) Me(c fiber.Ctx) error {
claims, ok := auth.ClaimsFromCtx(c)
claims, ok := authservice.ClaimsFromCtx(c)
if !ok {
return fiber.NewError(fiber.StatusUnauthorized, "missing claims")
}
db, err := dbFromCtx(c)
db, err := controllers.DBFromCtx(c)
if err != nil {
return err
}
@ -156,7 +129,7 @@ func (ac *AuthController) Me(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "failed to load user")
}
return c.JSON(success(models.ToUserShort(&user)))
return c.JSON(controllers.Success(models.ToUserShort(&user)))
}
// Register creates a new user with optional roles/types/preferences.
@ -165,11 +138,11 @@ func (ac *AuthController) Register(c fiber.Ctx) error {
if err := c.Bind().Body(&req); err != nil {
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
}
if err := validateStruct(&req); err != nil {
if err := controllers.ValidateStruct(&req); err != nil {
return err
}
db, err := dbFromCtx(c)
db, err := controllers.DBFromCtx(c)
if err != nil {
return err
}
@ -182,7 +155,7 @@ func (ac *AuthController) Register(c fiber.Ctx) error {
}
now := time.Now().UTC()
hashedPassword, err := auth.HashPassword(req.Password)
hashedPassword, err := authservice.HashPassword(req.Password)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
}
@ -210,7 +183,7 @@ func (ac *AuthController) Register(c fiber.Ctx) error {
}(),
Avatar: req.Avatar,
UUID: uuid.NewString(),
Details: toUserDetails(req.Details),
Details: controllers.ToUserDetails(req.Details),
Preferences: func() *models.UserPreferences {
if req.Preferences == nil {
return nil
@ -247,19 +220,19 @@ func (ac *AuthController) Register(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "failed to send registration email")
}
return c.Status(fiber.StatusCreated).JSON(success(models.ToUserShort(&user)))
return c.Status(fiber.StatusCreated).JSON(controllers.Success(models.ToUserShort(&user)))
}
func (ac *AuthController) ForgotPassword(c fiber.Ctx) error {
var req ForgotPasswordRequest
var req authmodel.ForgotPasswordRequest
if err := c.Bind().Body(&req); err != nil {
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
}
if err := validateStruct(&req); err != nil {
if err := controllers.ValidateStruct(&req); err != nil {
return err
}
db, err := dbFromCtx(c)
db, err := controllers.DBFromCtx(c)
if err != nil {
return err
}
@ -267,13 +240,13 @@ func (ac *AuthController) ForgotPassword(c fiber.Ctx) error {
var user models.User
if err := db.Where("email = ?", req.Email).First(&user).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return c.JSON(success(fiber.Map{"sent": true}))
return c.JSON(controllers.Success(fiber.Map{"sent": true}))
}
return fiber.NewError(fiber.StatusInternalServerError, "failed to load user")
}
if user.Status == models.UserStatusDisabled {
return c.JSON(success(fiber.Map{"sent": true}))
return c.JSON(controllers.Success(fiber.Map{"sent": true}))
}
resetToken, err := generateSecureToken()
@ -284,7 +257,7 @@ func (ac *AuthController) ForgotPassword(c fiber.Ctx) error {
now := time.Now().UTC()
record := models.PasswordResetToken{
UserID: user.ID,
TokenHash: hashToken(resetToken),
TokenHash: controllers.HashToken(resetToken),
ExpiresAt: now.Add(30 * time.Minute),
CreatedAt: now,
UpdatedAt: now,
@ -315,30 +288,30 @@ func (ac *AuthController) ForgotPassword(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "failed to send reset email")
}
return c.JSON(success(SimpleResponse{Message: "password reset email sent"}))
return c.JSON(controllers.Success(controllers.SimpleResponse{Message: "password reset email sent"}))
}
func (ac *AuthController) ResetPassword(c fiber.Ctx) error {
var req ResetPasswordRequest
var req authmodel.ResetPasswordRequest
if err := c.Bind().Body(&req); err != nil {
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
}
if err := validateStruct(&req); err != nil {
if err := controllers.ValidateStruct(&req); err != nil {
return err
}
db, err := dbFromCtx(c)
db, err := controllers.DBFromCtx(c)
if err != nil {
return err
}
hashedPassword, err := auth.HashPassword(req.Password)
hashedPassword, err := authservice.HashPassword(req.Password)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
}
now := time.Now().UTC()
tokenHash := hashToken(req.Token)
tokenHash := controllers.HashToken(req.Token)
if err := db.Transaction(func(tx *gorm.DB) error {
var resetToken models.PasswordResetToken
if err := tx.Where("token_hash = ?", tokenHash).First(&resetToken).Error; err != nil {
@ -378,7 +351,7 @@ func (ac *AuthController) ResetPassword(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "failed to reset password")
}
return c.JSON(success(SimpleResponse{Message: "password reset successful"}))
return c.JSON(controllers.Success(controllers.SimpleResponse{Message: "password reset successful"}))
}
func (ac *AuthController) ValidToken(c fiber.Ctx) error {
@ -387,7 +360,6 @@ func (ac *AuthController) ValidToken(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "token is required")
}
// Accept both plain text token payload and JSON string payload.
token := raw
if strings.HasPrefix(raw, "\"") && strings.HasSuffix(raw, "\"") {
if err := json.Unmarshal([]byte(raw), &token); err != nil {
@ -399,13 +371,13 @@ func (ac *AuthController) ValidToken(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "token is required")
}
db, err := dbFromCtx(c)
db, err := controllers.DBFromCtx(c)
if err != nil {
return err
}
now := time.Now().UTC()
tokenHash := hashToken(token)
tokenHash := controllers.HashToken(token)
var resetToken models.PasswordResetToken
if err := db.Where("token_hash = ?", tokenHash).First(&resetToken).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
@ -418,7 +390,7 @@ func (ac *AuthController) ValidToken(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "invalid or expired reset token")
}
return c.JSON(success(SimpleResponse{Message: "valid reset token"}))
return c.JSON(controllers.Success(controllers.SimpleResponse{Message: "valid reset token"}))
}
func generateSecureToken() (string, error) {

View File

@ -1,28 +1,28 @@
package routes
package endpoint
import (
"time"
"server/internal/auth"
"server/internal/http/controllers"
authcontroller "server/internal/auth/controller"
authservice "server/internal/auth/service"
"server/internal/mail"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/limiter"
)
func registerAuthRoutes(app *fiber.App, authService *auth.Service, mailService *mail.Service) {
authController := controllers.NewAuthController(authService, mailService)
func Register(app *fiber.App, authService *authservice.Service, mailService *mail.Service) {
authController := authcontroller.New(authService, mailService)
authRateLimiter := limiter.New(limiter.Config{
Max: 10,
Expiration: time.Minute,
LimiterMiddleware: limiter.SlidingWindow{},
})
// Typescript: TSEndpoint= path=/auth/login; name=login; method=POST; request=controllers.LoginRequest; response=auth.TokenPair
// Typescript: TSEndpoint= path=/auth/login; name=login; method=POST; request=model.LoginRequest; response=model.TokenPair
app.Post("/auth/login", authRateLimiter, authController.Login)
// Typescript: TSEndpoint= path=/auth/refresh; name=refresh; method=POST; request=controllers.RefreshRequest; response=auth.TokenPair
// Typescript: TSEndpoint= path=/auth/refresh; name=refresh; method=POST; request=model.RefreshRequest; response=model.TokenPair
app.Post("/auth/refresh", authService.Middleware(), authController.Refresh)
// Typescript: TSEndpoint= path=/auth/me; name=me; method=GET; response=models.UserShort
@ -31,10 +31,10 @@ func registerAuthRoutes(app *fiber.App, authService *auth.Service, mailService *
// Typescript: TSEndpoint= path=/auth/register; name=register; method=POST; request=models.UserCreateInput; response=models.UserShort
app.Post("/auth/register", authRateLimiter, authController.Register)
// Typescript: TSEndpoint= path=/auth/password/forgot; name=forgotPassword; method=POST; request=controllers.ForgotPasswordRequest; response=controllers.SimpleResponse
// Typescript: TSEndpoint= path=/auth/password/forgot; name=forgotPassword; method=POST; request=model.ForgotPasswordRequest; response=controllers.SimpleResponse
app.Post("/auth/password/forgot", authRateLimiter, authController.ForgotPassword)
// Typescript: TSEndpoint= path=/auth/password/reset; name=resetPassword; method=POST; request=controllers.ResetPasswordRequest; response=controllers.SimpleResponse
// Typescript: TSEndpoint= path=/auth/password/reset; name=resetPassword; method=POST; request=model.ResetPasswordRequest; response=controllers.SimpleResponse
app.Post("/auth/password/reset", authRateLimiter, authController.ResetPassword)
// Typescript: TSEndpoint= path=/auth/password/valid; name=validToken; method=POST; request=string; response=controllers.SimpleResponse

View File

@ -0,0 +1,47 @@
package model
import (
"time"
"github.com/golang-jwt/jwt/v5"
)
type Config struct {
Secret string
Issuer string
AccessTokenExpiry time.Duration
RefreshTokenExpiry time.Duration
}
type Claims struct {
Username string `json:"username"`
TokenType string `json:"type"`
jwt.RegisteredClaims
}
// Typescript: interface
type TokenPair struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
}
type Permission int
type Role struct {
Name string
Permissions Permission
}
const (
AdminPermission Permission = 0xff - (1<<iota - 1)
ManagerPermission
UserPermission
GuestPermission
)
var Roles = []Role{
{"admin", AdminPermission},
{"manager", ManagerPermission},
{"user", UserPermission},
{"guest", GuestPermission},
}

View File

@ -0,0 +1,23 @@
package model
// Typescript: interface
type LoginRequest struct {
Username string `json:"username" validate:"required,email"`
Password string `json:"password" validate:"required,min=8,max=128"`
}
// Typescript: interface
type RefreshRequest struct {
RefreshToken string `json:"refresh_token"`
}
// Typescript: interface
type ForgotPasswordRequest struct {
Email string `json:"email" validate:"required,email"`
}
// Typescript: interface
type ResetPasswordRequest struct {
Token string `json:"token" validate:"required,min=20,max=255"`
Password string `json:"password" validate:"required,min=8,max=128"`
}

View File

@ -1,21 +0,0 @@
package auth
type Permission int
type Role struct {
Name string
Permissions Permission
}
const (
AdminPermission Permission = 0xff - (1<<iota - 1)
ManagerPermission
UserPermission
GuestPermission
)
var Roles = []Role{
{"admin", AdminPermission},
{"manager", ManagerPermission},
{"user", UserPermission},
{"guest", GuestPermission},
}

View File

@ -1,46 +1,28 @@
package auth
package service
import (
"errors"
"strings"
"time"
"github.com/gofiber/fiber/v3"
"github.com/golang-jwt/jwt/v5"
authmodel "server/internal/auth/model"
)
type Config struct {
Secret string
Issuer string
AccessTokenExpiry time.Duration
RefreshTokenExpiry time.Duration
}
type Service struct {
cfg Config
cfg authmodel.Config
secret []byte
accessExpiry time.Duration
refreshExpiry time.Duration
}
type Claims struct {
Username string `json:"username"`
TokenType string `json:"type"`
jwt.RegisteredClaims
}
// Typescript: interface
type TokenPair struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
}
const (
tokenTypeAccess = "access"
tokenTypeRefresh = "refresh"
)
func New(cfg Config) (*Service, error) {
func New(cfg authmodel.Config) (*Service, error) {
if cfg.Secret == "" {
return nil, errors.New("jwt secret is required")
}
@ -59,29 +41,27 @@ func New(cfg Config) (*Service, error) {
}, nil
}
func (s *Service) GenerateTokenPair(username string) (TokenPair, error) {
func (s *Service) GenerateTokenPair(username string) (authmodel.TokenPair, error) {
access, err := s.generateToken(username, tokenTypeAccess, s.accessExpiry)
if err != nil {
return TokenPair{}, err
return authmodel.TokenPair{}, err
}
refresh, err := s.generateToken(username, tokenTypeRefresh, s.refreshExpiry)
if err != nil {
return TokenPair{}, err
return authmodel.TokenPair{}, err
}
return TokenPair{
return authmodel.TokenPair{
AccessToken: access,
RefreshToken: refresh,
}, nil
}
// AccessExpiry returns the configured access token lifetime.
func (s *Service) AccessExpiry() time.Duration {
return s.accessExpiry
}
// RefreshExpiry returns the configured refresh token lifetime.
func (s *Service) RefreshExpiry() time.Duration {
return s.refreshExpiry
}
@ -106,19 +86,18 @@ func (s *Service) Middleware() fiber.Handler {
}
}
func (s *Service) Refresh(refreshToken string) (TokenPair, error) {
func (s *Service) Refresh(refreshToken string) (authmodel.TokenPair, error) {
claims, err := s.parseToken(refreshToken)
if err != nil {
return TokenPair{}, err
return authmodel.TokenPair{}, err
}
if claims.TokenType != tokenTypeRefresh {
return TokenPair{}, errors.New("refresh token required")
return authmodel.TokenPair{}, errors.New("refresh token required")
}
return s.GenerateTokenPair(claims.Username)
}
// ValidateAccessToken parses and validates an access token string, ensuring type=access.
func (s *Service) ValidateAccessToken(tokenString string) (*Claims, error) {
func (s *Service) ValidateAccessToken(tokenString string) (*authmodel.Claims, error) {
claims, err := s.parseToken(tokenString)
if err != nil {
return nil, err
@ -129,8 +108,17 @@ func (s *Service) ValidateAccessToken(tokenString string) (*Claims, error) {
return claims, nil
}
func (s *Service) parseToken(tokenString string) (*Claims, error) {
claims := &Claims{}
func ClaimsFromCtx(c fiber.Ctx) (*authmodel.Claims, bool) {
val := c.Locals("authClaims")
if val == nil {
return nil, false
}
claims, ok := val.(*authmodel.Claims)
return claims, ok
}
func (s *Service) parseToken(tokenString string) (*authmodel.Claims, error) {
claims := &authmodel.Claims{}
token, err := jwt.ParseWithClaims(tokenString, claims, func(t *jwt.Token) (interface{}, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fiber.ErrUnauthorized
@ -148,7 +136,7 @@ func (s *Service) parseToken(tokenString string) (*Claims, error) {
}
func (s *Service) generateToken(username, tokenType string, expiry time.Duration) (string, error) {
claims := Claims{
claims := authmodel.Claims{
Username: username,
TokenType: tokenType,
RegisteredClaims: jwt.RegisteredClaims{
@ -161,27 +149,3 @@ func (s *Service) generateToken(username, tokenType string, expiry time.Duration
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(s.secret)
}
func bearerToken(header string) (string, error) {
if header == "" {
return "", errors.New("missing Auth-Token header")
}
if !strings.HasPrefix(header, "Bearer ") {
return "", errors.New("invalid Authorization header format")
}
token := strings.TrimSpace(strings.TrimPrefix(header, "Bearer "))
if token == "" {
return "", errors.New("empty bearer token")
}
return token, nil
}
func ClaimsFromCtx(c fiber.Ctx) (*Claims, bool) {
val := c.Locals("authClaims")
if val == nil {
return nil, false
}
claims, ok := val.(*Claims)
return claims, ok
}

View File

@ -1,4 +1,4 @@
package auth
package service
import (
"errors"

View File

@ -10,7 +10,7 @@ import (
"github.com/gofiber/fiber/v3"
"gorm.io/gorm"
"server/internal/auth"
authservice "server/internal/auth/service"
"server/internal/models"
)
@ -128,7 +128,7 @@ func (r *RoleResolver) RoleDefined(role string) bool {
// RequireRole ensures the authenticated user has the specified role (with inheritance).
func RequireRole(resolver *RoleResolver, role string) fiber.Handler {
return func(c fiber.Ctx) error {
claims, ok := auth.ClaimsFromCtx(c)
claims, ok := authservice.ClaimsFromCtx(c)
if !ok {
return fiber.NewError(fiber.StatusUnauthorized, "missing claims")
}
@ -156,7 +156,7 @@ func RequireRole(resolver *RoleResolver, role string) fiber.Handler {
// RequirePermission ensures the authenticated user has the given permission.
func RequirePermission(resolver *RoleResolver, perm string) fiber.Handler {
return func(c fiber.Ctx) error {
claims, ok := auth.ClaimsFromCtx(c)
claims, ok := authservice.ClaimsFromCtx(c)
if !ok {
return fiber.NewError(fiber.StatusUnauthorized, "missing claims")
}
@ -183,7 +183,7 @@ func RequirePermission(resolver *RoleResolver, perm string) fiber.Handler {
// RequireEndpointPermission enforces permission mapping defined in role config.
// If the endpoint is not configured, or mapped to "*", it allows the request.
func RequireEndpointPermission(resolver *RoleResolver, authService *auth.Service) fiber.Handler {
func RequireEndpointPermission(resolver *RoleResolver, authService *authservice.Service) fiber.Handler {
return func(c fiber.Ctx) error {
perm, ok := resolver.PermissionForEndpoint(c.Method(), c.Path())
if !ok || perm == "*" {

View File

@ -17,6 +17,10 @@ func dbFromCtx(c fiber.Ctx) (*gorm.DB, error) {
return db, nil
}
func DBFromCtx(c fiber.Ctx) (*gorm.DB, error) {
return dbFromCtx(c)
}
func toUserDetails(d *models.UserDetailsShort) *models.UserDetails {
if d == nil {
return nil
@ -33,6 +37,10 @@ func toUserDetails(d *models.UserDetailsShort) *models.UserDetails {
}
}
func ToUserDetails(d *models.UserDetailsShort) *models.UserDetails {
return toUserDetails(d)
}
func toUserPreferences(p *models.UserPreferencesShort) *models.UserPreferences {
if p == nil {
return nil
@ -48,3 +56,7 @@ func toUserPreferences(p *models.UserPreferencesShort) *models.UserPreferences {
Language: p.Language,
}
}
func ToUserPreferences(p *models.UserPreferencesShort) *models.UserPreferences {
return toUserPreferences(p)
}

View File

@ -9,3 +9,7 @@ func success(data any) fiber.Map {
"error": nil,
}
}
func Success(data any) fiber.Map {
return success(data)
}

View File

@ -0,0 +1,6 @@
package controllers
// Typescript: interface
type SimpleResponse struct {
Message string `json:"message"`
}

View File

@ -9,3 +9,7 @@ func hashToken(token string) string {
sum := sha256.Sum256([]byte(token))
return hex.EncodeToString(sum[:])
}
func HashToken(token string) string {
return hashToken(token)
}

View File

@ -9,7 +9,7 @@ import (
"github.com/google/uuid"
"gorm.io/gorm"
"server/internal/auth"
authservice "server/internal/auth/service"
"server/internal/models"
)
@ -63,7 +63,7 @@ func (uc *UserController) CreateUser(c fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "failed to check user")
}
hashedPassword, err := auth.HashPassword(req.Password)
hashedPassword, err := authservice.HashPassword(req.Password)
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
}

View File

@ -26,3 +26,7 @@ func validateStruct(payload any) error {
}
return nil
}
func ValidateStruct(payload any) error {
return validateStruct(payload)
}

View File

@ -1,7 +1,8 @@
package routes
import (
"server/internal/auth"
authendpoint "server/internal/auth/endpoint"
authservice "server/internal/auth/service"
"server/internal/mail"
"github.com/gofiber/fiber/v3"
@ -18,9 +19,9 @@ type FormResponse struct {
Test string `json:"test"`
}
func Register(app *fiber.App, authService *auth.Service, mailService *mail.Service) {
func Register(app *fiber.App, authService *authservice.Service, mailService *mail.Service) {
registerSystemRoutes(app)
registerAuthRoutes(app, authService, mailService)
authendpoint.Register(app, authService, mailService)
registerUserRoutes(app, authService)
registerAdminRoutes(app)
}

View File

@ -1,13 +1,13 @@
package routes
import (
"server/internal/auth"
authservice "server/internal/auth/service"
"server/internal/http/controllers"
"github.com/gofiber/fiber/v3"
)
func registerUserRoutes(app *fiber.App, authService *auth.Service) {
func registerUserRoutes(app *fiber.App, authService *authservice.Service) {
userController := controllers.NewUserController()
// Typescript: TSEndpoint= path=/users/:uuid; name=getUser; method=GET; response=models.UserProfile

View File

@ -9,7 +9,7 @@ import (
"github.com/brianvoe/gofakeit/v6"
"gorm.io/gorm"
"server/internal/auth"
authservice "server/internal/auth/service"
"server/internal/models"
)
@ -38,7 +38,7 @@ func SeedUsers(db *gorm.DB, n int) ([]models.User, []Credential, error) {
if err != nil {
return nil, nil, fmt.Errorf("generate password: %w", err)
}
passwordHash, err := auth.HashPassword(pw)
passwordHash, err := authservice.HashPassword(pw)
if err != nil {
return nil, nil, fmt.Errorf("hash seed password: %w", err)
}

View File

@ -4,7 +4,7 @@
//
// This file was generated by github.com/millevolte/ts-rpc
//
// Mar 15, 2026 16:33:29 UTC
// Apr 05, 2026 17:08:11 UTC
//
export interface ApiRestResponse {
@ -185,6 +185,30 @@ export default class Api {
}
}
async PUT(
url: string,
data: unknown,
timeout?: number,
): Promise<{
data: unknown;
error: string | null;
}> {
try {
const upload = url.includes("/upload/");
const result = await this.request(
"PUT",
this.apiUrl + url,
data,
timeout,
upload,
);
return this.processResult(result);
} catch (error: unknown) {
return this.processError(error);
}
}
async GET(
url: string,
timeout?: number,
@ -205,22 +229,6 @@ export default class Api {
}
}
async PUT(
url: string,
data: unknown,
timeout?: number,
): Promise<{
data: unknown;
error: string | null;
}> {
try {
const result = await this.request("PUT", this.apiUrl + url, data, timeout);
return this.processResult(result);
} catch (error: unknown) {
return this.processError(error);
}
}
async DELETE(
url: string,
timeout?: number,
@ -229,7 +237,12 @@ export default class Api {
error: string | null;
}> {
try {
const result = await this.request("DELETE", this.apiUrl + url, null, timeout);
const result = await this.request(
"DELETE",
this.apiUrl + url,
null,
timeout,
);
return this.processResult(result);
} catch (error: unknown) {
return this.processError(error);
@ -268,178 +281,73 @@ export type Nullable<T> = T | null;
export type Record<K extends string | number | symbol, T> = { [P in K]: T };
//
// package controllers
// package model
//
export interface LoginRequest {
username: string;
password: string;
}
export interface RefreshRequest {
refresh_token: string;
}
export interface SimpleResponse {
message: string;
export interface TokenPair {
access_token: string;
refresh_token: string;
}
export interface ForgotPasswordRequest {
email: string;
}
export interface LoginRequest {
username: string;
password: string;
}
export interface ResetPasswordRequest {
token: string;
password: string;
}
export interface ListUsersRequest {
page: number;
pageSize: number;
}
export interface ListUsersResponse {
page: number;
pageSize: number;
items: UserShort[];
}
//
// package controllers
//
export interface BlockUserRequest {
action: string;
}
//
// package models
//
export interface UserPreferencesShort {
useIdle: boolean;
idleTimeout: number;
useIdlePassword: boolean;
idlePin: string;
useDirectLogin: boolean;
useQuadcodeLogin: boolean;
sendNoticesMail: boolean;
language: string;
export interface ListUsersRequest {
page: number;
pageSize: number;
}
export interface UserPreferences {
id: number;
userId: number;
useIdle: boolean;
idleTimeout: number;
useIdlePassword: boolean;
idlePin: string;
useDirectLogin: boolean;
useQuadcodeLogin: boolean;
sendNoticesMail: boolean;
language: string;
createdAt: string;
updatedAt: string;
}
export interface UserShort {
email: string;
name: string;
roles: UserRoles;
status: UserStatus;
uuid: string;
details: Nullable<UserDetailsShort>;
preferences: Nullable<UserPreferencesShort>;
avatar: Nullable<string>;
}
export interface UserProfile {
id: number;
email: string;
name: string;
roles: UserRoles;
types: UserTypes;
status: UserStatus;
activatedAt: Nullable<string>;
uuid: string;
details: Nullable<UserDetails>;
preferences: Nullable<UserPreferences>;
avatar: Nullable<string>;
createdAt: string;
updatedAt: string;
}
export interface UserCreateInput {
name: string;
email: string;
password: string;
roles: UserRoles;
status: UserStatus;
types: UserTypes;
avatar: Nullable<string>;
details: Nullable<UserDetailsShort>;
preferences: Nullable<UserPreferencesShort>;
export interface SimpleResponse {
message: string;
}
export interface UpdateUserRequest {
name: string;
email: string;
password: string;
roles: UserRoles;
status: UserStatus;
types: UserTypes;
roles: models.UserRoles;
status: models.UserStatus;
types: models.UserTypes;
avatar: Nullable<string>;
details: Nullable<UserDetailsShort>;
preferences: Nullable<UserPreferencesShort>;
details: Nullable<models.UserDetailsShort>;
preferences: Nullable<models.UserPreferencesShort>;
}
export interface UserDetails {
id: number;
userId: number;
title: string;
firstName: string;
lastName: string;
address: string;
city: string;
zipCode: string;
country: string;
phone: string;
createdAt: string;
updatedAt: string;
}
export interface UserDetailsShort {
title: string;
firstName: string;
lastName: string;
address: string;
city: string;
zipCode: string;
country: string;
phone: string;
}
export type UserRoles = string[];
export type UserStatus = (typeof EnumUserStatus)[keyof typeof EnumUserStatus];
export type UserTypes = string[];
export type UsersShort = UserShort[];
export const EnumUserStatus = {
UserStatusPending: "pending",
UserStatusActive: "active",
UserStatusDisabled: "disabled",
} as const;
//
// package routes
//
// Typescript: TSEndpoint= path=/auth/password/valid; name=validToken; method=POST; request=string; response=controllers.SimpleResponse
// internal/http/routes/auth_routes.go Line: 40
export const validToken = async (
data: string,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/valid", data)) as {
data: SimpleResponse;
// Typescript: TSEndpoint= path=/metrics; name=metrics; method=GET; response=string
// internal/http/routes/system_routes.go Line: 37
export const metrics = async (): Promise<{
data: string;
error: Nullable<string>;
}> => {
return (await api.GET("/metrics")) as {
data: string;
error: Nullable<string>;
};
};
@ -456,89 +364,72 @@ export const mailDebug = async (): Promise<{
};
};
// Typescript: TSEndpoint= path=/users/:uuid; name=getUser; method=GET; response=models.UserProfile
// internal/http/routes/user_routes.go Line: 13
export const getUser = async (
uuid: string,
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.GET(`/users/${uuid}`)) as {
data: UserProfile;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/users/:uuid; name=updateUser; method=PUT; request=controllers.UpdateUserRequest; response=models.UserProfile
// internal/http/routes/user_routes.go Line: 19
export const updateUser = async (
data: UpdateUserRequest,
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.PUT("/users/:uuid", data)) as {
data: UserProfile;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/admin/users; name=listUsers; method=POST; request=controllers.ListUsersRequest; response=models.[]UserShort
// internal/http/routes/admin_routes.go Line: 12
export const listUsers = async (
data: ListUsersRequest,
): Promise<{ data: ListUsersResponse; error: Nullable<string> }> => {
): Promise<{ data: UserShort[]; error: Nullable<string> }> => {
return (await api.POST("/admin/users", data)) as {
data: ListUsersResponse;
data: UserShort[];
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/admin/users/:uuid/block; name=blockUser; method=PUT; request=controllers.BlockUserRequest; response=models.UserShort
// internal/http/routes/admin_routes.go Line: 15
export const blockUser = async (
uuid: string,
data: BlockUserRequest,
): Promise<{ data: UserShort; error: Nullable<string> }> => {
return (await api.PUT(`/admin/users/${uuid}/block`, data)) as {
return (await api.PUT("/admin/users/:uuid/block", data)) as {
data: UserShort;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/register; name=register; method=POST; request=models.UserCreateInput; response=models.UserShort
// internal/http/routes/auth_routes.go Line: 31
export const register = async (
// Typescript: TSEndpoint= path=/users; name=createUser; method=POST; request=models.UserCreateInput; response=models.UserProfile
// internal/http/routes/user_routes.go Line: 16
export const createUser = async (
data: UserCreateInput,
): Promise<{ data: UserShort; error: Nullable<string> }> => {
return (await api.POST("/auth/register", data)) as {
data: UserShort;
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.POST("/users", data)) as {
data: UserProfile;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/metrics; name=metrics; method=GET; response=string
// internal/http/routes/system_routes.go Line: 37
export const metrics = async (): Promise<{
data: string;
error: Nullable<string>;
}> => {
return (await api.GET("/metrics")) as {
data: string;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/users/:uuid; name=deleteUser; method=DELETE; response=controllers.SimpleResponse
// internal/http/routes/user_routes.go Line: 22
// Typescript: TSEndpoint= path=/auth/login; name=login; method=POST; request=controllers.LoginRequest; response=auth.TokenPair
// internal/http/routes/auth_routes.go Line: 22
export const login = async (
data: LoginRequest,
): Promise<{ data: TokenPair; error: Nullable<string> }> => {
return (await api.POST("/auth/login", data)) as {
data: TokenPair;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/refresh; name=refresh; method=POST; request=controllers.RefreshRequest; response=auth.TokenPair
// internal/http/routes/auth_routes.go Line: 25
export const refresh = async (
data: RefreshRequest,
): Promise<{ data: TokenPair; error: Nullable<string> }> => {
return (await api.POST("/auth/refresh", data)) as {
data: TokenPair;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/password/forgot; name=forgotPassword; method=POST; request=controllers.ForgotPasswordRequest; response=controllers.SimpleResponse
// internal/http/routes/auth_routes.go Line: 34
export const forgotPassword = async (
data: ForgotPasswordRequest,
export const deleteUser = async (
uuid: string,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/forgot", data)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/password/reset; name=resetPassword; method=POST; request=controllers.ResetPasswordRequest; response=controllers.SimpleResponse
// internal/http/routes/auth_routes.go Line: 37
export const resetPassword = async (
data: ResetPasswordRequest,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/reset", data)) as {
return (await api.DELETE(`/users/${uuid}`)) as {
data: SimpleResponse;
error: Nullable<string>;
};
@ -556,65 +447,6 @@ export const health = async (): Promise<{
};
};
// Typescript: TSEndpoint= path=/auth/me; name=me; method=GET; response=models.UserShort
// internal/http/routes/auth_routes.go Line: 28
export const me = async (): Promise<{
data: UserShort;
error: Nullable<string>;
}> => {
return (await api.GET("/auth/me")) as {
data: UserShort;
error: Nullable<string>;
};
};
export const listUsersCrud = async (): Promise<{
data: UserProfile[];
error: Nullable<string>;
}> => {
return (await api.GET("/users")) as {
data: UserProfile[];
error: Nullable<string>;
};
};
export const getUser = async (
uuid: string,
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.GET(`/users/${uuid}`)) as {
data: UserProfile;
error: Nullable<string>;
};
};
export const createUser = async (
data: UserCreateInput,
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.POST("/users", data)) as {
data: UserProfile;
error: Nullable<string>;
};
};
export const updateUser = async (
uuid: string,
data: UpdateUserRequest,
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
return (await api.PUT(`/users/${uuid}`, data)) as {
data: UserProfile;
error: Nullable<string>;
};
};
export const deleteUser = async (
uuid: string,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.DELETE(`/users/${uuid}`)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
export interface FormRequest {
req: string;
count: number;
@ -630,10 +462,152 @@ export interface MailDebugItem {
}
//
// package auth
// package endpoint
//
export interface TokenPair {
access_token: string;
refresh_token: string;
// Typescript: TSEndpoint= path=/auth/password/forgot; name=forgotPassword; method=POST; request=model.ForgotPasswordRequest; response=controllers.SimpleResponse
// internal/auth/endpoint/routes.go Line: 34
export const forgotPassword = async (
data: ForgotPasswordRequest,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/forgot", data)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/password/reset; name=resetPassword; method=POST; request=model.ResetPasswordRequest; response=controllers.SimpleResponse
// internal/auth/endpoint/routes.go Line: 37
export const resetPassword = async (
data: ResetPasswordRequest,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/reset", data)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/password/valid; name=validToken; method=POST; request=string; response=controllers.SimpleResponse
// internal/auth/endpoint/routes.go Line: 40
export const validToken = async (
data: string,
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
return (await api.POST("/auth/password/valid", data)) as {
data: SimpleResponse;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/login; name=login; method=POST; request=model.LoginRequest; response=model.TokenPair
// internal/auth/endpoint/routes.go Line: 22
export const login = async (
data: LoginRequest,
): Promise<{ data: TokenPair; error: Nullable<string> }> => {
return (await api.POST("/auth/login", data)) as {
data: TokenPair;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/refresh; name=refresh; method=POST; request=model.RefreshRequest; response=model.TokenPair
// internal/auth/endpoint/routes.go Line: 25
export const refresh = async (
data: RefreshRequest,
): Promise<{ data: TokenPair; error: Nullable<string> }> => {
return (await api.POST("/auth/refresh", data)) as {
data: TokenPair;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/me; name=me; method=GET; response=models.UserShort
// internal/auth/endpoint/routes.go Line: 28
export const me = async (): Promise<{
data: UserShort;
error: Nullable<string>;
}> => {
return (await api.GET("/auth/me")) as {
data: UserShort;
error: Nullable<string>;
};
};
// Typescript: TSEndpoint= path=/auth/register; name=register; method=POST; request=models.UserCreateInput; response=models.UserShort
// internal/auth/endpoint/routes.go Line: 31
export const register = async (
data: UserCreateInput,
): Promise<{ data: UserShort; error: Nullable<string> }> => {
return (await api.POST("/auth/register", data)) as {
data: UserShort;
error: Nullable<string>;
};
};
//
// package models
//
export interface UserCreateInput {
name: string;
email: string;
password: string;
roles: UserRoles;
status: UserStatus;
types: UserTypes;
avatar: Nullable<string>;
details: Nullable<UserDetailsShort>;
preferences: Nullable<UserPreferencesShort>;
}
export interface UserDetailsShort {
title: string;
firstName: string;
lastName: string;
address: string;
city: string;
zipCode: string;
country: string;
phone: string;
}
export interface UserPreferencesShort {
useIdle: boolean;
idleTimeout: number;
useIdlePassword: boolean;
idlePin: string;
useDirectLogin: boolean;
useQuadcodeLogin: boolean;
sendNoticesMail: boolean;
language: string;
}
export interface UserShort {
email: string;
name: string;
roles: UserRoles;
status: UserStatus;
uuid: string;
details: Nullable<UserDetailsShort>;
preferences: Nullable<UserPreferencesShort>;
avatar: Nullable<string>;
}
export type UserRoles = string[];
export type UserStatus = (typeof EnumUserStatus)[keyof typeof EnumUserStatus];
export type UserTypes = string[];
export type UsersShort = UserShort[];
export const EnumUserStatus = {
UserStatusPending: "pending",
UserStatusActive: "active",
UserStatusDisabled: "disabled",
} as const;