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:
parent
6920d7ae95
commit
36fca2af6c
|
|
@ -1,3 +1,11 @@
|
||||||
# go-quasar-partial-ssr
|
# go-quasar-partial-ssr
|
||||||
|
|
||||||
bakend in GO frontend quasar framework con generazione delle pagine statiche per la parte public
|
bakend in GO frontend quasar framework con generazione delle pagine statiche per la parte public
|
||||||
|
|
||||||
|
|
||||||
|
internal
|
||||||
|
auth
|
||||||
|
model
|
||||||
|
controller
|
||||||
|
service
|
||||||
|
endpoint
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
//
|
//
|
||||||
// This file was generated by github.com/millevolte/ts-rpc
|
// 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 {
|
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 };
|
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
|
// package routes
|
||||||
//
|
//
|
||||||
|
|
||||||
// Typescript: TSEndpoint= path=/users/:uuid; name=getUser; method=GET; response=models.UserProfile
|
// Typescript: TSEndpoint= path=/metrics; name=metrics; method=GET; response=string
|
||||||
// internal/http/routes/user_routes.go Line: 13
|
// internal/http/routes/system_routes.go Line: 37
|
||||||
export const getUser = async (
|
export const metrics = async (): Promise<{
|
||||||
uuid: string,
|
data: string;
|
||||||
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
|
error: Nullable<string>;
|
||||||
return (await api.GET(`/users/${uuid}`)) as {
|
}> => {
|
||||||
data: UserProfile;
|
return (await api.GET("/metrics")) as {
|
||||||
|
data: string;
|
||||||
error: Nullable<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
|
// Typescript: TSEndpoint= path=/users/:uuid; name=getUser; method=GET; response=models.UserProfile
|
||||||
// internal/http/routes/auth_routes.go Line: 22
|
// internal/http/routes/user_routes.go Line: 13
|
||||||
|
export const getUser = async (
|
||||||
export const login = async (
|
uuid: string,
|
||||||
data: LoginRequest,
|
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
|
||||||
): Promise<{ data: TokenPair; error: Nullable<string> }> => {
|
return (await api.GET(`/users/${uuid}`)) as {
|
||||||
return (await api.POST("/auth/login", data)) as {
|
data: UserProfile;
|
||||||
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;
|
|
||||||
error: Nullable<string>;
|
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
|
// Typescript: TSEndpoint= path=/admin/users; name=listUsers; method=POST; request=controllers.ListUsersRequest; response=models.[]UserShort
|
||||||
// internal/http/routes/admin_routes.go Line: 12
|
// 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
|
// Typescript: TSEndpoint= path=/users; name=createUser; method=POST; request=models.UserCreateInput; response=models.UserProfile
|
||||||
// internal/http/routes/auth_routes.go Line: 34
|
// internal/http/routes/user_routes.go Line: 16
|
||||||
|
|
||||||
export const forgotPassword = async (
|
export const createUser = async (
|
||||||
data: ForgotPasswordRequest,
|
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> }> => {
|
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
|
||||||
return (await api.POST("/auth/password/forgot", data)) as {
|
return (await api.DELETE(`/users/${uuid}`)) as {
|
||||||
data: SimpleResponse;
|
data: SimpleResponse;
|
||||||
error: Nullable<string>;
|
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 {
|
export interface FormRequest {
|
||||||
req: string;
|
req: string;
|
||||||
count: number;
|
count: number;
|
||||||
|
|
@ -489,6 +461,94 @@ export interface MailDebugItem {
|
||||||
content: string;
|
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
|
// package models
|
||||||
//
|
//
|
||||||
|
|
@ -516,17 +576,6 @@ export interface UserDetailsShort {
|
||||||
phone: string;
|
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 {
|
export interface UserPreferencesShort {
|
||||||
useIdle: boolean;
|
useIdle: boolean;
|
||||||
idleTimeout: number;
|
idleTimeout: number;
|
||||||
|
|
@ -538,7 +587,16 @@ export interface UserPreferencesShort {
|
||||||
language: string;
|
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[];
|
export type UserRoles = string[];
|
||||||
|
|
||||||
|
|
@ -546,64 +604,10 @@ export type UserStatus = (typeof EnumUserStatus)[keyof typeof EnumUserStatus];
|
||||||
|
|
||||||
export type UserTypes = string[];
|
export type UserTypes = string[];
|
||||||
|
|
||||||
|
export type UsersShort = UserShort[];
|
||||||
|
|
||||||
export const EnumUserStatus = {
|
export const EnumUserStatus = {
|
||||||
UserStatusPending: "pending",
|
UserStatusPending: "pending",
|
||||||
UserStatusActive: "active",
|
UserStatusActive: "active",
|
||||||
UserStatusDisabled: "disabled",
|
UserStatusDisabled: "disabled",
|
||||||
} as const;
|
} 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;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,8 @@ import (
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"server/internal/auth"
|
authmodel "server/internal/auth/model"
|
||||||
|
authservice "server/internal/auth/service"
|
||||||
"server/internal/config"
|
"server/internal/config"
|
||||||
"server/internal/db"
|
"server/internal/db"
|
||||||
"server/internal/http/controllers"
|
"server/internal/http/controllers"
|
||||||
|
|
@ -54,7 +55,7 @@ func main() {
|
||||||
log.Fatalf("init db: %v", err)
|
log.Fatalf("init db: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
authService, err := auth.New(auth.Config{
|
authService, err := authservice.New(authmodel.Config{
|
||||||
Secret: cfg.Auth.Secret,
|
Secret: cfg.Auth.Secret,
|
||||||
Issuer: cfg.Auth.Issuer,
|
Issuer: cfg.Auth.Issuer,
|
||||||
AccessTokenExpiry: time.Duration(cfg.Auth.AccessTokenExpiryMinutes) * time.Minute,
|
AccessTokenExpiry: time.Duration(cfg.Auth.AccessTokenExpiryMinutes) * time.Minute,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package controllers
|
package controller
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
|
@ -10,65 +10,39 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
|
"github.com/google/uuid"
|
||||||
"gorm.io/gorm"
|
"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/mail"
|
||||||
"server/internal/models"
|
"server/internal/models"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type AuthController struct {
|
type AuthController struct {
|
||||||
authService *auth.Service
|
authService *authservice.Service
|
||||||
mailService *mail.Service
|
mailService *mail.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typescript: interface
|
func New(authService *authservice.Service, mailService *mail.Service) *AuthController {
|
||||||
type SimpleResponse struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAuthController(authService *auth.Service, mailService *mail.Service) *AuthController {
|
|
||||||
return &AuthController{
|
return &AuthController{
|
||||||
authService: authService,
|
authService: authService,
|
||||||
mailService: mailService,
|
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.
|
// Login authenticates a user and issues an access/refresh token pair.
|
||||||
func (ac *AuthController) Login(c fiber.Ctx) error {
|
func (ac *AuthController) Login(c fiber.Ctx) error {
|
||||||
var req LoginRequest
|
var req authmodel.LoginRequest
|
||||||
if err := c.Bind().Body(&req); err != nil {
|
if err := c.Bind().Body(&req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
||||||
}
|
}
|
||||||
if err := validateStruct(&req); err != nil {
|
if err := controllers.ValidateStruct(&req); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := dbFromCtx(c)
|
db, err := controllers.DBFromCtx(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +54,7 @@ func (ac *AuthController) Login(c fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to fetch user")
|
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 {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to verify credentials")
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to verify credentials")
|
||||||
}
|
}
|
||||||
|
|
@ -102,8 +76,8 @@ func (ac *AuthController) Login(c fiber.Ctx) error {
|
||||||
session := models.Session{
|
session := models.Session{
|
||||||
UserID: &userID,
|
UserID: &userID,
|
||||||
Username: user.Email,
|
Username: user.Email,
|
||||||
AccessTokenHash: hashToken(tokens.AccessToken),
|
AccessTokenHash: controllers.HashToken(tokens.AccessToken),
|
||||||
RefreshTokenHash: hashToken(tokens.RefreshToken),
|
RefreshTokenHash: controllers.HashToken(tokens.RefreshToken),
|
||||||
ExpiresAt: now.Add(ac.authService.RefreshExpiry()),
|
ExpiresAt: now.Add(ac.authService.RefreshExpiry()),
|
||||||
IPAddress: c.IP(),
|
IPAddress: c.IP(),
|
||||||
UserAgent: c.Get("User-Agent"),
|
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")
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to record session")
|
||||||
}
|
}
|
||||||
|
|
||||||
//c.Set("Auth-Token", tokens.AccessToken)
|
|
||||||
c.Response().Header.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.
|
// Refresh renews an access/refresh token pair using a valid refresh token.
|
||||||
func (ac *AuthController) Refresh(c fiber.Ctx) error {
|
func (ac *AuthController) Refresh(c fiber.Ctx) error {
|
||||||
var req RefreshRequest
|
var req authmodel.RefreshRequest
|
||||||
if err := c.Bind().Body(&req); err != nil {
|
if err := c.Bind().Body(&req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
||||||
}
|
}
|
||||||
|
|
@ -133,17 +106,17 @@ func (ac *AuthController) Refresh(c fiber.Ctx) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusUnauthorized, err.Error())
|
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).
|
// Me returns the authenticated user's profile (short format).
|
||||||
func (ac *AuthController) Me(c fiber.Ctx) error {
|
func (ac *AuthController) Me(c fiber.Ctx) error {
|
||||||
claims, ok := auth.ClaimsFromCtx(c)
|
claims, ok := authservice.ClaimsFromCtx(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fiber.NewError(fiber.StatusUnauthorized, "missing claims")
|
return fiber.NewError(fiber.StatusUnauthorized, "missing claims")
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := dbFromCtx(c)
|
db, err := controllers.DBFromCtx(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +129,7 @@ func (ac *AuthController) Me(c fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to load user")
|
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.
|
// 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 {
|
if err := c.Bind().Body(&req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
||||||
}
|
}
|
||||||
if err := validateStruct(&req); err != nil {
|
if err := controllers.ValidateStruct(&req); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := dbFromCtx(c)
|
db, err := controllers.DBFromCtx(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -182,7 +155,7 @@ func (ac *AuthController) Register(c fiber.Ctx) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
hashedPassword, err := auth.HashPassword(req.Password)
|
hashedPassword, err := authservice.HashPassword(req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +183,7 @@ func (ac *AuthController) Register(c fiber.Ctx) error {
|
||||||
}(),
|
}(),
|
||||||
Avatar: req.Avatar,
|
Avatar: req.Avatar,
|
||||||
UUID: uuid.NewString(),
|
UUID: uuid.NewString(),
|
||||||
Details: toUserDetails(req.Details),
|
Details: controllers.ToUserDetails(req.Details),
|
||||||
Preferences: func() *models.UserPreferences {
|
Preferences: func() *models.UserPreferences {
|
||||||
if req.Preferences == nil {
|
if req.Preferences == nil {
|
||||||
return 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 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 {
|
func (ac *AuthController) ForgotPassword(c fiber.Ctx) error {
|
||||||
var req ForgotPasswordRequest
|
var req authmodel.ForgotPasswordRequest
|
||||||
if err := c.Bind().Body(&req); err != nil {
|
if err := c.Bind().Body(&req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
||||||
}
|
}
|
||||||
if err := validateStruct(&req); err != nil {
|
if err := controllers.ValidateStruct(&req); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := dbFromCtx(c)
|
db, err := controllers.DBFromCtx(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -267,13 +240,13 @@ func (ac *AuthController) ForgotPassword(c fiber.Ctx) error {
|
||||||
var user models.User
|
var user models.User
|
||||||
if err := db.Where("email = ?", req.Email).First(&user).Error; err != nil {
|
if err := db.Where("email = ?", req.Email).First(&user).Error; err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
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")
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to load user")
|
||||||
}
|
}
|
||||||
|
|
||||||
if user.Status == models.UserStatusDisabled {
|
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()
|
resetToken, err := generateSecureToken()
|
||||||
|
|
@ -284,7 +257,7 @@ func (ac *AuthController) ForgotPassword(c fiber.Ctx) error {
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
record := models.PasswordResetToken{
|
record := models.PasswordResetToken{
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
TokenHash: hashToken(resetToken),
|
TokenHash: controllers.HashToken(resetToken),
|
||||||
ExpiresAt: now.Add(30 * time.Minute),
|
ExpiresAt: now.Add(30 * time.Minute),
|
||||||
CreatedAt: now,
|
CreatedAt: now,
|
||||||
UpdatedAt: 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 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 {
|
func (ac *AuthController) ResetPassword(c fiber.Ctx) error {
|
||||||
var req ResetPasswordRequest
|
var req authmodel.ResetPasswordRequest
|
||||||
if err := c.Bind().Body(&req); err != nil {
|
if err := c.Bind().Body(&req); err != nil {
|
||||||
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
return fiber.NewError(fiber.StatusBadRequest, "invalid payload")
|
||||||
}
|
}
|
||||||
if err := validateStruct(&req); err != nil {
|
if err := controllers.ValidateStruct(&req); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := dbFromCtx(c)
|
db, err := controllers.DBFromCtx(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
hashedPassword, err := auth.HashPassword(req.Password)
|
hashedPassword, err := authservice.HashPassword(req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
tokenHash := hashToken(req.Token)
|
tokenHash := controllers.HashToken(req.Token)
|
||||||
if err := db.Transaction(func(tx *gorm.DB) error {
|
if err := db.Transaction(func(tx *gorm.DB) error {
|
||||||
var resetToken models.PasswordResetToken
|
var resetToken models.PasswordResetToken
|
||||||
if err := tx.Where("token_hash = ?", tokenHash).First(&resetToken).Error; err != nil {
|
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 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 {
|
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")
|
return fiber.NewError(fiber.StatusBadRequest, "token is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accept both plain text token payload and JSON string payload.
|
|
||||||
token := raw
|
token := raw
|
||||||
if strings.HasPrefix(raw, "\"") && strings.HasSuffix(raw, "\"") {
|
if strings.HasPrefix(raw, "\"") && strings.HasSuffix(raw, "\"") {
|
||||||
if err := json.Unmarshal([]byte(raw), &token); err != nil {
|
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")
|
return fiber.NewError(fiber.StatusBadRequest, "token is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
db, err := dbFromCtx(c)
|
db, err := controllers.DBFromCtx(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
tokenHash := hashToken(token)
|
tokenHash := controllers.HashToken(token)
|
||||||
var resetToken models.PasswordResetToken
|
var resetToken models.PasswordResetToken
|
||||||
if err := db.Where("token_hash = ?", tokenHash).First(&resetToken).Error; err != nil {
|
if err := db.Where("token_hash = ?", tokenHash).First(&resetToken).Error; err != nil {
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
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 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) {
|
func generateSecureToken() (string, error) {
|
||||||
|
|
@ -1,28 +1,28 @@
|
||||||
package routes
|
package endpoint
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"server/internal/auth"
|
authcontroller "server/internal/auth/controller"
|
||||||
"server/internal/http/controllers"
|
authservice "server/internal/auth/service"
|
||||||
"server/internal/mail"
|
"server/internal/mail"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
"github.com/gofiber/fiber/v3/middleware/limiter"
|
"github.com/gofiber/fiber/v3/middleware/limiter"
|
||||||
)
|
)
|
||||||
|
|
||||||
func registerAuthRoutes(app *fiber.App, authService *auth.Service, mailService *mail.Service) {
|
func Register(app *fiber.App, authService *authservice.Service, mailService *mail.Service) {
|
||||||
authController := controllers.NewAuthController(authService, mailService)
|
authController := authcontroller.New(authService, mailService)
|
||||||
authRateLimiter := limiter.New(limiter.Config{
|
authRateLimiter := limiter.New(limiter.Config{
|
||||||
Max: 10,
|
Max: 10,
|
||||||
Expiration: time.Minute,
|
Expiration: time.Minute,
|
||||||
LimiterMiddleware: limiter.SlidingWindow{},
|
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)
|
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)
|
app.Post("/auth/refresh", authService.Middleware(), authController.Refresh)
|
||||||
|
|
||||||
// Typescript: TSEndpoint= path=/auth/me; name=me; method=GET; response=models.UserShort
|
// 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
|
// Typescript: TSEndpoint= path=/auth/register; name=register; method=POST; request=models.UserCreateInput; response=models.UserShort
|
||||||
app.Post("/auth/register", authRateLimiter, authController.Register)
|
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)
|
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)
|
app.Post("/auth/password/reset", authRateLimiter, authController.ResetPassword)
|
||||||
|
|
||||||
// Typescript: TSEndpoint= path=/auth/password/valid; name=validToken; method=POST; request=string; response=controllers.SimpleResponse
|
// Typescript: TSEndpoint= path=/auth/password/valid; name=validToken; method=POST; request=string; response=controllers.SimpleResponse
|
||||||
|
|
@ -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},
|
||||||
|
}
|
||||||
|
|
@ -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"`
|
||||||
|
}
|
||||||
|
|
@ -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},
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +1,28 @@
|
||||||
package auth
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"strings"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"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 {
|
type Service struct {
|
||||||
cfg Config
|
cfg authmodel.Config
|
||||||
secret []byte
|
secret []byte
|
||||||
accessExpiry time.Duration
|
accessExpiry time.Duration
|
||||||
refreshExpiry 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 (
|
const (
|
||||||
tokenTypeAccess = "access"
|
tokenTypeAccess = "access"
|
||||||
tokenTypeRefresh = "refresh"
|
tokenTypeRefresh = "refresh"
|
||||||
)
|
)
|
||||||
|
|
||||||
func New(cfg Config) (*Service, error) {
|
func New(cfg authmodel.Config) (*Service, error) {
|
||||||
if cfg.Secret == "" {
|
if cfg.Secret == "" {
|
||||||
return nil, errors.New("jwt secret is required")
|
return nil, errors.New("jwt secret is required")
|
||||||
}
|
}
|
||||||
|
|
@ -59,29 +41,27 @@ func New(cfg Config) (*Service, error) {
|
||||||
}, nil
|
}, 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)
|
access, err := s.generateToken(username, tokenTypeAccess, s.accessExpiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return TokenPair{}, err
|
return authmodel.TokenPair{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
refresh, err := s.generateToken(username, tokenTypeRefresh, s.refreshExpiry)
|
refresh, err := s.generateToken(username, tokenTypeRefresh, s.refreshExpiry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return TokenPair{}, err
|
return authmodel.TokenPair{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return TokenPair{
|
return authmodel.TokenPair{
|
||||||
AccessToken: access,
|
AccessToken: access,
|
||||||
RefreshToken: refresh,
|
RefreshToken: refresh,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessExpiry returns the configured access token lifetime.
|
|
||||||
func (s *Service) AccessExpiry() time.Duration {
|
func (s *Service) AccessExpiry() time.Duration {
|
||||||
return s.accessExpiry
|
return s.accessExpiry
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshExpiry returns the configured refresh token lifetime.
|
|
||||||
func (s *Service) RefreshExpiry() time.Duration {
|
func (s *Service) RefreshExpiry() time.Duration {
|
||||||
return s.refreshExpiry
|
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)
|
claims, err := s.parseToken(refreshToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return TokenPair{}, err
|
return authmodel.TokenPair{}, err
|
||||||
}
|
}
|
||||||
if claims.TokenType != tokenTypeRefresh {
|
if claims.TokenType != tokenTypeRefresh {
|
||||||
return TokenPair{}, errors.New("refresh token required")
|
return authmodel.TokenPair{}, errors.New("refresh token required")
|
||||||
}
|
}
|
||||||
return s.GenerateTokenPair(claims.Username)
|
return s.GenerateTokenPair(claims.Username)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateAccessToken parses and validates an access token string, ensuring type=access.
|
func (s *Service) ValidateAccessToken(tokenString string) (*authmodel.Claims, error) {
|
||||||
func (s *Service) ValidateAccessToken(tokenString string) (*Claims, error) {
|
|
||||||
claims, err := s.parseToken(tokenString)
|
claims, err := s.parseToken(tokenString)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -129,8 +108,17 @@ func (s *Service) ValidateAccessToken(tokenString string) (*Claims, error) {
|
||||||
return claims, nil
|
return claims, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) parseToken(tokenString string) (*Claims, error) {
|
func ClaimsFromCtx(c fiber.Ctx) (*authmodel.Claims, bool) {
|
||||||
claims := &Claims{}
|
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) {
|
token, err := jwt.ParseWithClaims(tokenString, claims, func(t *jwt.Token) (interface{}, error) {
|
||||||
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||||
return nil, fiber.ErrUnauthorized
|
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) {
|
func (s *Service) generateToken(username, tokenType string, expiry time.Duration) (string, error) {
|
||||||
claims := Claims{
|
claims := authmodel.Claims{
|
||||||
Username: username,
|
Username: username,
|
||||||
TokenType: tokenType,
|
TokenType: tokenType,
|
||||||
RegisteredClaims: jwt.RegisteredClaims{
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
|
@ -161,27 +149,3 @@ func (s *Service) generateToken(username, tokenType string, expiry time.Duration
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
return token.SignedString(s.secret)
|
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
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package auth
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"server/internal/auth"
|
authservice "server/internal/auth/service"
|
||||||
"server/internal/models"
|
"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).
|
// RequireRole ensures the authenticated user has the specified role (with inheritance).
|
||||||
func RequireRole(resolver *RoleResolver, role string) fiber.Handler {
|
func RequireRole(resolver *RoleResolver, role string) fiber.Handler {
|
||||||
return func(c fiber.Ctx) error {
|
return func(c fiber.Ctx) error {
|
||||||
claims, ok := auth.ClaimsFromCtx(c)
|
claims, ok := authservice.ClaimsFromCtx(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fiber.NewError(fiber.StatusUnauthorized, "missing claims")
|
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.
|
// RequirePermission ensures the authenticated user has the given permission.
|
||||||
func RequirePermission(resolver *RoleResolver, perm string) fiber.Handler {
|
func RequirePermission(resolver *RoleResolver, perm string) fiber.Handler {
|
||||||
return func(c fiber.Ctx) error {
|
return func(c fiber.Ctx) error {
|
||||||
claims, ok := auth.ClaimsFromCtx(c)
|
claims, ok := authservice.ClaimsFromCtx(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fiber.NewError(fiber.StatusUnauthorized, "missing claims")
|
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.
|
// RequireEndpointPermission enforces permission mapping defined in role config.
|
||||||
// If the endpoint is not configured, or mapped to "*", it allows the request.
|
// 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 {
|
return func(c fiber.Ctx) error {
|
||||||
perm, ok := resolver.PermissionForEndpoint(c.Method(), c.Path())
|
perm, ok := resolver.PermissionForEndpoint(c.Method(), c.Path())
|
||||||
if !ok || perm == "*" {
|
if !ok || perm == "*" {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@ func dbFromCtx(c fiber.Ctx) (*gorm.DB, error) {
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DBFromCtx(c fiber.Ctx) (*gorm.DB, error) {
|
||||||
|
return dbFromCtx(c)
|
||||||
|
}
|
||||||
|
|
||||||
func toUserDetails(d *models.UserDetailsShort) *models.UserDetails {
|
func toUserDetails(d *models.UserDetailsShort) *models.UserDetails {
|
||||||
if d == nil {
|
if d == nil {
|
||||||
return 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 {
|
func toUserPreferences(p *models.UserPreferencesShort) *models.UserPreferences {
|
||||||
if p == nil {
|
if p == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -48,3 +56,7 @@ func toUserPreferences(p *models.UserPreferencesShort) *models.UserPreferences {
|
||||||
Language: p.Language,
|
Language: p.Language,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ToUserPreferences(p *models.UserPreferencesShort) *models.UserPreferences {
|
||||||
|
return toUserPreferences(p)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,7 @@ func success(data any) fiber.Map {
|
||||||
"error": nil,
|
"error": nil,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Success(data any) fiber.Map {
|
||||||
|
return success(data)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
package controllers
|
||||||
|
|
||||||
|
// Typescript: interface
|
||||||
|
type SimpleResponse struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
@ -9,3 +9,7 @@ func hashToken(token string) string {
|
||||||
sum := sha256.Sum256([]byte(token))
|
sum := sha256.Sum256([]byte(token))
|
||||||
return hex.EncodeToString(sum[:])
|
return hex.EncodeToString(sum[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HashToken(token string) string {
|
||||||
|
return hashToken(token)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"server/internal/auth"
|
authservice "server/internal/auth/service"
|
||||||
"server/internal/models"
|
"server/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -63,7 +63,7 @@ func (uc *UserController) CreateUser(c fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to check user")
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to check user")
|
||||||
}
|
}
|
||||||
|
|
||||||
hashedPassword, err := auth.HashPassword(req.Password)
|
hashedPassword, err := authservice.HashPassword(req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
|
return fiber.NewError(fiber.StatusInternalServerError, "failed to secure password")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,3 +26,7 @@ func validateStruct(payload any) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ValidateStruct(payload any) error {
|
||||||
|
return validateStruct(payload)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"server/internal/auth"
|
authendpoint "server/internal/auth/endpoint"
|
||||||
|
authservice "server/internal/auth/service"
|
||||||
"server/internal/mail"
|
"server/internal/mail"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
|
|
@ -18,9 +19,9 @@ type FormResponse struct {
|
||||||
Test string `json:"test"`
|
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)
|
registerSystemRoutes(app)
|
||||||
registerAuthRoutes(app, authService, mailService)
|
authendpoint.Register(app, authService, mailService)
|
||||||
registerUserRoutes(app, authService)
|
registerUserRoutes(app, authService)
|
||||||
registerAdminRoutes(app)
|
registerAdminRoutes(app)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"server/internal/auth"
|
authservice "server/internal/auth/service"
|
||||||
"server/internal/http/controllers"
|
"server/internal/http/controllers"
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v3"
|
"github.com/gofiber/fiber/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func registerUserRoutes(app *fiber.App, authService *auth.Service) {
|
func registerUserRoutes(app *fiber.App, authService *authservice.Service) {
|
||||||
userController := controllers.NewUserController()
|
userController := controllers.NewUserController()
|
||||||
|
|
||||||
// Typescript: TSEndpoint= path=/users/:uuid; name=getUser; method=GET; response=models.UserProfile
|
// Typescript: TSEndpoint= path=/users/:uuid; name=getUser; method=GET; response=models.UserProfile
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"github.com/brianvoe/gofakeit/v6"
|
"github.com/brianvoe/gofakeit/v6"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
"server/internal/auth"
|
authservice "server/internal/auth/service"
|
||||||
"server/internal/models"
|
"server/internal/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ func SeedUsers(db *gorm.DB, n int) ([]models.User, []Credential, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("generate password: %w", err)
|
return nil, nil, fmt.Errorf("generate password: %w", err)
|
||||||
}
|
}
|
||||||
passwordHash, err := auth.HashPassword(pw)
|
passwordHash, err := authservice.HashPassword(pw)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("hash seed password: %w", err)
|
return nil, nil, fmt.Errorf("hash seed password: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
//
|
//
|
||||||
// This file was generated by github.com/millevolte/ts-rpc
|
// 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 {
|
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(
|
async GET(
|
||||||
url: string,
|
url: string,
|
||||||
timeout?: number,
|
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(
|
async DELETE(
|
||||||
url: string,
|
url: string,
|
||||||
timeout?: number,
|
timeout?: number,
|
||||||
|
|
@ -229,7 +237,12 @@ export default class Api {
|
||||||
error: string | null;
|
error: string | null;
|
||||||
}> {
|
}> {
|
||||||
try {
|
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);
|
return this.processResult(result);
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
return this.processError(error);
|
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 };
|
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 {
|
export interface RefreshRequest {
|
||||||
refresh_token: string;
|
refresh_token: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SimpleResponse {
|
export interface TokenPair {
|
||||||
message: string;
|
access_token: string;
|
||||||
|
refresh_token: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ForgotPasswordRequest {
|
export interface ForgotPasswordRequest {
|
||||||
email: string;
|
email: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LoginRequest {
|
||||||
|
username: string;
|
||||||
|
password: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ResetPasswordRequest {
|
export interface ResetPasswordRequest {
|
||||||
token: string;
|
token: string;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ListUsersRequest {
|
//
|
||||||
page: number;
|
// package controllers
|
||||||
pageSize: number;
|
//
|
||||||
}
|
|
||||||
|
|
||||||
export interface ListUsersResponse {
|
|
||||||
page: number;
|
|
||||||
pageSize: number;
|
|
||||||
items: UserShort[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BlockUserRequest {
|
export interface BlockUserRequest {
|
||||||
action: string;
|
action: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
export interface ListUsersRequest {
|
||||||
// package models
|
page: number;
|
||||||
//
|
pageSize: number;
|
||||||
|
|
||||||
export interface UserPreferencesShort {
|
|
||||||
useIdle: boolean;
|
|
||||||
idleTimeout: number;
|
|
||||||
useIdlePassword: boolean;
|
|
||||||
idlePin: string;
|
|
||||||
useDirectLogin: boolean;
|
|
||||||
useQuadcodeLogin: boolean;
|
|
||||||
sendNoticesMail: boolean;
|
|
||||||
language: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UserPreferences {
|
export interface SimpleResponse {
|
||||||
id: number;
|
message: string;
|
||||||
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 UpdateUserRequest {
|
export interface UpdateUserRequest {
|
||||||
name: string;
|
name: string;
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
roles: UserRoles;
|
roles: models.UserRoles;
|
||||||
status: UserStatus;
|
status: models.UserStatus;
|
||||||
types: UserTypes;
|
types: models.UserTypes;
|
||||||
avatar: Nullable<string>;
|
avatar: Nullable<string>;
|
||||||
details: Nullable<UserDetailsShort>;
|
details: Nullable<models.UserDetailsShort>;
|
||||||
preferences: Nullable<UserPreferencesShort>;
|
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
|
// package routes
|
||||||
//
|
//
|
||||||
|
|
||||||
// Typescript: TSEndpoint= path=/auth/password/valid; name=validToken; method=POST; request=string; response=controllers.SimpleResponse
|
// Typescript: TSEndpoint= path=/metrics; name=metrics; method=GET; response=string
|
||||||
// internal/http/routes/auth_routes.go Line: 40
|
// internal/http/routes/system_routes.go Line: 37
|
||||||
export const validToken = async (
|
export const metrics = async (): Promise<{
|
||||||
data: string,
|
data: string;
|
||||||
): Promise<{ data: SimpleResponse; error: Nullable<string> }> => {
|
error: Nullable<string>;
|
||||||
return (await api.POST("/auth/password/valid", data)) as {
|
}> => {
|
||||||
data: SimpleResponse;
|
return (await api.GET("/metrics")) as {
|
||||||
|
data: string;
|
||||||
error: Nullable<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
|
// Typescript: TSEndpoint= path=/admin/users; name=listUsers; method=POST; request=controllers.ListUsersRequest; response=models.[]UserShort
|
||||||
// internal/http/routes/admin_routes.go Line: 12
|
// internal/http/routes/admin_routes.go Line: 12
|
||||||
|
|
||||||
export const listUsers = async (
|
export const listUsers = async (
|
||||||
data: ListUsersRequest,
|
data: ListUsersRequest,
|
||||||
): Promise<{ data: ListUsersResponse; error: Nullable<string> }> => {
|
): Promise<{ data: UserShort[]; error: Nullable<string> }> => {
|
||||||
return (await api.POST("/admin/users", data)) as {
|
return (await api.POST("/admin/users", data)) as {
|
||||||
data: ListUsersResponse;
|
data: UserShort[];
|
||||||
error: Nullable<string>;
|
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 (
|
export const blockUser = async (
|
||||||
uuid: string,
|
|
||||||
data: BlockUserRequest,
|
data: BlockUserRequest,
|
||||||
): Promise<{ data: UserShort; error: Nullable<string> }> => {
|
): 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;
|
data: UserShort;
|
||||||
error: Nullable<string>;
|
error: Nullable<string>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Typescript: TSEndpoint= path=/auth/register; name=register; method=POST; request=models.UserCreateInput; response=models.UserShort
|
// Typescript: TSEndpoint= path=/users; name=createUser; method=POST; request=models.UserCreateInput; response=models.UserProfile
|
||||||
// internal/http/routes/auth_routes.go Line: 31
|
// internal/http/routes/user_routes.go Line: 16
|
||||||
export const register = async (
|
|
||||||
|
export const createUser = async (
|
||||||
data: UserCreateInput,
|
data: UserCreateInput,
|
||||||
): Promise<{ data: UserShort; error: Nullable<string> }> => {
|
): Promise<{ data: UserProfile; error: Nullable<string> }> => {
|
||||||
return (await api.POST("/auth/register", data)) as {
|
return (await api.POST("/users", data)) as {
|
||||||
data: UserShort;
|
data: UserProfile;
|
||||||
error: Nullable<string>;
|
error: Nullable<string>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
// Typescript: TSEndpoint= path=/metrics; name=metrics; method=GET; response=string
|
// Typescript: TSEndpoint= path=/users/:uuid; name=deleteUser; method=DELETE; response=controllers.SimpleResponse
|
||||||
// internal/http/routes/system_routes.go Line: 37
|
// internal/http/routes/user_routes.go Line: 22
|
||||||
export const metrics = async (): Promise<{
|
|
||||||
data: string;
|
|
||||||
error: Nullable<string>;
|
|
||||||
}> => {
|
|
||||||
return (await api.GET("/metrics")) as {
|
|
||||||
data: string;
|
|
||||||
error: Nullable<string>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Typescript: TSEndpoint= path=/auth/login; name=login; method=POST; request=controllers.LoginRequest; response=auth.TokenPair
|
export const deleteUser = async (
|
||||||
// internal/http/routes/auth_routes.go Line: 22
|
uuid: string,
|
||||||
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,
|
|
||||||
): Promise<{ data: SimpleResponse; error: Nullable<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=/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;
|
data: SimpleResponse;
|
||||||
error: Nullable<string>;
|
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 {
|
export interface FormRequest {
|
||||||
req: string;
|
req: string;
|
||||||
count: number;
|
count: number;
|
||||||
|
|
@ -630,10 +462,152 @@ export interface MailDebugItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// package auth
|
// package endpoint
|
||||||
//
|
//
|
||||||
|
|
||||||
export interface TokenPair {
|
// Typescript: TSEndpoint= path=/auth/password/forgot; name=forgotPassword; method=POST; request=model.ForgotPasswordRequest; response=controllers.SimpleResponse
|
||||||
access_token: string;
|
// internal/auth/endpoint/routes.go Line: 34
|
||||||
refresh_token: string;
|
|
||||||
|
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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue