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{}{
|
||||
entity.ActivityLogs{},
|
||||
entity.ActivityLogTypes{},
|
||||
entity.Advertisement{},
|
||||
entity.Articles{},
|
||||
entity.ArticleCategories{},
|
||||
entity.ArticleApprovals{},
|
||||
|
|
@ -101,49 +100,14 @@ func Models() []interface{} {
|
|||
entity.Districts{},
|
||||
entity.Feedbacks{},
|
||||
entity.ForgotPasswords{},
|
||||
entity.Magazines{},
|
||||
entity.MagazineFiles{},
|
||||
entity.MasterMenus{},
|
||||
entity.MasterModules{},
|
||||
entity.MasterStatuses{},
|
||||
entity.MasterApprovalStatuses{},
|
||||
entity.Provinces{},
|
||||
entity.OneTimePasswords{},
|
||||
entity.Subscription{},
|
||||
user_levels.UserLevels{},
|
||||
entity.UserRoles{},
|
||||
entity.UserRoleAccesses{},
|
||||
users.Users{},
|
||||
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