475 lines
16 KiB
Go
475 lines
16 KiB
Go
|
|
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"},
|
||
|
|
})
|
||
|
|
}
|