feat: add chats features
This commit is contained in:
parent
86ea5f66d1
commit
9659007a06
|
|
@ -1,206 +0,0 @@
|
|||
# Chat History Implementation
|
||||
|
||||
This document describes the implementation of the chat history functionality based on the old web API code from the `plan/old` folder.
|
||||
|
||||
## Overview
|
||||
|
||||
The implementation includes:
|
||||
1. **New Chat History Module**: A complete module for managing chat sessions and messages
|
||||
2. **Updated AI Chat Module**: Enhanced with proper routing
|
||||
3. **Database Entities**: New entities for chat sessions and messages
|
||||
4. **API Endpoints**: RESTful endpoints for all chat history operations
|
||||
|
||||
## New Files Created
|
||||
|
||||
### Database Entities
|
||||
- `app/database/entity/chat_sessions.entity.go` - Chat sessions entity
|
||||
- `app/database/entity/chat_messages_new.entity.go` - Chat messages entity (renamed to avoid conflicts)
|
||||
|
||||
### Chat History Module
|
||||
- `app/module/chat_history/chat_history.module.go` - Module definition
|
||||
- `app/module/chat_history/chat_history.router.go` - Router configuration
|
||||
- `app/module/chat_history/request/chat_history.request.go` - Request DTOs
|
||||
- `app/module/chat_history/response/chat_history.response.go` - Response DTOs
|
||||
- `app/module/chat_history/mapper/chat_history.mapper.go` - Entity to response mappers
|
||||
- `app/module/chat_history/repository/chat_history.repository.go` - Data access layer
|
||||
- `app/module/chat_history/service/chat_history.service.go` - Business logic layer
|
||||
- `app/module/chat_history/controller/chat_history.controller.go` - API controller
|
||||
|
||||
### AI Chat Module Updates
|
||||
- `app/module/ai_chat/ai_chat.router.go` - Router configuration for AI chat
|
||||
|
||||
### Database Migration
|
||||
- `migrations/001_create_chat_history_tables.sql` - SQL migration script
|
||||
- `migrations/001_create_chat_history_tables.go` - Go migration script
|
||||
- `scripts/migrate.go` - Migration runner script
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Chat History Endpoints
|
||||
|
||||
#### Sessions
|
||||
- `GET /chat-history/sessions` - Get user's chat sessions
|
||||
- `GET /chat-history/sessions/{sessionId}` - Get specific session with messages
|
||||
- `POST /chat-history/sessions` - Create new session
|
||||
- `PUT /chat-history/sessions/{sessionId}` - Update session
|
||||
- `DELETE /chat-history/sessions/{sessionId}` - Delete session
|
||||
|
||||
#### Messages
|
||||
- `GET /chat-history/sessions/{sessionId}/messages` - Get session messages
|
||||
- `POST /chat-history/sessions/{sessionId}/messages` - Create message
|
||||
- `PUT /chat-history/messages/{messageId}` - Update message
|
||||
- `DELETE /chat-history/messages/{messageId}` - Delete message
|
||||
|
||||
#### Combined Operations
|
||||
- `POST /chat-history/save` - Save complete chat history (sessions + messages)
|
||||
|
||||
### AI Chat Endpoints (Updated)
|
||||
- `GET /ai-chat/sessions` - Get user's AI chat sessions
|
||||
- `GET /ai-chat/sessions/{id}` - Get specific AI chat session
|
||||
- `POST /ai-chat/sessions` - Create AI chat session
|
||||
- `PUT /ai-chat/sessions/{id}` - Update AI chat session
|
||||
- `DELETE /ai-chat/sessions/{id}` - Delete AI chat session
|
||||
- `GET /ai-chat/sessions/{sessionId}/messages` - Get AI chat messages
|
||||
- `POST /ai-chat/sessions/{sessionId}/messages` - Send AI chat message
|
||||
- `PUT /ai-chat/sessions/{sessionId}/messages/{messageId}` - Update AI chat message
|
||||
- `DELETE /ai-chat/sessions/{sessionId}/messages/{messageId}` - Delete AI chat message
|
||||
- `GET /ai-chat/logs` - Get user's AI chat logs
|
||||
- `GET /ai-chat/logs/{id}` - Get specific AI chat log
|
||||
|
||||
## Database Schema
|
||||
|
||||
### chat_sessions Table
|
||||
```sql
|
||||
CREATE TABLE chat_sessions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id VARCHAR(255) NOT NULL UNIQUE,
|
||||
user_id INTEGER NOT NULL,
|
||||
agent_id VARCHAR(255) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL DEFAULT 'Chat Session',
|
||||
message_count INTEGER DEFAULT 0,
|
||||
status VARCHAR(50) DEFAULT 'active',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
### chat_messages_new Table
|
||||
```sql
|
||||
CREATE TABLE chat_messages_new (
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id VARCHAR(255) NOT NULL,
|
||||
message_type VARCHAR(50) NOT NULL CHECK (message_type IN ('user', 'assistant')),
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
```
|
||||
|
||||
## Key Features Implemented
|
||||
|
||||
### 1. Session Management
|
||||
- Create, read, update, delete chat sessions
|
||||
- Session-based architecture with unique session IDs
|
||||
- User ownership validation
|
||||
- Message count tracking
|
||||
|
||||
### 2. Message Management
|
||||
- Create, read, update, delete messages within sessions
|
||||
- Support for user and assistant message types
|
||||
- Automatic message count updates
|
||||
- Cascade deletion when sessions are deleted
|
||||
|
||||
### 3. Combined Operations
|
||||
- Save complete chat history in one operation
|
||||
- Update existing sessions or create new ones
|
||||
- Bulk message operations
|
||||
|
||||
### 4. Security
|
||||
- User authentication required for all operations
|
||||
- User ownership validation for all resources
|
||||
- Proper error handling and validation
|
||||
|
||||
## Migration Instructions
|
||||
|
||||
### 1. Run Database Migration
|
||||
```bash
|
||||
# Option 1: Run the Go migration script
|
||||
go run scripts/migrate.go
|
||||
|
||||
# Option 2: Run SQL migration manually
|
||||
psql -d your_database -f migrations/001_create_chat_history_tables.sql
|
||||
```
|
||||
|
||||
### 2. Update Application
|
||||
The application has been updated to include:
|
||||
- New modules in `main.go`
|
||||
- Updated router configuration
|
||||
- New API endpoints
|
||||
|
||||
### 3. Test the Implementation
|
||||
```bash
|
||||
# Start the application
|
||||
go run main.go
|
||||
|
||||
# Test endpoints
|
||||
curl -X GET "http://localhost:8080/chat-history/sessions" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN"
|
||||
|
||||
curl -X POST "http://localhost:8080/chat-history/save" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"user_id": 1,
|
||||
"agent_id": "agent-123",
|
||||
"session_id": "session-456",
|
||||
"title": "Test Chat",
|
||||
"messages": [
|
||||
{"type": "user", "content": "Hello"},
|
||||
{"type": "assistant", "content": "Hi there!"}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
## Differences from Old Code
|
||||
|
||||
### Architecture Changes
|
||||
- **Language**: Converted from TypeScript/JavaScript to Go
|
||||
- **Framework**: Converted from Next.js API routes to Fiber (Go web framework)
|
||||
- **Database**: Converted from SQLite to PostgreSQL (via GORM)
|
||||
- **Structure**: Implemented clean architecture with repository, service, and controller layers
|
||||
|
||||
### API Changes
|
||||
- **Authentication**: Added Bearer token authentication
|
||||
- **Validation**: Added comprehensive request validation
|
||||
- **Error Handling**: Standardized error responses
|
||||
- **Pagination**: Added pagination support for list endpoints
|
||||
|
||||
### Database Changes
|
||||
- **Schema**: Adapted SQLite schema to PostgreSQL
|
||||
- **Relationships**: Added proper foreign key relationships
|
||||
- **Indexes**: Added performance indexes
|
||||
- **Constraints**: Added data validation constraints
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
1. **Real-time Features**: Add WebSocket support for real-time chat
|
||||
2. **File Attachments**: Support for file uploads in messages
|
||||
3. **Message Search**: Full-text search across messages
|
||||
4. **Analytics**: Chat analytics and reporting
|
||||
5. **Export**: Export chat history to various formats
|
||||
6. **Archiving**: Automatic archiving of old sessions
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Migration Errors**: Ensure database connection is properly configured
|
||||
2. **Authentication Errors**: Verify Bearer token is valid and user exists
|
||||
3. **Validation Errors**: Check request payload matches expected schema
|
||||
4. **Permission Errors**: Ensure user owns the resource being accessed
|
||||
|
||||
### Debug Mode
|
||||
Enable debug logging by setting the log level to debug in your configuration.
|
||||
|
||||
## Support
|
||||
|
||||
For issues or questions regarding this implementation, please refer to the application logs or contact the development team.
|
||||
|
|
@ -6,18 +6,19 @@ import (
|
|||
)
|
||||
|
||||
type ChatMessages struct {
|
||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||
ConversationID uint `json:"conversation_id" gorm:"type:int4;not null;index"`
|
||||
SenderID uint `json:"sender_id" gorm:"type:int4;not null;index"`
|
||||
MessageText *string `json:"message_text" gorm:"type:text"`
|
||||
MessageType string `json:"message_type" gorm:"type:varchar;not null;default:'text'"`
|
||||
FileURL *string `json:"file_url" gorm:"type:varchar"`
|
||||
FileName *string `json:"file_name" gorm:"type:varchar"`
|
||||
FileSize *int64 `json:"file_size" gorm:"type:bigint"`
|
||||
IsRead bool `json:"is_read" gorm:"default:false"`
|
||||
IsActive bool `json:"is_active" gorm:"type:bool;default:true"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
// Conversation *Conversations `json:"conversation" gorm:"foreignKey:ConversationID;references:ID"`
|
||||
Sender *users.Users `json:"sender" gorm:"foreignKey:SenderID;references:ID"`
|
||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||
ChatSessionID uint `json:"chat_session_id" gorm:"type:int4;not null;index"`
|
||||
SenderID uint `json:"sender_id" gorm:"type:int4;not null;index"`
|
||||
Message string `json:"message" gorm:"type:text;not null"`
|
||||
MessageType string `json:"message_type" gorm:"type:varchar(20);not null;default:'text';check:message_type IN ('text', 'image', 'file', 'user', 'assistant')"` // 'text', 'image', 'file', 'user', 'assistant'
|
||||
IsEdited bool `json:"is_edited" gorm:"default:false"`
|
||||
EditedAt *time.Time `json:"edited_at"`
|
||||
IsDeleted bool `json:"is_deleted" gorm:"default:false"`
|
||||
DeletedAt *time.Time `json:"deleted_at"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
|
||||
// Relationships
|
||||
ChatSession *ChatSessions `json:"chat_session" gorm:"foreignKey:ChatSessionID;references:ID"`
|
||||
Sender *users.Users `json:"sender" gorm:"foreignKey:SenderID;references:ID"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +0,0 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type ChatMessagesNew struct {
|
||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||
SessionID string `json:"session_id" gorm:"type:varchar;not null;index"`
|
||||
MessageType string `json:"message_type" gorm:"type:varchar;not null;check:message_type IN ('user', 'assistant')"`
|
||||
Content string `json:"content" gorm:"type:text;not null"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
Session *ChatSessions `json:"session" gorm:"foreignKey:SessionID;references:SessionID"`
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"narasi-ahli-be/app/database/entity/users"
|
||||
"time"
|
||||
)
|
||||
|
||||
type ChatParticipants struct {
|
||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||
ChatSessionID uint `json:"chat_session_id" gorm:"type:int4;not null;index"`
|
||||
UserID uint `json:"user_id" gorm:"type:int4;not null;index"`
|
||||
JoinedAt time.Time `json:"joined_at" gorm:"default:now()"`
|
||||
LeftAt *time.Time `json:"left_at"`
|
||||
IsActive bool `json:"is_active" gorm:"default:true"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
|
||||
// Relationships
|
||||
ChatSession *ChatSessions `json:"chat_session" gorm:"foreignKey:ChatSessionID;references:ID"`
|
||||
User *users.Users `json:"user" gorm:"foreignKey:UserID;references:ID"`
|
||||
}
|
||||
|
|
@ -6,14 +6,15 @@ import (
|
|||
)
|
||||
|
||||
type ChatSessions struct {
|
||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||
SessionID string `json:"session_id" gorm:"type:varchar;not null;unique;index"`
|
||||
UserID uint `json:"user_id" gorm:"type:int4;not null;index"`
|
||||
AgentID string `json:"agent_id" gorm:"type:varchar;not null"`
|
||||
Title string `json:"title" gorm:"type:varchar;not null"`
|
||||
MessageCount int `json:"message_count" gorm:"type:int4;default:0"`
|
||||
IsActive bool `json:"is_active" gorm:"type:bool;default:true"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
User *users.Users `json:"user" gorm:"foreignKey:UserID;references:ID"`
|
||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
||||
Name *string `json:"name" gorm:"type:varchar(255)"` // null for personal chat, filled for group chat
|
||||
Type string `json:"type" gorm:"type:varchar(20);not null;default:'personal'"` // 'personal' or 'group'
|
||||
CreatedBy uint `json:"created_by" gorm:"type:int4;not null;index"`
|
||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
||||
|
||||
// Relationships
|
||||
Creator *users.Users `json:"creator" gorm:"foreignKey:CreatedBy;references:ID"`
|
||||
Participants []*ChatParticipants `json:"participants" gorm:"foreignKey:ChatSessionID;references:ID"`
|
||||
Messages []*ChatMessages `json:"messages" gorm:"foreignKey:ChatSessionID;references:ID"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,8 @@ func Models() []interface{} {
|
|||
entity.ResearchJournals{},
|
||||
entity.Conversations{},
|
||||
entity.ChatMessages{},
|
||||
entity.ChatParticipants{},
|
||||
entity.ChatSessions{},
|
||||
entity.AIChatSessions{},
|
||||
entity.AIChatMessages{},
|
||||
entity.AIChatLogs{},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
package chat
|
||||
|
||||
import (
|
||||
"narasi-ahli-be/app/module/chat/controller"
|
||||
"narasi-ahli-be/app/module/chat/repository"
|
||||
"narasi-ahli-be/app/module/chat/service"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/fx"
|
||||
)
|
||||
|
||||
// struct of ChatRouter
|
||||
type ChatRouter struct {
|
||||
App fiber.Router
|
||||
Controller *controller.Controller
|
||||
}
|
||||
|
||||
// register bulky of Chat module
|
||||
var NewChatModule = fx.Options(
|
||||
// register repository of Chat module
|
||||
fx.Provide(repository.NewChatRepository),
|
||||
|
||||
// register service of Chat module
|
||||
fx.Provide(service.NewChatService),
|
||||
|
||||
// register controller of Chat module
|
||||
fx.Provide(controller.NewController),
|
||||
|
||||
// register router of Chat module
|
||||
fx.Provide(NewChatRouter),
|
||||
)
|
||||
|
||||
// init ChatRouter
|
||||
func NewChatRouter(fiber *fiber.App, controller *controller.Controller) *ChatRouter {
|
||||
return &ChatRouter{
|
||||
App: fiber,
|
||||
Controller: controller,
|
||||
}
|
||||
}
|
||||
|
||||
// register routes of Chat module
|
||||
func (_i *ChatRouter) RegisterChatRoutes() {
|
||||
// define controllers
|
||||
chatController := _i.Controller.Chat
|
||||
|
||||
// define routes
|
||||
_i.App.Route("/chat", func(router fiber.Router) {
|
||||
// Chat Session routes
|
||||
router.Route("/sessions", func(sessionRouter fiber.Router) {
|
||||
sessionRouter.Get("/", chatController.GetAllChatSessions)
|
||||
sessionRouter.Get("/:id", chatController.GetChatSessionByID)
|
||||
sessionRouter.Post("/", chatController.CreateChatSession)
|
||||
sessionRouter.Put("/:id", chatController.UpdateChatSession)
|
||||
sessionRouter.Delete("/:id", chatController.DeleteChatSession)
|
||||
|
||||
// Chat Participant routes
|
||||
sessionRouter.Post("/:chatSessionId/participants", chatController.AddParticipantToChat)
|
||||
sessionRouter.Delete("/:chatSessionId/participants", chatController.RemoveParticipantFromChat)
|
||||
})
|
||||
|
||||
// Chat Message routes
|
||||
router.Route("/messages", func(messageRouter fiber.Router) {
|
||||
messageRouter.Get("/", chatController.GetAllChatMessages)
|
||||
messageRouter.Get("/:id", chatController.GetChatMessageByID)
|
||||
messageRouter.Post("/", chatController.CreateChatMessage)
|
||||
messageRouter.Put("/:id", chatController.UpdateChatMessage)
|
||||
messageRouter.Delete("/:id", chatController.DeleteChatMessage)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,474 @@
|
|||
package controller
|
||||
|
||||
import (
|
||||
"narasi-ahli-be/app/module/chat/request"
|
||||
"narasi-ahli-be/app/module/chat/service"
|
||||
"narasi-ahli-be/utils/paginator"
|
||||
utilRes "narasi-ahli-be/utils/response"
|
||||
utilVal "narasi-ahli-be/utils/validator"
|
||||
"strconv"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
type chatController struct {
|
||||
chatService service.ChatService
|
||||
}
|
||||
|
||||
type ChatController interface {
|
||||
// Chat Session endpoints
|
||||
GetAllChatSessions(c *fiber.Ctx) error
|
||||
GetChatSessionByID(c *fiber.Ctx) error
|
||||
CreateChatSession(c *fiber.Ctx) error
|
||||
UpdateChatSession(c *fiber.Ctx) error
|
||||
DeleteChatSession(c *fiber.Ctx) error
|
||||
|
||||
// Chat Message endpoints
|
||||
GetAllChatMessages(c *fiber.Ctx) error
|
||||
GetChatMessageByID(c *fiber.Ctx) error
|
||||
CreateChatMessage(c *fiber.Ctx) error
|
||||
UpdateChatMessage(c *fiber.Ctx) error
|
||||
DeleteChatMessage(c *fiber.Ctx) error
|
||||
|
||||
// Chat Participant endpoints
|
||||
AddParticipantToChat(c *fiber.Ctx) error
|
||||
RemoveParticipantFromChat(c *fiber.Ctx) error
|
||||
}
|
||||
|
||||
func NewChatController(chatService service.ChatService) ChatController {
|
||||
return &chatController{
|
||||
chatService: chatService,
|
||||
}
|
||||
}
|
||||
|
||||
// GetAllChatSessions - Get all chat sessions for a user
|
||||
// @Summary Get all chat sessions
|
||||
// @Description API for getting all chat sessions for authenticated user
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param type query string false "Chat type (personal or group)"
|
||||
// @Param req query paginator.Pagination false "pagination parameters"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/sessions [get]
|
||||
func (_i *chatController) GetAllChatSessions(c *fiber.Ctx) error {
|
||||
paginate, err := paginator.Paginate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
reqContext := request.ChatSessionQueryRequestContext{
|
||||
Type: c.Query("type"),
|
||||
}
|
||||
req := reqContext.ToParamRequest()
|
||||
req.Pagination = paginate
|
||||
|
||||
chatSessions, paging, err := _i.chatService.GetAllChatSessions(authToken, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat sessions successfully retrieved"},
|
||||
Data: chatSessions,
|
||||
Meta: paging,
|
||||
})
|
||||
}
|
||||
|
||||
// GetChatSessionByID - Get one chat session
|
||||
// @Summary Get one chat session
|
||||
// @Description API for getting one chat session
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param id path int true "Chat Session ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/sessions/{id} [get]
|
||||
func (_i *chatController) GetChatSessionByID(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
chatSession, err := _i.chatService.GetChatSessionByID(authToken, uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat session successfully retrieved"},
|
||||
Data: chatSession,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateChatSession - Create chat session
|
||||
// @Summary Create chat session
|
||||
// @Description API for creating a new chat session (personal or group)
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param payload body request.ChatSessionCreateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/sessions [post]
|
||||
func (_i *chatController) CreateChatSession(c *fiber.Ctx) error {
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
req := new(request.ChatSessionCreateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataResult, err := _i.chatService.CreateChatSession(authToken, *req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat session successfully created"},
|
||||
Data: dataResult,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateChatSession - Update chat session
|
||||
// @Summary Update chat session
|
||||
// @Description API for updating chat session (only creator can update)
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param id path int true "Chat Session ID"
|
||||
// @Param payload body request.ChatSessionUpdateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/sessions/{id} [put]
|
||||
func (_i *chatController) UpdateChatSession(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
req := new(request.ChatSessionUpdateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = _i.chatService.UpdateChatSession(authToken, uint(id), *req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat session successfully updated"},
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteChatSession - Delete chat session
|
||||
// @Summary Delete chat session
|
||||
// @Description API for deleting chat session (only creator can delete)
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param id path int true "Chat Session ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/sessions/{id} [delete]
|
||||
func (_i *chatController) DeleteChatSession(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
err = _i.chatService.DeleteChatSession(authToken, uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat session successfully deleted"},
|
||||
})
|
||||
}
|
||||
|
||||
// GetAllChatMessages - Get all messages in a chat session
|
||||
// @Summary Get all chat messages
|
||||
// @Description API for getting all messages in a specific chat session
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param chatSessionId query uint true "Chat Session ID"
|
||||
// @Param req query paginator.Pagination false "pagination parameters"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/messages [get]
|
||||
func (_i *chatController) GetAllChatMessages(c *fiber.Ctx) error {
|
||||
paginate, err := paginator.Paginate(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
reqContext := request.ChatMessageQueryRequestContext{
|
||||
ChatSessionID: c.Query("chatSessionId"),
|
||||
}
|
||||
req := reqContext.ToParamRequest()
|
||||
req.Pagination = paginate
|
||||
|
||||
chatMessages, paging, err := _i.chatService.GetAllChatMessages(authToken, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat messages successfully retrieved"},
|
||||
Data: chatMessages,
|
||||
Meta: paging,
|
||||
})
|
||||
}
|
||||
|
||||
// GetChatMessageByID - Get one chat message
|
||||
// @Summary Get one chat message
|
||||
// @Description API for getting one chat message
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param id path int true "Chat Message ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/messages/{id} [get]
|
||||
func (_i *chatController) GetChatMessageByID(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
chatMessage, err := _i.chatService.GetChatMessageByID(authToken, uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat message successfully retrieved"},
|
||||
Data: chatMessage,
|
||||
})
|
||||
}
|
||||
|
||||
// CreateChatMessage - Create chat message
|
||||
// @Summary Create chat message
|
||||
// @Description API for creating a new chat message
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param payload body request.ChatMessageCreateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/messages [post]
|
||||
func (_i *chatController) CreateChatMessage(c *fiber.Ctx) error {
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
req := new(request.ChatMessageCreateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dataResult, err := _i.chatService.CreateChatMessage(authToken, *req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat message successfully created"},
|
||||
Data: dataResult,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateChatMessage - Update chat message
|
||||
// @Summary Update chat message
|
||||
// @Description API for updating chat message (only sender can update)
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param id path int true "Chat Message ID"
|
||||
// @Param payload body request.ChatMessageUpdateRequest true "Required payload"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/messages/{id} [put]
|
||||
func (_i *chatController) UpdateChatMessage(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
req := new(request.ChatMessageUpdateRequest)
|
||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = _i.chatService.UpdateChatMessage(authToken, uint(id), *req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat message successfully updated"},
|
||||
})
|
||||
}
|
||||
|
||||
// DeleteChatMessage - Delete chat message
|
||||
// @Summary Delete chat message
|
||||
// @Description API for deleting chat message (only sender can delete)
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param id path int true "Chat Message ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/messages/{id} [delete]
|
||||
func (_i *chatController) DeleteChatMessage(c *fiber.Ctx) error {
|
||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
err = _i.chatService.DeleteChatMessage(authToken, uint(id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Chat message successfully deleted"},
|
||||
})
|
||||
}
|
||||
|
||||
// AddParticipantToChat - Add participant to chat session
|
||||
// @Summary Add participant to chat session
|
||||
// @Description API for adding a participant to a chat session (only creator can add)
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param chatSessionId path int true "Chat Session ID"
|
||||
// @Param participantUserId query uint true "Participant User ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/sessions/{chatSessionId}/participants [post]
|
||||
func (_i *chatController) AddParticipantToChat(c *fiber.Ctx) error {
|
||||
chatSessionId, err := strconv.ParseUint(c.Params("chatSessionId"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
participantUserId, err := strconv.ParseUint(c.Query("participantUserId"), 10, 0)
|
||||
if err != nil {
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: false,
|
||||
Messages: utilRes.Messages{"participantUserId parameter is required and must be a valid number"},
|
||||
})
|
||||
}
|
||||
|
||||
err = _i.chatService.AddParticipantToChat(authToken, uint(chatSessionId), uint(participantUserId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Participant successfully added to chat session"},
|
||||
})
|
||||
}
|
||||
|
||||
// RemoveParticipantFromChat - Remove participant from chat session
|
||||
// @Summary Remove participant from chat session
|
||||
// @Description API for removing a participant from a chat session (creator can remove anyone, user can remove themselves)
|
||||
// @Tags Chat
|
||||
// @Security Bearer
|
||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
||||
// @Param chatSessionId path int true "Chat Session ID"
|
||||
// @Param participantUserId query uint true "Participant User ID"
|
||||
// @Success 200 {object} response.Response
|
||||
// @Failure 400 {object} response.BadRequestError
|
||||
// @Failure 401 {object} response.UnauthorizedError
|
||||
// @Failure 500 {object} response.InternalServerError
|
||||
// @Router /chat/sessions/{chatSessionId}/participants [delete]
|
||||
func (_i *chatController) RemoveParticipantFromChat(c *fiber.Ctx) error {
|
||||
chatSessionId, err := strconv.ParseUint(c.Params("chatSessionId"), 10, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authToken := c.Get("Authorization")
|
||||
|
||||
participantUserId, err := strconv.ParseUint(c.Query("participantUserId"), 10, 0)
|
||||
if err != nil {
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: false,
|
||||
Messages: utilRes.Messages{"participantUserId parameter is required and must be a valid number"},
|
||||
})
|
||||
}
|
||||
|
||||
err = _i.chatService.RemoveParticipantFromChat(authToken, uint(chatSessionId), uint(participantUserId))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return utilRes.Resp(c, utilRes.Response{
|
||||
Success: true,
|
||||
Messages: utilRes.Messages{"Participant successfully removed from chat session"},
|
||||
})
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package controller
|
||||
|
||||
import "narasi-ahli-be/app/module/chat/service"
|
||||
|
||||
type Controller struct {
|
||||
Chat ChatController
|
||||
}
|
||||
|
||||
func NewController(ChatService service.ChatService) *Controller {
|
||||
return &Controller{
|
||||
Chat: NewChatController(ChatService),
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
package mapper
|
||||
|
||||
import (
|
||||
"narasi-ahli-be/app/database/entity"
|
||||
"narasi-ahli-be/app/module/chat/response"
|
||||
)
|
||||
|
||||
// Chat Session Mapper
|
||||
func ChatSessionResponseMapper(chatSession *entity.ChatSessions) *response.ChatSessionResponse {
|
||||
result := &response.ChatSessionResponse{
|
||||
ID: chatSession.ID,
|
||||
Name: chatSession.Name,
|
||||
Type: chatSession.Type,
|
||||
CreatedBy: chatSession.CreatedBy,
|
||||
CreatedAt: chatSession.CreatedAt,
|
||||
UpdatedAt: chatSession.UpdatedAt,
|
||||
}
|
||||
|
||||
if chatSession.Creator != nil {
|
||||
result.Creator = &response.UserBasicInfo{
|
||||
ID: chatSession.Creator.ID,
|
||||
Username: chatSession.Creator.Username,
|
||||
Fullname: chatSession.Creator.Fullname,
|
||||
Email: chatSession.Creator.Email,
|
||||
}
|
||||
}
|
||||
|
||||
// Map participants
|
||||
if len(chatSession.Participants) > 0 {
|
||||
for _, participant := range chatSession.Participants {
|
||||
if participant.IsActive {
|
||||
result.Participants = append(result.Participants, ChatParticipantResponseMapper(participant))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Map last message
|
||||
if len(chatSession.Messages) > 0 {
|
||||
// Find the latest message that is not deleted
|
||||
var lastMessage *entity.ChatMessages
|
||||
for _, message := range chatSession.Messages {
|
||||
if !message.IsDeleted && (lastMessage == nil || message.CreatedAt.After(lastMessage.CreatedAt)) {
|
||||
lastMessage = message
|
||||
}
|
||||
}
|
||||
if lastMessage != nil {
|
||||
result.LastMessage = ChatMessageResponseMapper(lastMessage)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Chat Message Mapper
|
||||
func ChatMessageResponseMapper(chatMessage *entity.ChatMessages) *response.ChatMessageResponse {
|
||||
result := &response.ChatMessageResponse{
|
||||
ID: chatMessage.ID,
|
||||
ChatSessionID: chatMessage.ChatSessionID,
|
||||
SenderID: chatMessage.SenderID,
|
||||
Message: chatMessage.Message,
|
||||
MessageType: chatMessage.MessageType,
|
||||
IsEdited: chatMessage.IsEdited,
|
||||
EditedAt: chatMessage.EditedAt,
|
||||
IsDeleted: chatMessage.IsDeleted,
|
||||
DeletedAt: chatMessage.DeletedAt,
|
||||
CreatedAt: chatMessage.CreatedAt,
|
||||
UpdatedAt: chatMessage.UpdatedAt,
|
||||
}
|
||||
|
||||
if chatMessage.Sender != nil {
|
||||
result.Sender = &response.UserBasicInfo{
|
||||
ID: chatMessage.Sender.ID,
|
||||
Username: chatMessage.Sender.Username,
|
||||
Fullname: chatMessage.Sender.Fullname,
|
||||
Email: chatMessage.Sender.Email,
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Chat Participant Mapper
|
||||
func ChatParticipantResponseMapper(chatParticipant *entity.ChatParticipants) *response.ChatParticipantResponse {
|
||||
result := &response.ChatParticipantResponse{
|
||||
ID: chatParticipant.ID,
|
||||
ChatSessionID: chatParticipant.ChatSessionID,
|
||||
UserID: chatParticipant.UserID,
|
||||
JoinedAt: chatParticipant.JoinedAt,
|
||||
LeftAt: chatParticipant.LeftAt,
|
||||
IsActive: chatParticipant.IsActive,
|
||||
CreatedAt: chatParticipant.CreatedAt,
|
||||
UpdatedAt: chatParticipant.UpdatedAt,
|
||||
}
|
||||
|
||||
if chatParticipant.User != nil {
|
||||
result.User = &response.UserBasicInfo{
|
||||
ID: chatParticipant.User.ID,
|
||||
Username: chatParticipant.User.Username,
|
||||
Fullname: chatParticipant.User.Fullname,
|
||||
Email: chatParticipant.User.Email,
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
package repository
|
||||
|
||||
import (
|
||||
"narasi-ahli-be/app/database"
|
||||
"narasi-ahli-be/app/database/entity"
|
||||
"narasi-ahli-be/app/module/chat/request"
|
||||
"narasi-ahli-be/utils/paginator"
|
||||
)
|
||||
|
||||
type chatRepository struct {
|
||||
DB *database.Database
|
||||
}
|
||||
|
||||
type ChatRepository interface {
|
||||
// Chat Session methods
|
||||
GetAllChatSessions(userId uint, req request.ChatSessionQueryRequest) (chatSessions []*entity.ChatSessions, paging paginator.Pagination, err error)
|
||||
FindChatSessionByID(id uint) (chatSession *entity.ChatSessions, err error)
|
||||
FindChatSessionByUserAndID(userId uint, id uint) (chatSession *entity.ChatSessions, err error)
|
||||
CreateChatSession(chatSession *entity.ChatSessions) (result *entity.ChatSessions, err error)
|
||||
UpdateChatSession(id uint, chatSession *entity.ChatSessions) (err error)
|
||||
DeleteChatSession(id uint) (err error)
|
||||
|
||||
// Chat Message methods
|
||||
GetAllChatMessages(req request.ChatMessageQueryRequest) (chatMessages []*entity.ChatMessages, paging paginator.Pagination, err error)
|
||||
FindChatMessageByID(id uint) (chatMessage *entity.ChatMessages, err error)
|
||||
FindChatMessageByUserAndID(userId uint, id uint) (chatMessage *entity.ChatMessages, err error)
|
||||
CreateChatMessage(chatMessage *entity.ChatMessages) (result *entity.ChatMessages, err error)
|
||||
UpdateChatMessage(id uint, chatMessage *entity.ChatMessages) (err error)
|
||||
DeleteChatMessage(id uint) (err error)
|
||||
|
||||
// Chat Participant methods
|
||||
CreateChatParticipant(chatParticipant *entity.ChatParticipants) (result *entity.ChatParticipants, err error)
|
||||
FindChatParticipantsBySessionID(chatSessionID uint) (participants []*entity.ChatParticipants, err error)
|
||||
UpdateChatParticipant(id uint, chatParticipant *entity.ChatParticipants) (err error)
|
||||
DeleteChatParticipant(id uint) (err error)
|
||||
|
||||
// Utility methods
|
||||
FindPersonalChatSession(userId1 uint, userId2 uint) (chatSession *entity.ChatSessions, err error)
|
||||
CheckUserInChatSession(userId uint, chatSessionID uint) (isParticipant bool, err error)
|
||||
}
|
||||
|
||||
func NewChatRepository(db *database.Database) ChatRepository {
|
||||
return &chatRepository{
|
||||
DB: db,
|
||||
}
|
||||
}
|
||||
|
||||
// Chat Session Repository Methods
|
||||
func (_i *chatRepository) GetAllChatSessions(userId uint, req request.ChatSessionQueryRequest) (chatSessions []*entity.ChatSessions, paging paginator.Pagination, err error) {
|
||||
// Get chat sessions where user is a participant
|
||||
query := _i.DB.DB.Model(&entity.ChatSessions{}).
|
||||
Joins("INNER JOIN chat_participants cp ON chat_sessions.id = cp.chat_session_id").
|
||||
Where("cp.user_id = ? AND cp.is_active = true", userId)
|
||||
|
||||
// Apply filters
|
||||
if req.Type != nil {
|
||||
query = query.Where("chat_sessions.type = ?", *req.Type)
|
||||
}
|
||||
|
||||
// Include relationships
|
||||
query = query.Preload("Creator").
|
||||
Preload("Participants", "is_active = true").
|
||||
Preload("Participants.User").
|
||||
Preload("Messages", "is_deleted = false").
|
||||
Preload("Messages.Sender")
|
||||
|
||||
// Order by updated_at desc (most recent first)
|
||||
query = query.Order("chat_sessions.updated_at DESC")
|
||||
|
||||
// Apply pagination
|
||||
var count int64
|
||||
query.Count(&count)
|
||||
req.Pagination.Count = count
|
||||
req.Pagination = paginator.Paging(req.Pagination)
|
||||
|
||||
err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&chatSessions).Error
|
||||
paging = *req.Pagination
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) FindChatSessionByID(id uint) (chatSession *entity.ChatSessions, err error) {
|
||||
err = _i.DB.DB.Preload("Creator").
|
||||
Preload("Participants", "is_active = true").
|
||||
Preload("Participants.User").
|
||||
Preload("Messages", "is_deleted = false").
|
||||
Preload("Messages.Sender").
|
||||
First(&chatSession, id).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) FindChatSessionByUserAndID(userId uint, id uint) (chatSession *entity.ChatSessions, err error) {
|
||||
// Check if user is participant in this chat session
|
||||
var isParticipant bool
|
||||
err = _i.DB.DB.Table("chat_participants").
|
||||
Select("COUNT(*) > 0").
|
||||
Where("chat_session_id = ? AND user_id = ? AND is_active = true", id, userId).
|
||||
Scan(&isParticipant).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isParticipant {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
err = _i.DB.DB.Preload("Creator").
|
||||
Preload("Participants", "is_active = true").
|
||||
Preload("Participants.User").
|
||||
Preload("Messages", "is_deleted = false").
|
||||
Preload("Messages.Sender").
|
||||
First(&chatSession, id).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) CreateChatSession(chatSession *entity.ChatSessions) (result *entity.ChatSessions, err error) {
|
||||
err = _i.DB.DB.Create(chatSession).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Reload with relationships
|
||||
err = _i.DB.DB.Preload("Creator").
|
||||
Preload("Participants", "is_active = true").
|
||||
Preload("Participants.User").
|
||||
First(&result, chatSession.ID).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) UpdateChatSession(id uint, chatSession *entity.ChatSessions) (err error) {
|
||||
err = _i.DB.DB.Model(&entity.ChatSessions{}).Where("id = ?", id).Updates(chatSession).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) DeleteChatSession(id uint) (err error) {
|
||||
err = _i.DB.DB.Delete(&entity.ChatSessions{}, id).Error
|
||||
return
|
||||
}
|
||||
|
||||
// Chat Message Repository Methods
|
||||
func (_i *chatRepository) GetAllChatMessages(req request.ChatMessageQueryRequest) (chatMessages []*entity.ChatMessages, paging paginator.Pagination, err error) {
|
||||
// Check if user is participant in this chat session
|
||||
var isParticipant bool
|
||||
err = _i.DB.DB.Table("chat_participants").
|
||||
Select("COUNT(*) > 0").
|
||||
Where("chat_session_id = ? AND user_id = ? AND is_active = true", req.ChatSessionID, req.UserID).
|
||||
Scan(&isParticipant).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, paginator.Pagination{}, err
|
||||
}
|
||||
|
||||
if !isParticipant {
|
||||
return nil, paginator.Pagination{}, nil
|
||||
}
|
||||
|
||||
query := _i.DB.DB.Model(&entity.ChatMessages{}).Where("chat_session_id = ? AND is_deleted = false", req.ChatSessionID)
|
||||
|
||||
// Include relationships
|
||||
query = query.Preload("Sender")
|
||||
|
||||
// Order by created_at desc (most recent first)
|
||||
query = query.Order("created_at DESC")
|
||||
|
||||
// Apply pagination
|
||||
var count int64
|
||||
query.Count(&count)
|
||||
req.Pagination.Count = count
|
||||
req.Pagination = paginator.Paging(req.Pagination)
|
||||
|
||||
err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&chatMessages).Error
|
||||
paging = *req.Pagination
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) FindChatMessageByID(id uint) (chatMessage *entity.ChatMessages, err error) {
|
||||
err = _i.DB.DB.Preload("Sender").First(&chatMessage, id).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) FindChatMessageByUserAndID(userId uint, id uint) (chatMessage *entity.ChatMessages, err error) {
|
||||
// Check if user is participant in the chat session of this message
|
||||
var isParticipant bool
|
||||
err = _i.DB.DB.Table("chat_messages cm").
|
||||
Joins("INNER JOIN chat_participants cp ON cm.chat_session_id = cp.chat_session_id").
|
||||
Select("COUNT(*) > 0").
|
||||
Where("cm.id = ? AND cp.user_id = ? AND cp.is_active = true", id, userId).
|
||||
Scan(&isParticipant).Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !isParticipant {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
err = _i.DB.DB.Preload("Sender").First(&chatMessage, id).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) CreateChatMessage(chatMessage *entity.ChatMessages) (result *entity.ChatMessages, err error) {
|
||||
err = _i.DB.DB.Create(chatMessage).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Reload with relationships
|
||||
err = _i.DB.DB.Preload("Sender").First(&result, chatMessage.ID).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) UpdateChatMessage(id uint, chatMessage *entity.ChatMessages) (err error) {
|
||||
err = _i.DB.DB.Model(&entity.ChatMessages{}).Where("id = ?", id).Updates(chatMessage).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) DeleteChatMessage(id uint) (err error) {
|
||||
err = _i.DB.DB.Delete(&entity.ChatMessages{}, id).Error
|
||||
return
|
||||
}
|
||||
|
||||
// Chat Participant Repository Methods
|
||||
func (_i *chatRepository) CreateChatParticipant(chatParticipant *entity.ChatParticipants) (result *entity.ChatParticipants, err error) {
|
||||
err = _i.DB.DB.Create(chatParticipant).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Reload with relationships
|
||||
err = _i.DB.DB.Preload("User").First(&result, chatParticipant.ID).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) FindChatParticipantsBySessionID(chatSessionID uint) (participants []*entity.ChatParticipants, err error) {
|
||||
err = _i.DB.DB.Model(&entity.ChatParticipants{}).Where("chat_session_id = ? AND is_active = true", chatSessionID).
|
||||
Preload("User").Find(&participants).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) UpdateChatParticipant(id uint, chatParticipant *entity.ChatParticipants) (err error) {
|
||||
err = _i.DB.DB.Model(&entity.ChatParticipants{}).Where("id = ?", id).Updates(chatParticipant).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) DeleteChatParticipant(id uint) (err error) {
|
||||
err = _i.DB.DB.Delete(&entity.ChatParticipants{}, id).Error
|
||||
return
|
||||
}
|
||||
|
||||
// Utility Methods
|
||||
func (_i *chatRepository) FindPersonalChatSession(userId1 uint, userId2 uint) (chatSession *entity.ChatSessions, err error) {
|
||||
err = _i.DB.DB.Model(&entity.ChatSessions{}).
|
||||
Joins("INNER JOIN chat_participants cp1 ON chat_sessions.id = cp1.chat_session_id").
|
||||
Joins("INNER JOIN chat_participants cp2 ON chat_sessions.id = cp2.chat_session_id").
|
||||
Where("chat_sessions.type = 'personal' AND cp1.user_id = ? AND cp2.user_id = ? AND cp1.is_active = true AND cp2.is_active = true", userId1, userId2).
|
||||
Preload("Creator").
|
||||
Preload("Participants", "is_active = true").
|
||||
Preload("Participants.User").
|
||||
First(&chatSession).Error
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatRepository) CheckUserInChatSession(userId uint, chatSessionID uint) (isParticipant bool, err error) {
|
||||
err = _i.DB.DB.Table("chat_participants").
|
||||
Select("COUNT(*) > 0").
|
||||
Where("chat_session_id = ? AND user_id = ? AND is_active = true", chatSessionID, userId).
|
||||
Scan(&isParticipant).Error
|
||||
return
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
package request
|
||||
|
||||
import (
|
||||
"narasi-ahli-be/app/database/entity"
|
||||
"narasi-ahli-be/utils/paginator"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Chat Session Requests
|
||||
type ChatSessionQueryRequest struct {
|
||||
Type *string `json:"type"` // 'personal' or 'group'
|
||||
Pagination *paginator.Pagination `json:"pagination"`
|
||||
}
|
||||
|
||||
type ChatSessionCreateRequest struct {
|
||||
Name *string `json:"name" validate:"omitempty,min=2,max=255"` // null for personal chat
|
||||
Type string `json:"type" validate:"required,oneof=personal group"`
|
||||
UserIDs []uint `json:"userIds" validate:"required,min=1"` // participants (excluding creator)
|
||||
}
|
||||
|
||||
func (req ChatSessionCreateRequest) ToEntity(createdBy uint) *entity.ChatSessions {
|
||||
return &entity.ChatSessions{
|
||||
Name: req.Name,
|
||||
Type: req.Type,
|
||||
CreatedBy: createdBy,
|
||||
}
|
||||
}
|
||||
|
||||
type ChatSessionUpdateRequest struct {
|
||||
Name *string `json:"name" validate:"omitempty,min=2,max=255"`
|
||||
}
|
||||
|
||||
func (req ChatSessionUpdateRequest) ToEntity() *entity.ChatSessions {
|
||||
return &entity.ChatSessions{
|
||||
Name: req.Name,
|
||||
}
|
||||
}
|
||||
|
||||
type ChatSessionQueryRequestContext struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
func (req ChatSessionQueryRequestContext) ToParamRequest() ChatSessionQueryRequest {
|
||||
var request ChatSessionQueryRequest
|
||||
|
||||
if chatType := req.Type; chatType != "" {
|
||||
request.Type = &chatType
|
||||
}
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
// Chat Message Requests
|
||||
type ChatMessageQueryRequest struct {
|
||||
ChatSessionID uint `json:"chatSessionId" validate:"required"`
|
||||
UserID uint `json:"userId"` // Will be set in service layer
|
||||
Pagination *paginator.Pagination `json:"pagination"`
|
||||
}
|
||||
|
||||
type ChatMessageCreateRequest struct {
|
||||
ChatSessionID uint `json:"chatSessionId" validate:"required"`
|
||||
Message string `json:"message" validate:"required,min=1,max=1000"`
|
||||
MessageType string `json:"messageType" validate:"omitempty,oneof=text image file user assistant"`
|
||||
}
|
||||
|
||||
func (req ChatMessageCreateRequest) ToEntity(senderID uint) *entity.ChatMessages {
|
||||
messageType := req.MessageType
|
||||
if messageType == "" {
|
||||
messageType = "text"
|
||||
}
|
||||
|
||||
return &entity.ChatMessages{
|
||||
ChatSessionID: req.ChatSessionID,
|
||||
SenderID: senderID,
|
||||
Message: req.Message,
|
||||
MessageType: messageType,
|
||||
}
|
||||
}
|
||||
|
||||
type ChatMessageUpdateRequest struct {
|
||||
Message string `json:"message" validate:"required,min=1,max=1000"`
|
||||
}
|
||||
|
||||
func (req ChatMessageUpdateRequest) ToEntity() *entity.ChatMessages {
|
||||
return &entity.ChatMessages{
|
||||
Message: req.Message,
|
||||
IsEdited: true,
|
||||
EditedAt: &time.Time{},
|
||||
}
|
||||
}
|
||||
|
||||
type ChatMessageQueryRequestContext struct {
|
||||
ChatSessionID string `json:"chatSessionId"`
|
||||
}
|
||||
|
||||
func (req ChatMessageQueryRequestContext) ToParamRequest() ChatMessageQueryRequest {
|
||||
var request ChatMessageQueryRequest
|
||||
|
||||
if chatSessionId := req.ChatSessionID; chatSessionId != "" {
|
||||
chatSessionIdUint, err := strconv.ParseUint(chatSessionId, 10, 0)
|
||||
if err == nil {
|
||||
request.ChatSessionID = uint(chatSessionIdUint)
|
||||
}
|
||||
}
|
||||
|
||||
return request
|
||||
}
|
||||
|
||||
// Chat Participant Requests
|
||||
type ChatParticipantCreateRequest struct {
|
||||
ChatSessionID uint `json:"chatSessionId" validate:"required"`
|
||||
UserID uint `json:"userId" validate:"required"`
|
||||
}
|
||||
|
||||
func (req ChatParticipantCreateRequest) ToEntity() *entity.ChatParticipants {
|
||||
return &entity.ChatParticipants{
|
||||
ChatSessionID: req.ChatSessionID,
|
||||
UserID: req.UserID,
|
||||
IsActive: true,
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package response
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Chat Session Response
|
||||
type ChatSessionResponse struct {
|
||||
ID uint `json:"id"`
|
||||
Name *string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
CreatedBy uint `json:"createdBy"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Creator *UserBasicInfo `json:"creator,omitempty"`
|
||||
Participants []*ChatParticipantResponse `json:"participants,omitempty"`
|
||||
LastMessage *ChatMessageResponse `json:"lastMessage,omitempty"`
|
||||
UnreadCount int `json:"unreadCount"`
|
||||
}
|
||||
|
||||
// Chat Message Response
|
||||
type ChatMessageResponse struct {
|
||||
ID uint `json:"id"`
|
||||
ChatSessionID uint `json:"chatSessionId"`
|
||||
SenderID uint `json:"senderId"`
|
||||
Message string `json:"message"`
|
||||
MessageType string `json:"messageType"`
|
||||
IsEdited bool `json:"isEdited"`
|
||||
EditedAt *time.Time `json:"editedAt"`
|
||||
IsDeleted bool `json:"isDeleted"`
|
||||
DeletedAt *time.Time `json:"deletedAt"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
Sender *UserBasicInfo `json:"sender,omitempty"`
|
||||
}
|
||||
|
||||
// Chat Participant Response
|
||||
type ChatParticipantResponse struct {
|
||||
ID uint `json:"id"`
|
||||
ChatSessionID uint `json:"chatSessionId"`
|
||||
UserID uint `json:"userId"`
|
||||
JoinedAt time.Time `json:"joinedAt"`
|
||||
LeftAt *time.Time `json:"leftAt"`
|
||||
IsActive bool `json:"isActive"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
User *UserBasicInfo `json:"user,omitempty"`
|
||||
}
|
||||
|
||||
// User Basic Info (reused from work_history)
|
||||
type UserBasicInfo struct {
|
||||
ID uint `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Fullname string `json:"fullname"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
|
@ -0,0 +1,418 @@
|
|||
package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"narasi-ahli-be/app/database/entity"
|
||||
"narasi-ahli-be/app/module/chat/mapper"
|
||||
"narasi-ahli-be/app/module/chat/repository"
|
||||
"narasi-ahli-be/app/module/chat/request"
|
||||
"narasi-ahli-be/app/module/chat/response"
|
||||
usersRepository "narasi-ahli-be/app/module/users/repository"
|
||||
"narasi-ahli-be/utils/paginator"
|
||||
utilSvc "narasi-ahli-be/utils/service"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type chatService struct {
|
||||
Repo repository.ChatRepository
|
||||
UsersRepo usersRepository.UsersRepository
|
||||
Log zerolog.Logger
|
||||
}
|
||||
|
||||
type ChatService interface {
|
||||
// Chat Session methods
|
||||
GetAllChatSessions(authToken string, req request.ChatSessionQueryRequest) (chatSessions []*response.ChatSessionResponse, paging paginator.Pagination, err error)
|
||||
GetChatSessionByID(authToken string, id uint) (chatSession *response.ChatSessionResponse, err error)
|
||||
CreateChatSession(authToken string, req request.ChatSessionCreateRequest) (chatSession *response.ChatSessionResponse, err error)
|
||||
UpdateChatSession(authToken string, id uint, req request.ChatSessionUpdateRequest) (err error)
|
||||
DeleteChatSession(authToken string, id uint) error
|
||||
|
||||
// Chat Message methods
|
||||
GetAllChatMessages(authToken string, req request.ChatMessageQueryRequest) (chatMessages []*response.ChatMessageResponse, paging paginator.Pagination, err error)
|
||||
GetChatMessageByID(authToken string, id uint) (chatMessage *response.ChatMessageResponse, err error)
|
||||
CreateChatMessage(authToken string, req request.ChatMessageCreateRequest) (chatMessage *response.ChatMessageResponse, err error)
|
||||
UpdateChatMessage(authToken string, id uint, req request.ChatMessageUpdateRequest) (err error)
|
||||
DeleteChatMessage(authToken string, id uint) error
|
||||
|
||||
// Chat Participant methods
|
||||
AddParticipantToChat(authToken string, chatSessionID uint, participantUserID uint) error
|
||||
RemoveParticipantFromChat(authToken string, chatSessionID uint, participantUserID uint) error
|
||||
}
|
||||
|
||||
func NewChatService(repo repository.ChatRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger) ChatService {
|
||||
return &chatService{
|
||||
Repo: repo,
|
||||
UsersRepo: usersRepo,
|
||||
Log: log,
|
||||
}
|
||||
}
|
||||
|
||||
// Chat Session Service Methods
|
||||
func (_i *chatService) GetAllChatSessions(authToken string, req request.ChatSessionQueryRequest) (chatSessions []*response.ChatSessionResponse, paging paginator.Pagination, err error) {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return nil, paginator.Pagination{}, errors.New("user not found")
|
||||
}
|
||||
|
||||
results, paging, err := _i.Repo.GetAllChatSessions(userInfo.ID, req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
chatSessions = append(chatSessions, mapper.ChatSessionResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatService) GetChatSessionByID(authToken string, id uint) (chatSession *response.ChatSessionResponse, err error) {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
|
||||
result, err := _i.Repo.FindChatSessionByUserAndID(userInfo.ID, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result == nil {
|
||||
return nil, errors.New("chat session not found or access denied")
|
||||
}
|
||||
|
||||
return mapper.ChatSessionResponseMapper(result), nil
|
||||
}
|
||||
|
||||
func (_i *chatService) CreateChatSession(authToken string, req request.ChatSessionCreateRequest) (chatSession *response.ChatSessionResponse, err error) {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
|
||||
_i.Log.Info().Interface("data", req).Msg("Creating chat session")
|
||||
|
||||
// Validate business rules
|
||||
if req.Type == "personal" && len(req.UserIDs) != 1 {
|
||||
return nil, errors.New("personal chat must have exactly one other participant")
|
||||
}
|
||||
if req.Type == "group" && len(req.UserIDs) < 1 {
|
||||
return nil, errors.New("group chat must have at least one participant")
|
||||
}
|
||||
|
||||
// Check if personal chat already exists
|
||||
if req.Type == "personal" {
|
||||
existingChat, err := _i.Repo.FindPersonalChatSession(userInfo.ID, req.UserIDs[0])
|
||||
if err == nil && existingChat != nil {
|
||||
return mapper.ChatSessionResponseMapper(existingChat), nil
|
||||
}
|
||||
}
|
||||
|
||||
// Validate all user IDs exist
|
||||
for _, userID := range req.UserIDs {
|
||||
user, err := _i.UsersRepo.FindOne(userID)
|
||||
if err != nil || user == nil {
|
||||
return nil, errors.New("invalid user ID: " + string(rune(userID)))
|
||||
}
|
||||
}
|
||||
|
||||
// Create chat session
|
||||
entity := req.ToEntity(userInfo.ID)
|
||||
result, err := _i.Repo.CreateChatSession(entity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add creator as participant
|
||||
creatorParticipant := &request.ChatParticipantCreateRequest{
|
||||
ChatSessionID: result.ID,
|
||||
UserID: userInfo.ID,
|
||||
}
|
||||
_, err = _i.Repo.CreateChatParticipant(creatorParticipant.ToEntity())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Add other participants
|
||||
for _, userID := range req.UserIDs {
|
||||
participant := &request.ChatParticipantCreateRequest{
|
||||
ChatSessionID: result.ID,
|
||||
UserID: userID,
|
||||
}
|
||||
_, err = _i.Repo.CreateChatParticipant(participant.ToEntity())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Reload with all relationships
|
||||
finalResult, err := _i.Repo.FindChatSessionByID(result.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapper.ChatSessionResponseMapper(finalResult), nil
|
||||
}
|
||||
|
||||
func (_i *chatService) UpdateChatSession(authToken string, id uint, req request.ChatSessionUpdateRequest) (err error) {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
_i.Log.Info().Interface("data", req).Msg("Updating chat session")
|
||||
|
||||
// Check if chat session exists and user has access
|
||||
existing, err := _i.Repo.FindChatSessionByUserAndID(userInfo.ID, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing == nil {
|
||||
return errors.New("chat session not found or access denied")
|
||||
}
|
||||
|
||||
// Only creator can update chat session
|
||||
if existing.CreatedBy != userInfo.ID {
|
||||
return errors.New("only chat creator can update chat session")
|
||||
}
|
||||
|
||||
entity := req.ToEntity()
|
||||
return _i.Repo.UpdateChatSession(id, entity)
|
||||
}
|
||||
|
||||
func (_i *chatService) DeleteChatSession(authToken string, id uint) error {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
_i.Log.Info().Uint("userId", userInfo.ID).Uint("id", id).Msg("Deleting chat session")
|
||||
|
||||
// Check if chat session exists and user has access
|
||||
existing, err := _i.Repo.FindChatSessionByUserAndID(userInfo.ID, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing == nil {
|
||||
return errors.New("chat session not found or access denied")
|
||||
}
|
||||
|
||||
// Only creator can delete chat session
|
||||
if existing.CreatedBy != userInfo.ID {
|
||||
return errors.New("only chat creator can delete chat session")
|
||||
}
|
||||
|
||||
return _i.Repo.DeleteChatSession(id)
|
||||
}
|
||||
|
||||
// Chat Message Service Methods
|
||||
func (_i *chatService) GetAllChatMessages(authToken string, req request.ChatMessageQueryRequest) (chatMessages []*response.ChatMessageResponse, paging paginator.Pagination, err error) {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return nil, paginator.Pagination{}, errors.New("user not found")
|
||||
}
|
||||
|
||||
// Set user ID in request for repository
|
||||
req.UserID = userInfo.ID
|
||||
|
||||
results, paging, err := _i.Repo.GetAllChatMessages(req)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
chatMessages = append(chatMessages, mapper.ChatMessageResponseMapper(result))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (_i *chatService) GetChatMessageByID(authToken string, id uint) (chatMessage *response.ChatMessageResponse, err error) {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
|
||||
result, err := _i.Repo.FindChatMessageByUserAndID(userInfo.ID, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if result == nil {
|
||||
return nil, errors.New("chat message not found or access denied")
|
||||
}
|
||||
|
||||
return mapper.ChatMessageResponseMapper(result), nil
|
||||
}
|
||||
|
||||
func (_i *chatService) CreateChatMessage(authToken string, req request.ChatMessageCreateRequest) (chatMessage *response.ChatMessageResponse, err error) {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return nil, errors.New("user not found")
|
||||
}
|
||||
|
||||
_i.Log.Info().Interface("data", req).Msg("Creating chat message")
|
||||
|
||||
// Check if user is participant in the chat session
|
||||
isParticipant, err := _i.Repo.CheckUserInChatSession(userInfo.ID, req.ChatSessionID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !isParticipant {
|
||||
return nil, errors.New("user is not a participant in this chat session")
|
||||
}
|
||||
|
||||
entity := req.ToEntity(userInfo.ID)
|
||||
result, err := _i.Repo.CreateChatMessage(entity)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapper.ChatMessageResponseMapper(result), nil
|
||||
}
|
||||
|
||||
func (_i *chatService) UpdateChatMessage(authToken string, id uint, req request.ChatMessageUpdateRequest) (err error) {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
_i.Log.Info().Interface("data", req).Msg("Updating chat message")
|
||||
|
||||
// Check if message exists and user has access
|
||||
existing, err := _i.Repo.FindChatMessageByUserAndID(userInfo.ID, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing == nil {
|
||||
return errors.New("chat message not found or access denied")
|
||||
}
|
||||
|
||||
// Only sender can update message
|
||||
if existing.SenderID != userInfo.ID {
|
||||
return errors.New("only message sender can update message")
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
entity := req.ToEntity()
|
||||
entity.EditedAt = &now
|
||||
return _i.Repo.UpdateChatMessage(id, entity)
|
||||
}
|
||||
|
||||
func (_i *chatService) DeleteChatMessage(authToken string, id uint) error {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
_i.Log.Info().Uint("userId", userInfo.ID).Uint("id", id).Msg("Deleting chat message")
|
||||
|
||||
// Check if message exists and user has access
|
||||
existing, err := _i.Repo.FindChatMessageByUserAndID(userInfo.ID, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing == nil {
|
||||
return errors.New("chat message not found or access denied")
|
||||
}
|
||||
|
||||
// Only sender can delete message
|
||||
if existing.SenderID != userInfo.ID {
|
||||
return errors.New("only message sender can delete message")
|
||||
}
|
||||
|
||||
return _i.Repo.DeleteChatMessage(id)
|
||||
}
|
||||
|
||||
// Chat Participant Service Methods
|
||||
func (_i *chatService) AddParticipantToChat(authToken string, chatSessionID uint, participantUserID uint) error {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
_i.Log.Info().Uint("userId", userInfo.ID).Uint("chatSessionID", chatSessionID).Uint("participantUserID", participantUserID).Msg("Adding participant to chat")
|
||||
|
||||
// Check if user has access to chat session
|
||||
existing, err := _i.Repo.FindChatSessionByUserAndID(userInfo.ID, chatSessionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing == nil {
|
||||
return errors.New("chat session not found or access denied")
|
||||
}
|
||||
|
||||
// Only creator can add participants
|
||||
if existing.CreatedBy != userInfo.ID {
|
||||
return errors.New("only chat creator can add participants")
|
||||
}
|
||||
|
||||
// Validate participant user exists
|
||||
user, err := _i.UsersRepo.FindOne(participantUserID)
|
||||
if err != nil || user == nil {
|
||||
return errors.New("invalid user ID")
|
||||
}
|
||||
|
||||
// Check if user is already a participant
|
||||
isParticipant, err := _i.Repo.CheckUserInChatSession(participantUserID, chatSessionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isParticipant {
|
||||
return errors.New("user is already a participant in this chat")
|
||||
}
|
||||
|
||||
participant := &request.ChatParticipantCreateRequest{
|
||||
ChatSessionID: chatSessionID,
|
||||
UserID: participantUserID,
|
||||
}
|
||||
_, err = _i.Repo.CreateChatParticipant(participant.ToEntity())
|
||||
return err
|
||||
}
|
||||
|
||||
func (_i *chatService) RemoveParticipantFromChat(authToken string, chatSessionID uint, participantUserID uint) error {
|
||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
||||
if userInfo == nil {
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
_i.Log.Info().Uint("userId", userInfo.ID).Uint("chatSessionID", chatSessionID).Uint("participantUserID", participantUserID).Msg("Removing participant from chat")
|
||||
|
||||
// Check if user has access to chat session
|
||||
existing, err := _i.Repo.FindChatSessionByUserAndID(userInfo.ID, chatSessionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing == nil {
|
||||
return errors.New("chat session not found or access denied")
|
||||
}
|
||||
|
||||
// Only creator can remove participants (or user can remove themselves)
|
||||
if existing.CreatedBy != userInfo.ID && userInfo.ID != participantUserID {
|
||||
return errors.New("only chat creator can remove participants or user can remove themselves")
|
||||
}
|
||||
|
||||
// Find participant
|
||||
participants, err := _i.Repo.FindChatParticipantsBySessionID(chatSessionID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var participantToRemove *entity.ChatParticipants
|
||||
for _, participant := range participants {
|
||||
if participant.UserID == participantUserID {
|
||||
participantToRemove = participant
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if participantToRemove == nil {
|
||||
return errors.New("participant not found")
|
||||
}
|
||||
|
||||
// Soft delete by setting is_active to false
|
||||
now := time.Now()
|
||||
participantToRemove.IsActive = false
|
||||
participantToRemove.LeftAt = &now
|
||||
return _i.Repo.UpdateChatParticipant(participantToRemove.ID, participantToRemove)
|
||||
}
|
||||
|
|
@ -39,14 +39,14 @@ func ConversationsResponseMapper(conversation *entity.Conversations) *response.C
|
|||
func ChatMessagesResponseMapper(chatMessage *entity.ChatMessages) *response.ChatMessagesResponse {
|
||||
result := &response.ChatMessagesResponse{
|
||||
ID: chatMessage.ID,
|
||||
ConversationID: chatMessage.ConversationID,
|
||||
ConversationID: chatMessage.ChatSessionID,
|
||||
SenderID: chatMessage.SenderID,
|
||||
MessageText: chatMessage.MessageText,
|
||||
MessageText: &chatMessage.Message,
|
||||
MessageType: chatMessage.MessageType,
|
||||
FileURL: chatMessage.FileURL,
|
||||
FileName: chatMessage.FileName,
|
||||
FileSize: chatMessage.FileSize,
|
||||
IsRead: chatMessage.IsRead,
|
||||
FileURL: nil, // Not available in entity
|
||||
FileName: nil, // Not available in entity
|
||||
FileSize: nil, // Not available in entity
|
||||
IsRead: false, // Not available in entity, default to false
|
||||
CreatedAt: chatMessage.CreatedAt,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"narasi-ahli-be/utils/paginator"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type communicationsRepository struct {
|
||||
|
|
|
|||
|
|
@ -23,42 +23,40 @@ func (req ConversationsCreateRequest) ToEntity() *entity.Conversations {
|
|||
|
||||
// Chat Messages Request DTOs
|
||||
type ChatMessagesQueryRequest struct {
|
||||
ConversationID uint `json:"conversationId" validate:"required"`
|
||||
Pagination *paginator.Pagination `json:"pagination"`
|
||||
ChatSessionID uint `json:"chatSessionId" validate:"required"`
|
||||
Pagination *paginator.Pagination `json:"pagination"`
|
||||
}
|
||||
|
||||
type ChatMessagesCreateRequest struct {
|
||||
ConversationID uint `json:"conversationId" validate:"required"`
|
||||
MessageText string `json:"messageText"`
|
||||
MessageType string `json:"messageType" validate:"required,oneof=text image file audio"`
|
||||
ChatSessionID uint `json:"chatSessionId" validate:"required"`
|
||||
Message string `json:"message"`
|
||||
MessageType string `json:"messageType" validate:"required,oneof=text image file audio"`
|
||||
}
|
||||
|
||||
func (req ChatMessagesCreateRequest) ToEntity() *entity.ChatMessages {
|
||||
return &entity.ChatMessages{
|
||||
ConversationID: req.ConversationID,
|
||||
SenderID: 0, // Will be set in service layer
|
||||
MessageText: &req.MessageText,
|
||||
MessageType: req.MessageType,
|
||||
IsRead: false,
|
||||
ChatSessionID: req.ChatSessionID,
|
||||
SenderID: 0, // Will be set in service layer
|
||||
Message: req.Message,
|
||||
MessageType: req.MessageType,
|
||||
}
|
||||
}
|
||||
|
||||
type ChatMessagesFileUploadRequest struct {
|
||||
ConversationID uint `json:"conversationId" validate:"required"`
|
||||
MessageType string `json:"messageType" validate:"required,oneof=image file audio"`
|
||||
FileName string `json:"fileName"`
|
||||
FileSize int64 `json:"fileSize"`
|
||||
ChatSessionID uint `json:"chatSessionId" validate:"required"`
|
||||
MessageType string `json:"messageType" validate:"required,oneof=image file audio"`
|
||||
FileName string `json:"fileName"`
|
||||
FileSize int64 `json:"fileSize"`
|
||||
}
|
||||
|
||||
func (req ChatMessagesFileUploadRequest) ToEntity(fileURL string) *entity.ChatMessages {
|
||||
return &entity.ChatMessages{
|
||||
ConversationID: req.ConversationID,
|
||||
SenderID: 0, // Will be set in service layer
|
||||
MessageType: req.MessageType,
|
||||
FileURL: &fileURL,
|
||||
FileName: &req.FileName,
|
||||
FileSize: &req.FileSize,
|
||||
IsRead: false,
|
||||
ChatSessionID: req.ChatSessionID,
|
||||
SenderID: 0, // Will be set in service layer
|
||||
Message: "", // File messages might not have text content
|
||||
MessageType: req.MessageType,
|
||||
// Note: FileURL, FileName, FileSize, IsRead fields are not available in the entity
|
||||
// These would need to be stored separately or the entity needs to be updated
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,14 +73,14 @@ func (req ConversationsQueryRequestContext) ToParamRequest() ConversationsQueryR
|
|||
}
|
||||
|
||||
type ChatMessagesQueryRequestContext struct {
|
||||
ConversationID string `json:"conversationId"`
|
||||
ChatSessionID string `json:"chatSessionId"`
|
||||
}
|
||||
|
||||
func (req ChatMessagesQueryRequestContext) ToParamRequest() ChatMessagesQueryRequest {
|
||||
var request ChatMessagesQueryRequest
|
||||
|
||||
if conversationIDStr := req.ConversationID; conversationIDStr != "" {
|
||||
// Parse conversation ID from string to uint
|
||||
if chatSessionIDStr := req.ChatSessionID; chatSessionIDStr != "" {
|
||||
// Parse chat session ID from string to uint
|
||||
// This will be handled in the controller
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"narasi-ahli-be/app/module/article_comments"
|
||||
"narasi-ahli-be/app/module/article_files"
|
||||
"narasi-ahli-be/app/module/articles"
|
||||
"narasi-ahli-be/app/module/chat"
|
||||
"narasi-ahli-be/app/module/cities"
|
||||
"narasi-ahli-be/app/module/custom_static_pages"
|
||||
"narasi-ahli-be/app/module/districts"
|
||||
|
|
@ -48,6 +49,7 @@ type Router struct {
|
|||
ArticleCommentsRouter *article_comments.ArticleCommentsRouter
|
||||
ArticleApprovalsRouter *article_approvals.ArticleApprovalsRouter
|
||||
ArticlesRouter *articles.ArticlesRouter
|
||||
ChatRouter *chat.ChatRouter
|
||||
CitiesRouter *cities.CitiesRouter
|
||||
CustomStaticPagesRouter *custom_static_pages.CustomStaticPagesRouter
|
||||
DistrictsRouter *districts.DistrictsRouter
|
||||
|
|
@ -81,6 +83,7 @@ func NewRouter(
|
|||
articleCommentsRouter *article_comments.ArticleCommentsRouter,
|
||||
articleApprovalsRouter *article_approvals.ArticleApprovalsRouter,
|
||||
articlesRouter *articles.ArticlesRouter,
|
||||
chatRouter *chat.ChatRouter,
|
||||
citiesRouter *cities.CitiesRouter,
|
||||
customStaticPagesRouter *custom_static_pages.CustomStaticPagesRouter,
|
||||
districtsRouter *districts.DistrictsRouter,
|
||||
|
|
@ -112,6 +115,7 @@ func NewRouter(
|
|||
ArticleCommentsRouter: articleCommentsRouter,
|
||||
ArticleApprovalsRouter: articleApprovalsRouter,
|
||||
ArticlesRouter: articlesRouter,
|
||||
ChatRouter: chatRouter,
|
||||
CitiesRouter: citiesRouter,
|
||||
CustomStaticPagesRouter: customStaticPagesRouter,
|
||||
DistrictsRouter: districtsRouter,
|
||||
|
|
@ -153,6 +157,7 @@ func (r *Router) Register() {
|
|||
r.ArticleApprovalsRouter.RegisterArticleApprovalsRoutes()
|
||||
r.ArticlesRouter.RegisterArticlesRoutes()
|
||||
r.ArticleCommentsRouter.RegisterArticleCommentsRoutes()
|
||||
r.ChatRouter.RegisterChatRoutes()
|
||||
r.CitiesRouter.RegisterCitiesRoutes()
|
||||
r.CustomStaticPagesRouter.RegisterCustomStaticPagesRoutes()
|
||||
r.DistrictsRouter.RegisterDistrictsRoutes()
|
||||
|
|
|
|||
|
|
@ -4536,6 +4536,835 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/chat/messages": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for getting all messages in a specific chat session",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Get all chat messages",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "chatSessionId",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "count",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "nextPage",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "previousPage",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sort",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sortBy",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "totalPage",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for creating a new chat message",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Create chat message",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"description": "Required payload",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.ChatMessageCreateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chat/messages/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for getting one chat message",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Get one chat message",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Message ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for updating chat message (only sender can update)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Update chat message",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Message ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Required payload",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.ChatMessageUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for deleting chat message (only sender can delete)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Delete chat message",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Message ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chat/sessions": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for getting all chat sessions for authenticated user",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Get all chat sessions",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Chat type (personal or group)",
|
||||
"name": "type",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "count",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "nextPage",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "previousPage",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sort",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sortBy",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "totalPage",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for creating a new chat session (personal or group)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Create chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"description": "Required payload",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.ChatSessionCreateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chat/sessions/{chatSessionId}/participants": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for adding a participant to a chat session (only creator can add)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Add participant to chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "chatSessionId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Participant User ID",
|
||||
"name": "participantUserId",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for removing a participant from a chat session (creator can remove anyone, user can remove themselves)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Remove participant from chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "chatSessionId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Participant User ID",
|
||||
"name": "participantUserId",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chat/sessions/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for getting one chat session",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Get one chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for updating chat session (only creator can update)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Update chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Required payload",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.ChatSessionUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for deleting chat session (only creator can delete)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Delete chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/cities": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
|
@ -13763,6 +14592,86 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"request.ChatMessageCreateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"chatSessionId",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"chatSessionId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"maxLength": 1000,
|
||||
"minLength": 1
|
||||
},
|
||||
"messageType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"text",
|
||||
"image",
|
||||
"file",
|
||||
"user",
|
||||
"assistant"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.ChatMessageUpdateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string",
|
||||
"maxLength": 1000,
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.ChatSessionCreateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"userIds"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "null for personal chat",
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"minLength": 2
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"personal",
|
||||
"group"
|
||||
]
|
||||
},
|
||||
"userIds": {
|
||||
"description": "participants (excluding creator)",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.ChatSessionUpdateRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"minLength": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.CitiesCreateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -4525,6 +4525,835 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/chat/messages": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for getting all messages in a specific chat session",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Get all chat messages",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "chatSessionId",
|
||||
"in": "query",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "count",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "nextPage",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "previousPage",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sort",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sortBy",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "totalPage",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for creating a new chat message",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Create chat message",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"description": "Required payload",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.ChatMessageCreateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chat/messages/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for getting one chat message",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Get one chat message",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Message ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for updating chat message (only sender can update)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Update chat message",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Message ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Required payload",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.ChatMessageUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for deleting chat message (only sender can delete)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Delete chat message",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Message ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chat/sessions": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for getting all chat sessions for authenticated user",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Get all chat sessions",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Chat type (personal or group)",
|
||||
"name": "type",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "count",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "limit",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "nextPage",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "page",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "previousPage",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sort",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sortBy",
|
||||
"in": "query"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"name": "totalPage",
|
||||
"in": "query"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for creating a new chat session (personal or group)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Create chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"description": "Required payload",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.ChatSessionCreateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chat/sessions/{chatSessionId}/participants": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for adding a participant to a chat session (only creator can add)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Add participant to chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "chatSessionId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Participant User ID",
|
||||
"name": "participantUserId",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for removing a participant from a chat session (creator can remove anyone, user can remove themselves)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Remove participant from chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "chatSessionId",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Participant User ID",
|
||||
"name": "participantUserId",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/chat/sessions/{id}": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for getting one chat session",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Get one chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"put": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for updating chat session (only creator can update)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Update chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"description": "Required payload",
|
||||
"name": "payload",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.ChatSessionUpdateRequest"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"security": [
|
||||
{
|
||||
"Bearer": []
|
||||
}
|
||||
],
|
||||
"description": "API for deleting chat session (only creator can delete)",
|
||||
"tags": [
|
||||
"Chat"
|
||||
],
|
||||
"summary": "Delete chat session",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Insert the X-Csrf-Token",
|
||||
"name": "X-Csrf-Token",
|
||||
"in": "header",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"default": "Bearer \u003cAdd access token here\u003e",
|
||||
"description": "Insert your access token",
|
||||
"name": "Authorization",
|
||||
"in": "header"
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "Chat Session ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.Response"
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.BadRequestError"
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "Unauthorized",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.UnauthorizedError"
|
||||
}
|
||||
},
|
||||
"500": {
|
||||
"description": "Internal Server Error",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/response.InternalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/cities": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
|
@ -13752,6 +14581,86 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"request.ChatMessageCreateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"chatSessionId",
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"chatSessionId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"message": {
|
||||
"type": "string",
|
||||
"maxLength": 1000,
|
||||
"minLength": 1
|
||||
},
|
||||
"messageType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"text",
|
||||
"image",
|
||||
"file",
|
||||
"user",
|
||||
"assistant"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.ChatMessageUpdateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"message"
|
||||
],
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string",
|
||||
"maxLength": 1000,
|
||||
"minLength": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.ChatSessionCreateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"userIds"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "null for personal chat",
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"minLength": 2
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"personal",
|
||||
"group"
|
||||
]
|
||||
},
|
||||
"userIds": {
|
||||
"description": "participants (excluding creator)",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "integer"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.ChatSessionUpdateRequest": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"maxLength": 255,
|
||||
"minLength": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.CitiesCreateRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -378,6 +378,64 @@ definitions:
|
|||
- title
|
||||
- typeId
|
||||
type: object
|
||||
request.ChatMessageCreateRequest:
|
||||
properties:
|
||||
chatSessionId:
|
||||
type: integer
|
||||
message:
|
||||
maxLength: 1000
|
||||
minLength: 1
|
||||
type: string
|
||||
messageType:
|
||||
enum:
|
||||
- text
|
||||
- image
|
||||
- file
|
||||
- user
|
||||
- assistant
|
||||
type: string
|
||||
required:
|
||||
- chatSessionId
|
||||
- message
|
||||
type: object
|
||||
request.ChatMessageUpdateRequest:
|
||||
properties:
|
||||
message:
|
||||
maxLength: 1000
|
||||
minLength: 1
|
||||
type: string
|
||||
required:
|
||||
- message
|
||||
type: object
|
||||
request.ChatSessionCreateRequest:
|
||||
properties:
|
||||
name:
|
||||
description: null for personal chat
|
||||
maxLength: 255
|
||||
minLength: 2
|
||||
type: string
|
||||
type:
|
||||
enum:
|
||||
- personal
|
||||
- group
|
||||
type: string
|
||||
userIds:
|
||||
description: participants (excluding creator)
|
||||
items:
|
||||
type: integer
|
||||
minItems: 1
|
||||
type: array
|
||||
required:
|
||||
- type
|
||||
- userIds
|
||||
type: object
|
||||
request.ChatSessionUpdateRequest:
|
||||
properties:
|
||||
name:
|
||||
maxLength: 255
|
||||
minLength: 2
|
||||
type: string
|
||||
type: object
|
||||
request.CitiesCreateRequest:
|
||||
properties:
|
||||
cityName:
|
||||
|
|
@ -4077,6 +4135,544 @@ paths:
|
|||
summary: Viewer Articles Thumbnail
|
||||
tags:
|
||||
- Articles
|
||||
/chat/messages:
|
||||
get:
|
||||
description: API for getting all messages in a specific chat session
|
||||
parameters:
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat Session ID
|
||||
in: query
|
||||
name: chatSessionId
|
||||
required: true
|
||||
type: integer
|
||||
- in: query
|
||||
name: count
|
||||
type: integer
|
||||
- in: query
|
||||
name: limit
|
||||
type: integer
|
||||
- in: query
|
||||
name: nextPage
|
||||
type: integer
|
||||
- in: query
|
||||
name: page
|
||||
type: integer
|
||||
- in: query
|
||||
name: previousPage
|
||||
type: integer
|
||||
- in: query
|
||||
name: sort
|
||||
type: string
|
||||
- in: query
|
||||
name: sortBy
|
||||
type: string
|
||||
- in: query
|
||||
name: totalPage
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Get all chat messages
|
||||
tags:
|
||||
- Chat
|
||||
post:
|
||||
description: API for creating a new chat message
|
||||
parameters:
|
||||
- description: Insert the X-Csrf-Token
|
||||
in: header
|
||||
name: X-Csrf-Token
|
||||
required: true
|
||||
type: string
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Required payload
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.ChatMessageCreateRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Create chat message
|
||||
tags:
|
||||
- Chat
|
||||
/chat/messages/{id}:
|
||||
delete:
|
||||
description: API for deleting chat message (only sender can delete)
|
||||
parameters:
|
||||
- description: Insert the X-Csrf-Token
|
||||
in: header
|
||||
name: X-Csrf-Token
|
||||
required: true
|
||||
type: string
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat Message ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Delete chat message
|
||||
tags:
|
||||
- Chat
|
||||
get:
|
||||
description: API for getting one chat message
|
||||
parameters:
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat Message ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Get one chat message
|
||||
tags:
|
||||
- Chat
|
||||
put:
|
||||
description: API for updating chat message (only sender can update)
|
||||
parameters:
|
||||
- description: Insert the X-Csrf-Token
|
||||
in: header
|
||||
name: X-Csrf-Token
|
||||
required: true
|
||||
type: string
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat Message ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
- description: Required payload
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.ChatMessageUpdateRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Update chat message
|
||||
tags:
|
||||
- Chat
|
||||
/chat/sessions:
|
||||
get:
|
||||
description: API for getting all chat sessions for authenticated user
|
||||
parameters:
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat type (personal or group)
|
||||
in: query
|
||||
name: type
|
||||
type: string
|
||||
- in: query
|
||||
name: count
|
||||
type: integer
|
||||
- in: query
|
||||
name: limit
|
||||
type: integer
|
||||
- in: query
|
||||
name: nextPage
|
||||
type: integer
|
||||
- in: query
|
||||
name: page
|
||||
type: integer
|
||||
- in: query
|
||||
name: previousPage
|
||||
type: integer
|
||||
- in: query
|
||||
name: sort
|
||||
type: string
|
||||
- in: query
|
||||
name: sortBy
|
||||
type: string
|
||||
- in: query
|
||||
name: totalPage
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Get all chat sessions
|
||||
tags:
|
||||
- Chat
|
||||
post:
|
||||
description: API for creating a new chat session (personal or group)
|
||||
parameters:
|
||||
- description: Insert the X-Csrf-Token
|
||||
in: header
|
||||
name: X-Csrf-Token
|
||||
required: true
|
||||
type: string
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Required payload
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.ChatSessionCreateRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Create chat session
|
||||
tags:
|
||||
- Chat
|
||||
/chat/sessions/{chatSessionId}/participants:
|
||||
delete:
|
||||
description: API for removing a participant from a chat session (creator can
|
||||
remove anyone, user can remove themselves)
|
||||
parameters:
|
||||
- description: Insert the X-Csrf-Token
|
||||
in: header
|
||||
name: X-Csrf-Token
|
||||
required: true
|
||||
type: string
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat Session ID
|
||||
in: path
|
||||
name: chatSessionId
|
||||
required: true
|
||||
type: integer
|
||||
- description: Participant User ID
|
||||
in: query
|
||||
name: participantUserId
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Remove participant from chat session
|
||||
tags:
|
||||
- Chat
|
||||
post:
|
||||
description: API for adding a participant to a chat session (only creator can
|
||||
add)
|
||||
parameters:
|
||||
- description: Insert the X-Csrf-Token
|
||||
in: header
|
||||
name: X-Csrf-Token
|
||||
required: true
|
||||
type: string
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat Session ID
|
||||
in: path
|
||||
name: chatSessionId
|
||||
required: true
|
||||
type: integer
|
||||
- description: Participant User ID
|
||||
in: query
|
||||
name: participantUserId
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Add participant to chat session
|
||||
tags:
|
||||
- Chat
|
||||
/chat/sessions/{id}:
|
||||
delete:
|
||||
description: API for deleting chat session (only creator can delete)
|
||||
parameters:
|
||||
- description: Insert the X-Csrf-Token
|
||||
in: header
|
||||
name: X-Csrf-Token
|
||||
required: true
|
||||
type: string
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat Session ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Delete chat session
|
||||
tags:
|
||||
- Chat
|
||||
get:
|
||||
description: API for getting one chat session
|
||||
parameters:
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat Session ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Get one chat session
|
||||
tags:
|
||||
- Chat
|
||||
put:
|
||||
description: API for updating chat session (only creator can update)
|
||||
parameters:
|
||||
- description: Insert the X-Csrf-Token
|
||||
in: header
|
||||
name: X-Csrf-Token
|
||||
required: true
|
||||
type: string
|
||||
- default: Bearer <Add access token here>
|
||||
description: Insert your access token
|
||||
in: header
|
||||
name: Authorization
|
||||
type: string
|
||||
- description: Chat Session ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
- description: Required payload
|
||||
in: body
|
||||
name: payload
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.ChatSessionUpdateRequest'
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/response.Response'
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
$ref: '#/definitions/response.BadRequestError'
|
||||
"401":
|
||||
description: Unauthorized
|
||||
schema:
|
||||
$ref: '#/definitions/response.UnauthorizedError'
|
||||
"500":
|
||||
description: Internal Server Error
|
||||
schema:
|
||||
$ref: '#/definitions/response.InternalServerError'
|
||||
security:
|
||||
- Bearer: []
|
||||
summary: Update chat session
|
||||
tags:
|
||||
- Chat
|
||||
/cities:
|
||||
get:
|
||||
description: API for getting all Cities
|
||||
|
|
|
|||
2
main.go
2
main.go
|
|
@ -12,6 +12,7 @@ import (
|
|||
"narasi-ahli-be/app/module/article_comments"
|
||||
"narasi-ahli-be/app/module/article_files"
|
||||
"narasi-ahli-be/app/module/articles"
|
||||
"narasi-ahli-be/app/module/chat"
|
||||
"narasi-ahli-be/app/module/cities"
|
||||
"narasi-ahli-be/app/module/custom_static_pages"
|
||||
"narasi-ahli-be/app/module/districts"
|
||||
|
|
@ -74,6 +75,7 @@ func main() {
|
|||
article_approvals.NewArticleApprovalsModule,
|
||||
articles.NewArticlesModule,
|
||||
article_comments.NewArticleCommentsModule,
|
||||
chat.NewChatModule,
|
||||
cities.NewCitiesModule,
|
||||
custom_static_pages.NewCustomStaticPagesModule,
|
||||
districts.NewDistrictsModule,
|
||||
|
|
|
|||
|
|
@ -1,28 +0,0 @@
|
|||
package migrations
|
||||
|
||||
import (
|
||||
"narasi-ahli-be/app/database"
|
||||
"narasi-ahli-be/app/database/entity"
|
||||
)
|
||||
|
||||
// CreateChatHistoryTables creates the chat history tables
|
||||
func CreateChatHistoryTables(db *database.Database) error {
|
||||
// Auto-migrate the new entities
|
||||
err := db.DB.AutoMigrate(
|
||||
&entity.ChatSessions{},
|
||||
&entity.ChatMessagesNew{},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create indexes manually if needed
|
||||
db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_sessions_user_id ON chat_sessions (user_id)")
|
||||
db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_sessions_agent_id ON chat_sessions (agent_id)")
|
||||
db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_sessions_session_id ON chat_sessions (session_id)")
|
||||
db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_sessions_created_at ON chat_sessions (created_at)")
|
||||
db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_messages_new_session_id ON chat_messages_new (session_id)")
|
||||
db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_messages_new_created_at ON chat_messages_new (created_at)")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
-- Migration: Create Chat History Tables
|
||||
-- Description: Create tables for chat history functionality based on the old web API structure
|
||||
-- Date: 2024-01-01
|
||||
|
||||
-- Create chat_sessions table
|
||||
CREATE TABLE IF NOT EXISTS chat_sessions (
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id VARCHAR(255) NOT NULL UNIQUE,
|
||||
user_id INTEGER NOT NULL,
|
||||
agent_id VARCHAR(255) NOT NULL,
|
||||
title VARCHAR(255) NOT NULL DEFAULT 'Chat Session',
|
||||
message_count INTEGER DEFAULT 0,
|
||||
status VARCHAR(50) DEFAULT 'active',
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Create chat_messages_new table (to avoid conflict with existing chat_messages)
|
||||
CREATE TABLE IF NOT EXISTS chat_messages_new (
|
||||
id SERIAL PRIMARY KEY,
|
||||
session_id VARCHAR(255) NOT NULL,
|
||||
message_type VARCHAR(50) NOT NULL CHECK (message_type IN ('user', 'assistant')),
|
||||
content TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
-- Create indexes for better performance
|
||||
CREATE INDEX IF NOT EXISTS idx_chat_sessions_user_id ON chat_sessions (user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chat_sessions_agent_id ON chat_sessions (agent_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chat_sessions_session_id ON chat_sessions (session_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chat_sessions_created_at ON chat_sessions (created_at);
|
||||
CREATE INDEX IF NOT EXISTS idx_chat_messages_new_session_id ON chat_messages_new (session_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_chat_messages_new_created_at ON chat_messages_new (created_at);
|
||||
|
||||
-- Add foreign key constraints
|
||||
ALTER TABLE chat_sessions
|
||||
ADD CONSTRAINT fk_chat_sessions_user_id
|
||||
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE chat_messages_new
|
||||
ADD CONSTRAINT fk_chat_messages_new_session_id
|
||||
FOREIGN KEY (session_id) REFERENCES chat_sessions(session_id) ON DELETE CASCADE;
|
||||
|
||||
-- Insert sample data (optional)
|
||||
INSERT INTO chat_sessions (session_id, user_id, agent_id, title, message_count)
|
||||
VALUES ('sample-session-123', 1, 'd04bbced-ae93-4fb3-a015-9472e4e5e539', 'Sample Chat Session', 2)
|
||||
ON CONFLICT (session_id) DO NOTHING;
|
||||
|
||||
INSERT INTO chat_messages_new (session_id, message_type, content)
|
||||
VALUES
|
||||
('sample-session-123', 'user', 'Halo, ada yang bisa saya tanyakan?'),
|
||||
('sample-session-123', 'assistant', 'Halo! Tentu saja, saya siap membantu Anda dengan pertanyaan apapun.')
|
||||
ON CONFLICT DO NOTHING;
|
||||
Loading…
Reference in New Issue