feat: update minimal module

This commit is contained in:
hanif salafi 2025-11-15 23:39:46 +07:00
parent 169378b243
commit b3c5a0228f
204 changed files with 20 additions and 44684 deletions

View File

@ -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()"`
}

View File

@ -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"`
}

View File

@ -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()"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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()"`
}

View File

@ -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()"`
}

View File

@ -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()"`
}

View File

@ -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()"`
}

View File

@ -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"`
}

View File

@ -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()"`
}

View File

@ -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()"`
}

View File

@ -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()"`
}

View File

@ -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()"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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()"`
}

View File

@ -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"`
}

View File

@ -87,7 +87,6 @@ func Models() []interface{} {
return []interface{}{ return []interface{}{
entity.ActivityLogs{}, entity.ActivityLogs{},
entity.ActivityLogTypes{}, entity.ActivityLogTypes{},
entity.Advertisement{},
entity.Articles{}, entity.Articles{},
entity.ArticleCategories{}, entity.ArticleCategories{},
entity.ArticleApprovals{}, entity.ArticleApprovals{},
@ -101,49 +100,14 @@ func Models() []interface{} {
entity.Districts{}, entity.Districts{},
entity.Feedbacks{}, entity.Feedbacks{},
entity.ForgotPasswords{}, entity.ForgotPasswords{},
entity.Magazines{},
entity.MagazineFiles{},
entity.MasterMenus{},
entity.MasterModules{},
entity.MasterStatuses{},
entity.MasterApprovalStatuses{}, entity.MasterApprovalStatuses{},
entity.Provinces{}, entity.Provinces{},
entity.OneTimePasswords{}, entity.OneTimePasswords{},
entity.Subscription{},
user_levels.UserLevels{}, user_levels.UserLevels{},
entity.UserRoles{}, entity.UserRoles{},
entity.UserRoleAccesses{}, entity.UserRoleAccesses{},
users.Users{}, users.Users{},
entity.UserRoleLevelDetails{}, entity.UserRoleLevelDetails{},
// Narasi Ahli entities
entity.EducationHistory{},
entity.WorkHistory{},
entity.ResearchJournals{},
entity.Conversations{},
entity.ChatMessages{},
entity.ChatParticipants{},
entity.ChatSessions{},
entity.ChatSchedules{},
entity.ChatScheduleFiles{},
entity.AIChatSessions{},
entity.AIChatMessages{},
entity.AIChatLogs{},
// Ebook entities
entity.Ebooks{},
entity.EbookWishlists{},
entity.EbookPurchases{},
entity.EbookRatings{},
// Campaign entities
entity.CampaignTypes{},
entity.CampaignDestinations{},
entity.Campaigns{},
entity.CampaignFiles{},
entity.CampaignDestinationRelations{},
entity.CampaignApprovals{},
entity.CampaignChats{},
} }
} }

View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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)
}

View File

@ -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),
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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"`
}

View File

@ -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]
}

View File

@ -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)
})
}

View File

@ -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,
})
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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"`
}

View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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"},
})
}

View File

@ -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),
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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"`
}

View File

@ -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)
}

View File

@ -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)
})
}

View File

@ -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"},
})
}

View File

@ -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),
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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"`
}

View File

@ -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)
}

View File

@ -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)
})
}

View File

@ -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"},
})
}

View File

@ -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),
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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"`
}

View File

@ -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)
}

View File

@ -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)
})
}

View File

@ -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"},
})
}

View File

@ -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),
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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"`
}

View File

@ -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)
}

View File

@ -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)
})
})
}

View File

@ -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"},
})
}

View File

@ -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"},
})
}

View File

@ -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)
}

View File

@ -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),
}
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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,
}
}

View File

@ -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
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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"`
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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]
}

View File

@ -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
}

View File

@ -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