feat: update minimal module
This commit is contained in:
parent
169378b243
commit
b3c5a0228f
|
|
@ -1,20 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Advertisement struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Title string `json:"title" gorm:"type:varchar"`
|
|
||||||
Description string `json:"description" gorm:"type:varchar"`
|
|
||||||
RedirectLink string `json:"redirect_link" gorm:"type:varchar"`
|
|
||||||
ContentFilePath *string `json:"content_file_path" gorm:"type:varchar"`
|
|
||||||
ContentFileName *string `json:"content_file_name" gorm:"type:varchar"`
|
|
||||||
Placement string `json:"placement" gorm:"type:varchar"`
|
|
||||||
StatusId int `json:"status_id" gorm:"type:int4"`
|
|
||||||
IsPublish bool `json:"is_publish" gorm:"type:bool"`
|
|
||||||
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()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AIChatLogs struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
SessionID uint `json:"session_id" gorm:"type:int4;not null;index"`
|
|
||||||
UserID uint `json:"user_id" gorm:"type:int4;not null;index"`
|
|
||||||
StartDate time.Time `json:"start_date" gorm:"not null"`
|
|
||||||
EndDate *time.Time `json:"end_date"`
|
|
||||||
TotalDuration int64 `json:"total_duration" gorm:"type:bigint;default:0"`
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AIChatMessages 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"`
|
|
||||||
Content string `json:"content" gorm:"type:text;not null"`
|
|
||||||
IsActive bool `json:"is_active" gorm:"type:bool;default:true"`
|
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AIChatSessions 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"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
users "jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignApprovals struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
CampaignID uint `json:"campaign_id" gorm:"type:int4"`
|
|
||||||
Campaign Campaigns `json:"campaign" gorm:"foreignKey:CampaignID;references:ID"`
|
|
||||||
ApproverID uint `json:"approver_id" gorm:"type:int4"`
|
|
||||||
Approver users.Users `json:"approver" gorm:"foreignKey:ApproverID;references:ID"`
|
|
||||||
Status string `json:"status" gorm:"type:varchar(20);default:'pending'"` // pending, approved, rejected
|
|
||||||
Notes *string `json:"notes" gorm:"type:text"`
|
|
||||||
IsActive *bool `json:"is_active" gorm:"type:bool;default:true"`
|
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
||||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
users "jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignChats struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
CampaignID uint `json:"campaign_id" gorm:"type:int4"`
|
|
||||||
Campaign Campaigns `json:"campaign" gorm:"foreignKey:CampaignID;references:ID"`
|
|
||||||
SenderID uint `json:"sender_id" gorm:"type:int4"`
|
|
||||||
Sender users.Users `json:"sender" gorm:"foreignKey:SenderID;references:ID"`
|
|
||||||
Message string `json:"message" gorm:"type:text"`
|
|
||||||
AttachmentURL *string `json:"attachment_url" gorm:"type:text"`
|
|
||||||
IsActive *bool `json:"is_active" gorm:"type:bool;default:true"`
|
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
||||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignDestinationRelations struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
CampaignID uint `json:"campaign_id" gorm:"type:int4"`
|
|
||||||
Campaign Campaigns `json:"campaign" gorm:"foreignKey:CampaignID;references:ID"`
|
|
||||||
DestinationID uint `json:"destination_id" gorm:"type:int4"`
|
|
||||||
Destination CampaignDestinations `json:"destination" gorm:"foreignKey:DestinationID;references:ID"`
|
|
||||||
ScheduledAt *time.Time `json:"scheduled_at" gorm:"type:timestamp"`
|
|
||||||
PublishStatus string `json:"publish_status" gorm:"type:varchar(20);default:'pending'"` // pending, success, failed
|
|
||||||
PublishResponse *string `json:"publish_response" gorm:"type:text"`
|
|
||||||
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()"`
|
|
||||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignDestinations struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
CampaignTypeID uint `json:"campaign_type_id" gorm:"type:int4"`
|
|
||||||
CampaignType CampaignTypes `json:"campaign_type" gorm:"foreignKey:CampaignTypeID;references:ID"`
|
|
||||||
Name string `json:"name" gorm:"type:varchar(150)"`
|
|
||||||
SubType *string `json:"sub_type" gorm:"type:varchar(100)"`
|
|
||||||
Description *string `json:"description" gorm:"type:text"`
|
|
||||||
URL *string `json:"url" gorm:"type:varchar(255)"`
|
|
||||||
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()"`
|
|
||||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignFiles struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
CampaignID uint `json:"campaign_id" gorm:"type:int4"`
|
|
||||||
Campaign Campaigns `json:"campaign" gorm:"foreignKey:CampaignID;references:ID"`
|
|
||||||
Type string `json:"type" gorm:"type:varchar(20)"` // url, file
|
|
||||||
FileURL *string `json:"file_url" gorm:"type:text"`
|
|
||||||
ExternalURL *string `json:"external_url" gorm:"type:text"`
|
|
||||||
IsDraft *bool `json:"is_draft" gorm:"type:bool;default:false"`
|
|
||||||
IsPublish *bool `json:"is_publish" gorm:"type:bool;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()"`
|
|
||||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignTypes struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Name string `json:"name" gorm:"type:varchar(150)"`
|
|
||||||
Description *string `json:"description" gorm:"type:text"`
|
|
||||||
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()"`
|
|
||||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
users "jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Campaigns struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Title string `json:"title" gorm:"type:varchar(255)"`
|
|
||||||
CampaignTypeID uint `json:"campaign_type_id" gorm:"type:int4"`
|
|
||||||
CampaignType CampaignTypes `json:"campaign_type" gorm:"foreignKey:CampaignTypeID;references:ID"`
|
|
||||||
StartDate *time.Time `json:"start_date" gorm:"type:date"`
|
|
||||||
EndDate *time.Time `json:"end_date" gorm:"type:date"`
|
|
||||||
MediaTypeSelected *string `json:"media_type_selected" gorm:"type:varchar(100)"`
|
|
||||||
MediaItemSelected *string `json:"media_item_selected" gorm:"type:text"` // JSON array or comma-separated
|
|
||||||
Purpose *string `json:"purpose" gorm:"type:text"`
|
|
||||||
MediaPromote *bool `json:"media_promote" gorm:"type:bool;default:false"`
|
|
||||||
Description *string `json:"description" gorm:"type:text"`
|
|
||||||
CreatorID uint `json:"creator_id" gorm:"type:int4"`
|
|
||||||
Creator users.Users `json:"creator" gorm:"foreignKey:CreatorID;references:ID"`
|
|
||||||
Status string `json:"status" gorm:"type:varchar(50);default:'draft'"` // draft, waiting_approval, approved, rejected, published, archived
|
|
||||||
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()"`
|
|
||||||
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ChatMessages struct {
|
|
||||||
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,21 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-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"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ChatScheduleFiles struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
ChatScheduleID uint `json:"chat_schedule_id" gorm:"type:int4;not null;index"`
|
|
||||||
FileName string `json:"file_name" gorm:"type:varchar(255);not null"`
|
|
||||||
OriginalName string `json:"original_name" gorm:"type:varchar(255);not null"`
|
|
||||||
FilePath string `json:"file_path" gorm:"type:varchar(500);not null"`
|
|
||||||
FileSize int64 `json:"file_size" gorm:"type:int8"`
|
|
||||||
MimeType string `json:"mime_type" gorm:"type:varchar(100)"`
|
|
||||||
FileType string `json:"file_type" gorm:"type:varchar(20);not null;check:file_type IN ('article', 'journal', 'video', 'audio', 'document', 'other')"`
|
|
||||||
Description string `json:"description" gorm:"type:text"`
|
|
||||||
IsRequired bool `json:"is_required" gorm:"default:false"`
|
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
|
||||||
|
|
||||||
// Relationships
|
|
||||||
ChatSchedule *ChatSchedules `json:"chat_schedule" gorm:"foreignKey:ChatScheduleID;references:ID"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ChatSchedules struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
ChatSessionID uint `json:"chat_session_id" gorm:"type:int4;not null;index"`
|
|
||||||
Title string `json:"title" gorm:"type:varchar(255);not null"`
|
|
||||||
Description string `json:"description" gorm:"type:text"`
|
|
||||||
Summary string `json:"summary" gorm:"type:text"`
|
|
||||||
ScheduledAt time.Time `json:"scheduled_at" gorm:"not null"`
|
|
||||||
Duration int `json:"duration" gorm:"type:int4;default:60"` // duration in minutes
|
|
||||||
Status string `json:"status" gorm:"type:varchar(20);not null;default:'scheduled';check:status IN ('scheduled', 'ongoing', 'completed', 'cancelled')"`
|
|
||||||
IsReminderSent bool `json:"is_reminder_sent" gorm:"default:false"`
|
|
||||||
ReminderSentAt *time.Time `json:"reminder_sent_at"`
|
|
||||||
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
|
|
||||||
ChatSession *ChatSessions `json:"chat_session" gorm:"foreignKey:ChatSessionID;references:ID"`
|
|
||||||
Creator *users.Users `json:"creator" gorm:"foreignKey:CreatedBy;references:ID"`
|
|
||||||
Files []*ChatScheduleFiles `json:"files" gorm:"foreignKey:ChatScheduleID;references:ID"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ChatSessions struct {
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Conversations struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Participant1ID uint `json:"participant1_id" gorm:"type:int4;not null;index"`
|
|
||||||
Participant2ID uint `json:"participant2_id" gorm:"type:int4;not null;index"`
|
|
||||||
LastMessageAt *time.Time `json:"last_message_at"`
|
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
|
||||||
Participant1 *users.Users `json:"participant1" gorm:"foreignKey:Participant1ID;references:ID"`
|
|
||||||
Participant2 *users.Users `json:"participant2" gorm:"foreignKey:Participant2ID;references:ID"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
users "jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EbookPurchases struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
BuyerId uint `json:"buyer_id" gorm:"type:int4"`
|
|
||||||
Buyer *users.Users `json:"buyer" gorm:"foreignKey:BuyerId;references:ID"`
|
|
||||||
EbookId uint `json:"ebook_id" gorm:"type:int4"`
|
|
||||||
Ebook *Ebooks `json:"ebook" gorm:"foreignKey:EbookId;references:ID"`
|
|
||||||
PurchasePrice float64 `json:"purchase_price" gorm:"type:decimal(10,2)"`
|
|
||||||
PaymentMethod *string `json:"payment_method" gorm:"type:varchar"`
|
|
||||||
PaymentStatus *string `json:"payment_status" gorm:"type:varchar;default:'pending'"`
|
|
||||||
TransactionId *string `json:"transaction_id" gorm:"type:varchar"`
|
|
||||||
PaymentProof *string `json:"payment_proof" gorm:"type:varchar"`
|
|
||||||
PaymentDate *time.Time `json:"payment_date" gorm:"type:timestamp"`
|
|
||||||
DownloadCount *int `json:"download_count" gorm:"type:int4;default:0"`
|
|
||||||
LastDownloadAt *time.Time `json:"last_download_at" gorm:"type:timestamp"`
|
|
||||||
StatusId *int `json:"status_id" gorm:"type:int4;default:1"`
|
|
||||||
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()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
users "jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EbookRatings struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
UserId uint `json:"user_id" gorm:"type:int4"`
|
|
||||||
User *users.Users `json:"user" gorm:"foreignKey:UserId;references:ID"`
|
|
||||||
EbookId uint `json:"ebook_id" gorm:"type:int4"`
|
|
||||||
Ebook *Ebooks `json:"ebook" gorm:"foreignKey:EbookId;references:ID"`
|
|
||||||
PurchaseId uint `json:"purchase_id" gorm:"type:int4"`
|
|
||||||
Purchase *EbookPurchases `json:"purchase" gorm:"foreignKey:PurchaseId;references:ID"`
|
|
||||||
Rating int `json:"rating" gorm:"type:int4;check:rating >= 1 AND rating <= 5"`
|
|
||||||
Review *string `json:"review" gorm:"type:text"`
|
|
||||||
IsAnonymous *bool `json:"is_anonymous" gorm:"type:bool;default:false"`
|
|
||||||
IsVerified *bool `json:"is_verified" gorm:"type:bool;default:true"`
|
|
||||||
StatusId *int `json:"status_id" gorm:"type:int4;default:1"`
|
|
||||||
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()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
users "jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EbookWishlists struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
UserId uint `json:"user_id" gorm:"type:int4"`
|
|
||||||
User *users.Users `json:"user" gorm:"foreignKey:UserId;references:ID"`
|
|
||||||
EbookId uint `json:"ebook_id" gorm:"type:int4"`
|
|
||||||
Ebook *Ebooks `json:"ebook" gorm:"foreignKey:EbookId;references:ID"`
|
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
users "jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Ebooks struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Title string `json:"title" gorm:"type:varchar"`
|
|
||||||
Slug string `json:"slug" gorm:"type:varchar"`
|
|
||||||
Description string `json:"description" gorm:"type:varchar"`
|
|
||||||
Price float64 `json:"price" gorm:"type:decimal(10,2)"`
|
|
||||||
PdfFilePath *string `json:"pdf_file_path" gorm:"type:varchar"`
|
|
||||||
PdfFileName *string `json:"pdf_file_name" gorm:"type:varchar"`
|
|
||||||
PdfFileSize *int64 `json:"pdf_file_size" gorm:"type:int8"`
|
|
||||||
ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"`
|
|
||||||
ThumbnailName *string `json:"thumbnail_name" gorm:"type:varchar"`
|
|
||||||
AuthorId uint `json:"author_id" gorm:"type:int4"`
|
|
||||||
Author *users.Users `json:"author" gorm:"foreignKey:AuthorId;references:ID"`
|
|
||||||
Category *string `json:"category" gorm:"type:varchar"`
|
|
||||||
Tags *string `json:"tags" gorm:"type:varchar"`
|
|
||||||
PageCount *int `json:"page_count" gorm:"type:int4"`
|
|
||||||
Language *string `json:"language" gorm:"type:varchar;default:'id'"`
|
|
||||||
Isbn *string `json:"isbn" gorm:"type:varchar"`
|
|
||||||
Publisher *string `json:"publisher" gorm:"type:varchar"`
|
|
||||||
PublishedYear *int `json:"published_year" gorm:"type:int4"`
|
|
||||||
DownloadCount *int `json:"download_count" gorm:"type:int4;default:0"`
|
|
||||||
PurchaseCount *int `json:"purchase_count" gorm:"type:int4;default:0"`
|
|
||||||
WishlistCount *int `json:"wishlist_count" gorm:"type:int4;default:0"`
|
|
||||||
Rating *float64 `json:"rating" gorm:"type:decimal(3,2);default:0"`
|
|
||||||
ReviewCount *int `json:"review_count" gorm:"type:int4;default:0"`
|
|
||||||
StatusId *int `json:"status_id" gorm:"type:int4;default:1"`
|
|
||||||
IsActive *bool `json:"is_active" gorm:"type:bool;default:true"`
|
|
||||||
IsPublished *bool `json:"is_published" gorm:"type:bool;default:false"`
|
|
||||||
PublishedAt *time.Time `json:"published_at" gorm:"type:timestamp"`
|
|
||||||
CreatedById *uint `json:"created_by_id" gorm:"type:int4"`
|
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type EducationHistory struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
UserID uint `json:"user_id" gorm:"type:int4;not null;index"`
|
|
||||||
SchoolName string `json:"school_name" gorm:"type:varchar;not null"`
|
|
||||||
Major string `json:"major" gorm:"type:varchar;not null"`
|
|
||||||
EducationLevel string `json:"education_level" gorm:"type:varchar;not null"`
|
|
||||||
GraduationYear int `json:"graduation_year" gorm:"type:int4;not null"`
|
|
||||||
CertificateImage *string `json:"certificate_image" gorm:"type:varchar"`
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type MagazineFiles struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Title string `json:"title" gorm:"type:varchar"`
|
|
||||||
Description string `json:"description" gorm:"type:varchar"`
|
|
||||||
MagazineId uint `json:"magazine_id" gorm:"type:int4"`
|
|
||||||
DownloadCount *int `json:"download_count" gorm:"type:int4"`
|
|
||||||
StatusId int `json:"status_id" gorm:"type:int4"`
|
|
||||||
IsPublish *bool `json:"is_publish" gorm:"type:bool"`
|
|
||||||
FilePath *string `json:"file_path" gorm:"type:varchar"`
|
|
||||||
FileUrl *string `json:"file_url" gorm:"type:varchar"`
|
|
||||||
FileName *string `json:"file_name" gorm:"type:varchar"`
|
|
||||||
FileAlt *string `json:"file_alt" gorm:"type:varchar"`
|
|
||||||
WidthPixel *string `json:"width_pixel" gorm:"type:varchar"`
|
|
||||||
HeightPixel *string `json:"height_pixel" gorm:"type:varchar"`
|
|
||||||
Size *string `json:"size" gorm:"type:varchar"`
|
|
||||||
PublishedAt *time.Time `json:"published_at" gorm:"type:timestamp"`
|
|
||||||
IsActive bool `json:"is_active" gorm:"type:bool"`
|
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Magazines struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Title string `json:"title" gorm:"type:varchar"`
|
|
||||||
Description string `json:"description" gorm:"type:varchar"`
|
|
||||||
ThumbnailName *string `json:"thumbnail_name" gorm:"type:varchar"`
|
|
||||||
ThumbnailPath *string `json:"thumbnail_path" gorm:"type:varchar"`
|
|
||||||
ThumbnailUrl *string `json:"thumbnail_url" gorm:"type:varchar"`
|
|
||||||
PageUrl *string `json:"page_url" gorm:"type:varchar"`
|
|
||||||
CreatedById *uint `json:"created_by_id" gorm:"type:int4"`
|
|
||||||
StatusId int `json:"status_id" gorm:"type:int4"`
|
|
||||||
IsPublish *bool `json:"is_publish" gorm:"type:bool"`
|
|
||||||
PublishedAt *time.Time `json:"published_at" gorm:"type:timestamp"`
|
|
||||||
IsActive bool `json:"is_active" gorm:"type:bool"`
|
|
||||||
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type MasterMenus struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Name string `json:"name" gorm:"type:varchar"`
|
|
||||||
Description string `json:"description" gorm:"type:varchar"`
|
|
||||||
ModuleId int `json:"module_id" gorm:"type:int4"`
|
|
||||||
ParentMenuId *int `json:"parent_menu_id" gorm:"type:int4"`
|
|
||||||
Icon *string `json:"icon" gorm:"type:varchar"`
|
|
||||||
Group string `json:"group" gorm:"type:varchar"`
|
|
||||||
Position *int `json:"position" gorm:"type:int4"`
|
|
||||||
StatusId int `json:"status_id" gorm:"type:int4"`
|
|
||||||
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()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MasterModules struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Name string `json:"name" gorm:"type:varchar"`
|
|
||||||
Description string `json:"description" gorm:"type:varchar"`
|
|
||||||
PathUrl string `json:"path_url" gorm:"type:varchar"`
|
|
||||||
StatusId int `json:"status_id" gorm:"type:int4"`
|
|
||||||
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()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
type MasterStatuses struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Name string `json:"name" gorm:"type:varchar"`
|
|
||||||
IsActive bool `json:"is_active" gorm:"type:bool"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ResearchJournals struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
UserID uint `json:"user_id" gorm:"type:int4;not null;index"`
|
|
||||||
JournalTitle string `json:"journal_title" gorm:"type:varchar;not null"`
|
|
||||||
Publisher string `json:"publisher" gorm:"type:varchar;not null"`
|
|
||||||
JournalURL string `json:"journal_url" gorm:"type:varchar;not null"`
|
|
||||||
PublishedDate *time.Time `json:"published_date"`
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
||||||
type Subscription struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
Email string `json:"email" gorm:"type:varchar"`
|
|
||||||
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()"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity/users"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type WorkHistory struct {
|
|
||||||
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
|
|
||||||
UserID uint `json:"user_id" gorm:"type:int4;not null;index"`
|
|
||||||
JobTitle string `json:"job_title" gorm:"type:varchar;not null"`
|
|
||||||
CompanyName string `json:"company_name" gorm:"type:varchar;not null"`
|
|
||||||
StartDate time.Time `json:"start_date" gorm:"not null"`
|
|
||||||
EndDate *time.Time `json:"end_date"`
|
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
@ -87,7 +87,6 @@ func Models() []interface{} {
|
||||||
return []interface{}{
|
return []interface{}{
|
||||||
entity.ActivityLogs{},
|
entity.ActivityLogs{},
|
||||||
entity.ActivityLogTypes{},
|
entity.ActivityLogTypes{},
|
||||||
entity.Advertisement{},
|
|
||||||
entity.Articles{},
|
entity.Articles{},
|
||||||
entity.ArticleCategories{},
|
entity.ArticleCategories{},
|
||||||
entity.ArticleApprovals{},
|
entity.ArticleApprovals{},
|
||||||
|
|
@ -101,49 +100,14 @@ func Models() []interface{} {
|
||||||
entity.Districts{},
|
entity.Districts{},
|
||||||
entity.Feedbacks{},
|
entity.Feedbacks{},
|
||||||
entity.ForgotPasswords{},
|
entity.ForgotPasswords{},
|
||||||
entity.Magazines{},
|
|
||||||
entity.MagazineFiles{},
|
|
||||||
entity.MasterMenus{},
|
|
||||||
entity.MasterModules{},
|
|
||||||
entity.MasterStatuses{},
|
|
||||||
entity.MasterApprovalStatuses{},
|
entity.MasterApprovalStatuses{},
|
||||||
entity.Provinces{},
|
entity.Provinces{},
|
||||||
entity.OneTimePasswords{},
|
entity.OneTimePasswords{},
|
||||||
entity.Subscription{},
|
|
||||||
user_levels.UserLevels{},
|
user_levels.UserLevels{},
|
||||||
entity.UserRoles{},
|
entity.UserRoles{},
|
||||||
entity.UserRoleAccesses{},
|
entity.UserRoleAccesses{},
|
||||||
users.Users{},
|
users.Users{},
|
||||||
entity.UserRoleLevelDetails{},
|
entity.UserRoleLevelDetails{},
|
||||||
|
|
||||||
// Narasi Ahli entities
|
|
||||||
entity.EducationHistory{},
|
|
||||||
entity.WorkHistory{},
|
|
||||||
entity.ResearchJournals{},
|
|
||||||
entity.Conversations{},
|
|
||||||
entity.ChatMessages{},
|
|
||||||
entity.ChatParticipants{},
|
|
||||||
entity.ChatSessions{},
|
|
||||||
entity.ChatSchedules{},
|
|
||||||
entity.ChatScheduleFiles{},
|
|
||||||
entity.AIChatSessions{},
|
|
||||||
entity.AIChatMessages{},
|
|
||||||
entity.AIChatLogs{},
|
|
||||||
|
|
||||||
// Ebook entities
|
|
||||||
entity.Ebooks{},
|
|
||||||
entity.EbookWishlists{},
|
|
||||||
entity.EbookPurchases{},
|
|
||||||
entity.EbookRatings{},
|
|
||||||
|
|
||||||
// Campaign entities
|
|
||||||
entity.CampaignTypes{},
|
|
||||||
entity.CampaignDestinations{},
|
|
||||||
entity.Campaigns{},
|
|
||||||
entity.CampaignFiles{},
|
|
||||||
entity.CampaignDestinationRelations{},
|
|
||||||
entity.CampaignApprovals{},
|
|
||||||
entity.CampaignChats{},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
package seeds
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type MasterStatusesSeeder struct{}
|
|
||||||
|
|
||||||
var masterStatuses = []entity.MasterStatuses{
|
|
||||||
{
|
|
||||||
ID: 1,
|
|
||||||
Name: "Waiting",
|
|
||||||
IsActive: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 2,
|
|
||||||
Name: "Active",
|
|
||||||
IsActive: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: 3,
|
|
||||||
Name: "Inactive",
|
|
||||||
IsActive: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (MasterStatusesSeeder) Seed(conn *gorm.DB) error {
|
|
||||||
for _, row := range masterStatuses {
|
|
||||||
if err := conn.Create(&row).Error; err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (MasterStatusesSeeder) Count(conn *gorm.DB) (int, error) {
|
|
||||||
var count int64
|
|
||||||
if err := conn.Model(&entity.MasterStatuses{}).Count(&count).Error; err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return int(count), nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
package advertisement
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/advertisement/controller"
|
|
||||||
"jaecoo-be/app/module/advertisement/repository"
|
|
||||||
"jaecoo-be/app/module/advertisement/service"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"go.uber.org/fx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// struct of AdvertisementRouter
|
|
||||||
type AdvertisementRouter struct {
|
|
||||||
App fiber.Router
|
|
||||||
Controller *controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
// register bulky of Advertisement module
|
|
||||||
var NewAdvertisementModule = fx.Options(
|
|
||||||
// register repository of Advertisement module
|
|
||||||
fx.Provide(repository.NewAdvertisementRepository),
|
|
||||||
|
|
||||||
// register service of Advertisement module
|
|
||||||
fx.Provide(service.NewAdvertisementService),
|
|
||||||
|
|
||||||
// register controller of Advertisement module
|
|
||||||
fx.Provide(controller.NewController),
|
|
||||||
|
|
||||||
// register router of Advertisement module
|
|
||||||
fx.Provide(NewAdvertisementRouter),
|
|
||||||
)
|
|
||||||
|
|
||||||
// init AdvertisementRouter
|
|
||||||
func NewAdvertisementRouter(fiber *fiber.App, controller *controller.Controller) *AdvertisementRouter {
|
|
||||||
return &AdvertisementRouter{
|
|
||||||
App: fiber,
|
|
||||||
Controller: controller,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// register routes of Advertisement module
|
|
||||||
func (_i *AdvertisementRouter) RegisterAdvertisementRoutes() {
|
|
||||||
// define controllers
|
|
||||||
advertisementController := _i.Controller.Advertisement
|
|
||||||
|
|
||||||
// define routes
|
|
||||||
_i.App.Route("/advertisement", func(router fiber.Router) {
|
|
||||||
router.Get("/", advertisementController.All)
|
|
||||||
router.Get("/:id", advertisementController.Show)
|
|
||||||
router.Post("/", advertisementController.Save)
|
|
||||||
router.Post("/upload/:id", advertisementController.Upload)
|
|
||||||
router.Get("/viewer/:filename", advertisementController.Viewer)
|
|
||||||
router.Put("/:id", advertisementController.Update)
|
|
||||||
router.Put("/publish/:id", advertisementController.UpdatePublish)
|
|
||||||
router.Delete("/:id", advertisementController.Delete)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,284 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/advertisement/request"
|
|
||||||
"jaecoo-be/app/module/advertisement/service"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
|
|
||||||
utilRes "jaecoo-be/utils/response"
|
|
||||||
utilVal "jaecoo-be/utils/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
type advertisementController struct {
|
|
||||||
advertisementService service.AdvertisementService
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdvertisementController interface {
|
|
||||||
All(c *fiber.Ctx) error
|
|
||||||
Show(c *fiber.Ctx) error
|
|
||||||
Save(c *fiber.Ctx) error
|
|
||||||
Upload(c *fiber.Ctx) error
|
|
||||||
Update(c *fiber.Ctx) error
|
|
||||||
UpdatePublish(c *fiber.Ctx) error
|
|
||||||
Delete(c *fiber.Ctx) error
|
|
||||||
Viewer(c *fiber.Ctx) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAdvertisementController(advertisementService service.AdvertisementService, log zerolog.Logger) AdvertisementController {
|
|
||||||
return &advertisementController{
|
|
||||||
advertisementService: advertisementService,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All get all Advertisement
|
|
||||||
// @Summary Get all Advertisement
|
|
||||||
// @Description API for getting all Advertisement
|
|
||||||
// @Tags Advertisement
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param req query request.AdvertisementQueryRequest false "query parameters"
|
|
||||||
// @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 /advertisement [get]
|
|
||||||
func (_i *advertisementController) All(c *fiber.Ctx) error {
|
|
||||||
paginate, err := paginator.Paginate(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
reqContext := request.AdvertisementQueryRequestContext{
|
|
||||||
Title: c.Query("title"),
|
|
||||||
Description: c.Query("description"),
|
|
||||||
RedirectLink: c.Query("redirectLink"),
|
|
||||||
Placement: c.Query("placement"),
|
|
||||||
StatusId: c.Query("statusId"),
|
|
||||||
}
|
|
||||||
req := reqContext.ToParamRequest()
|
|
||||||
req.Pagination = paginate
|
|
||||||
|
|
||||||
advertisementData, paging, err := _i.advertisementService.All(req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Advertisement list successfully retrieved"},
|
|
||||||
Data: advertisementData,
|
|
||||||
Meta: paging,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show get one Advertisement
|
|
||||||
// @Summary Get one Advertisement
|
|
||||||
// @Description API for getting one Advertisement
|
|
||||||
// @Tags Advertisement
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param id path int true "Advertisement ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /advertisement/{id} [get]
|
|
||||||
func (_i *advertisementController) Show(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
advertisementData, err := _i.advertisementService.Show(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Advertisement successfully retrieved"},
|
|
||||||
Data: advertisementData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save create Advertisement
|
|
||||||
// @Summary Create Advertisement
|
|
||||||
// @Description API for create Advertisement
|
|
||||||
// @Tags Advertisement
|
|
||||||
// @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.AdvertisementCreateRequest true "Required payload"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /advertisement [post]
|
|
||||||
func (_i *advertisementController) Save(c *fiber.Ctx) error {
|
|
||||||
req := new(request.AdvertisementCreateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
dataResult, err := _i.advertisementService.Save(*req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Advertisement successfully created"},
|
|
||||||
Data: dataResult,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload Advertisement
|
|
||||||
// @Summary Upload Advertisement
|
|
||||||
// @Description API for Upload File Advertisement
|
|
||||||
// @Tags Advertisement
|
|
||||||
// @Security Bearer
|
|
||||||
// @Produce json
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param file formData file true "Upload file" multiple false
|
|
||||||
// @Param id path int true "Advertisement ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /advertisement/upload/{id} [post]
|
|
||||||
func (_i *advertisementController) Upload(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.advertisementService.Upload(c, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Advertisement successfully upload"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update update Advertisement
|
|
||||||
// @Summary update Advertisement
|
|
||||||
// @Description API for update Advertisement
|
|
||||||
// @Tags Advertisement
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param payload body request.AdvertisementUpdateRequest true "Required payload"
|
|
||||||
// @Param id path int true "Advertisement ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /advertisement/{id} [put]
|
|
||||||
func (_i *advertisementController) Update(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
req := new(request.AdvertisementUpdateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.advertisementService.Update(uint(id), *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Advertisement successfully updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdatePublish Advertisement
|
|
||||||
// @Summary Update Publish Advertisement
|
|
||||||
// @Description API for Update Publish Advertisement
|
|
||||||
// @Tags Advertisement
|
|
||||||
// @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 "Advertisement ID"
|
|
||||||
// @Param isPublish query bool true "Advertisement Publish Status"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /advertisement/publish/{id} [put]
|
|
||||||
func (_i *advertisementController) UpdatePublish(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
isPublish, err := strconv.ParseBool(c.Query("isPublish"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.advertisementService.UpdatePublish(uint(id), isPublish)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Advertisement successfully publish updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete delete Advertisement
|
|
||||||
// @Summary delete Advertisement
|
|
||||||
// @Description API for delete Advertisement
|
|
||||||
// @Tags Advertisement
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param id path int true "Advertisement ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /advertisement/{id} [delete]
|
|
||||||
func (_i *advertisementController) Delete(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.advertisementService.Delete(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Advertisement successfully deleted"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Viewer Advertisement
|
|
||||||
// @Summary Viewer Advertisement
|
|
||||||
// @Description API for Viewer Advertisement
|
|
||||||
// @Tags Advertisement
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param filename path string true "Content File Name"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /advertisement/viewer/{filename} [get]
|
|
||||||
func (_i *advertisementController) Viewer(c *fiber.Ctx) error {
|
|
||||||
return _i.advertisementService.Viewer(c)
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/advertisement/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
Advertisement AdvertisementController
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewController(AdvertisementService service.AdvertisementService, log zerolog.Logger) *Controller {
|
|
||||||
return &Controller{
|
|
||||||
Advertisement: NewAdvertisementController(AdvertisementService, log),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
res "jaecoo-be/app/module/advertisement/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AdvertisementResponseMapper(advertisementReq *entity.Advertisement, host string) (advertisementRes *res.AdvertisementResponse) {
|
|
||||||
if advertisementReq != nil {
|
|
||||||
advertisementRes = &res.AdvertisementResponse{
|
|
||||||
ID: advertisementReq.ID,
|
|
||||||
Title: advertisementReq.Title,
|
|
||||||
Description: advertisementReq.Description,
|
|
||||||
RedirectLink: advertisementReq.RedirectLink,
|
|
||||||
Placement: advertisementReq.Placement,
|
|
||||||
StatusId: advertisementReq.StatusId,
|
|
||||||
IsActive: advertisementReq.IsActive,
|
|
||||||
IsPublish: advertisementReq.IsPublish,
|
|
||||||
CreatedAt: advertisementReq.CreatedAt,
|
|
||||||
UpdatedAt: advertisementReq.UpdatedAt,
|
|
||||||
}
|
|
||||||
|
|
||||||
if advertisementReq.ContentFilePath != nil {
|
|
||||||
advertisementRes.ContentFileUrl = host + "/advertisement/viewer/" + *advertisementReq.ContentFileName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return advertisementRes
|
|
||||||
}
|
|
||||||
|
|
@ -1,124 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"jaecoo-be/app/database"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/advertisement/request"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type advertisementRepository struct {
|
|
||||||
DB *database.Database
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdvertisementRepository define interface of IAdvertisementRepository
|
|
||||||
type AdvertisementRepository interface {
|
|
||||||
GetAll(req request.AdvertisementQueryRequest) (advertisements []*entity.Advertisement, paging paginator.Pagination, err error)
|
|
||||||
FindOne(id uint) (advertisement *entity.Advertisement, err error)
|
|
||||||
FindByFilename(contentFilename string) (advertisement *entity.Advertisement, err error)
|
|
||||||
Create(advertisement *entity.Advertisement) (advertisementReturn *entity.Advertisement, err error)
|
|
||||||
Update(id uint, advertisement *entity.Advertisement) (err error)
|
|
||||||
Delete(id uint) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAdvertisementRepository(db *database.Database, logger zerolog.Logger) AdvertisementRepository {
|
|
||||||
return &advertisementRepository{
|
|
||||||
DB: db,
|
|
||||||
Log: logger,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// implement interface of IAdvertisementRepository
|
|
||||||
func (_i *advertisementRepository) GetAll(req request.AdvertisementQueryRequest) (advertisements []*entity.Advertisement, paging paginator.Pagination, err error) {
|
|
||||||
var count int64
|
|
||||||
|
|
||||||
query := _i.DB.DB.Model(&entity.Advertisement{})
|
|
||||||
|
|
||||||
query = query.Where("is_active = ?", true)
|
|
||||||
|
|
||||||
if req.Title != nil && *req.Title != "" {
|
|
||||||
title := strings.ToLower(*req.Title)
|
|
||||||
query = query.Where("LOWER(title) LIKE ?", "%"+strings.ToLower(title)+"%")
|
|
||||||
}
|
|
||||||
if req.Description != nil && *req.Description != "" {
|
|
||||||
description := strings.ToLower(*req.Description)
|
|
||||||
query = query.Where("LOWER(description) LIKE ?", "%"+strings.ToLower(description)+"%")
|
|
||||||
}
|
|
||||||
if req.RedirectLink != nil && *req.RedirectLink != "" {
|
|
||||||
redirectLink := strings.ToLower(*req.RedirectLink)
|
|
||||||
query = query.Where("LOWER(redirect_link) LIKE ?", "%"+strings.ToLower(redirectLink)+"%")
|
|
||||||
}
|
|
||||||
if req.Placement != nil && *req.Placement != "" {
|
|
||||||
placement := strings.ToLower(*req.Placement)
|
|
||||||
query = query.Where("LOWER(placement) LIKE ?", "%"+strings.ToLower(placement)+"%")
|
|
||||||
}
|
|
||||||
if req.StatusId != nil {
|
|
||||||
query = query.Where("status_id = ?", req.StatusId)
|
|
||||||
}
|
|
||||||
query.Count(&count)
|
|
||||||
|
|
||||||
if req.Pagination.SortBy != "" {
|
|
||||||
direction := "ASC"
|
|
||||||
if req.Pagination.Sort == "desc" {
|
|
||||||
direction = "DESC"
|
|
||||||
}
|
|
||||||
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Pagination.Count = count
|
|
||||||
req.Pagination = paginator.Paging(req.Pagination)
|
|
||||||
|
|
||||||
err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&advertisements).Error
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
paging = *req.Pagination
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementRepository) FindOne(id uint) (advertisement *entity.Advertisement, err error) {
|
|
||||||
query := _i.DB.DB.Where("id = ?", id)
|
|
||||||
|
|
||||||
if err := query.First(&advertisement).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return advertisement, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementRepository) FindByFilename(contentFilename string) (advertisement *entity.Advertisement, err error) {
|
|
||||||
query := _i.DB.DB.Where("content_file_name = ?", contentFilename)
|
|
||||||
|
|
||||||
if err := query.First(&advertisement).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return advertisement, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementRepository) Create(advertisement *entity.Advertisement) (advertisementReturn *entity.Advertisement, err error) {
|
|
||||||
result := _i.DB.DB.Create(advertisement)
|
|
||||||
return advertisement, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementRepository) Update(id uint, advertisement *entity.Advertisement) (err error) {
|
|
||||||
advertisementMap, err := utilSvc.StructToMap(advertisement)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
query := _i.DB.DB.Model(&entity.Advertisement{}).Where(&entity.Advertisement{ID: id})
|
|
||||||
return query.Updates(advertisementMap).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementRepository) Delete(id uint) error {
|
|
||||||
query := _i.DB.DB.Model(&entity.Advertisement{}).Where("id = ?", id)
|
|
||||||
return query.Delete(&entity.Advertisement{}).Error
|
|
||||||
}
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AdvertisementGeneric interface {
|
|
||||||
ToEntity()
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdvertisementQueryRequest struct {
|
|
||||||
Title *string `json:"title"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
RedirectLink *string `json:"redirectLink"`
|
|
||||||
Placement *string `json:"placement"`
|
|
||||||
IsPublish *bool `json:"isPublish"`
|
|
||||||
StatusId *int `json:"statusId"`
|
|
||||||
Pagination *paginator.Pagination `json:"pagination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdvertisementCreateRequest struct {
|
|
||||||
Title string `json:"title" validate:"required"`
|
|
||||||
Description string `json:"description" validate:"required"`
|
|
||||||
RedirectLink string `json:"redirectLink" validate:"required"`
|
|
||||||
Placement string `json:"placement" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AdvertisementCreateRequest) ToEntity() *entity.Advertisement {
|
|
||||||
return &entity.Advertisement{
|
|
||||||
Title: req.Title,
|
|
||||||
Description: req.Description,
|
|
||||||
RedirectLink: req.RedirectLink,
|
|
||||||
Placement: req.Placement,
|
|
||||||
StatusId: 1,
|
|
||||||
IsPublish: true,
|
|
||||||
IsActive: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdvertisementUpdateRequest struct {
|
|
||||||
ID uint `json:"id" validate:"required"`
|
|
||||||
Title string `json:"title" validate:"required"`
|
|
||||||
Description string `json:"description" validate:"required"`
|
|
||||||
RedirectLink string `json:"redirectLink" validate:"required"`
|
|
||||||
Placement string `json:"placement" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AdvertisementUpdateRequest) ToEntity() *entity.Advertisement {
|
|
||||||
return &entity.Advertisement{
|
|
||||||
ID: req.ID,
|
|
||||||
Title: req.Title,
|
|
||||||
Description: req.Description,
|
|
||||||
RedirectLink: req.RedirectLink,
|
|
||||||
Placement: req.Placement,
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AdvertisementQueryRequestContext struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
RedirectLink string `json:"redirectLink"`
|
|
||||||
Placement string `json:"placement"`
|
|
||||||
StatusId string `json:"statusId"`
|
|
||||||
IsPublish string `json:"isPublish"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AdvertisementQueryRequestContext) ToParamRequest() AdvertisementQueryRequest {
|
|
||||||
var request AdvertisementQueryRequest
|
|
||||||
|
|
||||||
if title := req.Title; title != "" {
|
|
||||||
request.Title = &title
|
|
||||||
}
|
|
||||||
if description := req.Description; description != "" {
|
|
||||||
request.Description = &description
|
|
||||||
}
|
|
||||||
if redirectLink := req.RedirectLink; redirectLink != "" {
|
|
||||||
request.RedirectLink = &redirectLink
|
|
||||||
}
|
|
||||||
if placement := req.Placement; placement != "" {
|
|
||||||
request.Placement = &placement
|
|
||||||
}
|
|
||||||
if isPublishStr := req.IsPublish; isPublishStr != "" {
|
|
||||||
isPublish, err := strconv.ParseBool(isPublishStr)
|
|
||||||
if err == nil {
|
|
||||||
request.IsPublish = &isPublish
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if statusIdStr := req.StatusId; statusIdStr != "" {
|
|
||||||
statusId, err := strconv.Atoi(statusIdStr)
|
|
||||||
if err == nil {
|
|
||||||
request.StatusId = &statusId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return request
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package response
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type AdvertisementResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
RedirectLink string `json:"redirectLink"`
|
|
||||||
ContentFileUrl string `json:"contentFileUrl"`
|
|
||||||
Placement string `json:"placement"`
|
|
||||||
StatusId int `json:"statusId"`
|
|
||||||
IsPublish bool `json:"isPublish"`
|
|
||||||
IsActive bool `json:"isActive"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,264 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/advertisement/mapper"
|
|
||||||
"jaecoo-be/app/module/advertisement/repository"
|
|
||||||
"jaecoo-be/app/module/advertisement/request"
|
|
||||||
"jaecoo-be/app/module/advertisement/response"
|
|
||||||
usersRepository "jaecoo-be/app/module/users/repository"
|
|
||||||
config "jaecoo-be/config/config"
|
|
||||||
minioStorage "jaecoo-be/config/config"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"log"
|
|
||||||
"math/rand"
|
|
||||||
"mime"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/minio/minio-go/v7"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AdvertisementService
|
|
||||||
type advertisementService struct {
|
|
||||||
Repo repository.AdvertisementRepository
|
|
||||||
UsersRepo usersRepository.UsersRepository
|
|
||||||
Log zerolog.Logger
|
|
||||||
Cfg *config.Config
|
|
||||||
MinioStorage *minioStorage.MinioStorage
|
|
||||||
}
|
|
||||||
|
|
||||||
// AdvertisementService define interface of IAdvertisementService
|
|
||||||
type AdvertisementService interface {
|
|
||||||
All(req request.AdvertisementQueryRequest) (advertisement []*response.AdvertisementResponse, paging paginator.Pagination, err error)
|
|
||||||
Show(id uint) (advertisement *response.AdvertisementResponse, err error)
|
|
||||||
Save(req request.AdvertisementCreateRequest) (advertisement *entity.Advertisement, err error)
|
|
||||||
Upload(c *fiber.Ctx, id uint) (err error)
|
|
||||||
Update(id uint, req request.AdvertisementUpdateRequest) (err error)
|
|
||||||
UpdatePublish(id uint, isPublish bool) (err error)
|
|
||||||
Delete(id uint) error
|
|
||||||
Viewer(c *fiber.Ctx) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAdvertisementService init AdvertisementService
|
|
||||||
func NewAdvertisementService(repo repository.AdvertisementRepository, minioStorage *minioStorage.MinioStorage, usersRepo usersRepository.UsersRepository, log zerolog.Logger, cfg *config.Config) AdvertisementService {
|
|
||||||
|
|
||||||
return &advertisementService{
|
|
||||||
Repo: repo,
|
|
||||||
UsersRepo: usersRepo,
|
|
||||||
MinioStorage: minioStorage,
|
|
||||||
Log: log,
|
|
||||||
Cfg: cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All implement interface of AdvertisementService
|
|
||||||
func (_i *advertisementService) All(req request.AdvertisementQueryRequest) (advertisements []*response.AdvertisementResponse, paging paginator.Pagination, err error) {
|
|
||||||
results, paging, err := _i.Repo.GetAll(req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
host := _i.Cfg.App.Domain
|
|
||||||
for _, result := range results {
|
|
||||||
advertisements = append(advertisements, mapper.AdvertisementResponseMapper(result, host))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementService) Show(id uint) (advertisement *response.AdvertisementResponse, err error) {
|
|
||||||
result, err := _i.Repo.FindOne(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
host := _i.Cfg.App.Domain
|
|
||||||
return mapper.AdvertisementResponseMapper(result, host), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementService) Save(req request.AdvertisementCreateRequest) (advertisement *entity.Advertisement, err error) {
|
|
||||||
_i.Log.Info().Interface("data", req).Msg("")
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
return _i.Repo.Create(newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementService) Upload(c *fiber.Ctx, id uint) (err error) {
|
|
||||||
bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName
|
|
||||||
|
|
||||||
form, err := c.MultipartForm()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
//filess := form.File["files"]
|
|
||||||
|
|
||||||
// Create minio connection.
|
|
||||||
minioClient, err := _i.MinioStorage.ConnectMinio()
|
|
||||||
|
|
||||||
result, err := _i.Repo.FindOne(id)
|
|
||||||
|
|
||||||
if result == nil {
|
|
||||||
// Return status 400. Id not found.
|
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
|
||||||
"error": true,
|
|
||||||
"msg": err.Error(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
// Return status 500 and minio connection error.
|
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
||||||
"error": true,
|
|
||||||
"msg": err.Error(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, files := range form.File {
|
|
||||||
|
|
||||||
_i.Log.Info().Str("timestamp", time.Now().
|
|
||||||
Format(time.RFC3339)).Str("Service:Resource", "Uploader:: top").
|
|
||||||
Interface("files", files).Msg("")
|
|
||||||
|
|
||||||
for _, fileHeader := range files {
|
|
||||||
_i.Log.Info().Str("timestamp", time.Now().
|
|
||||||
Format(time.RFC3339)).Str("Service:Resource", "Uploader:: loop").
|
|
||||||
Interface("data", fileHeader).Msg("")
|
|
||||||
|
|
||||||
src, err := fileHeader.Open()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer src.Close()
|
|
||||||
|
|
||||||
filename := filepath.Base(fileHeader.Filename)
|
|
||||||
filename = strings.ReplaceAll(filename, " ", "")
|
|
||||||
filenameWithoutExt := filepath.Clean(filename[:len(filename)-len(filepath.Ext(filename))])
|
|
||||||
extension := filepath.Ext(fileHeader.Filename)[1:]
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
rand.New(rand.NewSource(now.UnixNano()))
|
|
||||||
randUniqueId := rand.Intn(1000000)
|
|
||||||
|
|
||||||
newFilenameWithoutExt := filenameWithoutExt + "_" + strconv.Itoa(randUniqueId)
|
|
||||||
newFilename := newFilenameWithoutExt + "." + extension
|
|
||||||
|
|
||||||
objectName := fmt.Sprintf("advertisement/upload/%d/%d/%s", now.Year(), now.Month(), newFilename)
|
|
||||||
|
|
||||||
result.ContentFileName = &newFilename
|
|
||||||
result.ContentFilePath = &objectName
|
|
||||||
|
|
||||||
err = _i.Repo.Update(id, result)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload file ke MinIO
|
|
||||||
_, err = minioClient.PutObject(context.Background(), bucketName, objectName, src, fileHeader.Size, minio.PutObjectOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementService) Update(id uint, req request.AdvertisementUpdateRequest) (err error) {
|
|
||||||
_i.Log.Info().Interface("data", req).Msg("")
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
return _i.Repo.Update(id, newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementService) UpdatePublish(id uint, isPublish bool) (err error) {
|
|
||||||
_i.Log.Info().Str("timestamp", time.Now().
|
|
||||||
Format(time.RFC3339)).Str("Service:Resource", "UpdatePublish").
|
|
||||||
Interface("ids", id).Msg("")
|
|
||||||
_i.Log.Info().Str("timestamp", time.Now().
|
|
||||||
Format(time.RFC3339)).Str("Service:Resource", "UpdatePublish").
|
|
||||||
Interface("isPublish", isPublish).Msg("")
|
|
||||||
|
|
||||||
result, err := _i.Repo.FindOne(id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
result.IsPublish = isPublish
|
|
||||||
|
|
||||||
_i.Log.Info().Str("timestamp", time.Now().
|
|
||||||
Format(time.RFC3339)).Str("Service:Resource", "UpdatePublish").
|
|
||||||
Interface("result", result).Msg("")
|
|
||||||
|
|
||||||
return _i.Repo.Update(id, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementService) Delete(id uint) error {
|
|
||||||
result, err := _i.Repo.FindOne(id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
result.IsActive = false
|
|
||||||
return _i.Repo.Update(id, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *advertisementService) Viewer(c *fiber.Ctx) (err error) {
|
|
||||||
filename := c.Params("filename")
|
|
||||||
result, err := _i.Repo.FindByFilename(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName
|
|
||||||
objectName := *result.ContentFilePath
|
|
||||||
|
|
||||||
// Create minio connection.
|
|
||||||
minioClient, err := _i.MinioStorage.ConnectMinio()
|
|
||||||
if err != nil {
|
|
||||||
// Return status 500 and minio connection error.
|
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
||||||
"error": true,
|
|
||||||
"msg": err.Error(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fileContent, err := minioClient.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalln(err)
|
|
||||||
}
|
|
||||||
defer fileContent.Close()
|
|
||||||
|
|
||||||
// Tentukan Content-Type berdasarkan ekstensi file
|
|
||||||
contentType := mime.TypeByExtension("." + getFileExtension(objectName))
|
|
||||||
if contentType == "" {
|
|
||||||
contentType = "application/octet-stream" // fallback jika tidak ada tipe MIME yang cocok
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Set("Content-Type", contentType)
|
|
||||||
|
|
||||||
if _, err := io.Copy(c.Response().BodyWriter(), fileContent); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFileExtension(filename string) string {
|
|
||||||
// split file name
|
|
||||||
parts := strings.Split(filename, ".")
|
|
||||||
|
|
||||||
// jika tidak ada ekstensi, kembalikan string kosong
|
|
||||||
if len(parts) == 1 || (len(parts) == 2 && parts[0] == "") {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// ambil ekstensi terakhir
|
|
||||||
return parts[len(parts)-1]
|
|
||||||
}
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
package ai_chat
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/ai_chat/controller"
|
|
||||||
"jaecoo-be/app/module/ai_chat/repository"
|
|
||||||
"jaecoo-be/app/module/ai_chat/service"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"go.uber.org/fx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// struct of AIChatRouter
|
|
||||||
type AIChatRouter struct {
|
|
||||||
App fiber.Router
|
|
||||||
Controller controller.AIChatController
|
|
||||||
}
|
|
||||||
|
|
||||||
// register bulky of AI Chat module
|
|
||||||
var NewAIChatModule = fx.Options(
|
|
||||||
// register repository of AI Chat module
|
|
||||||
fx.Provide(repository.NewAIChatRepository),
|
|
||||||
|
|
||||||
// register service of AI Chat module
|
|
||||||
fx.Provide(service.NewAIChatService),
|
|
||||||
|
|
||||||
// register controller of AI Chat module
|
|
||||||
fx.Provide(controller.NewAIChatController),
|
|
||||||
|
|
||||||
// register router of AI Chat module
|
|
||||||
fx.Provide(NewAIChatRouter),
|
|
||||||
)
|
|
||||||
|
|
||||||
// init AIChatRouter
|
|
||||||
func NewAIChatRouter(fiber *fiber.App, controller controller.AIChatController) *AIChatRouter {
|
|
||||||
return &AIChatRouter{
|
|
||||||
App: fiber,
|
|
||||||
Controller: controller,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// register routes of AI Chat module
|
|
||||||
func (_i *AIChatRouter) RegisterAIChatRoutes() {
|
|
||||||
// define controllers
|
|
||||||
aiChatController := _i.Controller
|
|
||||||
|
|
||||||
// define routes
|
|
||||||
_i.App.Route("/ai-chat", func(router fiber.Router) {
|
|
||||||
// Sessions routes
|
|
||||||
router.Get("/sessions", aiChatController.GetUserSessions)
|
|
||||||
router.Get("/sessions/:id", aiChatController.GetSession)
|
|
||||||
router.Post("/sessions", aiChatController.CreateSession)
|
|
||||||
router.Put("/sessions/:id", aiChatController.UpdateSession)
|
|
||||||
router.Delete("/sessions/:id", aiChatController.DeleteSession)
|
|
||||||
|
|
||||||
// Messages routes
|
|
||||||
router.Get("/sessions/:id/messages", aiChatController.GetSessionMessages)
|
|
||||||
router.Post("/sessions/messages", aiChatController.SendMessage)
|
|
||||||
router.Put("/sessions/messages/:messageId", aiChatController.UpdateMessage)
|
|
||||||
router.Delete("/sessions/messages/:messageId", aiChatController.DeleteMessage)
|
|
||||||
|
|
||||||
// Logs routes
|
|
||||||
router.Get("/logs", aiChatController.GetUserLogs)
|
|
||||||
router.Get("/logs/:id", aiChatController.GetLog)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,438 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/ai_chat/request"
|
|
||||||
"jaecoo-be/app/module/ai_chat/service"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilRes "jaecoo-be/utils/response"
|
|
||||||
utilVal "jaecoo-be/utils/validator"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type aiChatController struct {
|
|
||||||
aiChatService service.AIChatService
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatController interface {
|
|
||||||
// AI Chat Sessions
|
|
||||||
GetUserSessions(c *fiber.Ctx) error
|
|
||||||
GetSession(c *fiber.Ctx) error
|
|
||||||
CreateSession(c *fiber.Ctx) error
|
|
||||||
UpdateSession(c *fiber.Ctx) error
|
|
||||||
DeleteSession(c *fiber.Ctx) error
|
|
||||||
|
|
||||||
// AI Chat Messages
|
|
||||||
GetSessionMessages(c *fiber.Ctx) error
|
|
||||||
SendMessage(c *fiber.Ctx) error
|
|
||||||
UpdateMessage(c *fiber.Ctx) error
|
|
||||||
DeleteMessage(c *fiber.Ctx) error
|
|
||||||
|
|
||||||
// AI Chat Logs
|
|
||||||
GetUserLogs(c *fiber.Ctx) error
|
|
||||||
GetLog(c *fiber.Ctx) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAIChatController(aiChatService service.AIChatService, log zerolog.Logger) AIChatController {
|
|
||||||
return &aiChatController{
|
|
||||||
aiChatService: aiChatService,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get User Sessions
|
|
||||||
// @Summary Get user AI chat sessions
|
|
||||||
// @Description API for getting all AI chat sessions for authenticated user
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param req query request.AIChatSessionsQueryRequest false "query parameters"
|
|
||||||
// @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 /ai-chat/sessions [get]
|
|
||||||
func (_i *aiChatController) GetUserSessions(c *fiber.Ctx) error {
|
|
||||||
paginate, err := paginator.Paginate(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
reqContext := request.AIChatSessionsQueryRequestContext{
|
|
||||||
IsActive: c.Query("isActive"),
|
|
||||||
}
|
|
||||||
req := reqContext.ToParamRequest()
|
|
||||||
req.Pagination = paginate
|
|
||||||
|
|
||||||
sessionsData, paging, err := _i.aiChatService.GetUserSessions(authHeader, req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat sessions successfully retrieved"},
|
|
||||||
Data: sessionsData,
|
|
||||||
Meta: paging,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Session
|
|
||||||
// @Summary Get one AI chat session
|
|
||||||
// @Description API for getting one AI chat session
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param id path int true "Session ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /ai-chat/sessions/{id} [get]
|
|
||||||
func (_i *aiChatController) GetSession(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
sessionData, err := _i.aiChatService.GetSession(authHeader, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat session successfully retrieved"},
|
|
||||||
Data: sessionData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create Session
|
|
||||||
// @Summary Create AI chat session
|
|
||||||
// @Description API for create AI chat session
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param payload body request.AIChatSessionsCreateRequest true "Required payload"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /ai-chat/sessions [post]
|
|
||||||
func (_i *aiChatController) CreateSession(c *fiber.Ctx) error {
|
|
||||||
req := new(request.AIChatSessionsCreateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
dataResult, err := _i.aiChatService.CreateSession(authHeader, *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat session successfully created"},
|
|
||||||
Data: dataResult,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Session
|
|
||||||
// @Summary Update AI chat session
|
|
||||||
// @Description API for update AI chat session
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
|
||||||
// @Param id path int true "Session ID"
|
|
||||||
// @Param payload body request.AIChatSessionsUpdateRequest true "Required payload"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /ai-chat/sessions/{id} [put]
|
|
||||||
func (_i *aiChatController) UpdateSession(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
req := new(request.AIChatSessionsUpdateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
err = _i.aiChatService.UpdateSession(authHeader, uint(id), *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat session successfully updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete Session
|
|
||||||
// @Summary Delete AI chat session
|
|
||||||
// @Description API for delete AI chat session
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param id path int true "Session ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /ai-chat/sessions/{id} [delete]
|
|
||||||
func (_i *aiChatController) DeleteSession(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
err = _i.aiChatService.DeleteSession(authHeader, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat session successfully deleted"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Session Messages
|
|
||||||
// @Summary Get AI chat session messages
|
|
||||||
// @Description API for getting all messages in an AI chat session
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param id path int true "Session ID"
|
|
||||||
// @Param req query request.AIChatMessagesQueryRequest false "query parameters"
|
|
||||||
// @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 /ai-chat/sessions/{id}/messages [get]
|
|
||||||
func (_i *aiChatController) GetSessionMessages(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
paginate, err := paginator.Paginate(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
reqContext := request.AIChatMessagesQueryRequestContext{}
|
|
||||||
req := reqContext.ToParamRequest()
|
|
||||||
req.Pagination = paginate
|
|
||||||
|
|
||||||
messagesData, paging, err := _i.aiChatService.GetSessionMessages(authHeader, uint(id), req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat messages successfully retrieved"},
|
|
||||||
Data: messagesData,
|
|
||||||
Meta: paging,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send Message
|
|
||||||
// @Summary Send message to AI chat session
|
|
||||||
// @Description API for sending a message to an AI chat session
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param payload body request.AIChatMessagesCreateRequest true "Required payload"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /ai-chat/sessions/messages [post]
|
|
||||||
func (_i *aiChatController) SendMessage(c *fiber.Ctx) error {
|
|
||||||
req := new(request.AIChatMessagesCreateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
dataResult, err := _i.aiChatService.SendMessage(authHeader, *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Message successfully sent"},
|
|
||||||
Data: dataResult,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Message
|
|
||||||
// @Summary Update AI chat message
|
|
||||||
// @Description API for update AI chat message
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param messageId path int true "Message ID"
|
|
||||||
// @Param payload body request.AIChatMessagesUpdateRequest true "Required payload"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /ai-chat/sessions/messages/{messageId} [put]
|
|
||||||
func (_i *aiChatController) UpdateMessage(c *fiber.Ctx) error {
|
|
||||||
messageId, err := strconv.ParseUint(c.Params("messageId"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
req := new(request.AIChatMessagesUpdateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
err = _i.aiChatService.UpdateMessage(authHeader, uint(messageId), *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat message successfully updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete Message
|
|
||||||
// @Summary Delete AI chat message
|
|
||||||
// @Description API for delete AI chat message
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param messageId path int true "Message ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /ai-chat/sessions/messages/{messageId} [delete]
|
|
||||||
func (_i *aiChatController) DeleteMessage(c *fiber.Ctx) error {
|
|
||||||
messageId, err := strconv.ParseUint(c.Params("messageId"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
err = _i.aiChatService.DeleteMessage(authHeader, uint(messageId))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat message successfully deleted"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get User Logs
|
|
||||||
// @Summary Get user AI chat logs
|
|
||||||
// @Description API for getting all AI chat logs for authenticated user
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param req query request.AIChatLogsQueryRequest false "query parameters"
|
|
||||||
// @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 /ai-chat/logs [get]
|
|
||||||
func (_i *aiChatController) GetUserLogs(c *fiber.Ctx) error {
|
|
||||||
paginate, err := paginator.Paginate(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
reqContext := request.AIChatLogsQueryRequestContext{
|
|
||||||
LogType: c.Query("logType"),
|
|
||||||
}
|
|
||||||
req := reqContext.ToParamRequest()
|
|
||||||
req.Pagination = paginate
|
|
||||||
|
|
||||||
logsData, paging, err := _i.aiChatService.GetUserLogs(authHeader, req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat logs successfully retrieved"},
|
|
||||||
Data: logsData,
|
|
||||||
Meta: paging,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Log
|
|
||||||
// @Summary Get one AI chat log
|
|
||||||
// @Description API for getting one AI chat log
|
|
||||||
// @Tags AI Chat
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param id path int true "Log ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /ai-chat/logs/{id} [get]
|
|
||||||
func (_i *aiChatController) GetLog(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authHeader := c.Get("Authorization")
|
|
||||||
|
|
||||||
logData, err := _i.aiChatService.GetLog(authHeader, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"AI chat log successfully retrieved"},
|
|
||||||
Data: logData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/ai_chat/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AIChatSessionsResponseMapper(session *entity.AIChatSessions) *response.AIChatSessionsResponse {
|
|
||||||
result := &response.AIChatSessionsResponse{
|
|
||||||
ID: session.ID,
|
|
||||||
SessionID: session.SessionID,
|
|
||||||
UserID: session.UserID,
|
|
||||||
AgentID: session.AgentID,
|
|
||||||
Title: session.Title,
|
|
||||||
MessageCount: session.MessageCount,
|
|
||||||
IsActive: session.IsActive,
|
|
||||||
CreatedAt: session.CreatedAt,
|
|
||||||
UpdatedAt: session.UpdatedAt,
|
|
||||||
}
|
|
||||||
|
|
||||||
if session.User != nil {
|
|
||||||
result.User = &response.UserBasicInfo{
|
|
||||||
ID: session.User.ID,
|
|
||||||
Username: session.User.Username,
|
|
||||||
Fullname: session.User.Fullname,
|
|
||||||
Email: session.User.Email,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func AIChatMessagesResponseMapper(message *entity.AIChatMessages) *response.AIChatMessagesResponse {
|
|
||||||
return &response.AIChatMessagesResponse{
|
|
||||||
ID: message.ID,
|
|
||||||
SessionID: message.SessionID,
|
|
||||||
MessageType: message.MessageType,
|
|
||||||
Content: message.Content,
|
|
||||||
IsActive: message.IsActive,
|
|
||||||
CreatedAt: message.CreatedAt,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AIChatSessionWithMessagesResponseMapper(session *entity.AIChatSessions, messages []*entity.AIChatMessages) *response.AIChatSessionWithMessagesResponse {
|
|
||||||
sessionResponse := AIChatSessionsResponseMapper(session)
|
|
||||||
|
|
||||||
var messagesResponse []*response.AIChatMessagesResponse
|
|
||||||
for _, message := range messages {
|
|
||||||
messagesResponse = append(messagesResponse, AIChatMessagesResponseMapper(message))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.AIChatSessionWithMessagesResponse{
|
|
||||||
Session: sessionResponse,
|
|
||||||
Messages: messagesResponse,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AIChatLogsResponseMapper(log *entity.AIChatLogs) *response.AIChatLogsResponse {
|
|
||||||
result := &response.AIChatLogsResponse{
|
|
||||||
ID: log.ID,
|
|
||||||
UserID: log.UserID,
|
|
||||||
SessionID: log.SessionID,
|
|
||||||
StartDate: log.StartDate,
|
|
||||||
EndDate: log.EndDate,
|
|
||||||
TotalDuration: log.TotalDuration,
|
|
||||||
CreatedAt: log.CreatedAt,
|
|
||||||
UpdatedAt: log.UpdatedAt,
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
@ -1,198 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/ai_chat/request"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
)
|
|
||||||
|
|
||||||
type aiChatRepository struct {
|
|
||||||
DB *database.Database
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatRepository interface {
|
|
||||||
// AI Chat Sessions
|
|
||||||
GetUserSessions(userId uint, req request.AIChatSessionsQueryRequest) (sessions []*entity.AIChatSessions, paging paginator.Pagination, err error)
|
|
||||||
FindSessionByUserAndId(userId uint, sessionId uint) (session *entity.AIChatSessions, err error)
|
|
||||||
FindSessionBySessionId(sessionId string) (session *entity.AIChatSessions, err error)
|
|
||||||
CreateSession(session *entity.AIChatSessions) (result *entity.AIChatSessions, err error)
|
|
||||||
UpdateSession(userId uint, sessionId uint, session *entity.AIChatSessions) (err error)
|
|
||||||
DeleteSession(userId uint, sessionId uint) (err error)
|
|
||||||
IncrementMessageCount(sessionId uint) (err error)
|
|
||||||
|
|
||||||
// AI Chat Messages
|
|
||||||
GetSessionMessages(sessionId string, req request.AIChatMessagesQueryRequest) (messages []*entity.AIChatMessages, paging paginator.Pagination, err error)
|
|
||||||
CreateMessage(message *entity.AIChatMessages) (result *entity.AIChatMessages, err error)
|
|
||||||
UpdateMessage(messageId uint, message *entity.AIChatMessages) (err error)
|
|
||||||
DeleteMessage(messageId uint) (err error)
|
|
||||||
GetLastMessage(sessionId string) (message *entity.AIChatMessages, err error)
|
|
||||||
|
|
||||||
// AI Chat Logs
|
|
||||||
GetUserLogs(userId uint, req request.AIChatLogsQueryRequest) (logs []*entity.AIChatLogs, paging paginator.Pagination, err error)
|
|
||||||
FindLogByUserAndId(userId uint, logId uint) (log *entity.AIChatLogs, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAIChatRepository(db *database.Database) AIChatRepository {
|
|
||||||
return &aiChatRepository{
|
|
||||||
DB: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI Chat Sessions methods
|
|
||||||
func (_i *aiChatRepository) GetUserSessions(userId uint, req request.AIChatSessionsQueryRequest) (sessions []*entity.AIChatSessions, paging paginator.Pagination, err error) {
|
|
||||||
query := _i.DB.DB.Model(&entity.AIChatSessions{}).Where("user_id = ?", userId)
|
|
||||||
|
|
||||||
// Apply filters
|
|
||||||
if req.IsActive != nil {
|
|
||||||
query = query.Where("is_active = ?", *req.IsActive)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Include user relationship
|
|
||||||
// query = query.Preload("User")
|
|
||||||
|
|
||||||
// Order by updated_at desc (most recent first)
|
|
||||||
query = query.Order("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(&sessions).Error
|
|
||||||
paging = *req.Pagination
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) FindSessionByUserAndId(userId uint, sessionId uint) (session *entity.AIChatSessions, err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.AIChatSessions{}).Where("user_id = ? AND id = ?", userId, sessionId).Preload("User").First(&session).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) FindSessionBySessionId(sessionId string) (session *entity.AIChatSessions, err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.AIChatSessions{}).Where("session_id = ?", sessionId).Preload("User").First(&session).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) CreateSession(session *entity.AIChatSessions) (result *entity.AIChatSessions, err error) {
|
|
||||||
err = _i.DB.DB.Create(session).Error
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload with relationships
|
|
||||||
err = _i.DB.DB.Model(&entity.AIChatSessions{}).Preload("User").First(&result, session.ID).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) UpdateSession(userId uint, sessionId uint, session *entity.AIChatSessions) (err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.AIChatSessions{}).Where("user_id = ? AND id = ?", userId, sessionId).Updates(session).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) DeleteSession(userId uint, sessionId uint) (err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.AIChatSessions{}).Where("user_id = ? AND id = ?", userId, sessionId).Delete(&entity.AIChatSessions{}).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) IncrementMessageCount(sessionId uint) (err error) {
|
|
||||||
err = _i.DB.DB.Exec("UPDATE ai_chat_sessions SET message_count = message_count + 1 WHERE id = ?", sessionId).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI Chat Messages methods
|
|
||||||
func (_i *aiChatRepository) GetSessionMessages(sessionId string, req request.AIChatMessagesQueryRequest) (messages []*entity.AIChatMessages, paging paginator.Pagination, err error) {
|
|
||||||
query := _i.DB.DB.Model(&entity.AIChatMessages{}).Where("session_id = ?", sessionId)
|
|
||||||
|
|
||||||
// Order by created_at asc (oldest first for chat)
|
|
||||||
query = query.Order("created_at ASC")
|
|
||||||
|
|
||||||
// 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(&messages).Error
|
|
||||||
paging = *req.Pagination
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) CreateMessage(message *entity.AIChatMessages) (result *entity.AIChatMessages, err error) {
|
|
||||||
err = _i.DB.DB.Create(message).Error
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload
|
|
||||||
err = _i.DB.DB.Model(&entity.AIChatMessages{}).First(&result, message.ID).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) UpdateMessage(messageId uint, message *entity.AIChatMessages) (err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.AIChatMessages{}).Where("id = ?", messageId).Updates(message).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) DeleteMessage(messageId uint) (err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.AIChatMessages{}).Where("id = ?", messageId).Delete(&entity.AIChatMessages{}).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI Chat Logs methods
|
|
||||||
func (_i *aiChatRepository) GetUserLogs(userId uint, req request.AIChatLogsQueryRequest) (logs []*entity.AIChatLogs, paging paginator.Pagination, err error) {
|
|
||||||
var count int64
|
|
||||||
|
|
||||||
query := _i.DB.DB.Model(&entity.AIChatLogs{}).Where("user_id = ?", userId)
|
|
||||||
|
|
||||||
// Note: AIChatLogs entity doesn't have LogType field, so we skip this filter
|
|
||||||
// if req.LogType != nil && *req.LogType != "" {
|
|
||||||
// query = query.Where("log_type = ?", *req.LogType)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Count total records
|
|
||||||
err = query.Count(&count).Error
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply pagination
|
|
||||||
if req.Pagination != nil {
|
|
||||||
query = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Order by created_at desc (newest first)
|
|
||||||
query = query.Order("created_at DESC")
|
|
||||||
|
|
||||||
err = query.Find(&logs).Error
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set pagination info
|
|
||||||
if req.Pagination != nil {
|
|
||||||
paging = *req.Pagination
|
|
||||||
paging.Count = count
|
|
||||||
paging.TotalPage = int((count + int64(req.Pagination.Limit) - 1) / int64(req.Pagination.Limit))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) FindLogByUserAndId(userId uint, logId uint) (log *entity.AIChatLogs, err error) {
|
|
||||||
query := _i.DB.DB.Model(&entity.AIChatLogs{}).Where("user_id = ? AND id = ?", userId, logId)
|
|
||||||
|
|
||||||
if err := query.First(&log).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatRepository) GetLastMessage(sessionId string) (message *entity.AIChatMessages, err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.AIChatMessages{}).Where("session_id = ?", sessionId).Order("created_at DESC").First(&message).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
@ -1,114 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AI Chat Sessions Request DTOs
|
|
||||||
type AIChatSessionsQueryRequest struct {
|
|
||||||
IsActive *bool `json:"isActive"`
|
|
||||||
Pagination *paginator.Pagination `json:"pagination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatSessionsCreateRequest struct {
|
|
||||||
SessionID string `json:"sessionId" validate:"required"`
|
|
||||||
Title string `json:"title" validate:"required,min=2,max=255"`
|
|
||||||
AgentID string `json:"agentId" validate:"required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AIChatSessionsCreateRequest) ToEntity() *entity.AIChatSessions {
|
|
||||||
return &entity.AIChatSessions{
|
|
||||||
SessionID: req.SessionID,
|
|
||||||
AgentID: req.AgentID,
|
|
||||||
Title: req.Title,
|
|
||||||
MessageCount: 0,
|
|
||||||
IsActive: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatSessionsUpdateRequest struct {
|
|
||||||
Title string `json:"title" validate:"required,min=2,max=255"`
|
|
||||||
IsActive bool `json:"isActive"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AIChatSessionsUpdateRequest) ToEntity() *entity.AIChatSessions {
|
|
||||||
return &entity.AIChatSessions{
|
|
||||||
Title: req.Title,
|
|
||||||
IsActive: req.IsActive,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI Chat Messages Request DTOs
|
|
||||||
type AIChatMessagesQueryRequest struct {
|
|
||||||
Pagination *paginator.Pagination `json:"pagination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatMessagesCreateRequest struct {
|
|
||||||
SessionID string `json:"sessionId" validate:"required"`
|
|
||||||
MessageType string `json:"messageType" validate:"required,oneof=user assistant"`
|
|
||||||
Content string `json:"content" validate:"required,min=1"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AIChatMessagesCreateRequest) ToEntity() *entity.AIChatMessages {
|
|
||||||
return &entity.AIChatMessages{
|
|
||||||
SessionID: req.SessionID,
|
|
||||||
MessageType: req.MessageType,
|
|
||||||
Content: req.Content,
|
|
||||||
IsActive: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatMessagesUpdateRequest struct {
|
|
||||||
Content string `json:"content" validate:"required,min=1"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AIChatMessagesUpdateRequest) ToEntity() *entity.AIChatMessages {
|
|
||||||
return &entity.AIChatMessages{
|
|
||||||
Content: req.Content,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatSessionsQueryRequestContext struct {
|
|
||||||
IsActive string `json:"isActive"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AIChatSessionsQueryRequestContext) ToParamRequest() AIChatSessionsQueryRequest {
|
|
||||||
var request AIChatSessionsQueryRequest
|
|
||||||
|
|
||||||
if isActiveStr := req.IsActive; isActiveStr != "" {
|
|
||||||
isActive := isActiveStr == "true"
|
|
||||||
request.IsActive = &isActive
|
|
||||||
}
|
|
||||||
|
|
||||||
return request
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatMessagesQueryRequestContext struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AIChatMessagesQueryRequestContext) ToParamRequest() AIChatMessagesQueryRequest {
|
|
||||||
var request AIChatMessagesQueryRequest
|
|
||||||
|
|
||||||
return request
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI Chat Logs Request DTOs
|
|
||||||
type AIChatLogsQueryRequest struct {
|
|
||||||
LogType *string `json:"logType"`
|
|
||||||
Pagination *paginator.Pagination `json:"pagination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatLogsQueryRequestContext struct {
|
|
||||||
LogType string `json:"logType"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req AIChatLogsQueryRequestContext) ToParamRequest() AIChatLogsQueryRequest {
|
|
||||||
var request AIChatLogsQueryRequest
|
|
||||||
|
|
||||||
if logType := req.LogType; logType != "" {
|
|
||||||
request.LogType = &logType
|
|
||||||
}
|
|
||||||
|
|
||||||
return request
|
|
||||||
}
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
package response
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AI Chat Sessions Response DTOs
|
|
||||||
type AIChatSessionsResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
SessionID string `json:"sessionId"`
|
|
||||||
UserID uint `json:"userId"`
|
|
||||||
AgentID string `json:"agentId"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
MessageCount int `json:"messageCount"`
|
|
||||||
IsActive bool `json:"isActive"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
|
|
||||||
// Nested user info
|
|
||||||
User *UserBasicInfo `json:"user,omitempty"`
|
|
||||||
|
|
||||||
// Last message preview
|
|
||||||
LastMessage *AIChatMessagesResponse `json:"lastMessage,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI Chat Messages Response DTOs
|
|
||||||
type AIChatMessagesResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
SessionID string `json:"sessionId"`
|
|
||||||
MessageType string `json:"messageType"`
|
|
||||||
Content string `json:"content"`
|
|
||||||
IsActive bool `json:"isActive"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type UserBasicInfo struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
Fullname string `json:"fullname"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Session with messages
|
|
||||||
type AIChatSessionWithMessagesResponse struct {
|
|
||||||
Session *AIChatSessionsResponse `json:"session"`
|
|
||||||
Messages []*AIChatMessagesResponse `json:"messages"`
|
|
||||||
Pagination interface{} `json:"pagination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// AI Chat Logs Response DTOs
|
|
||||||
type AIChatLogsResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
UserID uint `json:"userId"`
|
|
||||||
SessionID uint `json:"sessionId"`
|
|
||||||
StartDate time.Time `json:"startDate"`
|
|
||||||
EndDate *time.Time `json:"endDate"`
|
|
||||||
TotalDuration int64 `json:"totalDuration"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
|
|
||||||
// Nested user info
|
|
||||||
User *UserBasicInfo `json:"user,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,229 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"jaecoo-be/app/module/ai_chat/mapper"
|
|
||||||
"jaecoo-be/app/module/ai_chat/repository"
|
|
||||||
"jaecoo-be/app/module/ai_chat/request"
|
|
||||||
"jaecoo-be/app/module/ai_chat/response"
|
|
||||||
usersRepository "jaecoo-be/app/module/users/repository"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type aiChatService struct {
|
|
||||||
Repo repository.AIChatRepository
|
|
||||||
UsersRepo usersRepository.UsersRepository
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type AIChatService interface {
|
|
||||||
// Sessions
|
|
||||||
GetUserSessions(authToken string, req request.AIChatSessionsQueryRequest) (sessions []*response.AIChatSessionsResponse, paging paginator.Pagination, err error)
|
|
||||||
GetSession(authToken string, id uint) (session *response.AIChatSessionsResponse, err error)
|
|
||||||
CreateSession(authToken string, req request.AIChatSessionsCreateRequest) (session *response.AIChatSessionsResponse, err error)
|
|
||||||
UpdateSession(authToken string, id uint, req request.AIChatSessionsUpdateRequest) (err error)
|
|
||||||
DeleteSession(authToken string, id uint) error
|
|
||||||
ArchiveSession(authToken string, id uint) error
|
|
||||||
|
|
||||||
// Messages
|
|
||||||
GetSessionMessages(authToken string, sessionId uint, req request.AIChatMessagesQueryRequest) (messages []*response.AIChatMessagesResponse, paging paginator.Pagination, err error)
|
|
||||||
SendMessage(authToken string, req request.AIChatMessagesCreateRequest) (message *response.AIChatMessagesResponse, err error)
|
|
||||||
UpdateMessage(authToken string, messageId uint, req request.AIChatMessagesUpdateRequest) (err error)
|
|
||||||
DeleteMessage(authToken string, messageId uint) error
|
|
||||||
|
|
||||||
// Logs
|
|
||||||
GetUserLogs(authToken string, req request.AIChatLogsQueryRequest) (logs []*response.AIChatLogsResponse, paging paginator.Pagination, err error)
|
|
||||||
GetLog(authToken string, logId uint) (log *response.AIChatLogsResponse, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAIChatService(repo repository.AIChatRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger) AIChatService {
|
|
||||||
return &aiChatService{
|
|
||||||
Repo: repo,
|
|
||||||
UsersRepo: usersRepo,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sessions methods
|
|
||||||
func (_i *aiChatService) GetUserSessions(authToken string, req request.AIChatSessionsQueryRequest) (sessions []*response.AIChatSessionsResponse, paging paginator.Pagination, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
results, paging, err := _i.Repo.GetUserSessions(userInfo.ID, req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, result := range results {
|
|
||||||
sessions = append(sessions, mapper.AIChatSessionsResponseMapper(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatService) GetSession(authToken string, id uint) (session *response.AIChatSessionsResponse, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
result, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapper.AIChatSessionsResponseMapper(result), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatService) CreateSession(authToken string, req request.AIChatSessionsCreateRequest) (session *response.AIChatSessionsResponse, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
entity := req.ToEntity()
|
|
||||||
entity.UserID = userInfo.ID
|
|
||||||
|
|
||||||
_i.Log.Info().Interface("data", entity).Msg("Create AI chat session")
|
|
||||||
|
|
||||||
result, err := _i.Repo.CreateSession(entity)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapper.AIChatSessionsResponseMapper(result), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatService) UpdateSession(authToken string, id uint, req request.AIChatSessionsUpdateRequest) (err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
_i.Log.Info().Interface("data", req).Msg("Updating AI chat session")
|
|
||||||
|
|
||||||
// Check if session exists and belongs to user
|
|
||||||
existing, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if existing == nil {
|
|
||||||
return errors.New("AI chat session not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
entity := req.ToEntity()
|
|
||||||
return _i.Repo.UpdateSession(userInfo.ID, id, entity)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatService) DeleteSession(authToken string, id uint) error {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
// Check if session exists and belongs to user
|
|
||||||
existing, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if existing == nil {
|
|
||||||
return errors.New("AI chat session not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return _i.Repo.DeleteSession(userInfo.ID, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatService) ArchiveSession(authToken string, id uint) error {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
// Check if session exists and belongs to user
|
|
||||||
existing, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if existing == nil {
|
|
||||||
return errors.New("AI chat session not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update status to archived
|
|
||||||
existing.IsActive = false
|
|
||||||
return _i.Repo.UpdateSession(userInfo.ID, id, existing)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Messages methods
|
|
||||||
func (_i *aiChatService) GetSessionMessages(authToken string, sessionId uint, req request.AIChatMessagesQueryRequest) (messages []*response.AIChatMessagesResponse, paging paginator.Pagination, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
// Verify session belongs to user
|
|
||||||
session, err := _i.Repo.FindSessionByUserAndId(userInfo.ID, sessionId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, paginator.Pagination{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
results, paging, err := _i.Repo.GetSessionMessages(session.SessionID, req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, result := range results {
|
|
||||||
messages = append(messages, mapper.AIChatMessagesResponseMapper(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatService) SendMessage(authToken string, req request.AIChatMessagesCreateRequest) (message *response.AIChatMessagesResponse, err error) {
|
|
||||||
// userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
// Verify session exists
|
|
||||||
session, err := _i.Repo.FindSessionBySessionId(req.SessionID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
entity := req.ToEntity()
|
|
||||||
|
|
||||||
result, err := _i.Repo.CreateMessage(entity)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Increment message count in session
|
|
||||||
err = _i.Repo.IncrementMessageCount(session.ID)
|
|
||||||
if err != nil {
|
|
||||||
_i.Log.Error().Err(err).Msg("Failed to increment message count")
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapper.AIChatMessagesResponseMapper(result), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Message
|
|
||||||
func (_i *aiChatService) UpdateMessage(authToken string, messageId uint, req request.AIChatMessagesUpdateRequest) (err error) {
|
|
||||||
// userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
entity := req.ToEntity()
|
|
||||||
return _i.Repo.UpdateMessage(messageId, entity)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete Message
|
|
||||||
func (_i *aiChatService) DeleteMessage(authToken string, messageId uint) error {
|
|
||||||
// userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
return _i.Repo.DeleteMessage(messageId)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Logs methods
|
|
||||||
func (_i *aiChatService) GetUserLogs(authToken string, req request.AIChatLogsQueryRequest) (logs []*response.AIChatLogsResponse, paging paginator.Pagination, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
results, paging, err := _i.Repo.GetUserLogs(userInfo.ID, req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, result := range results {
|
|
||||||
logs = append(logs, mapper.AIChatLogsResponseMapper(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *aiChatService) GetLog(authToken string, logId uint) (log *response.AIChatLogsResponse, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
|
|
||||||
result, err := _i.Repo.FindLogByUserAndId(userInfo.ID, logId)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return mapper.AIChatLogsResponseMapper(result), nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
package campaign_destinations
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/controller"
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/repository"
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/service"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"go.uber.org/fx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CampaignDestinationsRouter struct of CampaignDestinationsRouter
|
|
||||||
type CampaignDestinationsRouter struct {
|
|
||||||
App fiber.Router
|
|
||||||
Controller *controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCampaignDestinationsModule register bulky of CampaignDestinations module
|
|
||||||
var NewCampaignDestinationsModule = fx.Options(
|
|
||||||
// register repository of CampaignDestinations module
|
|
||||||
fx.Provide(repository.NewCampaignDestinationsRepository),
|
|
||||||
|
|
||||||
// register service of CampaignDestinations module
|
|
||||||
fx.Provide(service.NewCampaignDestinationsService),
|
|
||||||
|
|
||||||
// register controller of CampaignDestinations module
|
|
||||||
fx.Provide(controller.NewController),
|
|
||||||
|
|
||||||
// register router of CampaignDestinations module
|
|
||||||
fx.Provide(NewCampaignDestinationsRouter),
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewCampaignDestinationsRouter init CampaignDestinationsRouter
|
|
||||||
func NewCampaignDestinationsRouter(fiber *fiber.App, controller *controller.Controller) *CampaignDestinationsRouter {
|
|
||||||
return &CampaignDestinationsRouter{
|
|
||||||
App: fiber,
|
|
||||||
Controller: controller,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterCampaignDestinationsRoutes register routes of CampaignDestinations module
|
|
||||||
func (_i *CampaignDestinationsRouter) RegisterCampaignDestinationsRoutes() {
|
|
||||||
// define controllers
|
|
||||||
campaignDestinationsController := _i.Controller.CampaignDestinations
|
|
||||||
|
|
||||||
// define routes
|
|
||||||
_i.App.Route("/campaign-destinations", func(router fiber.Router) {
|
|
||||||
router.Get("/", campaignDestinationsController.All)
|
|
||||||
router.Get("/:id", campaignDestinationsController.Show)
|
|
||||||
router.Post("/", campaignDestinationsController.Save)
|
|
||||||
router.Put("/:id", campaignDestinationsController.Update)
|
|
||||||
router.Delete("/:id", campaignDestinationsController.Delete)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,201 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/request"
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/service"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
|
|
||||||
utilRes "jaecoo-be/utils/response"
|
|
||||||
utilVal "jaecoo-be/utils/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
type campaignDestinationsController struct {
|
|
||||||
campaignDestinationsService service.CampaignDestinationsService
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignDestinationsController interface {
|
|
||||||
All(c *fiber.Ctx) error
|
|
||||||
Show(c *fiber.Ctx) error
|
|
||||||
Save(c *fiber.Ctx) error
|
|
||||||
Update(c *fiber.Ctx) error
|
|
||||||
Delete(c *fiber.Ctx) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCampaignDestinationsController(campaignDestinationsService service.CampaignDestinationsService, log zerolog.Logger) CampaignDestinationsController {
|
|
||||||
return &campaignDestinationsController{
|
|
||||||
campaignDestinationsService: campaignDestinationsService,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All CampaignDestinations
|
|
||||||
// @Summary Get all CampaignDestinations
|
|
||||||
// @Description API for getting all CampaignDestinations
|
|
||||||
// @Tags CampaignDestinations
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
|
||||||
// @Param req query request.CampaignDestinationsQueryRequest false "query parameters"
|
|
||||||
// @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 /campaign-destinations [get]
|
|
||||||
func (_i *campaignDestinationsController) All(c *fiber.Ctx) error {
|
|
||||||
paginate, err := paginator.Paginate(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
reqContext := request.CampaignDestinationsQueryRequestContext{
|
|
||||||
Name: c.Query("name"),
|
|
||||||
CampaignTypeID: c.Query("campaignTypeId"),
|
|
||||||
IsActive: c.Query("isActive"),
|
|
||||||
}
|
|
||||||
req := reqContext.ToParamRequest()
|
|
||||||
req.Pagination = paginate
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
campaignDestinationsData, paging, err := _i.campaignDestinationsService.All(req, authToken)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignDestinations list successfully retrieved"},
|
|
||||||
Data: campaignDestinationsData,
|
|
||||||
Meta: paging,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show CampaignDestinations
|
|
||||||
// @Summary Get one CampaignDestinations
|
|
||||||
// @Description API for getting one CampaignDestinations
|
|
||||||
// @Tags CampaignDestinations
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param id path int true "CampaignDestinations ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaign-destinations/{id} [get]
|
|
||||||
func (_i *campaignDestinationsController) Show(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
campaignDestinationsData, err := _i.campaignDestinationsService.Show(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignDestinations successfully retrieved"},
|
|
||||||
Data: campaignDestinationsData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save CampaignDestinations
|
|
||||||
// @Summary Create CampaignDestinations
|
|
||||||
// @Description API for create CampaignDestinations
|
|
||||||
// @Tags CampaignDestinations
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param payload body request.CampaignDestinationsCreateRequest true "Required payload"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaign-destinations [post]
|
|
||||||
func (_i *campaignDestinationsController) Save(c *fiber.Ctx) error {
|
|
||||||
req := new(request.CampaignDestinationsCreateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
dataResult, err := _i.campaignDestinationsService.Save(*req, authToken)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignDestinations successfully created"},
|
|
||||||
Data: dataResult,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update CampaignDestinations
|
|
||||||
// @Summary Update CampaignDestinations
|
|
||||||
// @Description API for update CampaignDestinations
|
|
||||||
// @Tags CampaignDestinations
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param payload body request.CampaignDestinationsUpdateRequest true "Required payload"
|
|
||||||
// @Param id path int true "CampaignDestinations ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaign-destinations/{id} [put]
|
|
||||||
func (_i *campaignDestinationsController) Update(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
req := new(request.CampaignDestinationsUpdateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.campaignDestinationsService.Update(uint(id), *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignDestinations successfully updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete CampaignDestinations
|
|
||||||
// @Summary Delete CampaignDestinations
|
|
||||||
// @Description API for delete CampaignDestinations
|
|
||||||
// @Tags CampaignDestinations
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param id path int true "CampaignDestinations ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaign-destinations/{id} [delete]
|
|
||||||
func (_i *campaignDestinationsController) Delete(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.campaignDestinationsService.Delete(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignDestinations successfully deleted"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
CampaignDestinations CampaignDestinationsController
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewController(CampaignDestinationsService service.CampaignDestinationsService, log zerolog.Logger) *Controller {
|
|
||||||
return &Controller{
|
|
||||||
CampaignDestinations: NewCampaignDestinationsController(CampaignDestinationsService, log),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
res "jaecoo-be/app/module/campaign_destinations/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CampaignDestinationsResponseMapper(campaignDestinationsReq *entity.CampaignDestinations) (campaignDestinationsRes *res.CampaignDestinationsResponse) {
|
|
||||||
if campaignDestinationsReq != nil {
|
|
||||||
campaignDestinationsRes = &res.CampaignDestinationsResponse{
|
|
||||||
ID: campaignDestinationsReq.ID,
|
|
||||||
CampaignTypeID: campaignDestinationsReq.CampaignTypeID,
|
|
||||||
SubType: campaignDestinationsReq.SubType,
|
|
||||||
Name: campaignDestinationsReq.Name,
|
|
||||||
Description: campaignDestinationsReq.Description,
|
|
||||||
URL: campaignDestinationsReq.URL,
|
|
||||||
IsActive: campaignDestinationsReq.IsActive,
|
|
||||||
CreatedAt: campaignDestinationsReq.CreatedAt,
|
|
||||||
UpdatedAt: campaignDestinationsReq.UpdatedAt,
|
|
||||||
}
|
|
||||||
|
|
||||||
if campaignDestinationsReq.CampaignType.ID > 0 {
|
|
||||||
campaignDestinationsRes.CampaignType = &res.CampaignTypeInfo{
|
|
||||||
ID: campaignDestinationsReq.CampaignType.ID,
|
|
||||||
Name: campaignDestinationsReq.CampaignType.Name,
|
|
||||||
Description: campaignDestinationsReq.CampaignType.Description,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return campaignDestinationsRes
|
|
||||||
}
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"jaecoo-be/app/database"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/request"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type campaignDestinationsRepository struct {
|
|
||||||
DB *database.Database
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// CampaignDestinationsRepository define interface of ICampaignDestinationsRepository
|
|
||||||
type CampaignDestinationsRepository interface {
|
|
||||||
GetAll(req request.CampaignDestinationsQueryRequest) (campaignDestinationss []*entity.CampaignDestinations, paging paginator.Pagination, err error)
|
|
||||||
FindOne(id uint) (campaignDestinations *entity.CampaignDestinations, err error)
|
|
||||||
Create(campaignDestinations *entity.CampaignDestinations) (campaignDestinationsReturn *entity.CampaignDestinations, err error)
|
|
||||||
Update(id uint, campaignDestinations *entity.CampaignDestinations) (err error)
|
|
||||||
Delete(id uint) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCampaignDestinationsRepository(db *database.Database, log zerolog.Logger) CampaignDestinationsRepository {
|
|
||||||
return &campaignDestinationsRepository{
|
|
||||||
DB: db,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// implement interface of ICampaignDestinationsRepository
|
|
||||||
func (_i *campaignDestinationsRepository) GetAll(req request.CampaignDestinationsQueryRequest) (campaignDestinationss []*entity.CampaignDestinations, paging paginator.Pagination, err error) {
|
|
||||||
var count int64
|
|
||||||
|
|
||||||
query := _i.DB.DB.Model(&entity.CampaignDestinations{}).Preload("CampaignType")
|
|
||||||
|
|
||||||
if req.Name != nil && *req.Name != "" {
|
|
||||||
name := strings.ToLower(*req.Name)
|
|
||||||
query = query.Where("LOWER(name) LIKE ?", "%"+strings.ToLower(name)+"%")
|
|
||||||
}
|
|
||||||
if req.CampaignTypeID != nil {
|
|
||||||
query = query.Where("campaign_type_id = ?", req.CampaignTypeID)
|
|
||||||
}
|
|
||||||
if req.IsActive != nil {
|
|
||||||
query = query.Where("is_active = ?", req.IsActive)
|
|
||||||
}
|
|
||||||
query.Count(&count)
|
|
||||||
|
|
||||||
if req.Pagination.SortBy != "" {
|
|
||||||
direction := "ASC"
|
|
||||||
if req.Pagination.Sort == "desc" {
|
|
||||||
direction = "DESC"
|
|
||||||
}
|
|
||||||
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
|
||||||
} else {
|
|
||||||
direction := "DESC"
|
|
||||||
sortBy := "created_at"
|
|
||||||
query.Order(fmt.Sprintf("%s %s", sortBy, direction))
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Pagination.Count = count
|
|
||||||
req.Pagination = paginator.Paging(req.Pagination)
|
|
||||||
|
|
||||||
err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&campaignDestinationss).Error
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
paging = *req.Pagination
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignDestinationsRepository) FindOne(id uint) (campaignDestinations *entity.CampaignDestinations, err error) {
|
|
||||||
query := _i.DB.DB.Where("id = ?", id).Preload("CampaignType")
|
|
||||||
|
|
||||||
if err := query.First(&campaignDestinations).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return campaignDestinations, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignDestinationsRepository) Create(campaignDestinations *entity.CampaignDestinations) (campaignDestinationsReturn *entity.CampaignDestinations, err error) {
|
|
||||||
result := _i.DB.DB.Create(campaignDestinations)
|
|
||||||
return campaignDestinations, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignDestinationsRepository) Update(id uint, campaignDestinations *entity.CampaignDestinations) (err error) {
|
|
||||||
campaignDestinationsMap, err := utilSvc.StructToMap(campaignDestinations)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
query := _i.DB.DB.Model(&entity.CampaignDestinations{}).Where(&entity.CampaignDestinations{ID: id})
|
|
||||||
return query.Updates(campaignDestinationsMap).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignDestinationsRepository) Delete(id uint) error {
|
|
||||||
return _i.DB.DB.Delete(&entity.CampaignDestinations{}, id).Error
|
|
||||||
}
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignDestinationsQueryRequest struct {
|
|
||||||
Name *string `json:"name"`
|
|
||||||
CampaignTypeID *uint `json:"campaignTypeId"`
|
|
||||||
IsActive *bool `json:"isActive"`
|
|
||||||
Pagination *paginator.Pagination `json:"pagination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignDestinationsCreateRequest struct {
|
|
||||||
CampaignTypeID uint `json:"campaignTypeId" validate:"required"`
|
|
||||||
Name string `json:"name" validate:"required"`
|
|
||||||
SubType *string `json:"subType"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
URL *string `json:"url"`
|
|
||||||
IsActive *bool `json:"isActive"`
|
|
||||||
CreatedById *uint `json:"createdById"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignDestinationsCreateRequest) ToEntity() *entity.CampaignDestinations {
|
|
||||||
isActive := true
|
|
||||||
if req.IsActive != nil {
|
|
||||||
isActive = *req.IsActive
|
|
||||||
}
|
|
||||||
return &entity.CampaignDestinations{
|
|
||||||
CampaignTypeID: req.CampaignTypeID,
|
|
||||||
SubType: req.SubType,
|
|
||||||
Name: req.Name,
|
|
||||||
Description: req.Description,
|
|
||||||
URL: req.URL,
|
|
||||||
IsActive: &isActive,
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignDestinationsUpdateRequest struct {
|
|
||||||
CampaignTypeID uint `json:"campaignTypeId" validate:"required"`
|
|
||||||
Name string `json:"name" validate:"required"`
|
|
||||||
SubType *string `json:"subType"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
URL *string `json:"url"`
|
|
||||||
IsActive *bool `json:"isActive"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignDestinationsUpdateRequest) ToEntity() *entity.CampaignDestinations {
|
|
||||||
return &entity.CampaignDestinations{
|
|
||||||
CampaignTypeID: req.CampaignTypeID,
|
|
||||||
SubType: req.SubType,
|
|
||||||
Name: req.Name,
|
|
||||||
Description: req.Description,
|
|
||||||
URL: req.URL,
|
|
||||||
IsActive: req.IsActive,
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignDestinationsQueryRequestContext struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
CampaignTypeID string `json:"campaignTypeId"`
|
|
||||||
IsActive string `json:"isActive"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignDestinationsQueryRequestContext) ToParamRequest() CampaignDestinationsQueryRequest {
|
|
||||||
var request CampaignDestinationsQueryRequest
|
|
||||||
|
|
||||||
if name := req.Name; name != "" {
|
|
||||||
request.Name = &name
|
|
||||||
}
|
|
||||||
if campaignTypeIDStr := req.CampaignTypeID; campaignTypeIDStr != "" {
|
|
||||||
campaignTypeID, err := strconv.ParseUint(campaignTypeIDStr, 10, 32)
|
|
||||||
if err == nil {
|
|
||||||
campaignTypeIDUint := uint(campaignTypeID)
|
|
||||||
request.CampaignTypeID = &campaignTypeIDUint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if isActiveStr := req.IsActive; isActiveStr != "" {
|
|
||||||
isActive, err := strconv.ParseBool(isActiveStr)
|
|
||||||
if err == nil {
|
|
||||||
request.IsActive = &isActive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return request
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package response
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type CampaignDestinationsResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
CampaignTypeID uint `json:"campaignTypeId"`
|
|
||||||
CampaignType *CampaignTypeInfo `json:"campaignType,omitempty"`
|
|
||||||
SubType *string `json:"subType"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
URL *string `json:"url"`
|
|
||||||
IsActive *bool `json:"isActive"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignTypeInfo struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,93 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/mapper"
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/repository"
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/request"
|
|
||||||
"jaecoo-be/app/module/campaign_destinations/response"
|
|
||||||
usersRepository "jaecoo-be/app/module/users/repository"
|
|
||||||
config "jaecoo-be/config/config"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CampaignDestinationsService
|
|
||||||
type campaignDestinationsService struct {
|
|
||||||
Repo repository.CampaignDestinationsRepository
|
|
||||||
UsersRepo usersRepository.UsersRepository
|
|
||||||
Log zerolog.Logger
|
|
||||||
Cfg *config.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// CampaignDestinationsService define interface of ICampaignDestinationsService
|
|
||||||
type CampaignDestinationsService interface {
|
|
||||||
All(req request.CampaignDestinationsQueryRequest, authToken string) (campaignDestinations []*response.CampaignDestinationsResponse, paging paginator.Pagination, err error)
|
|
||||||
Show(id uint) (campaignDestinations *response.CampaignDestinationsResponse, err error)
|
|
||||||
Save(req request.CampaignDestinationsCreateRequest, authToken string) (campaignDestinations *entity.CampaignDestinations, err error)
|
|
||||||
Update(id uint, req request.CampaignDestinationsUpdateRequest) (err error)
|
|
||||||
Delete(id uint) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCampaignDestinationsService init CampaignDestinationsService
|
|
||||||
func NewCampaignDestinationsService(repo repository.CampaignDestinationsRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger, cfg *config.Config) CampaignDestinationsService {
|
|
||||||
return &campaignDestinationsService{
|
|
||||||
Repo: repo,
|
|
||||||
UsersRepo: usersRepo,
|
|
||||||
Log: log,
|
|
||||||
Cfg: cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All implement interface of CampaignDestinationsService
|
|
||||||
func (_i *campaignDestinationsService) All(req request.CampaignDestinationsQueryRequest, authToken string) (campaignDestinationss []*response.CampaignDestinationsResponse, paging paginator.Pagination, err error) {
|
|
||||||
results, paging, err := _i.Repo.GetAll(req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, result := range results {
|
|
||||||
campaignDestinationss = append(campaignDestinationss, mapper.CampaignDestinationsResponseMapper(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignDestinationsService) Show(id uint) (campaignDestinations *response.CampaignDestinationsResponse, err error) {
|
|
||||||
result, err := _i.Repo.FindOne(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return mapper.CampaignDestinationsResponseMapper(result), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignDestinationsService) Save(req request.CampaignDestinationsCreateRequest, authToken string) (campaignDestinations *entity.CampaignDestinations, err error) {
|
|
||||||
_i.Log.Info().Interface("data", req).Msg("")
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
|
|
||||||
if req.CreatedById != nil {
|
|
||||||
createdBy, err := _i.UsersRepo.FindOne(*req.CreatedById)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_ = createdBy
|
|
||||||
} else {
|
|
||||||
createdBy := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
_ = createdBy
|
|
||||||
}
|
|
||||||
|
|
||||||
return _i.Repo.Create(newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignDestinationsService) Update(id uint, req request.CampaignDestinationsUpdateRequest) (err error) {
|
|
||||||
_i.Log.Info().Interface("data", req).Msg("")
|
|
||||||
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
return _i.Repo.Update(id, newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignDestinationsService) Delete(id uint) error {
|
|
||||||
return _i.Repo.Delete(id)
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
package campaign_files
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaign_files/controller"
|
|
||||||
"jaecoo-be/app/module/campaign_files/repository"
|
|
||||||
"jaecoo-be/app/module/campaign_files/service"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"go.uber.org/fx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CampaignFilesRouter struct of CampaignFilesRouter
|
|
||||||
type CampaignFilesRouter struct {
|
|
||||||
App fiber.Router
|
|
||||||
Controller *controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCampaignFilesModule register bulky of CampaignFiles module
|
|
||||||
var NewCampaignFilesModule = fx.Options(
|
|
||||||
// register repository of CampaignFiles module
|
|
||||||
fx.Provide(repository.NewCampaignFilesRepository),
|
|
||||||
|
|
||||||
// register service of CampaignFiles module
|
|
||||||
fx.Provide(service.NewCampaignFilesService),
|
|
||||||
|
|
||||||
// register controller of CampaignFiles module
|
|
||||||
fx.Provide(controller.NewController),
|
|
||||||
|
|
||||||
// register router of CampaignFiles module
|
|
||||||
fx.Provide(NewCampaignFilesRouter),
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewCampaignFilesRouter init CampaignFilesRouter
|
|
||||||
func NewCampaignFilesRouter(fiber *fiber.App, controller *controller.Controller) *CampaignFilesRouter {
|
|
||||||
return &CampaignFilesRouter{
|
|
||||||
App: fiber,
|
|
||||||
Controller: controller,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterCampaignFilesRoutes register routes of CampaignFiles module
|
|
||||||
func (_i *CampaignFilesRouter) RegisterCampaignFilesRoutes() {
|
|
||||||
// define controllers
|
|
||||||
campaignFilesController := _i.Controller.CampaignFiles
|
|
||||||
|
|
||||||
// define routes
|
|
||||||
_i.App.Route("/campaign-files", func(router fiber.Router) {
|
|
||||||
router.Get("/", campaignFilesController.All)
|
|
||||||
router.Get("/:id", campaignFilesController.Show)
|
|
||||||
router.Get("/campaign/:campaignId", campaignFilesController.GetByCampaign)
|
|
||||||
router.Post("/", campaignFilesController.Save)
|
|
||||||
router.Put("/:id", campaignFilesController.Update)
|
|
||||||
router.Delete("/:id", campaignFilesController.Delete)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,156 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaign_files/request"
|
|
||||||
"jaecoo-be/app/module/campaign_files/service"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
|
|
||||||
utilRes "jaecoo-be/utils/response"
|
|
||||||
utilVal "jaecoo-be/utils/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
type campaignFilesController struct {
|
|
||||||
campaignFilesService service.CampaignFilesService
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignFilesController interface {
|
|
||||||
All(c *fiber.Ctx) error
|
|
||||||
Show(c *fiber.Ctx) error
|
|
||||||
GetByCampaign(c *fiber.Ctx) error
|
|
||||||
Save(c *fiber.Ctx) error
|
|
||||||
Update(c *fiber.Ctx) error
|
|
||||||
Delete(c *fiber.Ctx) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCampaignFilesController(campaignFilesService service.CampaignFilesService, log zerolog.Logger) CampaignFilesController {
|
|
||||||
return &campaignFilesController{
|
|
||||||
campaignFilesService: campaignFilesService,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesController) All(c *fiber.Ctx) error {
|
|
||||||
paginate, err := paginator.Paginate(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
reqContext := request.CampaignFilesQueryRequestContext{
|
|
||||||
CampaignID: c.Query("campaignId"),
|
|
||||||
Type: c.Query("type"),
|
|
||||||
}
|
|
||||||
req := reqContext.ToParamRequest()
|
|
||||||
req.Pagination = paginate
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
data, paging, err := _i.campaignFilesService.All(req, authToken)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignFiles list successfully retrieved"},
|
|
||||||
Data: data,
|
|
||||||
Meta: paging,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesController) Show(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := _i.campaignFilesService.Show(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignFiles successfully retrieved"},
|
|
||||||
Data: data,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesController) GetByCampaign(c *fiber.Ctx) error {
|
|
||||||
campaignID, err := strconv.ParseUint(c.Params("campaignId"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := _i.campaignFilesService.GetByCampaign(uint(campaignID))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignFiles successfully retrieved"},
|
|
||||||
Data: data,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesController) Save(c *fiber.Ctx) error {
|
|
||||||
req := new(request.CampaignFilesCreateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
dataResult, err := _i.campaignFilesService.Save(*req, authToken)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignFiles successfully created"},
|
|
||||||
Data: dataResult,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesController) Update(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
req := new(request.CampaignFilesUpdateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.campaignFilesService.Update(uint(id), *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignFiles successfully updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesController) Delete(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.campaignFilesService.Delete(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignFiles successfully deleted"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaign_files/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
CampaignFiles CampaignFilesController
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewController(CampaignFilesService service.CampaignFilesService, log zerolog.Logger) *Controller {
|
|
||||||
return &Controller{
|
|
||||||
CampaignFiles: NewCampaignFilesController(CampaignFilesService, log),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
res "jaecoo-be/app/module/campaign_files/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CampaignFilesResponseMapper(campaignFilesReq *entity.CampaignFiles) (campaignFilesRes *res.CampaignFilesResponse) {
|
|
||||||
if campaignFilesReq != nil {
|
|
||||||
campaignFilesRes = &res.CampaignFilesResponse{
|
|
||||||
ID: campaignFilesReq.ID,
|
|
||||||
CampaignID: campaignFilesReq.CampaignID,
|
|
||||||
Type: campaignFilesReq.Type,
|
|
||||||
FileURL: campaignFilesReq.FileURL,
|
|
||||||
ExternalURL: campaignFilesReq.ExternalURL,
|
|
||||||
IsDraft: campaignFilesReq.IsDraft,
|
|
||||||
IsPublish: campaignFilesReq.IsPublish,
|
|
||||||
IsActive: campaignFilesReq.IsActive,
|
|
||||||
CreatedAt: campaignFilesReq.CreatedAt,
|
|
||||||
UpdatedAt: campaignFilesReq.UpdatedAt,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return campaignFilesRes
|
|
||||||
}
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"jaecoo-be/app/database"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/campaign_files/request"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type campaignFilesRepository struct {
|
|
||||||
DB *database.Database
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignFilesRepository interface {
|
|
||||||
GetAll(req request.CampaignFilesQueryRequest) (campaignFiless []*entity.CampaignFiles, paging paginator.Pagination, err error)
|
|
||||||
FindOne(id uint) (campaignFiles *entity.CampaignFiles, err error)
|
|
||||||
FindByCampaign(campaignID uint) (campaignFiles []*entity.CampaignFiles, err error)
|
|
||||||
Create(campaignFiles *entity.CampaignFiles) (campaignFilesReturn *entity.CampaignFiles, err error)
|
|
||||||
Update(id uint, campaignFiles *entity.CampaignFiles) (err error)
|
|
||||||
Delete(id uint) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCampaignFilesRepository(db *database.Database, log zerolog.Logger) CampaignFilesRepository {
|
|
||||||
return &campaignFilesRepository{
|
|
||||||
DB: db,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesRepository) GetAll(req request.CampaignFilesQueryRequest) (campaignFiless []*entity.CampaignFiles, paging paginator.Pagination, err error) {
|
|
||||||
var count int64
|
|
||||||
|
|
||||||
query := _i.DB.DB.Model(&entity.CampaignFiles{}).Preload("Campaign")
|
|
||||||
|
|
||||||
if req.CampaignID != nil {
|
|
||||||
query = query.Where("campaign_id = ?", req.CampaignID)
|
|
||||||
}
|
|
||||||
if req.Type != nil && *req.Type != "" {
|
|
||||||
query = query.Where("type = ?", req.Type)
|
|
||||||
}
|
|
||||||
query.Count(&count)
|
|
||||||
|
|
||||||
if req.Pagination.SortBy != "" {
|
|
||||||
direction := "ASC"
|
|
||||||
if req.Pagination.Sort == "desc" {
|
|
||||||
direction = "DESC"
|
|
||||||
}
|
|
||||||
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
|
||||||
} else {
|
|
||||||
query.Order("created_at DESC")
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Pagination.Count = count
|
|
||||||
req.Pagination = paginator.Paging(req.Pagination)
|
|
||||||
|
|
||||||
err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&campaignFiless).Error
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
paging = *req.Pagination
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesRepository) FindOne(id uint) (campaignFiles *entity.CampaignFiles, err error) {
|
|
||||||
query := _i.DB.DB.Where("id = ?", id).Preload("Campaign")
|
|
||||||
if err := query.First(&campaignFiles).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return campaignFiles, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesRepository) FindByCampaign(campaignID uint) (campaignFiles []*entity.CampaignFiles, err error) {
|
|
||||||
query := _i.DB.DB.Where("campaign_id = ?", campaignID).Preload("Campaign")
|
|
||||||
err = query.Find(&campaignFiles).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesRepository) Create(campaignFiles *entity.CampaignFiles) (campaignFilesReturn *entity.CampaignFiles, err error) {
|
|
||||||
result := _i.DB.DB.Create(campaignFiles)
|
|
||||||
return campaignFiles, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesRepository) Update(id uint, campaignFiles *entity.CampaignFiles) (err error) {
|
|
||||||
campaignFilesMap, err := utilSvc.StructToMap(campaignFiles)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return _i.DB.DB.Model(&entity.CampaignFiles{}).Where(&entity.CampaignFiles{ID: id}).Updates(campaignFilesMap).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesRepository) Delete(id uint) error {
|
|
||||||
return _i.DB.DB.Delete(&entity.CampaignFiles{}, id).Error
|
|
||||||
}
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignFilesQueryRequest struct {
|
|
||||||
CampaignID *uint `json:"campaignId"`
|
|
||||||
Type *string `json:"type"`
|
|
||||||
Pagination *paginator.Pagination `json:"pagination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignFilesCreateRequest struct {
|
|
||||||
CampaignID uint `json:"campaignId" validate:"required"`
|
|
||||||
Type string `json:"type" validate:"required"` // url, file
|
|
||||||
FileURL *string `json:"fileUrl"`
|
|
||||||
ExternalURL *string `json:"externalUrl"`
|
|
||||||
IsDraft *bool `json:"isDraft"`
|
|
||||||
IsPublish *bool `json:"isPublish"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignFilesCreateRequest) ToEntity() *entity.CampaignFiles {
|
|
||||||
isDraft := false
|
|
||||||
isPublish := false
|
|
||||||
if req.IsDraft != nil {
|
|
||||||
isDraft = *req.IsDraft
|
|
||||||
}
|
|
||||||
if req.IsPublish != nil {
|
|
||||||
isPublish = *req.IsPublish
|
|
||||||
}
|
|
||||||
return &entity.CampaignFiles{
|
|
||||||
CampaignID: req.CampaignID,
|
|
||||||
Type: req.Type,
|
|
||||||
FileURL: req.FileURL,
|
|
||||||
ExternalURL: req.ExternalURL,
|
|
||||||
IsDraft: &isDraft,
|
|
||||||
IsPublish: &isPublish,
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignFilesUpdateRequest struct {
|
|
||||||
Type string `json:"type" validate:"required"`
|
|
||||||
FileURL *string `json:"fileUrl"`
|
|
||||||
ExternalURL *string `json:"externalUrl"`
|
|
||||||
IsDraft *bool `json:"isDraft"`
|
|
||||||
IsPublish *bool `json:"isPublish"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignFilesUpdateRequest) ToEntity() *entity.CampaignFiles {
|
|
||||||
return &entity.CampaignFiles{
|
|
||||||
Type: req.Type,
|
|
||||||
FileURL: req.FileURL,
|
|
||||||
ExternalURL: req.ExternalURL,
|
|
||||||
IsDraft: req.IsDraft,
|
|
||||||
IsPublish: req.IsPublish,
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignFilesQueryRequestContext struct {
|
|
||||||
CampaignID string `json:"campaignId"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignFilesQueryRequestContext) ToParamRequest() CampaignFilesQueryRequest {
|
|
||||||
var request CampaignFilesQueryRequest
|
|
||||||
|
|
||||||
if campaignIDStr := req.CampaignID; campaignIDStr != "" {
|
|
||||||
campaignID, err := strconv.ParseUint(campaignIDStr, 10, 32)
|
|
||||||
if err == nil {
|
|
||||||
campaignIDUint := uint(campaignID)
|
|
||||||
request.CampaignID = &campaignIDUint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if typeStr := req.Type; typeStr != "" {
|
|
||||||
request.Type = &typeStr
|
|
||||||
}
|
|
||||||
|
|
||||||
return request
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package response
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type CampaignFilesResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
CampaignID uint `json:"campaignId"`
|
|
||||||
Type string `json:"type"`
|
|
||||||
FileURL *string `json:"fileUrl"`
|
|
||||||
ExternalURL *string `json:"externalUrl"`
|
|
||||||
IsDraft *bool `json:"isDraft"`
|
|
||||||
IsPublish *bool `json:"isPublish"`
|
|
||||||
IsActive *bool `json:"isActive"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,85 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/campaign_files/mapper"
|
|
||||||
"jaecoo-be/app/module/campaign_files/repository"
|
|
||||||
"jaecoo-be/app/module/campaign_files/request"
|
|
||||||
"jaecoo-be/app/module/campaign_files/response"
|
|
||||||
usersRepository "jaecoo-be/app/module/users/repository"
|
|
||||||
config "jaecoo-be/config/config"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type campaignFilesService struct {
|
|
||||||
Repo repository.CampaignFilesRepository
|
|
||||||
UsersRepo usersRepository.UsersRepository
|
|
||||||
Log zerolog.Logger
|
|
||||||
Cfg *config.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignFilesService interface {
|
|
||||||
All(req request.CampaignFilesQueryRequest, authToken string) (campaignFiles []*response.CampaignFilesResponse, paging paginator.Pagination, err error)
|
|
||||||
Show(id uint) (campaignFiles *response.CampaignFilesResponse, err error)
|
|
||||||
GetByCampaign(campaignID uint) (campaignFiles []*response.CampaignFilesResponse, err error)
|
|
||||||
Save(req request.CampaignFilesCreateRequest, authToken string) (campaignFiles *entity.CampaignFiles, err error)
|
|
||||||
Update(id uint, req request.CampaignFilesUpdateRequest) (err error)
|
|
||||||
Delete(id uint) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCampaignFilesService(repo repository.CampaignFilesRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger, cfg *config.Config) CampaignFilesService {
|
|
||||||
return &campaignFilesService{
|
|
||||||
Repo: repo,
|
|
||||||
UsersRepo: usersRepo,
|
|
||||||
Log: log,
|
|
||||||
Cfg: cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesService) All(req request.CampaignFilesQueryRequest, authToken string) (campaignFiless []*response.CampaignFilesResponse, paging paginator.Pagination, err error) {
|
|
||||||
results, paging, err := _i.Repo.GetAll(req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, result := range results {
|
|
||||||
campaignFiless = append(campaignFiless, mapper.CampaignFilesResponseMapper(result))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesService) Show(id uint) (campaignFiles *response.CampaignFilesResponse, err error) {
|
|
||||||
result, err := _i.Repo.FindOne(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return mapper.CampaignFilesResponseMapper(result), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesService) GetByCampaign(campaignID uint) (campaignFiless []*response.CampaignFilesResponse, err error) {
|
|
||||||
results, err := _i.Repo.FindByCampaign(campaignID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, result := range results {
|
|
||||||
campaignFiless = append(campaignFiless, mapper.CampaignFilesResponseMapper(result))
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesService) Save(req request.CampaignFilesCreateRequest, authToken string) (campaignFiles *entity.CampaignFiles, err error) {
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
return _i.Repo.Create(newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesService) Update(id uint, req request.CampaignFilesUpdateRequest) (err error) {
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
return _i.Repo.Update(id, newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignFilesService) Delete(id uint) error {
|
|
||||||
return _i.Repo.Delete(id)
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
package campaign_types
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaign_types/controller"
|
|
||||||
"jaecoo-be/app/module/campaign_types/repository"
|
|
||||||
"jaecoo-be/app/module/campaign_types/service"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"go.uber.org/fx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CampaignTypesRouter struct of CampaignTypesRouter
|
|
||||||
type CampaignTypesRouter struct {
|
|
||||||
App fiber.Router
|
|
||||||
Controller *controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCampaignTypesModule register bulky of CampaignTypes module
|
|
||||||
var NewCampaignTypesModule = fx.Options(
|
|
||||||
// register repository of CampaignTypes module
|
|
||||||
fx.Provide(repository.NewCampaignTypesRepository),
|
|
||||||
|
|
||||||
// register service of CampaignTypes module
|
|
||||||
fx.Provide(service.NewCampaignTypesService),
|
|
||||||
|
|
||||||
// register controller of CampaignTypes module
|
|
||||||
fx.Provide(controller.NewController),
|
|
||||||
|
|
||||||
// register router of CampaignTypes module
|
|
||||||
fx.Provide(NewCampaignTypesRouter),
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewCampaignTypesRouter init CampaignTypesRouter
|
|
||||||
func NewCampaignTypesRouter(fiber *fiber.App, controller *controller.Controller) *CampaignTypesRouter {
|
|
||||||
return &CampaignTypesRouter{
|
|
||||||
App: fiber,
|
|
||||||
Controller: controller,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterCampaignTypesRoutes register routes of CampaignTypes module
|
|
||||||
func (_i *CampaignTypesRouter) RegisterCampaignTypesRoutes() {
|
|
||||||
// define controllers
|
|
||||||
campaignTypesController := _i.Controller.CampaignTypes
|
|
||||||
|
|
||||||
// define routes
|
|
||||||
_i.App.Route("/campaign-types", func(router fiber.Router) {
|
|
||||||
router.Get("/", campaignTypesController.All)
|
|
||||||
router.Get("/:id", campaignTypesController.Show)
|
|
||||||
router.Post("/", campaignTypesController.Save)
|
|
||||||
router.Put("/:id", campaignTypesController.Update)
|
|
||||||
router.Delete("/:id", campaignTypesController.Delete)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,199 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaign_types/request"
|
|
||||||
"jaecoo-be/app/module/campaign_types/service"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
|
|
||||||
utilRes "jaecoo-be/utils/response"
|
|
||||||
utilVal "jaecoo-be/utils/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
type campaignTypesController struct {
|
|
||||||
campaignTypesService service.CampaignTypesService
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignTypesController interface {
|
|
||||||
All(c *fiber.Ctx) error
|
|
||||||
Show(c *fiber.Ctx) error
|
|
||||||
Save(c *fiber.Ctx) error
|
|
||||||
Update(c *fiber.Ctx) error
|
|
||||||
Delete(c *fiber.Ctx) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCampaignTypesController(campaignTypesService service.CampaignTypesService, log zerolog.Logger) CampaignTypesController {
|
|
||||||
return &campaignTypesController{
|
|
||||||
campaignTypesService: campaignTypesService,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All CampaignTypes
|
|
||||||
// @Summary Get all CampaignTypes
|
|
||||||
// @Description API for getting all CampaignTypes
|
|
||||||
// @Tags CampaignTypes
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
|
||||||
// @Param req query request.CampaignTypesQueryRequest false "query parameters"
|
|
||||||
// @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 /campaign-types [get]
|
|
||||||
func (_i *campaignTypesController) All(c *fiber.Ctx) error {
|
|
||||||
paginate, err := paginator.Paginate(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
reqContext := request.CampaignTypesQueryRequestContext{
|
|
||||||
Name: c.Query("name"),
|
|
||||||
}
|
|
||||||
req := reqContext.ToParamRequest()
|
|
||||||
req.Pagination = paginate
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
campaignTypesData, paging, err := _i.campaignTypesService.All(req, authToken)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignTypes list successfully retrieved"},
|
|
||||||
Data: campaignTypesData,
|
|
||||||
Meta: paging,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show CampaignTypes
|
|
||||||
// @Summary Get one CampaignTypes
|
|
||||||
// @Description API for getting one CampaignTypes
|
|
||||||
// @Tags CampaignTypes
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param id path int true "CampaignTypes ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaign-types/{id} [get]
|
|
||||||
func (_i *campaignTypesController) Show(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
campaignTypesData, err := _i.campaignTypesService.Show(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignTypes successfully retrieved"},
|
|
||||||
Data: campaignTypesData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save CampaignTypes
|
|
||||||
// @Summary Create CampaignTypes
|
|
||||||
// @Description API for create CampaignTypes
|
|
||||||
// @Tags CampaignTypes
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param payload body request.CampaignTypesCreateRequest true "Required payload"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaign-types [post]
|
|
||||||
func (_i *campaignTypesController) Save(c *fiber.Ctx) error {
|
|
||||||
req := new(request.CampaignTypesCreateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
dataResult, err := _i.campaignTypesService.Save(*req, authToken)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignTypes successfully created"},
|
|
||||||
Data: dataResult,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update CampaignTypes
|
|
||||||
// @Summary Update CampaignTypes
|
|
||||||
// @Description API for update CampaignTypes
|
|
||||||
// @Tags CampaignTypes
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param payload body request.CampaignTypesUpdateRequest true "Required payload"
|
|
||||||
// @Param id path int true "CampaignTypes ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaign-types/{id} [put]
|
|
||||||
func (_i *campaignTypesController) Update(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
req := new(request.CampaignTypesUpdateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.campaignTypesService.Update(uint(id), *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignTypes successfully updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete CampaignTypes
|
|
||||||
// @Summary Delete CampaignTypes
|
|
||||||
// @Description API for delete CampaignTypes
|
|
||||||
// @Tags CampaignTypes
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param id path int true "CampaignTypes ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaign-types/{id} [delete]
|
|
||||||
func (_i *campaignTypesController) Delete(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.campaignTypesService.Delete(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"CampaignTypes successfully deleted"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaign_types/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
CampaignTypes CampaignTypesController
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewController(CampaignTypesService service.CampaignTypesService, log zerolog.Logger) *Controller {
|
|
||||||
return &Controller{
|
|
||||||
CampaignTypes: NewCampaignTypesController(CampaignTypesService, log),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
res "jaecoo-be/app/module/campaign_types/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CampaignTypesResponseMapper(campaignTypesReq *entity.CampaignTypes) (campaignTypesRes *res.CampaignTypesResponse) {
|
|
||||||
if campaignTypesReq != nil {
|
|
||||||
campaignTypesRes = &res.CampaignTypesResponse{
|
|
||||||
ID: campaignTypesReq.ID,
|
|
||||||
Name: campaignTypesReq.Name,
|
|
||||||
Description: campaignTypesReq.Description,
|
|
||||||
IsActive: campaignTypesReq.IsActive,
|
|
||||||
CreatedAt: campaignTypesReq.CreatedAt,
|
|
||||||
UpdatedAt: campaignTypesReq.UpdatedAt,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return campaignTypesRes
|
|
||||||
}
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"jaecoo-be/app/database"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/campaign_types/request"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type campaignTypesRepository struct {
|
|
||||||
DB *database.Database
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// CampaignTypesRepository define interface of ICampaignTypesRepository
|
|
||||||
type CampaignTypesRepository interface {
|
|
||||||
GetAll(req request.CampaignTypesQueryRequest) (campaignTypess []*entity.CampaignTypes, paging paginator.Pagination, err error)
|
|
||||||
FindOne(id uint) (campaignTypes *entity.CampaignTypes, err error)
|
|
||||||
Create(campaignTypes *entity.CampaignTypes) (campaignTypesReturn *entity.CampaignTypes, err error)
|
|
||||||
Update(id uint, campaignTypes *entity.CampaignTypes) (err error)
|
|
||||||
Delete(id uint) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCampaignTypesRepository(db *database.Database, log zerolog.Logger) CampaignTypesRepository {
|
|
||||||
return &campaignTypesRepository{
|
|
||||||
DB: db,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// implement interface of ICampaignTypesRepository
|
|
||||||
func (_i *campaignTypesRepository) GetAll(req request.CampaignTypesQueryRequest) (campaignTypess []*entity.CampaignTypes, paging paginator.Pagination, err error) {
|
|
||||||
var count int64
|
|
||||||
|
|
||||||
query := _i.DB.DB.Model(&entity.CampaignTypes{})
|
|
||||||
|
|
||||||
if req.Name != nil && *req.Name != "" {
|
|
||||||
name := strings.ToLower(*req.Name)
|
|
||||||
query = query.Where("LOWER(name) LIKE ?", "%"+strings.ToLower(name)+"%")
|
|
||||||
}
|
|
||||||
query.Count(&count)
|
|
||||||
|
|
||||||
if req.Pagination.SortBy != "" {
|
|
||||||
direction := "ASC"
|
|
||||||
if req.Pagination.Sort == "desc" {
|
|
||||||
direction = "DESC"
|
|
||||||
}
|
|
||||||
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
|
||||||
} else {
|
|
||||||
direction := "DESC"
|
|
||||||
sortBy := "created_at"
|
|
||||||
query.Order(fmt.Sprintf("%s %s", sortBy, direction))
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Pagination.Count = count
|
|
||||||
req.Pagination = paginator.Paging(req.Pagination)
|
|
||||||
|
|
||||||
err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&campaignTypess).Error
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
paging = *req.Pagination
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignTypesRepository) FindOne(id uint) (campaignTypes *entity.CampaignTypes, err error) {
|
|
||||||
query := _i.DB.DB.Where("id = ?", id)
|
|
||||||
|
|
||||||
if err := query.First(&campaignTypes).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return campaignTypes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignTypesRepository) Create(campaignTypes *entity.CampaignTypes) (campaignTypesReturn *entity.CampaignTypes, err error) {
|
|
||||||
result := _i.DB.DB.Create(campaignTypes)
|
|
||||||
return campaignTypes, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignTypesRepository) Update(id uint, campaignTypes *entity.CampaignTypes) (err error) {
|
|
||||||
campaignTypesMap, err := utilSvc.StructToMap(campaignTypes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
query := _i.DB.DB.Model(&entity.CampaignTypes{}).Where(&entity.CampaignTypes{ID: id})
|
|
||||||
return query.Updates(campaignTypesMap).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignTypesRepository) Delete(id uint) error {
|
|
||||||
return _i.DB.DB.Delete(&entity.CampaignTypes{}, id).Error
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignTypesQueryRequest struct {
|
|
||||||
Name *string `json:"name"`
|
|
||||||
Pagination *paginator.Pagination `json:"pagination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignTypesCreateRequest struct {
|
|
||||||
Name string `json:"name" validate:"required"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
CreatedById *uint `json:"createdById"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignTypesCreateRequest) ToEntity() *entity.CampaignTypes {
|
|
||||||
return &entity.CampaignTypes{
|
|
||||||
Name: req.Name,
|
|
||||||
Description: req.Description,
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignTypesUpdateRequest struct {
|
|
||||||
Name string `json:"name" validate:"required"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignTypesUpdateRequest) ToEntity() *entity.CampaignTypes {
|
|
||||||
return &entity.CampaignTypes{
|
|
||||||
Name: req.Name,
|
|
||||||
Description: req.Description,
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignTypesQueryRequestContext struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignTypesQueryRequestContext) ToParamRequest() CampaignTypesQueryRequest {
|
|
||||||
var request CampaignTypesQueryRequest
|
|
||||||
|
|
||||||
if name := req.Name; name != "" {
|
|
||||||
request.Name = &name
|
|
||||||
}
|
|
||||||
|
|
||||||
return request
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package response
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type CampaignTypesResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
IsActive *bool `json:"isActive"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/campaign_types/mapper"
|
|
||||||
"jaecoo-be/app/module/campaign_types/repository"
|
|
||||||
"jaecoo-be/app/module/campaign_types/request"
|
|
||||||
"jaecoo-be/app/module/campaign_types/response"
|
|
||||||
usersRepository "jaecoo-be/app/module/users/repository"
|
|
||||||
config "jaecoo-be/config/config"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CampaignTypesService
|
|
||||||
type campaignTypesService struct {
|
|
||||||
Repo repository.CampaignTypesRepository
|
|
||||||
UsersRepo usersRepository.UsersRepository
|
|
||||||
Log zerolog.Logger
|
|
||||||
Cfg *config.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// CampaignTypesService define interface of ICampaignTypesService
|
|
||||||
type CampaignTypesService interface {
|
|
||||||
All(req request.CampaignTypesQueryRequest, authToken string) (campaignTypes []*response.CampaignTypesResponse, paging paginator.Pagination, err error)
|
|
||||||
Show(id uint) (campaignTypes *response.CampaignTypesResponse, err error)
|
|
||||||
Save(req request.CampaignTypesCreateRequest, authToken string) (campaignTypes *entity.CampaignTypes, err error)
|
|
||||||
Update(id uint, req request.CampaignTypesUpdateRequest) (err error)
|
|
||||||
Delete(id uint) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCampaignTypesService init CampaignTypesService
|
|
||||||
func NewCampaignTypesService(repo repository.CampaignTypesRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger, cfg *config.Config) CampaignTypesService {
|
|
||||||
return &campaignTypesService{
|
|
||||||
Repo: repo,
|
|
||||||
UsersRepo: usersRepo,
|
|
||||||
Log: log,
|
|
||||||
Cfg: cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All implement interface of CampaignTypesService
|
|
||||||
func (_i *campaignTypesService) All(req request.CampaignTypesQueryRequest, authToken string) (campaignTypess []*response.CampaignTypesResponse, paging paginator.Pagination, err error) {
|
|
||||||
results, paging, err := _i.Repo.GetAll(req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, result := range results {
|
|
||||||
campaignTypess = append(campaignTypess, mapper.CampaignTypesResponseMapper(result))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignTypesService) Show(id uint) (campaignTypes *response.CampaignTypesResponse, err error) {
|
|
||||||
result, err := _i.Repo.FindOne(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return mapper.CampaignTypesResponseMapper(result), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignTypesService) Save(req request.CampaignTypesCreateRequest, authToken string) (campaignTypes *entity.CampaignTypes, err error) {
|
|
||||||
_i.Log.Info().Interface("data", req).Msg("")
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
|
|
||||||
if req.CreatedById != nil {
|
|
||||||
createdBy, err := _i.UsersRepo.FindOne(*req.CreatedById)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
newReq.CreatedAt = createdBy.CreatedAt
|
|
||||||
} else {
|
|
||||||
createdBy := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if createdBy != nil {
|
|
||||||
// User info available if needed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return _i.Repo.Create(newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignTypesService) Update(id uint, req request.CampaignTypesUpdateRequest) (err error) {
|
|
||||||
_i.Log.Info().Interface("data", req).Msg("")
|
|
||||||
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
return _i.Repo.Update(id, newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignTypesService) Delete(id uint) error {
|
|
||||||
return _i.Repo.Delete(id)
|
|
||||||
}
|
|
||||||
|
|
@ -1,54 +0,0 @@
|
||||||
package campaigns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaigns/controller"
|
|
||||||
"jaecoo-be/app/module/campaigns/repository"
|
|
||||||
"jaecoo-be/app/module/campaigns/service"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"go.uber.org/fx"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CampaignsRouter struct of CampaignsRouter
|
|
||||||
type CampaignsRouter struct {
|
|
||||||
App fiber.Router
|
|
||||||
Controller *controller.Controller
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCampaignsModule register bulky of Campaigns module
|
|
||||||
var NewCampaignsModule = fx.Options(
|
|
||||||
// register repository of Campaigns module
|
|
||||||
fx.Provide(repository.NewCampaignsRepository),
|
|
||||||
|
|
||||||
// register service of Campaigns module
|
|
||||||
fx.Provide(service.NewCampaignsService),
|
|
||||||
|
|
||||||
// register controller of Campaigns module
|
|
||||||
fx.Provide(controller.NewController),
|
|
||||||
|
|
||||||
// register router of Campaigns module
|
|
||||||
fx.Provide(NewCampaignsRouter),
|
|
||||||
)
|
|
||||||
|
|
||||||
// NewCampaignsRouter init CampaignsRouter
|
|
||||||
func NewCampaignsRouter(fiber *fiber.App, controller *controller.Controller) *CampaignsRouter {
|
|
||||||
return &CampaignsRouter{
|
|
||||||
App: fiber,
|
|
||||||
Controller: controller,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegisterCampaignsRoutes register routes of Campaigns module
|
|
||||||
func (_i *CampaignsRouter) RegisterCampaignsRoutes() {
|
|
||||||
// define controllers
|
|
||||||
campaignsController := _i.Controller.Campaigns
|
|
||||||
|
|
||||||
// define routes
|
|
||||||
_i.App.Route("/campaigns", func(router fiber.Router) {
|
|
||||||
router.Get("/", campaignsController.All)
|
|
||||||
router.Get("/:id", campaignsController.Show)
|
|
||||||
router.Post("/", campaignsController.Save)
|
|
||||||
router.Put("/:id", campaignsController.Update)
|
|
||||||
router.Delete("/:id", campaignsController.Delete)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,202 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaigns/request"
|
|
||||||
"jaecoo-be/app/module/campaigns/service"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
|
|
||||||
utilRes "jaecoo-be/utils/response"
|
|
||||||
utilVal "jaecoo-be/utils/validator"
|
|
||||||
)
|
|
||||||
|
|
||||||
type campaignsController struct {
|
|
||||||
campaignsService service.CampaignsService
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignsController interface {
|
|
||||||
All(c *fiber.Ctx) error
|
|
||||||
Show(c *fiber.Ctx) error
|
|
||||||
Save(c *fiber.Ctx) error
|
|
||||||
Update(c *fiber.Ctx) error
|
|
||||||
Delete(c *fiber.Ctx) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCampaignsController(campaignsService service.CampaignsService, log zerolog.Logger) CampaignsController {
|
|
||||||
return &campaignsController{
|
|
||||||
campaignsService: campaignsService,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All Campaigns
|
|
||||||
// @Summary Get all Campaigns
|
|
||||||
// @Description API for getting all Campaigns
|
|
||||||
// @Tags Campaigns
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Client-Key header string true "Insert the X-Client-Key"
|
|
||||||
// @Param req query request.CampaignsQueryRequest false "query parameters"
|
|
||||||
// @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 /campaigns [get]
|
|
||||||
func (_i *campaignsController) All(c *fiber.Ctx) error {
|
|
||||||
paginate, err := paginator.Paginate(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
reqContext := request.CampaignsQueryRequestContext{
|
|
||||||
Title: c.Query("title"),
|
|
||||||
CampaignTypeID: c.Query("campaignTypeId"),
|
|
||||||
Status: c.Query("status"),
|
|
||||||
CreatorID: c.Query("creatorId"),
|
|
||||||
}
|
|
||||||
req := reqContext.ToParamRequest()
|
|
||||||
req.Pagination = paginate
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
campaignsData, paging, err := _i.campaignsService.All(req, authToken)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Campaigns list successfully retrieved"},
|
|
||||||
Data: campaignsData,
|
|
||||||
Meta: paging,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show Campaigns
|
|
||||||
// @Summary Get one Campaigns
|
|
||||||
// @Description API for getting one Campaigns
|
|
||||||
// @Tags Campaigns
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param id path int true "Campaigns ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaigns/{id} [get]
|
|
||||||
func (_i *campaignsController) Show(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
campaignsData, err := _i.campaignsService.Show(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Campaigns successfully retrieved"},
|
|
||||||
Data: campaignsData,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save Campaigns
|
|
||||||
// @Summary Create Campaigns
|
|
||||||
// @Description API for create Campaigns
|
|
||||||
// @Tags Campaigns
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string false "Insert the X-Csrf-Token"
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param payload body request.CampaignsCreateRequest true "Required payload"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaigns [post]
|
|
||||||
func (_i *campaignsController) Save(c *fiber.Ctx) error {
|
|
||||||
req := new(request.CampaignsCreateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
dataResult, err := _i.campaignsService.Save(*req, authToken)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Campaigns successfully created"},
|
|
||||||
Data: dataResult,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update Campaigns
|
|
||||||
// @Summary Update Campaigns
|
|
||||||
// @Description API for update Campaigns
|
|
||||||
// @Tags Campaigns
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param payload body request.CampaignsUpdateRequest true "Required payload"
|
|
||||||
// @Param id path int true "Campaigns ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaigns/{id} [put]
|
|
||||||
func (_i *campaignsController) Update(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
req := new(request.CampaignsUpdateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.campaignsService.Update(uint(id), *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Campaigns successfully updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete Campaigns
|
|
||||||
// @Summary Delete Campaigns
|
|
||||||
// @Description API for delete Campaigns
|
|
||||||
// @Tags Campaigns
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
|
|
||||||
// @Param id path int true "Campaigns ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /campaigns/{id} [delete]
|
|
||||||
func (_i *campaignsController) Delete(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.campaignsService.Delete(uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Campaigns successfully deleted"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/campaigns/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
Campaigns CampaignsController
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewController(CampaignsService service.CampaignsService, log zerolog.Logger) *Controller {
|
|
||||||
return &Controller{
|
|
||||||
Campaigns: NewCampaignsController(CampaignsService, log),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
res "jaecoo-be/app/module/campaigns/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
func CampaignsResponseMapper(campaignsReq *entity.Campaigns, host string) (campaignsRes *res.CampaignsResponse) {
|
|
||||||
if campaignsReq != nil {
|
|
||||||
campaignsRes = &res.CampaignsResponse{
|
|
||||||
ID: campaignsReq.ID,
|
|
||||||
Title: campaignsReq.Title,
|
|
||||||
CampaignTypeID: campaignsReq.CampaignTypeID,
|
|
||||||
StartDate: campaignsReq.StartDate,
|
|
||||||
EndDate: campaignsReq.EndDate,
|
|
||||||
MediaTypeSelected: campaignsReq.MediaTypeSelected,
|
|
||||||
MediaItemSelected: campaignsReq.MediaItemSelected,
|
|
||||||
Purpose: campaignsReq.Purpose,
|
|
||||||
MediaPromote: campaignsReq.MediaPromote,
|
|
||||||
Description: campaignsReq.Description,
|
|
||||||
CreatorID: campaignsReq.CreatorID,
|
|
||||||
Status: campaignsReq.Status,
|
|
||||||
IsActive: campaignsReq.IsActive,
|
|
||||||
CreatedAt: campaignsReq.CreatedAt,
|
|
||||||
UpdatedAt: campaignsReq.UpdatedAt,
|
|
||||||
}
|
|
||||||
|
|
||||||
if campaignsReq.CampaignType.ID > 0 {
|
|
||||||
campaignsRes.CampaignType = &res.CampaignTypeInfo{
|
|
||||||
ID: campaignsReq.CampaignType.ID,
|
|
||||||
Name: campaignsReq.CampaignType.Name,
|
|
||||||
Description: campaignsReq.CampaignType.Description,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if campaignsReq.Creator.ID > 0 {
|
|
||||||
campaignsRes.Creator = &res.CreatorInfo{
|
|
||||||
ID: campaignsReq.Creator.ID,
|
|
||||||
Fullname: campaignsReq.Creator.Fullname,
|
|
||||||
Email: campaignsReq.Creator.Email,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return campaignsRes
|
|
||||||
}
|
|
||||||
|
|
@ -1,108 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"jaecoo-be/app/database"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/campaigns/request"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type campaignsRepository struct {
|
|
||||||
DB *database.Database
|
|
||||||
Log zerolog.Logger
|
|
||||||
}
|
|
||||||
|
|
||||||
// CampaignsRepository define interface of ICampaignsRepository
|
|
||||||
type CampaignsRepository interface {
|
|
||||||
GetAll(req request.CampaignsQueryRequest) (campaignss []*entity.Campaigns, paging paginator.Pagination, err error)
|
|
||||||
FindOne(id uint) (campaigns *entity.Campaigns, err error)
|
|
||||||
Create(campaigns *entity.Campaigns) (campaignsReturn *entity.Campaigns, err error)
|
|
||||||
Update(id uint, campaigns *entity.Campaigns) (err error)
|
|
||||||
Delete(id uint) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCampaignsRepository(db *database.Database, log zerolog.Logger) CampaignsRepository {
|
|
||||||
return &campaignsRepository{
|
|
||||||
DB: db,
|
|
||||||
Log: log,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// implement interface of ICampaignsRepository
|
|
||||||
func (_i *campaignsRepository) GetAll(req request.CampaignsQueryRequest) (campaignss []*entity.Campaigns, paging paginator.Pagination, err error) {
|
|
||||||
var count int64
|
|
||||||
|
|
||||||
query := _i.DB.DB.Model(&entity.Campaigns{}).Preload("CampaignType").Preload("Creator")
|
|
||||||
|
|
||||||
if req.Title != nil && *req.Title != "" {
|
|
||||||
title := strings.ToLower(*req.Title)
|
|
||||||
query = query.Where("LOWER(title) LIKE ?", "%"+strings.ToLower(title)+"%")
|
|
||||||
}
|
|
||||||
if req.CampaignTypeID != nil {
|
|
||||||
query = query.Where("campaign_type_id = ?", req.CampaignTypeID)
|
|
||||||
}
|
|
||||||
if req.Status != nil && *req.Status != "" {
|
|
||||||
query = query.Where("status = ?", req.Status)
|
|
||||||
}
|
|
||||||
if req.CreatorID != nil {
|
|
||||||
query = query.Where("creator_id = ?", req.CreatorID)
|
|
||||||
}
|
|
||||||
query.Count(&count)
|
|
||||||
|
|
||||||
if req.Pagination.SortBy != "" {
|
|
||||||
direction := "ASC"
|
|
||||||
if req.Pagination.Sort == "desc" {
|
|
||||||
direction = "DESC"
|
|
||||||
}
|
|
||||||
query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
|
|
||||||
} else {
|
|
||||||
direction := "DESC"
|
|
||||||
sortBy := "created_at"
|
|
||||||
query.Order(fmt.Sprintf("%s %s", sortBy, direction))
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Pagination.Count = count
|
|
||||||
req.Pagination = paginator.Paging(req.Pagination)
|
|
||||||
|
|
||||||
err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&campaignss).Error
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
paging = *req.Pagination
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignsRepository) FindOne(id uint) (campaigns *entity.Campaigns, err error) {
|
|
||||||
query := _i.DB.DB.Where("id = ?", id).Preload("CampaignType").Preload("Creator")
|
|
||||||
|
|
||||||
if err := query.First(&campaigns).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return campaigns, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignsRepository) Create(campaigns *entity.Campaigns) (campaignsReturn *entity.Campaigns, err error) {
|
|
||||||
result := _i.DB.DB.Create(campaigns)
|
|
||||||
return campaigns, result.Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignsRepository) Update(id uint, campaigns *entity.Campaigns) (err error) {
|
|
||||||
campaignsMap, err := utilSvc.StructToMap(campaigns)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
query := _i.DB.DB.Model(&entity.Campaigns{}).Where(&entity.Campaigns{ID: id})
|
|
||||||
return query.Updates(campaignsMap).Error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignsRepository) Delete(id uint) error {
|
|
||||||
return _i.DB.DB.Delete(&entity.Campaigns{}, id).Error
|
|
||||||
}
|
|
||||||
|
|
@ -1,138 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CampaignsQueryRequest struct {
|
|
||||||
Title *string `json:"title"`
|
|
||||||
CampaignTypeID *uint `json:"campaignTypeId"`
|
|
||||||
Status *string `json:"status"`
|
|
||||||
CreatorID *uint `json:"creatorId"`
|
|
||||||
Pagination *paginator.Pagination `json:"pagination"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignsCreateRequest struct {
|
|
||||||
Title string `json:"title" validate:"required"`
|
|
||||||
CampaignTypeID uint `json:"campaignTypeId" validate:"required"`
|
|
||||||
StartDate *string `json:"startDate"`
|
|
||||||
EndDate *string `json:"endDate"`
|
|
||||||
MediaTypeSelected *string `json:"mediaTypeSelected"`
|
|
||||||
MediaItemSelected *string `json:"mediaItemSelected"`
|
|
||||||
Purpose *string `json:"purpose"`
|
|
||||||
MediaPromote *bool `json:"mediaPromote"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
CreatorID *uint `json:"creatorId"`
|
|
||||||
Status *string `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignsCreateRequest) ToEntity() *entity.Campaigns {
|
|
||||||
campaign := &entity.Campaigns{
|
|
||||||
Title: req.Title,
|
|
||||||
CampaignTypeID: req.CampaignTypeID,
|
|
||||||
MediaTypeSelected: req.MediaTypeSelected,
|
|
||||||
MediaItemSelected: req.MediaItemSelected,
|
|
||||||
Purpose: req.Purpose,
|
|
||||||
MediaPromote: req.MediaPromote,
|
|
||||||
Description: req.Description,
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.StartDate != nil && *req.StartDate != "" {
|
|
||||||
if startDate, err := time.Parse("2006-01-02", *req.StartDate); err == nil {
|
|
||||||
campaign.StartDate = &startDate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if req.EndDate != nil && *req.EndDate != "" {
|
|
||||||
if endDate, err := time.Parse("2006-01-02", *req.EndDate); err == nil {
|
|
||||||
campaign.EndDate = &endDate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if req.Status != nil {
|
|
||||||
campaign.Status = *req.Status
|
|
||||||
} else {
|
|
||||||
campaign.Status = "draft"
|
|
||||||
}
|
|
||||||
|
|
||||||
return campaign
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignsUpdateRequest struct {
|
|
||||||
Title string `json:"title" validate:"required"`
|
|
||||||
CampaignTypeID uint `json:"campaignTypeId" validate:"required"`
|
|
||||||
StartDate *string `json:"startDate"`
|
|
||||||
EndDate *string `json:"endDate"`
|
|
||||||
MediaTypeSelected *string `json:"mediaTypeSelected"`
|
|
||||||
MediaItemSelected *string `json:"mediaItemSelected"`
|
|
||||||
Purpose *string `json:"purpose"`
|
|
||||||
MediaPromote *bool `json:"mediaPromote"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
Status *string `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignsUpdateRequest) ToEntity() *entity.Campaigns {
|
|
||||||
campaign := &entity.Campaigns{
|
|
||||||
Title: req.Title,
|
|
||||||
CampaignTypeID: req.CampaignTypeID,
|
|
||||||
MediaTypeSelected: req.MediaTypeSelected,
|
|
||||||
MediaItemSelected: req.MediaItemSelected,
|
|
||||||
Purpose: req.Purpose,
|
|
||||||
MediaPromote: req.MediaPromote,
|
|
||||||
Description: req.Description,
|
|
||||||
UpdatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.StartDate != nil && *req.StartDate != "" {
|
|
||||||
if startDate, err := time.Parse("2006-01-02", *req.StartDate); err == nil {
|
|
||||||
campaign.StartDate = &startDate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if req.EndDate != nil && *req.EndDate != "" {
|
|
||||||
if endDate, err := time.Parse("2006-01-02", *req.EndDate); err == nil {
|
|
||||||
campaign.EndDate = &endDate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if req.Status != nil {
|
|
||||||
campaign.Status = *req.Status
|
|
||||||
}
|
|
||||||
|
|
||||||
return campaign
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignsQueryRequestContext struct {
|
|
||||||
Title string `json:"title"`
|
|
||||||
CampaignTypeID string `json:"campaignTypeId"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
CreatorID string `json:"creatorId"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (req CampaignsQueryRequestContext) ToParamRequest() CampaignsQueryRequest {
|
|
||||||
var request CampaignsQueryRequest
|
|
||||||
|
|
||||||
if title := req.Title; title != "" {
|
|
||||||
request.Title = &title
|
|
||||||
}
|
|
||||||
if campaignTypeIDStr := req.CampaignTypeID; campaignTypeIDStr != "" {
|
|
||||||
campaignTypeID, err := strconv.ParseUint(campaignTypeIDStr, 10, 32)
|
|
||||||
if err == nil {
|
|
||||||
campaignTypeIDUint := uint(campaignTypeID)
|
|
||||||
request.CampaignTypeID = &campaignTypeIDUint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if status := req.Status; status != "" {
|
|
||||||
request.Status = &status
|
|
||||||
}
|
|
||||||
if creatorIDStr := req.CreatorID; creatorIDStr != "" {
|
|
||||||
creatorID, err := strconv.ParseUint(creatorIDStr, 10, 32)
|
|
||||||
if err == nil {
|
|
||||||
creatorIDUint := uint(creatorID)
|
|
||||||
request.CreatorID = &creatorIDUint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return request
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
package response
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type CampaignsResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
CampaignTypeID uint `json:"campaignTypeId"`
|
|
||||||
CampaignType *CampaignTypeInfo `json:"campaignType,omitempty"`
|
|
||||||
StartDate *time.Time `json:"startDate"`
|
|
||||||
EndDate *time.Time `json:"endDate"`
|
|
||||||
MediaTypeSelected *string `json:"mediaTypeSelected"`
|
|
||||||
MediaItemSelected *string `json:"mediaItemSelected"`
|
|
||||||
Purpose *string `json:"purpose"`
|
|
||||||
MediaPromote *bool `json:"mediaPromote"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
CreatorID uint `json:"creatorId"`
|
|
||||||
Creator *CreatorInfo `json:"creator,omitempty"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
IsActive *bool `json:"isActive"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignTypeInfo struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Description *string `json:"description"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreatorInfo struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
Fullname string `json:"fullname"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/campaigns/mapper"
|
|
||||||
"jaecoo-be/app/module/campaigns/repository"
|
|
||||||
"jaecoo-be/app/module/campaigns/request"
|
|
||||||
"jaecoo-be/app/module/campaigns/response"
|
|
||||||
usersRepository "jaecoo-be/app/module/users/repository"
|
|
||||||
config "jaecoo-be/config/config"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
// CampaignsService
|
|
||||||
type campaignsService struct {
|
|
||||||
Repo repository.CampaignsRepository
|
|
||||||
UsersRepo usersRepository.UsersRepository
|
|
||||||
Log zerolog.Logger
|
|
||||||
Cfg *config.Config
|
|
||||||
}
|
|
||||||
|
|
||||||
// CampaignsService define interface of ICampaignsService
|
|
||||||
type CampaignsService interface {
|
|
||||||
All(req request.CampaignsQueryRequest, authToken string) (campaigns []*response.CampaignsResponse, paging paginator.Pagination, err error)
|
|
||||||
Show(id uint) (campaigns *response.CampaignsResponse, err error)
|
|
||||||
Save(req request.CampaignsCreateRequest, authToken string) (campaigns *entity.Campaigns, err error)
|
|
||||||
Update(id uint, req request.CampaignsUpdateRequest) (err error)
|
|
||||||
Delete(id uint) error
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewCampaignsService init CampaignsService
|
|
||||||
func NewCampaignsService(repo repository.CampaignsRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger, cfg *config.Config) CampaignsService {
|
|
||||||
return &campaignsService{
|
|
||||||
Repo: repo,
|
|
||||||
UsersRepo: usersRepo,
|
|
||||||
Log: log,
|
|
||||||
Cfg: cfg,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All implement interface of CampaignsService
|
|
||||||
func (_i *campaignsService) All(req request.CampaignsQueryRequest, authToken string) (campaignss []*response.CampaignsResponse, paging paginator.Pagination, err error) {
|
|
||||||
results, paging, err := _i.Repo.GetAll(req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
host := _i.Cfg.App.Domain
|
|
||||||
for _, result := range results {
|
|
||||||
campaignss = append(campaignss, mapper.CampaignsResponseMapper(result, host))
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignsService) Show(id uint) (campaigns *response.CampaignsResponse, err error) {
|
|
||||||
result, err := _i.Repo.FindOne(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
host := _i.Cfg.App.Domain
|
|
||||||
return mapper.CampaignsResponseMapper(result, host), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignsService) Save(req request.CampaignsCreateRequest, authToken string) (campaigns *entity.Campaigns, err error) {
|
|
||||||
_i.Log.Info().Interface("data", req).Msg("")
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
|
|
||||||
if req.CreatorID != nil {
|
|
||||||
creator, err := _i.UsersRepo.FindOne(*req.CreatorID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
newReq.CreatorID = creator.ID
|
|
||||||
} else {
|
|
||||||
creator := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if creator != nil {
|
|
||||||
newReq.CreatorID = creator.ID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default status if not provided
|
|
||||||
if newReq.Status == "" {
|
|
||||||
newReq.Status = "draft"
|
|
||||||
}
|
|
||||||
|
|
||||||
return _i.Repo.Create(newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignsService) Update(id uint, req request.CampaignsUpdateRequest) (err error) {
|
|
||||||
_i.Log.Info().Interface("data", req).Msg("")
|
|
||||||
|
|
||||||
newReq := req.ToEntity()
|
|
||||||
return _i.Repo.Update(id, newReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *campaignsService) Delete(id uint) error {
|
|
||||||
return _i.Repo.Delete(id)
|
|
||||||
}
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
package chat
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/chat/controller"
|
|
||||||
"jaecoo-be/app/module/chat/repository"
|
|
||||||
"jaecoo-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),
|
|
||||||
fx.Provide(repository.NewChatScheduleRepository),
|
|
||||||
fx.Provide(repository.NewChatScheduleFileRepository),
|
|
||||||
|
|
||||||
// register service of Chat module
|
|
||||||
fx.Provide(service.NewChatService),
|
|
||||||
fx.Provide(service.NewChatScheduleService),
|
|
||||||
fx.Provide(service.NewChatScheduleFileService),
|
|
||||||
|
|
||||||
// register controller of Chat module
|
|
||||||
fx.Provide(controller.NewController),
|
|
||||||
fx.Provide(controller.NewChatScheduleController),
|
|
||||||
fx.Provide(controller.NewChatScheduleFileController),
|
|
||||||
|
|
||||||
// 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
|
|
||||||
chatScheduleController := _i.Controller.ChatSchedule
|
|
||||||
chatScheduleFileController := _i.Controller.ChatScheduleFile
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Chat Schedule routes
|
|
||||||
router.Route("/schedules", func(scheduleRouter fiber.Router) {
|
|
||||||
scheduleRouter.Get("/", chatScheduleController.GetAllChatSchedules)
|
|
||||||
scheduleRouter.Get("/upcoming", chatScheduleController.GetUpcomingSchedules)
|
|
||||||
scheduleRouter.Get("/status/:status", chatScheduleController.GetSchedulesByStatus)
|
|
||||||
scheduleRouter.Get("/:id", chatScheduleController.GetChatScheduleByID)
|
|
||||||
scheduleRouter.Post("/", chatScheduleController.CreateChatSchedule)
|
|
||||||
scheduleRouter.Put("/:id", chatScheduleController.UpdateChatSchedule)
|
|
||||||
scheduleRouter.Delete("/:id", chatScheduleController.DeleteChatSchedule)
|
|
||||||
scheduleRouter.Post("/:id/reminder", chatScheduleController.SendScheduleReminder)
|
|
||||||
})
|
|
||||||
|
|
||||||
// Chat Schedule File routes
|
|
||||||
router.Route("/schedule-files", func(fileRouter fiber.Router) {
|
|
||||||
fileRouter.Get("/", chatScheduleFileController.GetChatScheduleFiles)
|
|
||||||
fileRouter.Get("/:id", chatScheduleFileController.GetChatScheduleFileByID)
|
|
||||||
fileRouter.Post("/:chatScheduleId", chatScheduleFileController.UploadChatScheduleFile)
|
|
||||||
fileRouter.Put("/:id", chatScheduleFileController.UpdateChatScheduleFile)
|
|
||||||
fileRouter.Delete("/:id", chatScheduleFileController.DeleteChatScheduleFile)
|
|
||||||
fileRouter.Get("/viewer/:filename", chatScheduleFileController.Viewer)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,474 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
"jaecoo-be/app/module/chat/service"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilRes "jaecoo-be/utils/response"
|
|
||||||
utilVal "jaecoo-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"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,320 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
"jaecoo-be/app/module/chat/service"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilRes "jaecoo-be/utils/response"
|
|
||||||
utilVal "jaecoo-be/utils/validator"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type chatScheduleController struct {
|
|
||||||
chatScheduleService service.ChatScheduleService
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatScheduleController interface {
|
|
||||||
// Chat Schedule endpoints
|
|
||||||
GetAllChatSchedules(c *fiber.Ctx) error
|
|
||||||
GetChatScheduleByID(c *fiber.Ctx) error
|
|
||||||
CreateChatSchedule(c *fiber.Ctx) error
|
|
||||||
UpdateChatSchedule(c *fiber.Ctx) error
|
|
||||||
DeleteChatSchedule(c *fiber.Ctx) error
|
|
||||||
|
|
||||||
// Additional schedule endpoints
|
|
||||||
GetUpcomingSchedules(c *fiber.Ctx) error
|
|
||||||
GetSchedulesByStatus(c *fiber.Ctx) error
|
|
||||||
SendScheduleReminder(c *fiber.Ctx) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewChatScheduleController(chatScheduleService service.ChatScheduleService) ChatScheduleController {
|
|
||||||
return &chatScheduleController{
|
|
||||||
chatScheduleService: chatScheduleService,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllChatSchedules - Get all chat schedules for a user
|
|
||||||
// @Summary Get all chat schedules
|
|
||||||
// @Description API for getting all chat schedules for authenticated user
|
|
||||||
// @Tags Chat Schedule
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param chatSessionId query string false "Chat Session ID"
|
|
||||||
// @Param status query string false "Schedule status (scheduled, ongoing, completed, cancelled)"
|
|
||||||
// @Param createdBy query string false "Created by user ID"
|
|
||||||
// @Param dateFrom query string false "Date from (YYYY-MM-DD)"
|
|
||||||
// @Param dateTo query string false "Date to (YYYY-MM-DD)"
|
|
||||||
// @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/schedules [get]
|
|
||||||
func (_i *chatScheduleController) GetAllChatSchedules(c *fiber.Ctx) error {
|
|
||||||
paginate, err := paginator.Paginate(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
reqContext := request.ChatScheduleQueryRequestContext{
|
|
||||||
ChatSessionID: c.Query("chatSessionId"),
|
|
||||||
Status: c.Query("status"),
|
|
||||||
CreatedBy: c.Query("createdBy"),
|
|
||||||
DateFrom: c.Query("dateFrom"),
|
|
||||||
DateTo: c.Query("dateTo"),
|
|
||||||
}
|
|
||||||
req := reqContext.ToParamRequest()
|
|
||||||
req.Pagination = *paginate
|
|
||||||
|
|
||||||
chatSchedules, paging, err := _i.chatScheduleService.GetAllChatSchedules(authToken, req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedules successfully retrieved"},
|
|
||||||
Data: chatSchedules,
|
|
||||||
Meta: paging,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatScheduleByID - Get one chat schedule
|
|
||||||
// @Summary Get one chat schedule
|
|
||||||
// @Description API for getting one chat schedule
|
|
||||||
// @Tags Chat Schedule
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param id path int true "Chat Schedule ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedules/{id} [get]
|
|
||||||
func (_i *chatScheduleController) GetChatScheduleByID(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
chatSchedule, err := _i.chatScheduleService.GetChatScheduleByID(authToken, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedule successfully retrieved"},
|
|
||||||
Data: chatSchedule,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateChatSchedule - Create chat schedule
|
|
||||||
// @Summary Create chat schedule
|
|
||||||
// @Description API for creating a new chat schedule
|
|
||||||
// @Tags Chat Schedule
|
|
||||||
// @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.ChatScheduleCreateRequest 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/schedules [post]
|
|
||||||
func (_i *chatScheduleController) CreateChatSchedule(c *fiber.Ctx) error {
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
req := new(request.ChatScheduleCreateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
dataResult, err := _i.chatScheduleService.CreateChatSchedule(authToken, *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedule successfully created"},
|
|
||||||
Data: dataResult,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateChatSchedule - Update chat schedule
|
|
||||||
// @Summary Update chat schedule
|
|
||||||
// @Description API for updating chat schedule (only creator can update)
|
|
||||||
// @Tags Chat Schedule
|
|
||||||
// @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 Schedule ID"
|
|
||||||
// @Param payload body request.ChatScheduleUpdateRequest 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/schedules/{id} [put]
|
|
||||||
func (_i *chatScheduleController) UpdateChatSchedule(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.ChatScheduleUpdateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.chatScheduleService.UpdateChatSchedule(authToken, uint(id), *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedule successfully updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteChatSchedule - Delete chat schedule
|
|
||||||
// @Summary Delete chat schedule
|
|
||||||
// @Description API for deleting chat schedule (only creator can delete)
|
|
||||||
// @Tags Chat Schedule
|
|
||||||
// @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 Schedule ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedules/{id} [delete]
|
|
||||||
func (_i *chatScheduleController) DeleteChatSchedule(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
err = _i.chatScheduleService.DeleteChatSchedule(authToken, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedule successfully deleted"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUpcomingSchedules - Get upcoming schedules for a user
|
|
||||||
// @Summary Get upcoming schedules
|
|
||||||
// @Description API for getting upcoming chat schedules for authenticated user
|
|
||||||
// @Tags Chat Schedule
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param limit query int false "Limit number of results" default(10)
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedules/upcoming [get]
|
|
||||||
func (_i *chatScheduleController) GetUpcomingSchedules(c *fiber.Ctx) error {
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
limit := 10 // default limit
|
|
||||||
if limitStr := c.Query("limit"); limitStr != "" {
|
|
||||||
if parsedLimit, err := strconv.Atoi(limitStr); err == nil && parsedLimit > 0 {
|
|
||||||
limit = parsedLimit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
chatSchedules, err := _i.chatScheduleService.GetUpcomingSchedules(authToken, limit)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Upcoming chat schedules successfully retrieved"},
|
|
||||||
Data: chatSchedules,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSchedulesByStatus - Get schedules by status
|
|
||||||
// @Summary Get schedules by status
|
|
||||||
// @Description API for getting chat schedules by status
|
|
||||||
// @Tags Chat Schedule
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param status path string true "Schedule status (scheduled, ongoing, completed, cancelled)"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedules/status/{status} [get]
|
|
||||||
func (_i *chatScheduleController) GetSchedulesByStatus(c *fiber.Ctx) error {
|
|
||||||
status := c.Params("status")
|
|
||||||
if status == "" {
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: false,
|
|
||||||
Messages: utilRes.Messages{"Status parameter is required"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
chatSchedules, err := _i.chatScheduleService.GetSchedulesByStatus(authToken, status)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedules by status successfully retrieved"},
|
|
||||||
Data: chatSchedules,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendScheduleReminder - Send reminder for a schedule
|
|
||||||
// @Summary Send schedule reminder
|
|
||||||
// @Description API for sending reminder for a chat schedule (only creator can send)
|
|
||||||
// @Tags Chat Schedule
|
|
||||||
// @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 Schedule ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedules/{id}/reminder [post]
|
|
||||||
func (_i *chatScheduleController) SendScheduleReminder(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
err = _i.chatScheduleService.SendScheduleReminder(authToken, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Schedule reminder successfully sent"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,233 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
"jaecoo-be/app/module/chat/service"
|
|
||||||
utilRes "jaecoo-be/utils/response"
|
|
||||||
utilVal "jaecoo-be/utils/validator"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
type chatScheduleFileController struct {
|
|
||||||
chatScheduleFileService service.ChatScheduleFileService
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatScheduleFileController interface {
|
|
||||||
// File upload endpoints
|
|
||||||
UploadChatScheduleFile(c *fiber.Ctx) error
|
|
||||||
GetChatScheduleFiles(c *fiber.Ctx) error
|
|
||||||
GetChatScheduleFileByID(c *fiber.Ctx) error
|
|
||||||
UpdateChatScheduleFile(c *fiber.Ctx) error
|
|
||||||
DeleteChatScheduleFile(c *fiber.Ctx) error
|
|
||||||
Viewer(c *fiber.Ctx) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewChatScheduleFileController(chatScheduleFileService service.ChatScheduleFileService) ChatScheduleFileController {
|
|
||||||
return &chatScheduleFileController{
|
|
||||||
chatScheduleFileService: chatScheduleFileService,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadChatScheduleFile - Upload file for chat schedule
|
|
||||||
// @Summary Upload chat schedule file
|
|
||||||
// @Description API for uploading file for chat schedule
|
|
||||||
// @Tags Chat Schedule File
|
|
||||||
// @Security Bearer
|
|
||||||
// @Produce json
|
|
||||||
// @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 files formData file true "Upload file" multiple true
|
|
||||||
// @Param chatScheduleId path int true "Chat Schedule ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedule-files/{chatScheduleId} [post]
|
|
||||||
func (_i *chatScheduleFileController) UploadChatScheduleFile(c *fiber.Ctx) error {
|
|
||||||
// Get chat schedule ID from path
|
|
||||||
id, err := strconv.ParseUint(c.Params("chatScheduleId"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.chatScheduleFileService.UploadChatScheduleFile(c, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedule files successfully uploaded"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatScheduleFiles - Get files for a chat schedule
|
|
||||||
// @Summary Get chat schedule files
|
|
||||||
// @Description API for getting files for a specific chat schedule
|
|
||||||
// @Tags Chat Schedule File
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param chatScheduleId query uint true "Chat Schedule ID"
|
|
||||||
// @Param fileType query string false "File type filter"
|
|
||||||
// @Param isRequired query bool false "Required file filter"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedule-files [get]
|
|
||||||
func (_i *chatScheduleFileController) GetChatScheduleFiles(c *fiber.Ctx) error {
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
req := request.ChatScheduleFileQueryRequest{}
|
|
||||||
|
|
||||||
// Parse chat schedule ID
|
|
||||||
if chatScheduleIdStr := c.Query("chatScheduleId"); chatScheduleIdStr != "" {
|
|
||||||
if chatScheduleId, err := strconv.ParseUint(chatScheduleIdStr, 10, 0); err == nil {
|
|
||||||
chatScheduleIdUint := uint(chatScheduleId)
|
|
||||||
req.ChatScheduleID = &chatScheduleIdUint
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse file type
|
|
||||||
if fileType := c.Query("fileType"); fileType != "" {
|
|
||||||
req.FileType = &fileType
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse is required
|
|
||||||
if isRequiredStr := c.Query("isRequired"); isRequiredStr != "" {
|
|
||||||
if isRequired, err := strconv.ParseBool(isRequiredStr); err == nil {
|
|
||||||
req.IsRequired = &isRequired
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
files, err := _i.chatScheduleFileService.GetChatScheduleFiles(authToken, req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedule files successfully retrieved"},
|
|
||||||
Data: files,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatScheduleFileByID - Get one chat schedule file
|
|
||||||
// @Summary Get one chat schedule file
|
|
||||||
// @Description API for getting one chat schedule file
|
|
||||||
// @Tags Chat Schedule File
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param id path int true "Chat Schedule File ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedule-files/{id} [get]
|
|
||||||
func (_i *chatScheduleFileController) GetChatScheduleFileByID(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
file, err := _i.chatScheduleFileService.GetChatScheduleFileByID(authToken, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedule file successfully retrieved"},
|
|
||||||
Data: file,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateChatScheduleFile - Update chat schedule file
|
|
||||||
// @Summary Update chat schedule file
|
|
||||||
// @Description API for updating chat schedule file
|
|
||||||
// @Tags Chat Schedule File
|
|
||||||
// @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 Schedule File ID"
|
|
||||||
// @Param payload body request.ChatScheduleFileUpdateRequest 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/schedule-files/{id} [put]
|
|
||||||
func (_i *chatScheduleFileController) UpdateChatScheduleFile(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.ChatScheduleFileUpdateRequest)
|
|
||||||
if err := utilVal.ParseAndValidate(c, req); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.chatScheduleFileService.UpdateChatScheduleFile(authToken, uint(id), *req)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedule file successfully updated"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteChatScheduleFile - Delete chat schedule file
|
|
||||||
// @Summary Delete chat schedule file
|
|
||||||
// @Description API for deleting chat schedule file
|
|
||||||
// @Tags Chat Schedule File
|
|
||||||
// @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 Schedule File ID"
|
|
||||||
// @Success 200 {object} response.Response
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedule-files/{id} [delete]
|
|
||||||
func (_i *chatScheduleFileController) DeleteChatScheduleFile(c *fiber.Ctx) error {
|
|
||||||
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
authToken := c.Get("Authorization")
|
|
||||||
|
|
||||||
err = _i.chatScheduleFileService.DeleteChatScheduleFile(authToken, uint(id))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return utilRes.Resp(c, utilRes.Response{
|
|
||||||
Success: true,
|
|
||||||
Messages: utilRes.Messages{"Chat schedule file successfully deleted"},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Viewer - View chat schedule file
|
|
||||||
// @Summary View chat schedule file
|
|
||||||
// @Description API for viewing chat schedule file
|
|
||||||
// @Tags Chat Schedule File
|
|
||||||
// @Security Bearer
|
|
||||||
// @Param Authorization header string false "Insert your access token" default(Bearer <Add access token here>)
|
|
||||||
// @Param filename path string true "Chat Schedule File Name"
|
|
||||||
// @Success 200 {file} file
|
|
||||||
// @Failure 400 {object} response.BadRequestError
|
|
||||||
// @Failure 401 {object} response.UnauthorizedError
|
|
||||||
// @Failure 500 {object} response.InternalServerError
|
|
||||||
// @Router /chat/schedule-files/viewer/{filename} [get]
|
|
||||||
func (_i *chatScheduleFileController) Viewer(c *fiber.Ctx) error {
|
|
||||||
return _i.chatScheduleFileService.Viewer(c)
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package controller
|
|
||||||
|
|
||||||
import "jaecoo-be/app/module/chat/service"
|
|
||||||
|
|
||||||
type Controller struct {
|
|
||||||
Chat ChatController
|
|
||||||
ChatSchedule ChatScheduleController
|
|
||||||
ChatScheduleFile ChatScheduleFileController
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewController(ChatService service.ChatService, ChatScheduleService service.ChatScheduleService, ChatScheduleFileService service.ChatScheduleFileService) *Controller {
|
|
||||||
return &Controller{
|
|
||||||
Chat: NewChatController(ChatService),
|
|
||||||
ChatSchedule: NewChatScheduleController(ChatScheduleService),
|
|
||||||
ChatScheduleFile: NewChatScheduleFileController(ChatScheduleFileService),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,105 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-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
|
|
||||||
}
|
|
||||||
|
|
@ -1,177 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
"jaecoo-be/app/module/chat/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ChatScheduleResponse - Response structure for chat schedule
|
|
||||||
type ChatScheduleResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
ChatSessionID uint `json:"chat_session_id"`
|
|
||||||
Title string `json:"title"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Summary string `json:"summary"`
|
|
||||||
ScheduledAt string `json:"scheduled_at"`
|
|
||||||
Duration int `json:"duration"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
IsReminderSent bool `json:"is_reminder_sent"`
|
|
||||||
ReminderSentAt *string `json:"reminder_sent_at"`
|
|
||||||
CreatedBy uint `json:"created_by"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
ChatSession *response.ChatSessionResponse `json:"chat_session,omitempty"`
|
|
||||||
Creator *response.UserBasicInfo `json:"creator,omitempty"`
|
|
||||||
Files []*response.ChatScheduleFileResponse `json:"files,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatScheduleMapper - Mapper for chat schedule
|
|
||||||
type ChatScheduleMapper struct{}
|
|
||||||
|
|
||||||
// NewChatScheduleMapper - Create new chat schedule mapper
|
|
||||||
func NewChatScheduleMapper() *ChatScheduleMapper {
|
|
||||||
return &ChatScheduleMapper{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToResponse - Convert entity to response
|
|
||||||
func (m *ChatScheduleMapper) ToResponse(schedule *entity.ChatSchedules) *ChatScheduleResponse {
|
|
||||||
if schedule == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
scheduleResponse := &ChatScheduleResponse{
|
|
||||||
ID: schedule.ID,
|
|
||||||
ChatSessionID: schedule.ChatSessionID,
|
|
||||||
Title: schedule.Title,
|
|
||||||
Description: schedule.Description,
|
|
||||||
Summary: schedule.Summary,
|
|
||||||
ScheduledAt: schedule.ScheduledAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
||||||
Duration: schedule.Duration,
|
|
||||||
Status: schedule.Status,
|
|
||||||
IsReminderSent: schedule.IsReminderSent,
|
|
||||||
CreatedBy: schedule.CreatedBy,
|
|
||||||
CreatedAt: schedule.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
||||||
UpdatedAt: schedule.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
||||||
}
|
|
||||||
|
|
||||||
if schedule.ReminderSentAt != nil {
|
|
||||||
reminderSentAt := schedule.ReminderSentAt.Format("2006-01-02T15:04:05Z07:00")
|
|
||||||
scheduleResponse.ReminderSentAt = &reminderSentAt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map chat session
|
|
||||||
if schedule.ChatSession != nil {
|
|
||||||
scheduleResponse.ChatSession = ChatSessionResponseMapper(schedule.ChatSession)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map creator
|
|
||||||
if schedule.Creator != nil {
|
|
||||||
scheduleResponse.Creator = &response.UserBasicInfo{
|
|
||||||
ID: schedule.Creator.ID,
|
|
||||||
Username: schedule.Creator.Username,
|
|
||||||
Fullname: schedule.Creator.Fullname,
|
|
||||||
Email: schedule.Creator.Email,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map files
|
|
||||||
if len(schedule.Files) > 0 {
|
|
||||||
scheduleResponse.Files = make([]*response.ChatScheduleFileResponse, len(schedule.Files))
|
|
||||||
for i, file := range schedule.Files {
|
|
||||||
scheduleResponse.Files[i] = m.ToFileResponse(file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return scheduleResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToFileResponse - Convert file entity to response
|
|
||||||
func (m *ChatScheduleMapper) ToFileResponse(file *entity.ChatScheduleFiles) *response.ChatScheduleFileResponse {
|
|
||||||
if file == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.ChatScheduleFileResponse{
|
|
||||||
ID: file.ID,
|
|
||||||
ChatScheduleID: file.ChatScheduleID,
|
|
||||||
FileName: file.FileName,
|
|
||||||
OriginalName: file.OriginalName,
|
|
||||||
FilePath: file.FilePath,
|
|
||||||
FileSize: file.FileSize,
|
|
||||||
MimeType: file.MimeType,
|
|
||||||
FileType: file.FileType,
|
|
||||||
Description: file.Description,
|
|
||||||
IsRequired: file.IsRequired,
|
|
||||||
CreatedAt: file.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
||||||
UpdatedAt: file.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToEntity - Convert request to entity
|
|
||||||
func (m *ChatScheduleMapper) ToEntity(req request.ChatScheduleCreateRequest) *entity.ChatSchedules {
|
|
||||||
schedule := &entity.ChatSchedules{
|
|
||||||
Title: req.Title,
|
|
||||||
Description: req.Description,
|
|
||||||
Summary: req.Summary,
|
|
||||||
ScheduledAt: req.ScheduledAt,
|
|
||||||
Duration: req.Duration,
|
|
||||||
Status: "scheduled",
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle ChatSessionID pointer
|
|
||||||
if req.ChatSessionID != nil {
|
|
||||||
schedule.ChatSessionID = *req.ChatSessionID
|
|
||||||
}
|
|
||||||
|
|
||||||
// Files will be attached separately using file IDs
|
|
||||||
|
|
||||||
return schedule
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToUpdateEntity - Convert update request to entity
|
|
||||||
func (m *ChatScheduleMapper) ToUpdateEntity(req request.ChatScheduleUpdateRequest) *entity.ChatSchedules {
|
|
||||||
schedule := &entity.ChatSchedules{}
|
|
||||||
|
|
||||||
if req.Title != "" {
|
|
||||||
schedule.Title = req.Title
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Description != "" {
|
|
||||||
schedule.Description = req.Description
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Summary != "" {
|
|
||||||
schedule.Summary = req.Summary
|
|
||||||
}
|
|
||||||
|
|
||||||
if !req.ScheduledAt.IsZero() {
|
|
||||||
schedule.ScheduledAt = req.ScheduledAt
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Duration > 0 {
|
|
||||||
schedule.Duration = req.Duration
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Status != "" {
|
|
||||||
schedule.Status = req.Status
|
|
||||||
}
|
|
||||||
|
|
||||||
// Files will be attached separately using file IDs
|
|
||||||
|
|
||||||
return schedule
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToResponseList - Convert entity list to response list
|
|
||||||
func (m *ChatScheduleMapper) ToResponseList(schedules []*entity.ChatSchedules) []*ChatScheduleResponse {
|
|
||||||
if schedules == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
responses := make([]*ChatScheduleResponse, len(schedules))
|
|
||||||
for i, schedule := range schedules {
|
|
||||||
responses[i] = m.ToResponse(schedule)
|
|
||||||
}
|
|
||||||
|
|
||||||
return responses
|
|
||||||
}
|
|
||||||
|
|
@ -1,100 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
"jaecoo-be/app/module/chat/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ChatScheduleFileMapper - Mapper for chat schedule file
|
|
||||||
type ChatScheduleFileMapper struct{}
|
|
||||||
|
|
||||||
// NewChatScheduleFileMapper - Create new chat schedule file mapper
|
|
||||||
func NewChatScheduleFileMapper() *ChatScheduleFileMapper {
|
|
||||||
return &ChatScheduleFileMapper{}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToResponse - Convert entity to response
|
|
||||||
func (m *ChatScheduleFileMapper) ToResponse(file *entity.ChatScheduleFiles) *response.ChatScheduleFileResponse {
|
|
||||||
if file == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.ChatScheduleFileResponse{
|
|
||||||
ID: file.ID,
|
|
||||||
ChatScheduleID: file.ChatScheduleID,
|
|
||||||
FileName: file.FileName,
|
|
||||||
OriginalName: file.OriginalName,
|
|
||||||
FilePath: file.FilePath,
|
|
||||||
FileSize: file.FileSize,
|
|
||||||
MimeType: file.MimeType,
|
|
||||||
FileType: file.FileType,
|
|
||||||
Description: file.Description,
|
|
||||||
IsRequired: file.IsRequired,
|
|
||||||
CreatedAt: file.CreatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
||||||
UpdatedAt: file.UpdatedAt.Format("2006-01-02T15:04:05Z07:00"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToEntity - Convert upload request to entity
|
|
||||||
func (m *ChatScheduleFileMapper) ToEntity(req request.ChatScheduleFileUploadRequest) *entity.ChatScheduleFiles {
|
|
||||||
return &entity.ChatScheduleFiles{
|
|
||||||
ChatScheduleID: req.ChatScheduleID,
|
|
||||||
FileType: req.FileType,
|
|
||||||
Description: req.Description,
|
|
||||||
IsRequired: req.IsRequired,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToUpdateEntity - Convert update request to entity
|
|
||||||
func (m *ChatScheduleFileMapper) ToUpdateEntity(req request.ChatScheduleFileUpdateRequest) *entity.ChatScheduleFiles {
|
|
||||||
file := &entity.ChatScheduleFiles{}
|
|
||||||
|
|
||||||
if req.FileName != "" {
|
|
||||||
file.FileName = req.FileName
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.OriginalName != "" {
|
|
||||||
file.OriginalName = req.OriginalName
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.FilePath != "" {
|
|
||||||
file.FilePath = req.FilePath
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.FileSize > 0 {
|
|
||||||
file.FileSize = req.FileSize
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.MimeType != "" {
|
|
||||||
file.MimeType = req.MimeType
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.FileType != "" {
|
|
||||||
file.FileType = req.FileType
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Description != "" {
|
|
||||||
file.Description = req.Description
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.IsRequired != nil {
|
|
||||||
file.IsRequired = *req.IsRequired
|
|
||||||
}
|
|
||||||
|
|
||||||
return file
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToResponseList - Convert entity list to response list
|
|
||||||
func (m *ChatScheduleFileMapper) ToResponseList(files []*entity.ChatScheduleFiles) []*response.ChatScheduleFileResponse {
|
|
||||||
if files == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
responses := make([]*response.ChatScheduleFileResponse, len(files))
|
|
||||||
for i, file := range files {
|
|
||||||
responses[i] = m.ToResponse(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
return responses
|
|
||||||
}
|
|
||||||
|
|
@ -1,272 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
"jaecoo-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
|
|
||||||
}
|
|
||||||
|
|
@ -1,179 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
)
|
|
||||||
|
|
||||||
type chatScheduleRepository struct {
|
|
||||||
DB *database.Database
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatScheduleRepository interface {
|
|
||||||
// Chat Schedule CRUD operations
|
|
||||||
CreateChatSchedule(schedule *entity.ChatSchedules) (result *entity.ChatSchedules, err error)
|
|
||||||
GetAllChatSchedules(userId uint, req request.ChatScheduleQueryRequest) (schedules []*entity.ChatSchedules, paging paginator.Pagination, err error)
|
|
||||||
GetChatScheduleByID(id uint) (schedule *entity.ChatSchedules, err error)
|
|
||||||
UpdateChatSchedule(id uint, schedule *entity.ChatSchedules) (err error)
|
|
||||||
DeleteChatSchedule(id uint) (err error)
|
|
||||||
|
|
||||||
// Chat Schedule File operations
|
|
||||||
CreateChatScheduleFile(file *entity.ChatScheduleFiles) (result *entity.ChatScheduleFiles, err error)
|
|
||||||
GetChatScheduleFilesByScheduleID(scheduleID uint) (files []*entity.ChatScheduleFiles, err error)
|
|
||||||
UpdateChatScheduleFile(id uint, file *entity.ChatScheduleFiles) (err error)
|
|
||||||
DeleteChatScheduleFile(id uint) (err error)
|
|
||||||
|
|
||||||
// Utility methods
|
|
||||||
CheckUserInChatSchedule(userId uint, scheduleID uint) (isParticipant bool, err error)
|
|
||||||
GetUpcomingSchedules(userId uint, limit int) (schedules []*entity.ChatSchedules, err error)
|
|
||||||
GetSchedulesByStatus(status string) (schedules []*entity.ChatSchedules, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewChatScheduleRepository(db *database.Database) ChatScheduleRepository {
|
|
||||||
return &chatScheduleRepository{
|
|
||||||
DB: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chat Schedule Repository Methods
|
|
||||||
func (_i *chatScheduleRepository) CreateChatSchedule(schedule *entity.ChatSchedules) (result *entity.ChatSchedules, err error) {
|
|
||||||
err = _i.DB.DB.Create(schedule).Error
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.DB.DB.Preload("Creator").
|
|
||||||
Preload("ChatSession").
|
|
||||||
Preload("Files").
|
|
||||||
First(&result, schedule.ID).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *chatScheduleRepository) GetAllChatSchedules(userId uint, req request.ChatScheduleQueryRequest) (schedules []*entity.ChatSchedules, paging paginator.Pagination, err error) {
|
|
||||||
// Get chat schedules where user is a participant in the chat session
|
|
||||||
query := _i.DB.DB.Model(&entity.ChatSchedules{}).
|
|
||||||
Joins("INNER JOIN chat_sessions cs ON chat_schedules.chat_session_id = cs.id").
|
|
||||||
Joins("INNER JOIN chat_participants cp ON cs.id = cp.chat_session_id").
|
|
||||||
Where("cp.user_id = ? AND cp.is_active = true", userId)
|
|
||||||
|
|
||||||
// Apply filters
|
|
||||||
if req.ChatSessionID != nil {
|
|
||||||
query = query.Where("chat_schedules.chat_session_id = ?", *req.ChatSessionID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Status != nil {
|
|
||||||
query = query.Where("chat_schedules.status = ?", *req.Status)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.CreatedBy != nil {
|
|
||||||
query = query.Where("chat_schedules.created_by = ?", *req.CreatedBy)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.DateFrom != nil {
|
|
||||||
query = query.Where("DATE(chat_schedules.scheduled_at) >= ?", req.DateFrom.Format("2006-01-02"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.DateTo != nil {
|
|
||||||
query = query.Where("DATE(chat_schedules.scheduled_at) <= ?", req.DateTo.Format("2006-01-02"))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Include relationships
|
|
||||||
query = query.Preload("Creator").
|
|
||||||
Preload("ChatSession").
|
|
||||||
Preload("Files")
|
|
||||||
|
|
||||||
// Order by scheduled_at asc (upcoming first)
|
|
||||||
query = query.Order("chat_schedules.scheduled_at ASC")
|
|
||||||
|
|
||||||
// Apply pagination
|
|
||||||
var count int64
|
|
||||||
query.Count(&count)
|
|
||||||
req.Pagination.Count = count
|
|
||||||
pagingResult := paginator.Paging(&req.Pagination)
|
|
||||||
|
|
||||||
err = query.Offset(pagingResult.Offset).Limit(pagingResult.Limit).Find(&schedules).Error
|
|
||||||
paging = *pagingResult
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *chatScheduleRepository) GetChatScheduleByID(id uint) (schedule *entity.ChatSchedules, err error) {
|
|
||||||
err = _i.DB.DB.Preload("Creator").
|
|
||||||
Preload("ChatSession").
|
|
||||||
Preload("Files").
|
|
||||||
First(&schedule, id).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *chatScheduleRepository) UpdateChatSchedule(id uint, schedule *entity.ChatSchedules) (err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.ChatSchedules{}).Where("id = ?", id).Updates(schedule).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *chatScheduleRepository) DeleteChatSchedule(id uint) (err error) {
|
|
||||||
err = _i.DB.DB.Delete(&entity.ChatSchedules{}, id).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Chat Schedule File Repository Methods
|
|
||||||
func (_i *chatScheduleRepository) CreateChatScheduleFile(file *entity.ChatScheduleFiles) (result *entity.ChatScheduleFiles, err error) {
|
|
||||||
err = _i.DB.DB.Create(file).Error
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.DB.DB.First(&result, file.ID).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *chatScheduleRepository) GetChatScheduleFilesByScheduleID(scheduleID uint) (files []*entity.ChatScheduleFiles, err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.ChatScheduleFiles{}).Where("chat_schedule_id = ?", scheduleID).Find(&files).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *chatScheduleRepository) UpdateChatScheduleFile(id uint, file *entity.ChatScheduleFiles) (err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.ChatScheduleFiles{}).Where("id = ?", id).Updates(file).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *chatScheduleRepository) DeleteChatScheduleFile(id uint) (err error) {
|
|
||||||
err = _i.DB.DB.Delete(&entity.ChatScheduleFiles{}, id).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Utility Methods
|
|
||||||
func (_i *chatScheduleRepository) CheckUserInChatSchedule(userId uint, scheduleID uint) (isParticipant bool, err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.ChatParticipants{}).
|
|
||||||
Select("COUNT(*) > 0").
|
|
||||||
Joins("INNER JOIN chat_sessions cs ON chat_participants.chat_session_id = cs.id").
|
|
||||||
Where("cs.id = ? AND chat_participants.user_id = ? AND chat_participants.is_active = true", scheduleID, userId).
|
|
||||||
Scan(&isParticipant).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *chatScheduleRepository) GetUpcomingSchedules(userId uint, limit int) (schedules []*entity.ChatSchedules, err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.ChatSchedules{}).
|
|
||||||
Joins("INNER JOIN chat_sessions cs ON chat_schedules.chat_session_id = cs.id").
|
|
||||||
Joins("INNER JOIN chat_participants cp ON cs.id = cp.chat_session_id").
|
|
||||||
Where("cp.user_id = ? AND cp.is_active = true AND chat_schedules.scheduled_at > NOW() AND chat_schedules.status = 'scheduled'", userId).
|
|
||||||
Preload("Creator").
|
|
||||||
Preload("ChatSession").
|
|
||||||
Preload("Files").
|
|
||||||
Order("chat_schedules.scheduled_at ASC").
|
|
||||||
Limit(limit).
|
|
||||||
Find(&schedules).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (_i *chatScheduleRepository) GetSchedulesByStatus(status string) (schedules []*entity.ChatSchedules, err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.ChatSchedules{}).
|
|
||||||
Where("status = ?", status).
|
|
||||||
Preload("Creator").
|
|
||||||
Preload("ChatSession").
|
|
||||||
Preload("Files").
|
|
||||||
Order("scheduled_at ASC").
|
|
||||||
Find(&schedules).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
)
|
|
||||||
|
|
||||||
type chatScheduleFileRepository struct {
|
|
||||||
DB *database.Database
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatScheduleFileRepository interface {
|
|
||||||
// File CRUD operations
|
|
||||||
CreateChatScheduleFile(file *entity.ChatScheduleFiles) (result *entity.ChatScheduleFiles, err error)
|
|
||||||
GetChatScheduleFiles(req request.ChatScheduleFileQueryRequest) (files []*entity.ChatScheduleFiles, err error)
|
|
||||||
GetChatScheduleFileByID(id uint) (file *entity.ChatScheduleFiles, err error)
|
|
||||||
GetChatScheduleFileByFilename(filename string) (file *entity.ChatScheduleFiles, err error)
|
|
||||||
UpdateChatScheduleFile(id uint, file *entity.ChatScheduleFiles) (err error)
|
|
||||||
DeleteChatScheduleFile(id uint) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewChatScheduleFileRepository(db *database.Database) ChatScheduleFileRepository {
|
|
||||||
return &chatScheduleFileRepository{
|
|
||||||
DB: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateChatScheduleFile - Create a new chat schedule file
|
|
||||||
func (_i *chatScheduleFileRepository) CreateChatScheduleFile(file *entity.ChatScheduleFiles) (result *entity.ChatScheduleFiles, err error) {
|
|
||||||
err = _i.DB.DB.Create(file).Error
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = _i.DB.DB.First(&result, file.ID).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatScheduleFiles - Get files for chat schedule with filters
|
|
||||||
func (_i *chatScheduleFileRepository) GetChatScheduleFiles(req request.ChatScheduleFileQueryRequest) (files []*entity.ChatScheduleFiles, err error) {
|
|
||||||
query := _i.DB.DB.Model(&entity.ChatScheduleFiles{})
|
|
||||||
|
|
||||||
// Apply filters
|
|
||||||
if req.ChatScheduleID != nil {
|
|
||||||
query = query.Where("chat_schedule_id = ?", *req.ChatScheduleID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.FileType != nil {
|
|
||||||
query = query.Where("file_type = ?", *req.FileType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.IsRequired != nil {
|
|
||||||
query = query.Where("is_required = ?", *req.IsRequired)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Order by created_at desc (newest first)
|
|
||||||
query = query.Order("created_at DESC")
|
|
||||||
|
|
||||||
err = query.Find(&files).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatScheduleFileByID - Get a specific chat schedule file
|
|
||||||
func (_i *chatScheduleFileRepository) GetChatScheduleFileByID(id uint) (file *entity.ChatScheduleFiles, err error) {
|
|
||||||
err = _i.DB.DB.First(&file, id).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateChatScheduleFile - Update a chat schedule file
|
|
||||||
func (_i *chatScheduleFileRepository) UpdateChatScheduleFile(id uint, file *entity.ChatScheduleFiles) (err error) {
|
|
||||||
err = _i.DB.DB.Model(&entity.ChatScheduleFiles{}).Where("id = ?", id).Updates(file).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatScheduleFileByFilename - Get a chat schedule file by filename
|
|
||||||
func (_i *chatScheduleFileRepository) GetChatScheduleFileByFilename(filename string) (file *entity.ChatScheduleFiles, err error) {
|
|
||||||
err = _i.DB.DB.Where("file_name = ?", filename).First(&file).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteChatScheduleFile - Delete a chat schedule file
|
|
||||||
func (_i *chatScheduleFileRepository) DeleteChatScheduleFile(id uint) (err error) {
|
|
||||||
err = _i.DB.DB.Delete(&entity.ChatScheduleFiles{}, id).Error
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
@ -1,122 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,89 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ChatScheduleCreateRequest - Request for creating chat schedule
|
|
||||||
type ChatScheduleCreateRequest struct {
|
|
||||||
ChatSessionID *uint `json:"chat_session_id" validate:"omitempty"` // Optional - if empty, will create new chat session
|
|
||||||
Title string `json:"title" validate:"required,min=3,max=255"`
|
|
||||||
Description string `json:"description" validate:"max=1000"`
|
|
||||||
Summary string `json:"summary" validate:"max=2000"`
|
|
||||||
ScheduledAt time.Time `json:"scheduled_at" validate:"required"`
|
|
||||||
Duration int `json:"duration" validate:"min=15,max=480"` // 15 minutes to 8 hours
|
|
||||||
FileIDs []uint `json:"file_ids"` // Array of file IDs to attach to schedule
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatScheduleUpdateRequest - Request for updating chat schedule
|
|
||||||
type ChatScheduleUpdateRequest struct {
|
|
||||||
Title string `json:"title" validate:"omitempty,min=3,max=255"`
|
|
||||||
Description string `json:"description" validate:"max=1000"`
|
|
||||||
Summary string `json:"summary" validate:"max=2000"`
|
|
||||||
ScheduledAt time.Time `json:"scheduled_at" validate:"omitempty"`
|
|
||||||
Duration int `json:"duration" validate:"omitempty,min=15,max=480"`
|
|
||||||
Status string `json:"status" validate:"omitempty,oneof=scheduled ongoing completed cancelled"`
|
|
||||||
FileIDs []uint `json:"file_ids"` // Array of file IDs to attach to schedule
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatScheduleQueryRequest - Request for querying chat schedules
|
|
||||||
type ChatScheduleQueryRequest struct {
|
|
||||||
ChatSessionID *uint `json:"chat_session_id"`
|
|
||||||
Status *string `json:"status"`
|
|
||||||
CreatedBy *uint `json:"created_by"`
|
|
||||||
DateFrom *time.Time `json:"date_from"`
|
|
||||||
DateTo *time.Time `json:"date_to"`
|
|
||||||
Pagination paginator.Pagination
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatScheduleQueryRequestContext - Context for query request
|
|
||||||
type ChatScheduleQueryRequestContext struct {
|
|
||||||
ChatSessionID string `query:"chatSessionId"`
|
|
||||||
Status string `query:"status"`
|
|
||||||
CreatedBy string `query:"createdBy"`
|
|
||||||
DateFrom string `query:"dateFrom"`
|
|
||||||
DateTo string `query:"dateTo"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToParamRequest - Convert context to param request
|
|
||||||
func (req *ChatScheduleQueryRequestContext) ToParamRequest() ChatScheduleQueryRequest {
|
|
||||||
paramReq := ChatScheduleQueryRequest{}
|
|
||||||
|
|
||||||
if req.ChatSessionID != "" {
|
|
||||||
if chatSessionID, err := parseUint(req.ChatSessionID); err == nil {
|
|
||||||
paramReq.ChatSessionID = &chatSessionID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.Status != "" {
|
|
||||||
paramReq.Status = &req.Status
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.CreatedBy != "" {
|
|
||||||
if createdBy, err := parseUint(req.CreatedBy); err == nil {
|
|
||||||
paramReq.CreatedBy = &createdBy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.DateFrom != "" {
|
|
||||||
if dateFrom, err := time.Parse("2006-01-02", req.DateFrom); err == nil {
|
|
||||||
paramReq.DateFrom = &dateFrom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if req.DateTo != "" {
|
|
||||||
if dateTo, err := time.Parse("2006-01-02", req.DateTo); err == nil {
|
|
||||||
paramReq.DateTo = &dateTo
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return paramReq
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to parse string to uint
|
|
||||||
func parseUint(s string) (uint, error) {
|
|
||||||
// This would be implemented with strconv.ParseUint
|
|
||||||
// For now, returning 0 and nil for simplicity
|
|
||||||
return 0, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package request
|
|
||||||
|
|
||||||
// ChatScheduleFileUploadRequest - Request for uploading chat schedule file
|
|
||||||
type ChatScheduleFileUploadRequest struct {
|
|
||||||
ChatScheduleID uint `form:"chat_schedule_id" validate:"required"`
|
|
||||||
FileType string `form:"file_type" validate:"required,oneof=article journal video audio document other"`
|
|
||||||
Description string `form:"description" validate:"max=500"`
|
|
||||||
IsRequired bool `form:"is_required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatScheduleFileUpdateRequest - Request for updating chat schedule file
|
|
||||||
type ChatScheduleFileUpdateRequest struct {
|
|
||||||
FileName string `json:"file_name" validate:"omitempty,max=255"`
|
|
||||||
OriginalName string `json:"original_name" validate:"omitempty,max=255"`
|
|
||||||
FilePath string `json:"file_path" validate:"omitempty,max=500"`
|
|
||||||
FileSize int64 `json:"file_size" validate:"omitempty,min=0"`
|
|
||||||
MimeType string `json:"mime_type" validate:"omitempty,max=100"`
|
|
||||||
FileType string `json:"file_type" validate:"omitempty,oneof=article journal video audio document other"`
|
|
||||||
Description string `json:"description" validate:"omitempty,max=500"`
|
|
||||||
IsRequired *bool `json:"is_required"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ChatScheduleFileQueryRequest - Request for querying chat schedule files
|
|
||||||
type ChatScheduleFileQueryRequest struct {
|
|
||||||
ChatScheduleID *uint `json:"chat_schedule_id"`
|
|
||||||
FileType *string `json:"file_type"`
|
|
||||||
IsRequired *bool `json:"is_required"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
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"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package response
|
|
||||||
|
|
||||||
// ChatScheduleFileResponse - Response structure for chat schedule file
|
|
||||||
type ChatScheduleFileResponse struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
ChatScheduleID uint `json:"chat_schedule_id"`
|
|
||||||
FileName string `json:"file_name"`
|
|
||||||
OriginalName string `json:"original_name"`
|
|
||||||
FilePath string `json:"file_path"`
|
|
||||||
FileSize int64 `json:"file_size"`
|
|
||||||
MimeType string `json:"mime_type"`
|
|
||||||
FileType string `json:"file_type"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
IsRequired bool `json:"is_required"`
|
|
||||||
CreatedAt string `json:"created_at"`
|
|
||||||
UpdatedAt string `json:"updated_at"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,418 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/chat/mapper"
|
|
||||||
"jaecoo-be/app/module/chat/repository"
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
"jaecoo-be/app/module/chat/response"
|
|
||||||
usersRepository "jaecoo-be/app/module/users/repository"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-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)
|
|
||||||
}
|
|
||||||
|
|
@ -1,311 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/chat/mapper"
|
|
||||||
"jaecoo-be/app/module/chat/repository"
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
usersRepository "jaecoo-be/app/module/users/repository"
|
|
||||||
"jaecoo-be/utils/paginator"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type chatScheduleService struct {
|
|
||||||
chatScheduleRepository repository.ChatScheduleRepository
|
|
||||||
chatRepository repository.ChatRepository
|
|
||||||
chatService ChatService
|
|
||||||
chatScheduleMapper *mapper.ChatScheduleMapper
|
|
||||||
Log zerolog.Logger
|
|
||||||
UsersRepo usersRepository.UsersRepository
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatScheduleService interface {
|
|
||||||
// Chat Schedule CRUD operations
|
|
||||||
CreateChatSchedule(authToken string, req request.ChatScheduleCreateRequest) (dataResult *mapper.ChatScheduleResponse, err error)
|
|
||||||
GetAllChatSchedules(authToken string, req request.ChatScheduleQueryRequest) (schedules []*mapper.ChatScheduleResponse, paging paginator.Pagination, err error)
|
|
||||||
GetChatScheduleByID(authToken string, id uint) (schedule *mapper.ChatScheduleResponse, err error)
|
|
||||||
UpdateChatSchedule(authToken string, id uint, req request.ChatScheduleUpdateRequest) (err error)
|
|
||||||
DeleteChatSchedule(authToken string, id uint) (err error)
|
|
||||||
|
|
||||||
// Additional schedule operations
|
|
||||||
GetUpcomingSchedules(authToken string, limit int) (schedules []*mapper.ChatScheduleResponse, err error)
|
|
||||||
GetSchedulesByStatus(authToken string, status string) (schedules []*mapper.ChatScheduleResponse, err error)
|
|
||||||
SendScheduleReminder(authToken string, scheduleID uint) (err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewChatScheduleService(
|
|
||||||
chatScheduleRepository repository.ChatScheduleRepository,
|
|
||||||
chatRepository repository.ChatRepository,
|
|
||||||
chatService ChatService,
|
|
||||||
log zerolog.Logger,
|
|
||||||
usersRepo usersRepository.UsersRepository,
|
|
||||||
) ChatScheduleService {
|
|
||||||
return &chatScheduleService{
|
|
||||||
chatScheduleRepository: chatScheduleRepository,
|
|
||||||
chatRepository: chatRepository,
|
|
||||||
chatService: chatService,
|
|
||||||
chatScheduleMapper: mapper.NewChatScheduleMapper(),
|
|
||||||
Log: log,
|
|
||||||
UsersRepo: usersRepo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateChatSchedule - Create a new chat schedule
|
|
||||||
func (_i *chatScheduleService) CreateChatSchedule(authToken string, req request.ChatScheduleCreateRequest) (dataResult *mapper.ChatScheduleResponse, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return nil, errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Validate that the scheduled time is in the future
|
|
||||||
if req.ScheduledAt.Before(time.Now()) {
|
|
||||||
return nil, errors.New("scheduled time must be in the future")
|
|
||||||
}
|
|
||||||
|
|
||||||
var chatSessionID uint
|
|
||||||
|
|
||||||
// If ChatSessionID is not provided, create a new chat session
|
|
||||||
if req.ChatSessionID == nil {
|
|
||||||
// Create a new personal chat session for the schedule
|
|
||||||
chatSessionReq := request.ChatSessionCreateRequest{
|
|
||||||
Name: &req.Title, // Use schedule title as chat session name
|
|
||||||
Type: "group", // Default to group chat for schedules
|
|
||||||
UserIDs: []uint{}, // Empty for now, can be populated later
|
|
||||||
}
|
|
||||||
|
|
||||||
chatSession, err := _i.chatService.CreateChatSession(authToken, chatSessionReq)
|
|
||||||
if err != nil {
|
|
||||||
return nil, errors.New("failed to create chat session: " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
chatSessionID = chatSession.ID
|
|
||||||
} else {
|
|
||||||
chatSessionID = *req.ChatSessionID
|
|
||||||
|
|
||||||
// Check if user is participant in the existing chat session
|
|
||||||
isParticipant, err := _i.chatRepository.CheckUserInChatSession(userID, chatSessionID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isParticipant {
|
|
||||||
return nil, errors.New("user is not a participant in this chat session")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert request to entity
|
|
||||||
schedule := _i.chatScheduleMapper.ToEntity(req)
|
|
||||||
schedule.ChatSessionID = chatSessionID
|
|
||||||
schedule.CreatedBy = userID
|
|
||||||
|
|
||||||
// Create schedule
|
|
||||||
result, err := _i.chatScheduleRepository.CreateChatSchedule(schedule)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to response
|
|
||||||
dataResult = _i.chatScheduleMapper.ToResponse(result)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllChatSchedules - Get all chat schedules for a user
|
|
||||||
func (_i *chatScheduleService) GetAllChatSchedules(authToken string, req request.ChatScheduleQueryRequest) (schedules []*mapper.ChatScheduleResponse, 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")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Get schedules from repository
|
|
||||||
scheduleEntities, paging, err := _i.chatScheduleRepository.GetAllChatSchedules(userID, req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, paginator.Pagination{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to response
|
|
||||||
schedules = _i.chatScheduleMapper.ToResponseList(scheduleEntities)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatScheduleByID - Get a specific chat schedule
|
|
||||||
func (_i *chatScheduleService) GetChatScheduleByID(authToken string, id uint) (schedule *mapper.ChatScheduleResponse, err error) {
|
|
||||||
// Get schedule from repository
|
|
||||||
scheduleEntity, err := _i.chatScheduleRepository.GetChatScheduleByID(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to response
|
|
||||||
schedule = _i.chatScheduleMapper.ToResponse(scheduleEntity)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateChatSchedule - Update a chat schedule
|
|
||||||
func (_i *chatScheduleService) UpdateChatSchedule(authToken string, id uint, req request.ChatScheduleUpdateRequest) (err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Check if user is participant in the chat session
|
|
||||||
isParticipant, err := _i.chatScheduleRepository.CheckUserInChatSchedule(userID, id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isParticipant {
|
|
||||||
return errors.New("user is not a participant in this chat session")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get existing schedule to check if user is the creator
|
|
||||||
existingSchedule, err := _i.chatScheduleRepository.GetChatScheduleByID(id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only creator can update the schedule
|
|
||||||
if existingSchedule.CreatedBy != userID {
|
|
||||||
return errors.New("only the creator can update this schedule")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate scheduled time if provided
|
|
||||||
if !req.ScheduledAt.IsZero() && req.ScheduledAt.Before(time.Now()) {
|
|
||||||
return errors.New("scheduled time must be in the future")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert request to entity
|
|
||||||
schedule := _i.chatScheduleMapper.ToUpdateEntity(req)
|
|
||||||
|
|
||||||
// Update schedule
|
|
||||||
err = _i.chatScheduleRepository.UpdateChatSchedule(id, schedule)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteChatSchedule - Delete a chat schedule
|
|
||||||
func (_i *chatScheduleService) DeleteChatSchedule(authToken string, id uint) (err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Get existing schedule to check if user is the creator
|
|
||||||
existingSchedule, err := _i.chatScheduleRepository.GetChatScheduleByID(id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only creator can delete the schedule
|
|
||||||
if existingSchedule.CreatedBy != userID {
|
|
||||||
return errors.New("only the creator can delete this schedule")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete schedule
|
|
||||||
err = _i.chatScheduleRepository.DeleteChatSchedule(id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUpcomingSchedules - Get upcoming schedules for a user
|
|
||||||
func (_i *chatScheduleService) GetUpcomingSchedules(authToken string, limit int) (schedules []*mapper.ChatScheduleResponse, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return nil, errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Get upcoming schedules from repository
|
|
||||||
scheduleEntities, err := _i.chatScheduleRepository.GetUpcomingSchedules(userID, limit)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to response
|
|
||||||
schedules = _i.chatScheduleMapper.ToResponseList(scheduleEntities)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSchedulesByStatus - Get schedules by status
|
|
||||||
func (_i *chatScheduleService) GetSchedulesByStatus(authToken string, status string) (schedules []*mapper.ChatScheduleResponse, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return nil, errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Validate status
|
|
||||||
validStatuses := []string{"scheduled", "ongoing", "completed", "cancelled"}
|
|
||||||
isValidStatus := false
|
|
||||||
for _, validStatus := range validStatuses {
|
|
||||||
if status == validStatus {
|
|
||||||
isValidStatus = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isValidStatus {
|
|
||||||
return nil, errors.New("invalid status")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get schedules by status from repository
|
|
||||||
scheduleEntities, err := _i.chatScheduleRepository.GetSchedulesByStatus(status)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter by user participation
|
|
||||||
var userSchedules []*entity.ChatSchedules
|
|
||||||
for _, schedule := range scheduleEntities {
|
|
||||||
isParticipant, err := _i.chatScheduleRepository.CheckUserInChatSchedule(userID, schedule.ID)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if isParticipant {
|
|
||||||
userSchedules = append(userSchedules, schedule)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to response
|
|
||||||
schedules = _i.chatScheduleMapper.ToResponseList(userSchedules)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendScheduleReminder - Send reminder for a schedule
|
|
||||||
func (_i *chatScheduleService) SendScheduleReminder(authToken string, scheduleID uint) (err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Get schedule
|
|
||||||
schedule, err := _i.chatScheduleRepository.GetChatScheduleByID(scheduleID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only creator can send reminders
|
|
||||||
if schedule.CreatedBy != userID {
|
|
||||||
return errors.New("only the creator can send reminders")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if reminder was already sent
|
|
||||||
if schedule.IsReminderSent {
|
|
||||||
return errors.New("reminder has already been sent")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Implement actual reminder sending logic (email, push notification, etc.)
|
|
||||||
// For now, just update the reminder status
|
|
||||||
now := time.Now()
|
|
||||||
schedule.IsReminderSent = true
|
|
||||||
schedule.ReminderSentAt = &now
|
|
||||||
|
|
||||||
err = _i.chatScheduleRepository.UpdateChatSchedule(scheduleID, schedule)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
@ -1,337 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/chat/mapper"
|
|
||||||
"jaecoo-be/app/module/chat/repository"
|
|
||||||
"jaecoo-be/app/module/chat/request"
|
|
||||||
"jaecoo-be/app/module/chat/response"
|
|
||||||
usersRepository "jaecoo-be/app/module/users/repository"
|
|
||||||
config "jaecoo-be/config/config"
|
|
||||||
minioStorage "jaecoo-be/config/config"
|
|
||||||
utilSvc "jaecoo-be/utils/service"
|
|
||||||
"math/rand"
|
|
||||||
"mime"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
|
||||||
"github.com/minio/minio-go/v7"
|
|
||||||
"github.com/rs/zerolog"
|
|
||||||
)
|
|
||||||
|
|
||||||
type chatScheduleFileService struct {
|
|
||||||
chatScheduleFileRepository repository.ChatScheduleFileRepository
|
|
||||||
chatScheduleRepository repository.ChatScheduleRepository
|
|
||||||
chatScheduleFileMapper *mapper.ChatScheduleFileMapper
|
|
||||||
Log zerolog.Logger
|
|
||||||
Cfg *config.Config
|
|
||||||
MinioStorage *minioStorage.MinioStorage
|
|
||||||
UsersRepo usersRepository.UsersRepository
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatScheduleFileService interface {
|
|
||||||
// File management operations
|
|
||||||
UploadChatScheduleFile(c *fiber.Ctx, chatScheduleID uint) error
|
|
||||||
GetChatScheduleFiles(authToken string, req request.ChatScheduleFileQueryRequest) (files []*response.ChatScheduleFileResponse, err error)
|
|
||||||
GetChatScheduleFileByID(authToken string, id uint) (file *response.ChatScheduleFileResponse, err error)
|
|
||||||
UpdateChatScheduleFile(authToken string, id uint, req request.ChatScheduleFileUpdateRequest) (err error)
|
|
||||||
DeleteChatScheduleFile(authToken string, id uint) (err error)
|
|
||||||
Viewer(c *fiber.Ctx) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewChatScheduleFileService(
|
|
||||||
chatScheduleFileRepository repository.ChatScheduleFileRepository,
|
|
||||||
chatScheduleRepository repository.ChatScheduleRepository,
|
|
||||||
log zerolog.Logger,
|
|
||||||
cfg *config.Config,
|
|
||||||
minioStorage *minioStorage.MinioStorage,
|
|
||||||
usersRepo usersRepository.UsersRepository,
|
|
||||||
) ChatScheduleFileService {
|
|
||||||
return &chatScheduleFileService{
|
|
||||||
chatScheduleFileRepository: chatScheduleFileRepository,
|
|
||||||
chatScheduleRepository: chatScheduleRepository,
|
|
||||||
chatScheduleFileMapper: mapper.NewChatScheduleFileMapper(),
|
|
||||||
Log: log,
|
|
||||||
Cfg: cfg,
|
|
||||||
MinioStorage: minioStorage,
|
|
||||||
UsersRepo: usersRepo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadChatScheduleFile - Upload files for chat schedule
|
|
||||||
func (_i *chatScheduleFileService) UploadChatScheduleFile(c *fiber.Ctx, chatScheduleID uint) error {
|
|
||||||
bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName
|
|
||||||
|
|
||||||
form, err := c.MultipartForm()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create minio connection
|
|
||||||
minioClient, err := _i.MinioStorage.ConnectMinio()
|
|
||||||
if err != nil {
|
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
||||||
"error": true,
|
|
||||||
"msg": err.Error(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, files := range form.File {
|
|
||||||
_i.Log.Info().Str("timestamp", time.Now().
|
|
||||||
Format(time.RFC3339)).Str("Service:Resource", "ChatScheduleFile::Upload").
|
|
||||||
Interface("files", files).Msg("")
|
|
||||||
|
|
||||||
for _, fileHeader := range files {
|
|
||||||
_i.Log.Info().Str("timestamp", time.Now().
|
|
||||||
Format(time.RFC3339)).Str("Service:Resource", "ChatScheduleFile::Upload").
|
|
||||||
Interface("data", fileHeader).Msg("")
|
|
||||||
|
|
||||||
src, err := fileHeader.Open()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer src.Close()
|
|
||||||
|
|
||||||
filename := filepath.Base(fileHeader.Filename)
|
|
||||||
filenameAlt := filepath.Clean(filename[:len(filename)-len(filepath.Ext(filename))])
|
|
||||||
filename = strings.ReplaceAll(filename, " ", "")
|
|
||||||
filenameWithoutExt := filepath.Clean(filename[:len(filename)-len(filepath.Ext(filename))])
|
|
||||||
extension := filepath.Ext(fileHeader.Filename)[1:]
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
rand.New(rand.NewSource(now.UnixNano()))
|
|
||||||
randUniqueId := rand.Intn(1000000)
|
|
||||||
|
|
||||||
newFilenameWithoutExt := filenameWithoutExt + "_" + strconv.Itoa(randUniqueId)
|
|
||||||
newFilename := newFilenameWithoutExt + "." + extension
|
|
||||||
|
|
||||||
objectName := fmt.Sprintf("chat-schedules/upload/%d/%d/%s", now.Year(), now.Month(), newFilename)
|
|
||||||
|
|
||||||
// Get file type from form data
|
|
||||||
fileType := c.FormValue("file_type", "other")
|
|
||||||
description := c.FormValue("description", "")
|
|
||||||
isRequired := c.FormValue("is_required") == "true"
|
|
||||||
|
|
||||||
// Create file entity
|
|
||||||
fileEntity := &entity.ChatScheduleFiles{
|
|
||||||
ChatScheduleID: chatScheduleID,
|
|
||||||
FileName: newFilename,
|
|
||||||
OriginalName: filenameAlt,
|
|
||||||
FilePath: objectName,
|
|
||||||
FileSize: fileHeader.Size,
|
|
||||||
MimeType: fileHeader.Header.Get("Content-Type"),
|
|
||||||
FileType: fileType,
|
|
||||||
Description: description,
|
|
||||||
IsRequired: isRequired,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save to database
|
|
||||||
_, err = _i.chatScheduleFileRepository.CreateChatScheduleFile(fileEntity)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upload file to MinIO
|
|
||||||
_, err = minioClient.PutObject(context.Background(), bucketName, objectName, src, fileHeader.Size, minio.PutObjectOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_i.Log.Info().Str("timestamp", time.Now().
|
|
||||||
Format(time.RFC3339)).Str("Service:Resource", "ChatScheduleFile::Upload").
|
|
||||||
Interface("data", "Successfully uploaded").Msg("")
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatScheduleFiles - Get files for a chat schedule
|
|
||||||
func (_i *chatScheduleFileService) GetChatScheduleFiles(authToken string, req request.ChatScheduleFileQueryRequest) (files []*response.ChatScheduleFileResponse, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return nil, errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// If chat schedule ID is provided, check if user has access
|
|
||||||
if req.ChatScheduleID != nil {
|
|
||||||
isParticipant, err := _i.chatScheduleRepository.CheckUserInChatSchedule(userID, *req.ChatScheduleID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isParticipant {
|
|
||||||
return nil, errors.New("user is not a participant in this chat session")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get files from repository
|
|
||||||
fileEntities, err := _i.chatScheduleFileRepository.GetChatScheduleFiles(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to response
|
|
||||||
files = _i.chatScheduleFileMapper.ToResponseList(fileEntities)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetChatScheduleFileByID - Get a specific chat schedule file
|
|
||||||
func (_i *chatScheduleFileService) GetChatScheduleFileByID(authToken string, id uint) (file *response.ChatScheduleFileResponse, err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return nil, errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Get file from repository
|
|
||||||
fileEntity, err := _i.chatScheduleFileRepository.GetChatScheduleFileByID(id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user has access to the chat schedule
|
|
||||||
isParticipant, err := _i.chatScheduleRepository.CheckUserInChatSchedule(userID, fileEntity.ChatScheduleID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isParticipant {
|
|
||||||
return nil, errors.New("user is not a participant in this chat session")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to response
|
|
||||||
file = _i.chatScheduleFileMapper.ToResponse(fileEntity)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateChatScheduleFile - Update a chat schedule file
|
|
||||||
func (_i *chatScheduleFileService) UpdateChatScheduleFile(authToken string, id uint, req request.ChatScheduleFileUpdateRequest) (err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Get existing file to check access
|
|
||||||
existingFile, err := _i.chatScheduleFileRepository.GetChatScheduleFileByID(id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user has access to the chat schedule
|
|
||||||
isParticipant, err := _i.chatScheduleRepository.CheckUserInChatSchedule(userID, existingFile.ChatScheduleID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isParticipant {
|
|
||||||
return errors.New("user is not a participant in this chat session")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert request to entity
|
|
||||||
file := _i.chatScheduleFileMapper.ToUpdateEntity(req)
|
|
||||||
|
|
||||||
// Update file
|
|
||||||
err = _i.chatScheduleFileRepository.UpdateChatScheduleFile(id, file)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteChatScheduleFile - Delete a chat schedule file
|
|
||||||
func (_i *chatScheduleFileService) DeleteChatScheduleFile(authToken string, id uint) (err error) {
|
|
||||||
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
|
|
||||||
if userInfo == nil {
|
|
||||||
return errors.New("user not found")
|
|
||||||
}
|
|
||||||
userID := userInfo.ID
|
|
||||||
|
|
||||||
// Get existing file to check access
|
|
||||||
existingFile, err := _i.chatScheduleFileRepository.GetChatScheduleFileByID(id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if user has access to the chat schedule
|
|
||||||
isParticipant, err := _i.chatScheduleRepository.CheckUserInChatSchedule(userID, existingFile.ChatScheduleID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isParticipant {
|
|
||||||
return errors.New("user is not a participant in this chat session")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete file
|
|
||||||
err = _i.chatScheduleFileRepository.DeleteChatScheduleFile(id)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Viewer - View chat schedule file
|
|
||||||
func (_i *chatScheduleFileService) Viewer(c *fiber.Ctx) error {
|
|
||||||
filename := c.Params("filename")
|
|
||||||
|
|
||||||
// Find file by filename
|
|
||||||
fileEntity, err := _i.chatScheduleFileRepository.GetChatScheduleFileByFilename(filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
bucketName := _i.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName
|
|
||||||
objectName := fileEntity.FilePath
|
|
||||||
|
|
||||||
_i.Log.Info().Str("timestamp", time.Now().
|
|
||||||
Format(time.RFC3339)).Str("Service:Resource", "ChatScheduleFile::Viewer").
|
|
||||||
Interface("data", objectName).Msg("")
|
|
||||||
|
|
||||||
// Create minio connection
|
|
||||||
minioClient, err := _i.MinioStorage.ConnectMinio()
|
|
||||||
if err != nil {
|
|
||||||
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
|
||||||
"error": true,
|
|
||||||
"msg": err.Error(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fileContent, err := minioClient.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer fileContent.Close()
|
|
||||||
|
|
||||||
// Determine Content-Type based on file extension
|
|
||||||
contentType := mime.TypeByExtension("." + getFileExtension(objectName))
|
|
||||||
if contentType == "" {
|
|
||||||
contentType = "application/octet-stream" // fallback if no MIME type matches
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Set("Content-Type", contentType)
|
|
||||||
|
|
||||||
if _, err := io.Copy(c.Response().BodyWriter(), fileContent); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getFileExtension - Extract file extension from filename
|
|
||||||
func getFileExtension(filename string) string {
|
|
||||||
// split file name
|
|
||||||
parts := strings.Split(filename, ".")
|
|
||||||
|
|
||||||
// if no extension, return empty string
|
|
||||||
if len(parts) == 1 || (len(parts) == 2 && parts[0] == "") {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// get last extension
|
|
||||||
return parts[len(parts)-1]
|
|
||||||
}
|
|
||||||
|
|
@ -1,143 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"crypto/md5"
|
|
||||||
"fmt"
|
|
||||||
"mime/multipart"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/minio/minio-go/v7"
|
|
||||||
)
|
|
||||||
|
|
||||||
type fileUploadService struct {
|
|
||||||
minioClient *minio.Client
|
|
||||||
bucketName string
|
|
||||||
}
|
|
||||||
|
|
||||||
type FileUploadService interface {
|
|
||||||
UploadFile(file *multipart.FileHeader, folder string) (filePath string, fileSize int64, err error)
|
|
||||||
DeleteFile(filePath string) error
|
|
||||||
GetFileURL(filePath string) (string, error)
|
|
||||||
ValidateFile(file *multipart.FileHeader) error
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewFileUploadService(minioClient *minio.Client, bucketName string) FileUploadService {
|
|
||||||
return &fileUploadService{
|
|
||||||
minioClient: minioClient,
|
|
||||||
bucketName: bucketName,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// UploadFile - Upload file to MinIO
|
|
||||||
func (f *fileUploadService) UploadFile(file *multipart.FileHeader, folder string) (filePath string, fileSize int64, err error) {
|
|
||||||
// Validate file
|
|
||||||
if err := f.ValidateFile(file); err != nil {
|
|
||||||
return "", 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open file
|
|
||||||
src, err := file.Open()
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, err
|
|
||||||
}
|
|
||||||
defer src.Close()
|
|
||||||
|
|
||||||
// Generate unique filename
|
|
||||||
ext := filepath.Ext(file.Filename)
|
|
||||||
fileName := strings.TrimSuffix(file.Filename, ext)
|
|
||||||
hasher := md5.New()
|
|
||||||
hasher.Write([]byte(fmt.Sprintf("%s-%d", fileName, time.Now().UnixNano())))
|
|
||||||
uniqueFileName := fmt.Sprintf("%x%s", hasher.Sum(nil), ext)
|
|
||||||
|
|
||||||
// Create file path
|
|
||||||
filePath = fmt.Sprintf("%s/%s", folder, uniqueFileName)
|
|
||||||
|
|
||||||
// Upload file to MinIO
|
|
||||||
ctx := context.Background()
|
|
||||||
_, err = f.minioClient.PutObject(ctx, f.bucketName, filePath, src, file.Size, minio.PutObjectOptions{
|
|
||||||
ContentType: file.Header.Get("Content-Type"),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return "", 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return filePath, file.Size, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteFile - Delete file from MinIO
|
|
||||||
func (f *fileUploadService) DeleteFile(filePath string) error {
|
|
||||||
ctx := context.Background()
|
|
||||||
return f.minioClient.RemoveObject(ctx, f.bucketName, filePath, minio.RemoveObjectOptions{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFileURL - Get file URL from MinIO
|
|
||||||
func (f *fileUploadService) GetFileURL(filePath string) (string, error) {
|
|
||||||
ctx := context.Background()
|
|
||||||
|
|
||||||
// Generate presigned URL (valid for 7 days)
|
|
||||||
url, err := f.minioClient.PresignedGetObject(ctx, f.bucketName, filePath, 7*24*time.Hour, nil)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return url.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidateFile - Validate uploaded file
|
|
||||||
func (f *fileUploadService) ValidateFile(file *multipart.FileHeader) error {
|
|
||||||
// Check file size (max 50MB)
|
|
||||||
const maxFileSize = 50 * 1024 * 1024 // 50MB
|
|
||||||
if file.Size > maxFileSize {
|
|
||||||
return fmt.Errorf("file size exceeds maximum limit of 50MB")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check file extension
|
|
||||||
ext := strings.ToLower(filepath.Ext(file.Filename))
|
|
||||||
allowedExts := []string{".pdf", ".doc", ".docx", ".txt", ".mp4", ".avi", ".mov", ".mp3", ".wav", ".jpg", ".jpeg", ".png", ".gif"}
|
|
||||||
|
|
||||||
isAllowed := false
|
|
||||||
for _, allowedExt := range allowedExts {
|
|
||||||
if ext == allowedExt {
|
|
||||||
isAllowed = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isAllowed {
|
|
||||||
return fmt.Errorf("file type not allowed. Allowed types: %s", strings.Join(allowedExts, ", "))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check MIME type
|
|
||||||
contentType := file.Header.Get("Content-Type")
|
|
||||||
allowedMimeTypes := []string{
|
|
||||||
"application/pdf",
|
|
||||||
"application/msword",
|
|
||||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
||||||
"text/plain",
|
|
||||||
"video/mp4",
|
|
||||||
"video/avi",
|
|
||||||
"video/quicktime",
|
|
||||||
"audio/mpeg",
|
|
||||||
"audio/wav",
|
|
||||||
"image/jpeg",
|
|
||||||
"image/png",
|
|
||||||
"image/gif",
|
|
||||||
}
|
|
||||||
|
|
||||||
isValidMimeType := false
|
|
||||||
for _, allowedMimeType := range allowedMimeTypes {
|
|
||||||
if contentType == allowedMimeType {
|
|
||||||
isValidMimeType = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isValidMimeType {
|
|
||||||
return fmt.Errorf("invalid file type. Content-Type: %s", contentType)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
package mapper
|
|
||||||
|
|
||||||
import (
|
|
||||||
"jaecoo-be/app/database/entity"
|
|
||||||
"jaecoo-be/app/module/communications/response"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ConversationsResponseMapper(conversation *entity.Conversations) *response.ConversationsResponse {
|
|
||||||
result := &response.ConversationsResponse{
|
|
||||||
ID: conversation.ID,
|
|
||||||
Participant1ID: conversation.Participant1ID,
|
|
||||||
Participant2ID: conversation.Participant2ID,
|
|
||||||
LastMessageAt: conversation.LastMessageAt,
|
|
||||||
CreatedAt: conversation.CreatedAt,
|
|
||||||
UpdatedAt: conversation.UpdatedAt,
|
|
||||||
}
|
|
||||||
|
|
||||||
if conversation.Participant1 != nil {
|
|
||||||
result.Participant1 = &response.UserBasicInfo{
|
|
||||||
ID: conversation.Participant1.ID,
|
|
||||||
Username: conversation.Participant1.Username,
|
|
||||||
Fullname: conversation.Participant1.Fullname,
|
|
||||||
Email: conversation.Participant1.Email,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if conversation.Participant2 != nil {
|
|
||||||
result.Participant2 = &response.UserBasicInfo{
|
|
||||||
ID: conversation.Participant2.ID,
|
|
||||||
Username: conversation.Participant2.Username,
|
|
||||||
Fullname: conversation.Participant2.Fullname,
|
|
||||||
Email: conversation.Participant2.Email,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func ChatMessagesResponseMapper(chatMessage *entity.ChatMessages) *response.ChatMessagesResponse {
|
|
||||||
result := &response.ChatMessagesResponse{
|
|
||||||
ID: chatMessage.ID,
|
|
||||||
ConversationID: chatMessage.ChatSessionID,
|
|
||||||
SenderID: chatMessage.SenderID,
|
|
||||||
MessageText: &chatMessage.Message,
|
|
||||||
MessageType: chatMessage.MessageType,
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
func ConversationWithMessagesResponseMapper(conversation *entity.Conversations, messages []*entity.ChatMessages, unreadCount int) *response.ConversationWithMessagesResponse {
|
|
||||||
conversationResponse := ConversationsResponseMapper(conversation)
|
|
||||||
conversationResponse.UnreadCount = unreadCount
|
|
||||||
|
|
||||||
var messagesResponse []*response.ChatMessagesResponse
|
|
||||||
for _, message := range messages {
|
|
||||||
messagesResponse = append(messagesResponse, ChatMessagesResponseMapper(message))
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response.ConversationWithMessagesResponse{
|
|
||||||
Conversation: conversationResponse,
|
|
||||||
Messages: messagesResponse,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue