feat: Revamp logs page with new HTML structure and styles
- Updated logs.html to include a modern design with Tailwind CSS. - Added a login section for admin access to logs. - Implemented JavaScript functions for login, log retrieval, and month selection. - Enhanced user experience with loading indicators and error handling. feat: Add ServeLogsPage method to LogsController - Introduced ServeLogsPage method to serve the logs HTML page. - Configured to respond with HTML when the Accept header is text/html. refactor: Update logs routes to serve HTML page - Modified routes to serve the logs HTML page without authentication. - Adjusted protected routes for log retrieval to use API versioning. docs: Add API documentation for user and role controllers - Added Swagger documentation comments for user and role controller methods. - Documented endpoints for user registration, login, and email verification.
This commit is contained in:
parent
80825a70af
commit
2546a094a3
152
README.md
152
README.md
|
|
@ -1,7 +1,9 @@
|
|||
# Golang Gin Clean Starter
|
||||
|
||||
You can join in the development (Open Source). **Let's Go!!!**
|
||||
|
||||
## Introduction 👋
|
||||
|
||||
> This project implements **Clean Architecture** principles with the Controller–Service–Repository pattern. This approach emphasizes clear separation of responsibilities across different layers in Golang applications. The architecture helps keep the codebase clean, testable, and scalable by dividing application logic into distinct modules with well-defined boundaries.
|
||||
|
||||

|
||||
|
|
@ -11,14 +13,18 @@ You can join in the development (Open Source). **Let's Go!!!**
|
|||
The application includes a built-in logging system that allows you to monitor and track system queries. You can access the logs through a modern, user-friendly interface.
|
||||
|
||||
### Accessing Logs
|
||||
|
||||
To view the logs:
|
||||
|
||||
1. Make sure the application is running
|
||||
2. Open your browser and navigate to:
|
||||
|
||||
```bash
|
||||
http://your-domain/logs
|
||||
```
|
||||
|
||||
### Features
|
||||
|
||||
- **Monthly Filtering**: Filter logs by selecting different months
|
||||
- **Real-time Refresh**: Instantly refresh logs with the refresh button
|
||||
- **Expandable Entries**: Click on any log entry to view its full content
|
||||
|
|
@ -26,29 +32,37 @@ http://your-domain/logs
|
|||
|
||||

|
||||
|
||||
|
||||
## Prerequisite 🏆
|
||||
|
||||
- Go Version `>= go 1.20`
|
||||
- PostgreSQL Version `>= version 15.0`
|
||||
|
||||
## How To Use
|
||||
|
||||
1. Clone the repository or **Use This Template**
|
||||
```bash
|
||||
git clone https://github.com/Caknoooo/go-gin-clean-starter.git
|
||||
```
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Caknoooo/go-gin-clean-starter.git
|
||||
```
|
||||
|
||||
2. Navigate to the project directory:
|
||||
```bash
|
||||
cd go-gin-clean-starter
|
||||
```
|
||||
|
||||
```bash
|
||||
cd go-gin-clean-starter
|
||||
```
|
||||
|
||||
3. Copy the example environment file and configure it:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
## Available Make Commands 🚀
|
||||
|
||||
The project includes a comprehensive Makefile with the following commands:
|
||||
|
||||
### Development Commands
|
||||
|
||||
```bash
|
||||
make dep # Install and tidy dependencies
|
||||
make run # Run the application locally
|
||||
|
|
@ -57,13 +71,15 @@ make test # Run tests
|
|||
```
|
||||
|
||||
### Local Database Commands (without Docker)
|
||||
|
||||
```bash
|
||||
make migrate-local # Run migrations locally
|
||||
make seed-local # Run seeders locally
|
||||
make seed-local # Run seeders locally
|
||||
make migrate-seed-local # Run migrations + seeders locally
|
||||
```
|
||||
|
||||
### Docker Commands
|
||||
|
||||
```bash
|
||||
make init-docker # Initialize and build Docker containers
|
||||
make up # Start Docker containers
|
||||
|
|
@ -72,6 +88,7 @@ make logs # View Docker logs
|
|||
```
|
||||
|
||||
### Docker Database Commands
|
||||
|
||||
```bash
|
||||
make migrate # Run migrations in Docker
|
||||
make seed # Run seeders in Docker
|
||||
|
|
@ -81,89 +98,114 @@ make container-postgres # Access PostgreSQL container
|
|||
```
|
||||
|
||||
There are 2 ways to run the application:
|
||||
|
||||
### With Docker
|
||||
|
||||
1. Build and start Docker containers:
|
||||
```bash
|
||||
make init-docker
|
||||
```
|
||||
|
||||
```bash
|
||||
make init-docker
|
||||
```
|
||||
|
||||
2. Run Initial UUID V4 for Auto Generate UUID:
|
||||
```bash
|
||||
make init-uuid
|
||||
```
|
||||
|
||||
```bash
|
||||
make init-uuid
|
||||
```
|
||||
|
||||
3. Run Migration and Seeder:
|
||||
```bash
|
||||
make migrate-seed
|
||||
```
|
||||
|
||||
```bash
|
||||
make migrate-seed
|
||||
```
|
||||
|
||||
### Without Docker
|
||||
|
||||
1. Configure `.env` with your PostgreSQL credentials:
|
||||
```bash
|
||||
DB_HOST=localhost
|
||||
DB_USER=postgres
|
||||
DB_PASS=
|
||||
DB_NAME=
|
||||
DB_PORT=5432
|
||||
```
|
||||
|
||||
```bash
|
||||
DB_HOST=localhost
|
||||
DB_USER=postgres
|
||||
DB_PASS=
|
||||
DB_NAME=
|
||||
DB_PORT=5432
|
||||
```
|
||||
|
||||
2. Open the terminal and set up PostgreSQL:
|
||||
- If you haven't downloaded PostgreSQL, download it first.
|
||||
- Run:
|
||||
```bash
|
||||
psql -U postgres
|
||||
```
|
||||
- Create the database according to what you put in `.env`:
|
||||
```bash
|
||||
CREATE DATABASE your_database;
|
||||
\c your_database
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
\q
|
||||
```
|
||||
3. Install dependencies and run the application:
|
||||
|
||||
- If you haven't downloaded PostgreSQL, download it first.
|
||||
- Run:
|
||||
```bash
|
||||
make dep # Install dependencies
|
||||
make migrate-local # Run migrations
|
||||
make seed-local # Run seeders (optional)
|
||||
make run # Start the application
|
||||
psql -U postgres
|
||||
```
|
||||
- Create the database according to what you put in `.env`:
|
||||
```bash
|
||||
CREATE DATABASE your_database;
|
||||
\c your_database
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
\q
|
||||
```
|
||||
|
||||
3. Install dependencies and run the application:
|
||||
|
||||
```bash
|
||||
make dep # Install dependencies
|
||||
make migrate-local # Run migrations
|
||||
make seed-local # Run seeders (optional)
|
||||
make run # Start the application
|
||||
```
|
||||
|
||||
## Run Migrations, Seeder, and Script
|
||||
|
||||
To run migrations, seed the database, and execute a script while keeping the application running, use the following command:
|
||||
|
||||
```bash
|
||||
go run cmd/main.go --migrate --seed --run --script:example_script
|
||||
```
|
||||
|
||||
- ``--migrate`` will apply all pending migrations.
|
||||
- ``--seed`` will seed the database with initial data.
|
||||
- ``--script:example_script`` will run the specified script (replace ``example_script`` with your script name).
|
||||
- ``--run`` will ensure the application continues running after executing the commands above.
|
||||
- `--migrate` will apply all pending migrations.
|
||||
- `--seed` will seed the database with initial data.
|
||||
- `--script:example_script` will run the specified script (replace `example_script` with your script name).
|
||||
- `--run` will ensure the application continues running after executing the commands above.
|
||||
|
||||
#### Migrate Database
|
||||
|
||||
To migrate the database schema
|
||||
|
||||
#### Migrate Database
|
||||
To migrate the database schema
|
||||
```bash
|
||||
go run cmd/main.go --migrate
|
||||
```
|
||||
|
||||
This command will apply all pending migrations to your PostgreSQL database specified in `.env`
|
||||
|
||||
#### Seeder Database
|
||||
#### Seeder Database
|
||||
|
||||
To seed the database with initial data:
|
||||
|
||||
```bash
|
||||
go run cmd/main.go --seed
|
||||
```
|
||||
|
||||
This command will populate the database with initial data using the seeders defined in your application.
|
||||
|
||||
#### Script Run
|
||||
|
||||
To run a specific script:
|
||||
|
||||
```bash
|
||||
go run cmd/main.go --script:example_script
|
||||
```
|
||||
Replace ``example_script`` with the actual script name in **script.go** at script folder
|
||||
|
||||
If you need the application to continue running after performing migrations, seeding, or executing a script, always append the ``--run`` option.
|
||||
Replace `example_script` with the actual script name in **script.go** at script folder
|
||||
|
||||
If you need the application to continue running after performing migrations, seeding, or executing a script, always append the `--run` option.
|
||||
|
||||
## What did you get?
|
||||
|
||||
By using this template, you get a ready-to-go architecture with pre-configured endpoints. The template provides a structured foundation for building your application using Golang with Clean Architecture principles.
|
||||
|
||||
### Postman Documentation
|
||||
|
||||
You can explore the available endpoints and their usage in the [Postman Documentation](https://documenter.getpostman.com/view/29665461/2s9YJaZQCG). This documentation provides a comprehensive overview of the API endpoints, including request and response examples, making it easier to understand how to interact with the API.
|
||||
|
||||
### Issue / Pull Request Template
|
||||
|
|
@ -171,4 +213,6 @@ You can explore the available endpoints and their usage in the [Postman Document
|
|||
The repository includes templates for issues and pull requests to standardize contributions and improve the quality of discussions and code reviews.
|
||||
|
||||
- **Issue Template**: Helps in reporting bugs or suggesting features by providing a structured format to capture all necessary information.
|
||||
- **Pull Request Template**: Guides contributors to provide a clear description of changes, related issues, and testing steps, ensuring smooth and efficient code reviews.
|
||||
- **Pull Request Template**: Guides contributors to provide a clear description of changes, related issues, and testing steps, ensuring smooth and efficient code reviews.
|
||||
|
||||
swag init -g ./cmd/main.go -o ./docs
|
||||
|
|
|
|||
34
cmd/main.go
34
cmd/main.go
|
|
@ -5,9 +5,12 @@ import (
|
|||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/Caknoooo/go-gin-clean-starter/docs"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/middlewares"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/auth"
|
||||
"github.com/Caknoooo/go-gin-clean-starter/modules/role"
|
||||
swaggerFiles "github.com/swaggo/files"
|
||||
ginSwagger "github.com/swaggo/gin-swagger"
|
||||
|
||||
// "github.com/Caknoooo/go-gin-clean-starter/modules/role"
|
||||
|
||||
|
|
@ -53,12 +56,40 @@ func run(server *gin.Engine) {
|
|||
}
|
||||
}
|
||||
|
||||
// @title WMS Wareify API Docs
|
||||
// @version 1.0
|
||||
// @description This is a sample server celler server.
|
||||
// @termsOfService http://swagger.io/terms/
|
||||
|
||||
// @contact.name API Support
|
||||
// @contact.url http://www.swagger.io/support
|
||||
// @contact.email support@swagger.io
|
||||
|
||||
// @license.name Apache 2.0
|
||||
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
// @host localhost:8888
|
||||
// @BasePath /api/v1
|
||||
|
||||
// @securityDefinitions.apikey BearerAuth
|
||||
// @in header
|
||||
// @name Authorization
|
||||
// @description Bearer token for authentication
|
||||
// @tokenUrl http://localhost:3000/auth/login
|
||||
|
||||
// @externalDocs.description OpenAPI
|
||||
// @externalDocs.url https://swagger.io/resources/open-api/
|
||||
func main() {
|
||||
var (
|
||||
injector = do.New()
|
||||
)
|
||||
|
||||
providers.RegisterDependencies(injector)
|
||||
// set Swagger info (opsional)
|
||||
docs.SwaggerInfo.Title = "WMS Wareify API"
|
||||
docs.SwaggerInfo.Version = "1.0"
|
||||
docs.SwaggerInfo.Host = "localhost:8888"
|
||||
docs.SwaggerInfo.BasePath = "/api/v1"
|
||||
|
||||
if !args(injector) {
|
||||
return
|
||||
|
|
@ -88,5 +119,8 @@ func main() {
|
|||
role.RegisterRoutes(server, injector)
|
||||
logs.RegisterRoutes(server, injector)
|
||||
|
||||
// register swagger route
|
||||
server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
|
||||
|
||||
run(server)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,10 +9,11 @@ server {
|
|||
proxy_set_header Connection keep-alive;
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_bypass $http_upgrade;
|
||||
proxy_set_header Authorization $http_authorization;
|
||||
}
|
||||
|
||||
# Tambahkan route khusus untuk /logs
|
||||
location /logs {
|
||||
# Tambahkan route khusus untuk /admin/logs
|
||||
location /admin/logs {
|
||||
proxy_pass http://app:8888;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,711 @@
|
|||
// Package docs Code generated by swaggo/swag. DO NOT EDIT
|
||||
package docs
|
||||
|
||||
import "github.com/swaggo/swag"
|
||||
|
||||
const docTemplate = `{
|
||||
"schemes": {{ marshal .Schemes }},
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "{{escape .Description}}",
|
||||
"title": "{{.Title}}",
|
||||
"termsOfService": "http://swagger.io/terms/",
|
||||
"contact": {
|
||||
"name": "API Support",
|
||||
"url": "http://www.swagger.io/support",
|
||||
"email": "support@swagger.io"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"version": "{{.Version}}"
|
||||
},
|
||||
"host": "{{.Host}}",
|
||||
"basePath": "{{.BasePath}}",
|
||||
"paths": {
|
||||
"/auth/login": {
|
||||
"post": {
|
||||
"description": "Authenticate user and return access \u0026 refresh tokens.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "User login",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Login payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserLoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/refresh": {
|
||||
"post": {
|
||||
"description": "Exchange a refresh token for a new access token (and optionally a new refresh token).",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Refresh auth token",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Refresh token payload",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/example/helloworld": {
|
||||
"get": {
|
||||
"description": "do ping",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"example"
|
||||
],
|
||||
"summary": "ping example",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Get paginated list of users for the current client. Supports filtering by name and including related roles.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Get list of users",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by name (partial match)",
|
||||
"name": "name",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page number (default: 1)",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page size (default: 10)",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Sort expression, e.g. created_at desc",
|
||||
"name": "sort",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Update profile of the authenticated user. Use multipart/form-data if uploading files (photo).",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Update current user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Update payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Delete the authenticated user's account (soft/hard depends on implementation).",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Delete current user",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/me": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Return the authenticated user's profile.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Get current user",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/register": {
|
||||
"post": {
|
||||
"description": "Create a new user under the authenticated client. Validates input and returns created user.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Register a new user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Register payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserCreateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/send-verification-email": {
|
||||
"post": {
|
||||
"description": "Send email with verification code/link to a user's email address.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Send verification email",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Email request payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SendVerificationEmailRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/verify-email": {
|
||||
"post": {
|
||||
"description": "Verify a user's email using code or token sent via email.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Verify user email",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Verify email payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.VerifyEmailRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Get details of a user by their ID. Requires appropriate permissions.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Get user by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"dto.SendVerificationEmailRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"email"
|
||||
],
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserCreateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"client_id",
|
||||
"email",
|
||||
"name",
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"type": "string",
|
||||
"maxLength": 10
|
||||
},
|
||||
"location_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"maintenance_group_user_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"minLength": 2
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 8
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"maxLength": 20,
|
||||
"minLength": 8
|
||||
},
|
||||
"photo_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"minLength": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserLoginRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"email",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"photo_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.UserRolesResponse"
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserRolesResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserUpdateRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"type": "string",
|
||||
"maxLength": 10
|
||||
},
|
||||
"location_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"maintenance_group_user_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"minLength": 2
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 8
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"maxLength": 20,
|
||||
"minLength": 8
|
||||
},
|
||||
"photo_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"minLength": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.VerifyEmailRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"token"
|
||||
],
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"BearerAuth": {
|
||||
"description": "Bearer token for authentication",
|
||||
"type": "apiKey",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
}
|
||||
},
|
||||
"externalDocs": {
|
||||
"description": "OpenAPI",
|
||||
"url": "https://swagger.io/resources/open-api/"
|
||||
}
|
||||
}`
|
||||
|
||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||
var SwaggerInfo = &swag.Spec{
|
||||
Version: "1.0",
|
||||
Host: "localhost:8888",
|
||||
BasePath: "/api/v1",
|
||||
Schemes: []string{},
|
||||
Title: "WMS Wareify API Docs",
|
||||
Description: "This is a sample server celler server.",
|
||||
InfoInstanceName: "swagger",
|
||||
SwaggerTemplate: docTemplate,
|
||||
LeftDelim: "{{",
|
||||
RightDelim: "}}",
|
||||
}
|
||||
|
||||
func init() {
|
||||
swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
|
||||
}
|
||||
|
|
@ -0,0 +1,687 @@
|
|||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "This is a sample server celler server.",
|
||||
"title": "WMS Wareify API Docs",
|
||||
"termsOfService": "http://swagger.io/terms/",
|
||||
"contact": {
|
||||
"name": "API Support",
|
||||
"url": "http://www.swagger.io/support",
|
||||
"email": "support@swagger.io"
|
||||
},
|
||||
"license": {
|
||||
"name": "Apache 2.0",
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
},
|
||||
"version": "1.0"
|
||||
},
|
||||
"host": "localhost:8888",
|
||||
"basePath": "/api/v1",
|
||||
"paths": {
|
||||
"/auth/login": {
|
||||
"post": {
|
||||
"description": "Authenticate user and return access \u0026 refresh tokens.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "User login",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Login payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserLoginRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/refresh": {
|
||||
"post": {
|
||||
"description": "Exchange a refresh token for a new access token (and optionally a new refresh token).",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Refresh auth token",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Refresh token payload",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/example/helloworld": {
|
||||
"get": {
|
||||
"description": "do ping",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"example"
|
||||
],
|
||||
"summary": "ping example",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Get paginated list of users for the current client. Supports filtering by name and including related roles.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Get list of users",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Filter by name (partial match)",
|
||||
"name": "name",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page number (default: 1)",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Page size (default: 10)",
|
||||
"name": "page_size",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Sort expression, e.g. created_at desc",
|
||||
"name": "sort",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Update profile of the authenticated user. Use multipart/form-data if uploading files (photo).",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Update current user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Update payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Delete the authenticated user's account (soft/hard depends on implementation).",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Delete current user",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/me": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Return the authenticated user's profile.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Get current user",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/register": {
|
||||
"post": {
|
||||
"description": "Create a new user under the authenticated client. Validates input and returns created user.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Register a new user",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Register payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserCreateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/send-verification-email": {
|
||||
"post": {
|
||||
"description": "Send email with verification code/link to a user's email address.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Send verification email",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Email request payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.SendVerificationEmailRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/verify-email": {
|
||||
"post": {
|
||||
"description": "Verify a user's email using code or token sent via email.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Verify user email",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "Verify email payload",
|
||||
"name": "body",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.VerifyEmailRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/users/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "Get details of a user by their ID. Requires appropriate permissions.",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"produces": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"Users"
|
||||
],
|
||||
"summary": "Get user by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "User ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/dto.UserResponse"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"dto.SendVerificationEmailRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"email"
|
||||
],
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserCreateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"client_id",
|
||||
"email",
|
||||
"name",
|
||||
"password",
|
||||
"username"
|
||||
],
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"type": "string",
|
||||
"maxLength": 10
|
||||
},
|
||||
"location_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"maintenance_group_user_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"minLength": 2
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 8
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"maxLength": 20,
|
||||
"minLength": 8
|
||||
},
|
||||
"photo_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"minLength": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserLoginRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"email",
|
||||
"password"
|
||||
],
|
||||
"properties": {
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"password": {
|
||||
"type": "string"
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
"photo_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/dto.UserRolesResponse"
|
||||
}
|
||||
},
|
||||
"username": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserRolesResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.UserUpdateRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string"
|
||||
},
|
||||
"client_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"email": {
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"type": "string",
|
||||
"maxLength": 10
|
||||
},
|
||||
"location_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"maintenance_group_user_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"minLength": 2
|
||||
},
|
||||
"password": {
|
||||
"type": "string",
|
||||
"minLength": 8
|
||||
},
|
||||
"phone": {
|
||||
"type": "string",
|
||||
"maxLength": 20,
|
||||
"minLength": 8
|
||||
},
|
||||
"photo_url": {
|
||||
"type": "string"
|
||||
},
|
||||
"username": {
|
||||
"type": "string",
|
||||
"maxLength": 100,
|
||||
"minLength": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"dto.VerifyEmailRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"token"
|
||||
],
|
||||
"properties": {
|
||||
"token": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"securityDefinitions": {
|
||||
"BearerAuth": {
|
||||
"description": "Bearer token for authentication",
|
||||
"type": "apiKey",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
}
|
||||
},
|
||||
"externalDocs": {
|
||||
"description": "OpenAPI",
|
||||
"url": "https://swagger.io/resources/open-api/"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,462 @@
|
|||
basePath: /api/v1
|
||||
definitions:
|
||||
dto.SendVerificationEmailRequest:
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
required:
|
||||
- email
|
||||
type: object
|
||||
dto.UserCreateRequest:
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
client_id:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
gender:
|
||||
maxLength: 10
|
||||
type: string
|
||||
location_id:
|
||||
type: string
|
||||
maintenance_group_user_id:
|
||||
type: string
|
||||
name:
|
||||
maxLength: 100
|
||||
minLength: 2
|
||||
type: string
|
||||
password:
|
||||
minLength: 8
|
||||
type: string
|
||||
phone:
|
||||
maxLength: 20
|
||||
minLength: 8
|
||||
type: string
|
||||
photo_url:
|
||||
type: string
|
||||
username:
|
||||
maxLength: 100
|
||||
minLength: 2
|
||||
type: string
|
||||
required:
|
||||
- client_id
|
||||
- email
|
||||
- name
|
||||
- password
|
||||
- username
|
||||
type: object
|
||||
dto.UserLoginRequest:
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
required:
|
||||
- email
|
||||
- password
|
||||
type: object
|
||||
dto.UserResponse:
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
gender:
|
||||
type: string
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
password:
|
||||
type: string
|
||||
phone:
|
||||
type: string
|
||||
photo_url:
|
||||
type: string
|
||||
roles:
|
||||
items:
|
||||
$ref: '#/definitions/dto.UserRolesResponse'
|
||||
type: array
|
||||
username:
|
||||
type: string
|
||||
type: object
|
||||
dto.UserRolesResponse:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
type: object
|
||||
dto.UserUpdateRequest:
|
||||
properties:
|
||||
address:
|
||||
type: string
|
||||
client_id:
|
||||
type: string
|
||||
email:
|
||||
type: string
|
||||
gender:
|
||||
maxLength: 10
|
||||
type: string
|
||||
location_id:
|
||||
type: string
|
||||
maintenance_group_user_id:
|
||||
type: string
|
||||
name:
|
||||
maxLength: 100
|
||||
minLength: 2
|
||||
type: string
|
||||
password:
|
||||
minLength: 8
|
||||
type: string
|
||||
phone:
|
||||
maxLength: 20
|
||||
minLength: 8
|
||||
type: string
|
||||
photo_url:
|
||||
type: string
|
||||
username:
|
||||
maxLength: 100
|
||||
minLength: 2
|
||||
type: string
|
||||
type: object
|
||||
dto.VerifyEmailRequest:
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
required:
|
||||
- token
|
||||
type: object
|
||||
externalDocs:
|
||||
description: OpenAPI
|
||||
url: https://swagger.io/resources/open-api/
|
||||
host: localhost:8888
|
||||
info:
|
||||
contact:
|
||||
email: support@swagger.io
|
||||
name: API Support
|
||||
url: http://www.swagger.io/support
|
||||
description: This is a sample server celler server.
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
termsOfService: http://swagger.io/terms/
|
||||
title: WMS Wareify API Docs
|
||||
version: "1.0"
|
||||
paths:
|
||||
/auth/login:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Authenticate user and return access & refresh tokens.
|
||||
parameters:
|
||||
- description: Login payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UserLoginRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: User login
|
||||
tags:
|
||||
- Auth
|
||||
/auth/refresh:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Exchange a refresh token for a new access token (and optionally
|
||||
a new refresh token).
|
||||
parameters:
|
||||
- description: Refresh token payload
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
type: object
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: Refresh auth token
|
||||
tags:
|
||||
- Auth
|
||||
/example/helloworld:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: do ping
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
type: string
|
||||
summary: ping example
|
||||
tags:
|
||||
- example
|
||||
/users:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Delete the authenticated user's account (soft/hard depends on implementation).
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Delete current user
|
||||
tags:
|
||||
- Users
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Get paginated list of users for the current client. Supports filtering
|
||||
by name and including related roles.
|
||||
parameters:
|
||||
- description: Filter by name (partial match)
|
||||
in: query
|
||||
name: name
|
||||
type: string
|
||||
- description: 'Page number (default: 1)'
|
||||
in: query
|
||||
name: page
|
||||
type: integer
|
||||
- description: 'Page size (default: 10)'
|
||||
in: query
|
||||
name: page_size
|
||||
type: integer
|
||||
- description: Sort expression, e.g. created_at desc
|
||||
in: query
|
||||
name: sort
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/dto.UserResponse'
|
||||
type: array
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get list of users
|
||||
tags:
|
||||
- Users
|
||||
put:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Update profile of the authenticated user. Use multipart/form-data
|
||||
if uploading files (photo).
|
||||
parameters:
|
||||
- description: Update payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UserUpdateRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UserResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Update current user
|
||||
tags:
|
||||
- Users
|
||||
/users/{id}:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Get details of a user by their ID. Requires appropriate permissions.
|
||||
parameters:
|
||||
- description: User ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: string
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UserResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get user by ID
|
||||
tags:
|
||||
- Users
|
||||
/users/me:
|
||||
get:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Return the authenticated user's profile.
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UserResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get current user
|
||||
tags:
|
||||
- Users
|
||||
/users/register:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Create a new user under the authenticated client. Validates input
|
||||
and returns created user.
|
||||
parameters:
|
||||
- description: Register payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UserCreateRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UserResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: Register a new user
|
||||
tags:
|
||||
- Users
|
||||
/users/send-verification-email:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Send email with verification code/link to a user's email address.
|
||||
parameters:
|
||||
- description: Email request payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.SendVerificationEmailRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: Send verification email
|
||||
tags:
|
||||
- Users
|
||||
/users/verify-email:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: Verify a user's email using code or token sent via email.
|
||||
parameters:
|
||||
- description: Verify email payload
|
||||
in: body
|
||||
name: body
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/dto.VerifyEmailRequest'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/dto.UserResponse'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
summary: Verify user email
|
||||
tags:
|
||||
- Users
|
||||
securityDefinitions:
|
||||
BearerAuth:
|
||||
description: Bearer token for authentication
|
||||
in: header
|
||||
name: Authorization
|
||||
type: apiKey
|
||||
swagger: "2.0"
|
||||
66
go.mod
66
go.mod
|
|
@ -1,52 +1,72 @@
|
|||
module github.com/Caknoooo/go-gin-clean-starter
|
||||
|
||||
go 1.23.0
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.1
|
||||
|
||||
require (
|
||||
github.com/Caknoooo/go-pagination v0.1.0
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/gin-gonic/gin v1.11.0
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/samber/do v1.6.0
|
||||
github.com/spf13/viper v1.20.0
|
||||
github.com/stretchr/testify v1.10.0
|
||||
golang.org/x/crypto v0.36.0
|
||||
github.com/stretchr/testify v1.11.1
|
||||
golang.org/x/crypto v0.43.0
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gorm.io/driver/postgres v1.5.11
|
||||
gorm.io/gorm v1.25.12
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.13.1 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/bytedance/gopkg v0.1.3 // indirect
|
||||
github.com/bytedance/sonic v1.14.1 // indirect
|
||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.6 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.8.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v1.0.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.22.1 // indirect
|
||||
github.com/go-openapi/jsonreference v0.21.2 // indirect
|
||||
github.com/go-openapi/spec v0.22.0 // indirect
|
||||
github.com/go-openapi/swag v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/conv v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/jsonname v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/jsonutils v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/loading v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/stringutils v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/typeutils v0.25.1 // indirect
|
||||
github.com/go-openapi/swag/yamlutils v0.25.1 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.25.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.28.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.7.2 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.5.1 // indirect
|
||||
github.com/quic-go/quic-go v0.55.0 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
github.com/sagikazarmark/locafero v0.8.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
|
|
@ -55,15 +75,23 @@ require (
|
|||
github.com/spf13/cast v1.7.1 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/swaggo/files v1.0.1 // indirect
|
||||
github.com/swaggo/gin-swagger v1.6.1 // indirect
|
||||
github.com/swaggo/swag v1.16.6 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||
go.uber.org/mock v0.6.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.15.0 // indirect
|
||||
golang.org/x/net v0.37.0 // indirect
|
||||
golang.org/x/sync v0.12.0 // indirect
|
||||
golang.org/x/sys v0.31.0 // indirect
|
||||
golang.org/x/text v0.23.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/arch v0.22.0 // indirect
|
||||
golang.org/x/mod v0.29.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/sync v0.17.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
golang.org/x/tools v0.38.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
|
|
|||
120
go.sum
120
go.sum
|
|
@ -1,12 +1,26 @@
|
|||
github.com/Caknoooo/go-pagination v0.1.0 h1:DoSs9IaNmzOMb7I8zZddZeqyU/6Ss27lrv1G3N8b3KA=
|
||||
github.com/Caknoooo/go-pagination v0.1.0/go.mod h1:JFrym1XOpBuX5ovwsJ885n6onqIVWMZwOmh1W3P2wbk=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28=
|
||||
github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/bytedance/gopkg v0.1.3 h1:TPBSwH8RsouGCBcMBktLt1AymVo2TVsBVCY4b6TnZ/M=
|
||||
github.com/bytedance/gopkg v0.1.3/go.mod h1:576VvJ+eJgyCzdjS+c4+77QF3p7ubbtiKARP3TxducM=
|
||||
github.com/bytedance/sonic v1.13.1 h1:Jyd5CIvdFnkOWuKXr+wm4Nyk2h0yAFsr8ucJgEasO3g=
|
||||
github.com/bytedance/sonic v1.13.1/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
github.com/bytedance/sonic v1.14.1 h1:FBMC0zVz5XUmE4z9wF4Jey0An5FueFvOsTKKKtwIl7w=
|
||||
github.com/bytedance/sonic v1.14.1/go.mod h1:gi6uhQLMbTdeP0muCnrjHLeCUPyb70ujhnNlhOylAFc=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/bytedance/sonic/loader v0.3.0 h1:dskwH8edlzNMctoruo8FPTJDF3vLtDT0sXZwvZJyqeA=
|
||||
github.com/bytedance/sonic/loader v0.3.0/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/base64x v0.1.6 h1:t11wG9AECkCDk5fMSoxmufanudBtJ+/HemLstXDLI2M=
|
||||
github.com/cloudwego/base64x v0.1.6/go.mod h1:OFcloc187FXDaYHvrNIjxSe8ncn0OOM8gEHfghB2IPU=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ=
|
||||
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w=
|
||||
|
|
@ -19,10 +33,38 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/
|
|||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10 h1:zyueNbySn/z8mJZHLt6IPw0KoZsiQNszIpU+bX4+ZK0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.10/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
|
||||
github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
|
||||
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/gin-gonic/gin v1.11.0 h1:OW/6PLjyusp2PPXtyxKHU0RbX6I/l28FTdDlae5ueWk=
|
||||
github.com/gin-gonic/gin v1.11.0/go.mod h1:+iq/FyxlGzII0KHiBGjuNn4UNENUlKbGlNmc+W50Dls=
|
||||
github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk=
|
||||
github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM=
|
||||
github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU=
|
||||
github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ=
|
||||
github.com/go-openapi/spec v0.22.0 h1:xT/EsX4frL3U09QviRIZXvkh80yibxQmtoEvyqug0Tw=
|
||||
github.com/go-openapi/spec v0.22.0/go.mod h1:K0FhKxkez8YNS94XzF8YKEMULbFrRw4m15i2YUht4L0=
|
||||
github.com/go-openapi/swag v0.25.1 h1:6uwVsx+/OuvFVPqfQmOOPsqTcm5/GkBhNwLqIR916n8=
|
||||
github.com/go-openapi/swag v0.25.1/go.mod h1:bzONdGlT0fkStgGPd3bhZf1MnuPkf2YAys6h+jZipOo=
|
||||
github.com/go-openapi/swag/conv v0.25.1 h1:+9o8YUg6QuqqBM5X6rYL/p1dpWeZRhoIt9x7CCP+he0=
|
||||
github.com/go-openapi/swag/conv v0.25.1/go.mod h1:Z1mFEGPfyIKPu0806khI3zF+/EUXde+fdeksUl2NiDs=
|
||||
github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU=
|
||||
github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo=
|
||||
github.com/go-openapi/swag/jsonutils v0.25.1 h1:AihLHaD0brrkJoMqEZOBNzTLnk81Kg9cWr+SPtxtgl8=
|
||||
github.com/go-openapi/swag/jsonutils v0.25.1/go.mod h1:JpEkAjxQXpiaHmRO04N1zE4qbUEg3b7Udll7AMGTNOo=
|
||||
github.com/go-openapi/swag/loading v0.25.1 h1:6OruqzjWoJyanZOim58iG2vj934TysYVptyaoXS24kw=
|
||||
github.com/go-openapi/swag/loading v0.25.1/go.mod h1:xoIe2EG32NOYYbqxvXgPzne989bWvSNoWoyQVWEZicc=
|
||||
github.com/go-openapi/swag/stringutils v0.25.1 h1:Xasqgjvk30eUe8VKdmyzKtjkVjeiXx1Iz0zDfMNpPbw=
|
||||
github.com/go-openapi/swag/stringutils v0.25.1/go.mod h1:JLdSAq5169HaiDUbTvArA2yQxmgn4D6h4A+4HqVvAYg=
|
||||
github.com/go-openapi/swag/typeutils v0.25.1 h1:rD/9HsEQieewNt6/k+JBwkxuAHktFtH3I3ysiFZqukA=
|
||||
github.com/go-openapi/swag/typeutils v0.25.1/go.mod h1:9McMC/oCdS4BKwk2shEB7x17P6HmMmA6dQRtAkSnNb8=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.1 h1:mry5ez8joJwzvMbaTGLhw8pXUnhDK91oSJLDPF1bmGk=
|
||||
github.com/go-openapi/swag/yamlutils v0.25.1/go.mod h1:cm9ywbzncy3y6uPm/97ysW8+wZ09qsks+9RS8fLWKqg=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
|
|
@ -31,14 +73,19 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
|
|||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
|
||||
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/go-playground/validator/v10 v10.28.0 h1:Q7ibns33JjyW48gHkuFT91qX48KG0ktULL6FgHdG688=
|
||||
github.com/go-playground/validator/v10 v10.28.0/go.mod h1:GoI6I1SjPBh9p7ykNE/yj3fFYbyDOpwMn5KXd+m2hUU=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo=
|
||||
github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
|
|
@ -56,11 +103,15 @@ github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
|||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
|
||||
github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
|
|
@ -68,6 +119,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
|||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/mailru/easyjson v0.9.1 h1:LbtsOm5WAswyWbvTEOqhypdPeZzHavpZx96/n553mR8=
|
||||
github.com/mailru/easyjson v0.9.1/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
|
|
@ -79,8 +132,14 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
|
|||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/quic-go/qpack v0.5.1 h1:giqksBPnT/HDtZ6VhtFKgoLOWmlyo9Ei6u9PqzIMbhI=
|
||||
github.com/quic-go/qpack v0.5.1/go.mod h1:+PC4XFrEskIVkcLzpEkbLqq1uCoxPhQuvK5rH1ZgaEg=
|
||||
github.com/quic-go/quic-go v0.55.0 h1:zccPQIqYCXDt5NmcEabyYvOnomjs8Tlwl7tISjJh9Mk=
|
||||
github.com/quic-go/quic-go v0.55.0/go.mod h1:DR51ilwU1uE164KuWXhinFcKWGlEjzys2l8zUl5Ss1U=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
|
|
@ -113,30 +172,89 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
|
|||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/swaggo/files v1.0.1 h1:J1bVJ4XHZNq0I46UU90611i9/YzdrF7x92oX1ig5IdE=
|
||||
github.com/swaggo/files v1.0.1/go.mod h1:0qXmMNH6sXNf+73t65aKeB+ApmgxdnkQzVTAj2uaMUg=
|
||||
github.com/swaggo/gin-swagger v1.6.1 h1:Ri06G4gc9N4t4k8hekMigJ9zKTFSlqj/9paAQCQs7cY=
|
||||
github.com/swaggo/gin-swagger v1.6.1/go.mod h1:LQ+hJStHakCWRiK/YNYtJOu4mR2FP+pxLnILT/qNiTw=
|
||||
github.com/swaggo/swag v1.16.6 h1:qBNcx53ZaX+M5dxVyTrgQ0PJ/ACK+NzhwcbieTt+9yI=
|
||||
github.com/swaggo/swag v1.16.6/go.mod h1:ngP2etMK5a0P3QBizic5MEwpRmluJZPHjXcMoj4Xesg=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA=
|
||||
github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
|
||||
go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
golang.org/x/arch v0.15.0 h1:QtOrQd0bTUnhNVNndMpLHNWrDmYzZ2KDqSrEymqInZw=
|
||||
golang.org/x/arch v0.15.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||
golang.org/x/arch v0.22.0 h1:c/Zle32i5ttqRXjdLyyHZESLD/bB90DCU1g9l/0YBDI=
|
||||
golang.org/x/arch v0.22.0/go.mod h1:dNHoOeKiyja7GTvF9NJS1l3Z2yntpQNzgrjh1cU103A=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
|
||||
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
|
||||
golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
|
||||
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
|
||||
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
|
||||
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
|
||||
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
|
@ -144,6 +262,8 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN
|
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
604
logs.html
604
logs.html
|
|
@ -1,4 +1,4 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- <!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
|
|
@ -197,4 +197,606 @@
|
|||
</script>
|
||||
</body>
|
||||
|
||||
</html> -->
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Logs - Admin</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script
|
||||
src="https://kit.fontawesome.com/a82697a287.js"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<style>
|
||||
body {
|
||||
background: linear-gradient(135deg, #f6f8fc 0%, #e9ecef 100%);
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.glass-effect {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.log-item {
|
||||
position: relative;
|
||||
max-height: 10rem;
|
||||
overflow: hidden;
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
border: 1px solid rgba(226, 232, 240, 0.7);
|
||||
}
|
||||
|
||||
.log-text {
|
||||
display: block;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
color: #4a5568;
|
||||
}
|
||||
|
||||
.log-item:hover {
|
||||
max-height: none;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.log-item:hover .log-text {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.custom-select {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
color: #4f46e5;
|
||||
border: 2px solid rgba(79, 70, 229, 0.2);
|
||||
font-weight: 600;
|
||||
padding-right: 2.5rem;
|
||||
appearance: none;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%234f46e5'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M19 9l-7 7-7-7'%3E%3C/path%3E%3C/svg%3E");
|
||||
background-repeat: no-repeat;
|
||||
background-position: right 0.75rem center;
|
||||
background-size: 1.25rem;
|
||||
}
|
||||
|
||||
.custom-select:hover {
|
||||
border-color: #4f46e5;
|
||||
background-color: rgba(79, 70, 229, 0.05);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.custom-select:focus {
|
||||
outline: none;
|
||||
border-color: #4f46e5;
|
||||
box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.1);
|
||||
}
|
||||
|
||||
.refresh-button {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
color: #4f46e5;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.4s ease;
|
||||
border: 2px solid rgba(79, 70, 229, 0.2);
|
||||
font-size: 1.25rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.refresh-button::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
45deg,
|
||||
rgba(79, 70, 229, 0.1) 0%,
|
||||
rgba(79, 70, 229, 0) 100%
|
||||
);
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.refresh-button:hover {
|
||||
border-color: #4f46e5;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 16px rgba(79, 70, 229, 0.15);
|
||||
}
|
||||
|
||||
.refresh-button:hover::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.refresh-button:hover i {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.refresh-button i {
|
||||
transition: transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1);
|
||||
}
|
||||
|
||||
.controls-wrapper {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
align-items: center;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
padding: 0.5rem;
|
||||
border-radius: 20px;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
|
||||
.login-container {
|
||||
max-width: 400px;
|
||||
margin: 100px auto;
|
||||
padding: 2rem;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
|
||||
color: white;
|
||||
padding: 12px 24px;
|
||||
border-radius: 12px;
|
||||
border: none;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(79, 70, 229, 0.3);
|
||||
}
|
||||
|
||||
.btn-primary:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
width: 100%;
|
||||
padding: 12px 16px;
|
||||
border: 2px solid #e2e8f0;
|
||||
border-radius: 12px;
|
||||
transition: all 0.3s ease;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.input-field:focus {
|
||||
outline: none;
|
||||
border-color: #4f46e5;
|
||||
box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.1);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.loading {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background: #fee2e2;
|
||||
border: 1px solid #fecaca;
|
||||
color: #dc2626;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class="font-sans">
|
||||
<!-- Login Section -->
|
||||
<div
|
||||
id="loginSection"
|
||||
class="max-w-md mx-auto p-8 glass-effect rounded-3xl shadow-2xl mt-12 login-container"
|
||||
>
|
||||
<div class="text-center mb-8">
|
||||
<h1
|
||||
class="text-3xl font-bold bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent mb-2"
|
||||
>
|
||||
Admin Logs
|
||||
</h1>
|
||||
<p class="text-gray-500">Login to access system logs</p>
|
||||
</div>
|
||||
|
||||
<form id="loginForm" onsubmit="login(event)">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label
|
||||
for="email"
|
||||
class="block text-sm font-medium text-gray-700 mb-2"
|
||||
>Email</label
|
||||
>
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
required
|
||||
placeholder="admin@example.com"
|
||||
class="input-field"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label
|
||||
for="password"
|
||||
class="block text-sm font-medium text-gray-700 mb-2"
|
||||
>Password</label
|
||||
>
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
required
|
||||
placeholder="Enter your password"
|
||||
class="input-field"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" id="loginBtn" class="btn-primary mt-6">
|
||||
<span id="loginText">Login</span>
|
||||
<span id="loginLoading" class="hidden">
|
||||
<i class="fa-solid fa-spinner fa-spin"></i> Logging in...
|
||||
</span>
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div id="errorMessage" class="error-message hidden"></div>
|
||||
</div>
|
||||
|
||||
<!-- Logs Section (Hidden until login) -->
|
||||
<div id="logsSection" class="hidden">
|
||||
<div
|
||||
class="max-w-5xl mx-auto p-8 glass-effect rounded-3xl shadow-2xl mt-12 mb-12"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-12">
|
||||
<div class="flex items-center gap-4">
|
||||
<div>
|
||||
<h1
|
||||
class="text-4xl font-bold bg-gradient-to-r from-indigo-600 to-purple-600 bg-clip-text text-transparent"
|
||||
>
|
||||
Query Logs
|
||||
</h1>
|
||||
<p class="text-gray-500 mt-2">Monitor and track system queries</p>
|
||||
</div>
|
||||
<!-- <span
|
||||
class="bg-green-100 text-green-800 px-3 py-1 rounded-full text-sm font-medium"
|
||||
>
|
||||
<i class="fa-solid fa-circle-check mr-1"></i> Admin
|
||||
</span> -->
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="controls-wrapper">
|
||||
<button
|
||||
onclick="refreshLogs()"
|
||||
class="refresh-button"
|
||||
title="Refresh logs"
|
||||
>
|
||||
<i class="fa-solid fa-arrows-rotate"></i>
|
||||
</button>
|
||||
|
||||
<div class="relative">
|
||||
<select
|
||||
id="month"
|
||||
onchange="changeMonth()"
|
||||
class="custom-select w-48 px-6 py-3 rounded-xl text-sm font-medium"
|
||||
>
|
||||
<option value="january">January</option>
|
||||
<option value="february">February</option>
|
||||
<option value="march">March</option>
|
||||
<option value="april">April</option>
|
||||
<option value="may">May</option>
|
||||
<option value="june">June</option>
|
||||
<option value="july">July</option>
|
||||
<option value="august">August</option>
|
||||
<option value="september">September</option>
|
||||
<option value="october">October</option>
|
||||
<option value="november">November</option>
|
||||
<option value="december">December</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
onclick="logout()"
|
||||
class="bg-red-500 hover:bg-red-600 text-white px-4 py-2 rounded-xl transition-all flex items-center gap-2"
|
||||
>
|
||||
<i class="fa-solid fa-right-from-bracket"></i>
|
||||
Logout
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="logsContent">
|
||||
<!-- Logs will be loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const API_BASE = "/api/v1/auth";
|
||||
const LOGS_BASE = "/api/v1/logs";
|
||||
|
||||
// Check if already logged in on page load
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const token = localStorage.getItem("admin_token");
|
||||
if (token) {
|
||||
showLogsSection();
|
||||
loadLogs();
|
||||
} else {
|
||||
showLoginSection();
|
||||
}
|
||||
|
||||
// Set current month as default
|
||||
const currentMonthIndex = new Date().getMonth();
|
||||
const months = [
|
||||
"january",
|
||||
"february",
|
||||
"march",
|
||||
"april",
|
||||
"may",
|
||||
"june",
|
||||
"july",
|
||||
"august",
|
||||
"september",
|
||||
"october",
|
||||
"november",
|
||||
"december",
|
||||
];
|
||||
document.getElementById("month").value = months[currentMonthIndex];
|
||||
});
|
||||
|
||||
async function login(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const email = document.getElementById("email").value;
|
||||
const password = document.getElementById("password").value;
|
||||
const loginBtn = document.getElementById("loginBtn");
|
||||
const loginText = document.getElementById("loginText");
|
||||
const loginLoading = document.getElementById("loginLoading");
|
||||
const errorMessage = document.getElementById("errorMessage");
|
||||
|
||||
// Show loading state
|
||||
loginBtn.disabled = true;
|
||||
loginText.classList.add("hidden");
|
||||
loginLoading.classList.remove("hidden");
|
||||
errorMessage.classList.add("hidden");
|
||||
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/login`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ email, password }),
|
||||
});
|
||||
|
||||
// Read raw text first to avoid 'Unexpected token <' when server returns HTML
|
||||
const raw = await response.text();
|
||||
let data = null;
|
||||
try {
|
||||
data = JSON.parse(raw);
|
||||
} catch (e) {
|
||||
// non-JSON response (HTML/error page) — keep raw for logging
|
||||
console.warn("Non-JSON response:", raw);
|
||||
}
|
||||
|
||||
console.log("Data response login:", data || raw);
|
||||
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
(data && data.message) || `Request failed (${response.status})`;
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
// Extract token supporting both shapes: { access_token } or { data: { access_token } }
|
||||
const token =
|
||||
(data && data.access_token) ||
|
||||
(data && data.data && data.data.access_token);
|
||||
|
||||
if (!token) {
|
||||
throw new Error("Login succeeded but no access token returned");
|
||||
}
|
||||
|
||||
localStorage.setItem("admin_token", token);
|
||||
|
||||
// Show logs section
|
||||
showLogsSection();
|
||||
loadLogs();
|
||||
} catch (error) {
|
||||
errorMessage.textContent = error.message;
|
||||
errorMessage.classList.remove("hidden");
|
||||
} finally {
|
||||
// Reset loading state
|
||||
loginBtn.disabled = false;
|
||||
loginText.classList.remove("hidden");
|
||||
loginLoading.classList.add("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function showLoginSection() {
|
||||
document.getElementById("loginSection").classList.remove("hidden");
|
||||
document.getElementById("logsSection").classList.add("hidden");
|
||||
}
|
||||
|
||||
function showLogsSection() {
|
||||
document.getElementById("loginSection").classList.add("hidden");
|
||||
document.getElementById("logsSection").classList.remove("hidden");
|
||||
}
|
||||
|
||||
async function loadLogs(month = null) {
|
||||
const logsContent = document.getElementById("logsContent");
|
||||
const token = localStorage.getItem("admin_token");
|
||||
|
||||
if (!token) {
|
||||
showLoginSection();
|
||||
return;
|
||||
}
|
||||
|
||||
const selectedMonth = month || document.getElementById("month").value;
|
||||
|
||||
try {
|
||||
logsContent.innerHTML = `
|
||||
<div class="text-center py-8">
|
||||
<i class="fa-solid fa-spinner fa-spin text-2xl text-indigo-600 mb-3"></i>
|
||||
<p class="text-gray-500">Loading logs...</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const response = await fetch(`${LOGS_BASE}/${selectedMonth}`, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
Authorization: `Bearer ${token}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
// read raw and try parse JSON (avoid "Unexpected token '<'")
|
||||
const raw = await response.text();
|
||||
let payload = null;
|
||||
try {
|
||||
payload = JSON.parse(raw);
|
||||
} catch (e) {
|
||||
payload = raw; // fallback to raw HTML/text
|
||||
console.warn("Non-JSON logs response:", raw);
|
||||
}
|
||||
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
localStorage.removeItem("admin_token");
|
||||
showLoginSection();
|
||||
throw new Error("Session expired. Please login again.");
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const message =
|
||||
(payload && payload.message) ||
|
||||
`Request failed (${response.status})`;
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
// normalize logs array from possible response shapes
|
||||
let logs = [];
|
||||
if (Array.isArray(payload)) {
|
||||
logs = payload;
|
||||
} else if (
|
||||
payload &&
|
||||
payload.data &&
|
||||
Array.isArray(payload.data.logs)
|
||||
) {
|
||||
logs = payload.data.logs;
|
||||
} else if (payload && Array.isArray(payload.logs)) {
|
||||
logs = payload.logs;
|
||||
}
|
||||
|
||||
displayLogs(logs);
|
||||
} catch (error) {
|
||||
logsContent.innerHTML = `
|
||||
<div class="error-message text-center">
|
||||
<i class="fa-solid fa-exclamation-triangle mr-2"></i>
|
||||
${error.message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
function displayLogs(logsOrPayload) {
|
||||
const logsContent = document.getElementById("logsContent");
|
||||
|
||||
// Normalize input ke array logs
|
||||
let logs = [];
|
||||
if (!logsOrPayload) {
|
||||
logs = [];
|
||||
} else if (Array.isArray(logsOrPayload)) {
|
||||
logs = logsOrPayload;
|
||||
} else if (
|
||||
logsOrPayload.data &&
|
||||
Array.isArray(logsOrPayload.data.logs)
|
||||
) {
|
||||
logs = logsOrPayload.data.logs;
|
||||
} else if (Array.isArray(logsOrPayload.logs)) {
|
||||
logs = logsOrPayload.logs;
|
||||
} else if (typeof logsOrPayload === "object") {
|
||||
// support wrapper like { month, logs, total } or { status, message, data: { logs } }
|
||||
if (Array.isArray(logsOrPayload.logs)) logs = logsOrPayload.logs;
|
||||
else if (logsOrPayload.data && Array.isArray(logsOrPayload.data.logs))
|
||||
logs = logsOrPayload.data.logs;
|
||||
else logs = [];
|
||||
}
|
||||
|
||||
// Clear area
|
||||
logsContent.innerHTML = "";
|
||||
|
||||
if (!logs || logs.length === 0) {
|
||||
logsContent.innerHTML = `
|
||||
<div class="p-8 glass-effect rounded-2xl text-center">
|
||||
<i class="fa-solid fa-inbox text-4xl text-gray-300 mb-3"></i>
|
||||
<p class="text-gray-500">No logs found for this month.</p>
|
||||
</div>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
const ul = document.createElement("ul");
|
||||
ul.className = "space-y-6";
|
||||
|
||||
logs.forEach((log) => {
|
||||
const li = document.createElement("li");
|
||||
li.className =
|
||||
"log-item p-6 glass-effect rounded-2xl hover:bg-gradient-to-r hover:from-indigo-50 hover:to-purple-50 transition-all";
|
||||
|
||||
const header = document.createElement("div");
|
||||
header.className = "flex items-center gap-2 text-indigo-600 mb-3";
|
||||
header.innerHTML = `<i class="fa-solid fa-terminal text-sm"></i><span class="font-semibold">Log Entry</span>`;
|
||||
|
||||
const pre = document.createElement("pre");
|
||||
pre.className = "text-sm whitespace-pre-wrap break-words log-text";
|
||||
// gunakan textContent agar aman dari HTML injection
|
||||
if (typeof log === "string") {
|
||||
pre.textContent = log;
|
||||
} else {
|
||||
try {
|
||||
pre.textContent = JSON.stringify(log, null, 2);
|
||||
} catch (e) {
|
||||
pre.textContent = String(log);
|
||||
}
|
||||
}
|
||||
|
||||
li.appendChild(header);
|
||||
li.appendChild(pre);
|
||||
ul.appendChild(li);
|
||||
});
|
||||
|
||||
logsContent.appendChild(ul);
|
||||
}
|
||||
|
||||
function changeMonth() {
|
||||
const selectedMonth = document.getElementById("month").value;
|
||||
loadLogs(selectedMonth);
|
||||
}
|
||||
|
||||
function refreshLogs() {
|
||||
loadLogs();
|
||||
}
|
||||
|
||||
function logout() {
|
||||
localStorage.removeItem("admin_token");
|
||||
showLoginSection();
|
||||
|
||||
// Clear form
|
||||
document.getElementById("email").value = "";
|
||||
document.getElementById("password").value = "";
|
||||
document.getElementById("errorMessage").classList.add("hidden");
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ type (
|
|||
LogsController interface {
|
||||
GetLogs(ctx *gin.Context)
|
||||
GetLogsByMonth(ctx *gin.Context)
|
||||
ServeLogsPage(ctx *gin.Context)
|
||||
}
|
||||
|
||||
logsController struct {
|
||||
|
|
@ -32,6 +33,19 @@ func NewLogsController(injector *do.Injector) LogsController {
|
|||
}
|
||||
}
|
||||
|
||||
func (c *logsController) ServeLogsPage(ctx *gin.Context) {
|
||||
acceptHeader := ctx.GetHeader("Accept")
|
||||
if strings.Contains(acceptHeader, "text/html") {
|
||||
month := strings.ToLower(time.Now().Format("January"))
|
||||
ctx.HTML(http.StatusOK, "logs.html", gin.H{
|
||||
"Month": month,
|
||||
"Logs": []string{},
|
||||
})
|
||||
return
|
||||
}
|
||||
ctx.Next()
|
||||
}
|
||||
|
||||
func (c *logsController) GetLogs(ctx *gin.Context) {
|
||||
month := strings.ToLower(time.Now().Format("January"))
|
||||
c.getLogsForMonth(ctx, month)
|
||||
|
|
@ -74,6 +88,11 @@ func (c *logsController) getLogsForMonth(ctx *gin.Context, month string) {
|
|||
logs = []string{}
|
||||
}
|
||||
|
||||
// buat logs terbaru muncul paling atas (reverse slice)
|
||||
for i, j := 0, len(logs)-1; i < j; i, j = i+1, j-1 {
|
||||
logs[i], logs[j] = logs[j], logs[i]
|
||||
}
|
||||
|
||||
// Jika request Accept header adalah application/json, kembalikan JSON
|
||||
if ctx.GetHeader("Accept") == "application/json" {
|
||||
res := utils.BuildResponseSuccess("Success get logs", gin.H{
|
||||
|
|
|
|||
|
|
@ -16,14 +16,27 @@ func RegisterRoutes(server *gin.Engine, injector *do.Injector) {
|
|||
jwtService := do.MustInvokeNamed[service.JWTService](injector, constants.JWTService)
|
||||
|
||||
// Public routes (tanpa auth) - untuk testing
|
||||
publicLogs := server.Group("/logs")
|
||||
{
|
||||
publicLogs.GET("", logsController.GetLogs)
|
||||
publicLogs.GET("/:month", logsController.GetLogsByMonth)
|
||||
}
|
||||
// publicLogs := server.Group("/logs")
|
||||
// {
|
||||
// publicLogs.GET("", logsController.GetLogs)
|
||||
// publicLogs.GET("/:month", logsController.GetLogsByMonth)
|
||||
// }
|
||||
|
||||
// Serve HTML page when browser requests text/html (no auth) — placed BEFORE protected group
|
||||
// server.GET("/admin/logs", func(ctx *gin.Context) {
|
||||
// acceptHeader := ctx.GetHeader("Accept")
|
||||
// if strings.Contains(acceptHeader, "text/html") {
|
||||
// ctx.HTML(http.StatusOK, "logs.html", gin.H{})
|
||||
// return
|
||||
// }
|
||||
// // untuk API call lanjut ke handler berikutnya (mis. protected group)
|
||||
// ctx.Next()
|
||||
// })
|
||||
|
||||
server.GET("/admin/logs", logsController.ServeLogsPage)
|
||||
|
||||
// Protected routes (hanya superadmin)
|
||||
protectedLogs := server.Group("/admin/logs")
|
||||
protectedLogs := server.Group("/api/v1/logs")
|
||||
protectedLogs.Use(middlewares.Authenticate(jwtService))
|
||||
protectedLogs.Use(middlewares.RoleSuperAdmin(userService))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -35,7 +35,15 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
// AssignPermissionsToRole implements RoleController.
|
||||
// PingExample godoc
|
||||
// @Summary ping example
|
||||
// @Schemes
|
||||
// @Description do ping
|
||||
// @Tags example
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Success 200 {string} Helloworld
|
||||
// @Router /example/helloworld [get]
|
||||
func (r *roleController) AssignPermissionsToRole(ctx *gin.Context) {
|
||||
var req dto.AssignPermissionRequest
|
||||
roleId := ctx.Param("id")
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import (
|
|||
"github.com/Caknoooo/go-pagination"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/samber/do"
|
||||
"github.com/sirupsen/logrus"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
|
|
@ -45,6 +44,17 @@ func NewUserController(injector *do.Injector, us service.UserService) UserContro
|
|||
}
|
||||
}
|
||||
|
||||
// Register godoc
|
||||
// @Summary Register a new user
|
||||
// @Description Create a new user under the authenticated client. Validates input and returns created user.
|
||||
// @Tags Users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body dto.UserCreateRequest true "Register payload"
|
||||
// @Success 200 {object} dto.UserResponse
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Failure 500 {object} map[string]interface{}
|
||||
// @Router /users/register [post]
|
||||
func (c *userController) Register(ctx *gin.Context) {
|
||||
var user dto.UserCreateRequest
|
||||
if err := ctx.ShouldBind(&user); err != nil {
|
||||
|
|
@ -64,32 +74,52 @@ func (c *userController) Register(ctx *gin.Context) {
|
|||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
// GetAllUser godoc
|
||||
// @Summary Get list of users
|
||||
// @Description Get paginated list of users for the current client. Supports filtering by name and including related roles.
|
||||
// @Tags Users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param name query string false "Filter by name (partial match)"
|
||||
// @Param page query int false "Page number (default: 1)"
|
||||
// @Param page_size query int false "Page size (default: 10)"
|
||||
// @Param sort query string false "Sort expression, e.g. created_at desc"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {array} dto.UserResponse
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Router /users [get]
|
||||
func (c *userController) GetAllUser(ctx *gin.Context) {
|
||||
clientId := ctx.MustGet("client_id").(string)
|
||||
logrus.Info("Client ID: ", clientId)
|
||||
var filter = &query.UserFilter{
|
||||
ClientID: clientId,
|
||||
Name: ctx.Query("name"),
|
||||
Includes: []string{"Roles"}, // Tambahkan ini
|
||||
Includes: []string{"Roles"},
|
||||
}
|
||||
filter.BindPagination(ctx)
|
||||
|
||||
ctx.ShouldBindQuery(filter)
|
||||
logrus.Info("Filter sebelum query: ")
|
||||
users, total, err := pagination.PaginatedQueryWithIncludable[query.M_User](c.db, filter)
|
||||
// logrus.Info("Filter: ", filter)
|
||||
if err != nil {
|
||||
res := utils.BuildResponseFailed(dto.MESSAGE_FAILED_GET_USER, err.Error(), nil)
|
||||
ctx.JSON(http.StatusBadRequest, res)
|
||||
return
|
||||
}
|
||||
// Convert ke DTO
|
||||
userResponses := ToUserResponses(users)
|
||||
paginationResponse := pagination.CalculatePagination(filter.Pagination, total)
|
||||
response := pagination.NewPaginatedResponse(http.StatusOK, dto.MESSAGE_SUCCESS_GET_LIST_USER, userResponses, paginationResponse)
|
||||
ctx.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
// Me godoc
|
||||
// @Summary Get current user
|
||||
// @Description Return the authenticated user's profile.
|
||||
// @Tags Users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} dto.UserResponse
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Router /users/me [get]
|
||||
func (c *userController) Me(ctx *gin.Context) {
|
||||
userId := ctx.MustGet("user_id").(string)
|
||||
|
||||
|
|
@ -104,6 +134,17 @@ func (c *userController) Me(ctx *gin.Context) {
|
|||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
// GetUserById godoc
|
||||
// @Summary Get user by ID
|
||||
// @Description Get details of a user by their ID. Requires appropriate permissions.
|
||||
// @Tags Users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "User ID"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} dto.UserResponse
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Router /users/{id} [get]
|
||||
func (c *userController) GetUserById(ctx *gin.Context) {
|
||||
userId := ctx.Param("id")
|
||||
|
||||
|
|
@ -118,6 +159,16 @@ func (c *userController) GetUserById(ctx *gin.Context) {
|
|||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
// Login godoc
|
||||
// @Summary User login
|
||||
// @Description Authenticate user and return access & refresh tokens.
|
||||
// @Tags Auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body dto.UserLoginRequest true "Login payload"
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Router /auth/login [post]
|
||||
func (c *userController) Login(ctx *gin.Context) {
|
||||
var req dto.UserLoginRequest
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
|
|
@ -137,6 +188,16 @@ func (c *userController) Login(ctx *gin.Context) {
|
|||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
// SendVerificationEmail godoc
|
||||
// @Summary Send verification email
|
||||
// @Description Send email with verification code/link to a user's email address.
|
||||
// @Tags Users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body dto.SendVerificationEmailRequest true "Email request payload"
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Router /users/send-verification-email [post]
|
||||
func (c *userController) SendVerificationEmail(ctx *gin.Context) {
|
||||
var req dto.SendVerificationEmailRequest
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
|
|
@ -156,6 +217,16 @@ func (c *userController) SendVerificationEmail(ctx *gin.Context) {
|
|||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
// VerifyEmail godoc
|
||||
// @Summary Verify user email
|
||||
// @Description Verify a user's email using code or token sent via email.
|
||||
// @Tags Users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body dto.VerifyEmailRequest true "Verify email payload"
|
||||
// @Success 200 {object} dto.UserResponse
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Router /users/verify-email [post]
|
||||
func (c *userController) VerifyEmail(ctx *gin.Context) {
|
||||
var req dto.VerifyEmailRequest
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
|
|
@ -175,6 +246,17 @@ func (c *userController) VerifyEmail(ctx *gin.Context) {
|
|||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
// Update godoc
|
||||
// @Summary Update current user
|
||||
// @Description Update profile of the authenticated user. Use multipart/form-data if uploading files (photo).
|
||||
// @Tags Users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param body body dto.UserUpdateRequest true "Update payload"
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} dto.UserResponse
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Router /users [put]
|
||||
func (c *userController) Update(ctx *gin.Context) {
|
||||
var req dto.UserUpdateRequest
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
|
|
@ -195,6 +277,16 @@ func (c *userController) Update(ctx *gin.Context) {
|
|||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
// Delete godoc
|
||||
// @Summary Delete current user
|
||||
// @Description Delete the authenticated user's account (soft/hard depends on implementation).
|
||||
// @Tags Users
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security ApiKeyAuth
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Router /users [delete]
|
||||
func (c *userController) Delete(ctx *gin.Context) {
|
||||
userId := ctx.MustGet("user_id").(string)
|
||||
|
||||
|
|
@ -208,6 +300,17 @@ func (c *userController) Delete(ctx *gin.Context) {
|
|||
ctx.JSON(http.StatusOK, res)
|
||||
}
|
||||
|
||||
// Refresh godoc
|
||||
// @Summary Refresh auth token
|
||||
// @Description Exchange a refresh token for a new access token (and optionally a new refresh token).
|
||||
// @Tags Auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body object true "Refresh token payload" example:{"refresh_token":"string"}
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Failure 401 {object} map[string]interface{}
|
||||
// @Failure 400 {object} map[string]interface{}
|
||||
// @Router /auth/refresh [post]
|
||||
func (c *userController) Refresh(ctx *gin.Context) {
|
||||
var req authDto.RefreshTokenRequest
|
||||
if err := ctx.ShouldBind(&req); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in New Issue