package v1 import ( "context" "time" "github.com/gochat/gochat/internal/model" "gorm.io/gorm" ) type chatwootContactMeta struct { Count int64 `json:"count"` CurrentPage int `json:"current_page"` HasMore *bool `json:"has_more,omitempty"` } type chatwootCompanyMeta struct { TotalCount int64 `json:"total_count"` Page int `json:"page"` } func contactListResponse(ctx context.Context, db *gorm.DB, contacts []model.Contact, total int64, page int, includeInboxes bool, hasMore *bool) map[string]any { payload := make([]any, 0, len(contacts)) for i := range contacts { payload = append(payload, serializeCRMContact(ctx, db, &contacts[i], includeInboxes)) } return map[string]any{ "meta": chatwootContactMeta{Count: total, CurrentPage: page, HasMore: hasMore}, "payload": payload, } } func contactPayloadResponse(ctx context.Context, db *gorm.DB, contact *model.Contact, includeInboxes bool) map[string]any { payload := serializeCRMContact(ctx, db, contact, includeInboxes) return map[string]any{"payload": payload} } func contactCreateResponse(ctx context.Context, db *gorm.DB, contact *model.Contact, contactInbox *model.ContactInbox) map[string]any { payload := map[string]any{ "contact": serializeCRMContact(ctx, db, contact, true), "contact_inbox": serializeContactInboxShell(contactInbox), } return map[string]any{"payload": payload} } func serializeCRMContact(ctx context.Context, db *gorm.DB, contact *model.Contact, includeInboxes bool) map[string]any { payload := map[string]any{ "additional_attributes": jsonObject(contact.AdditionalAttributes), "availability_status": "offline", "email": contact.Email, "id": contact.ID, "name": contact.Name, "phone_number": contact.PhoneNumber, "blocked": contact.Blocked, "identifier": contact.Identifier, "thumbnail": contact.AvatarURL, "custom_attributes": jsonObject(contact.CustomAttributes), } if contact.LastActivityAt != nil { payload["last_activity_at"] = *contact.LastActivityAt } if !contact.CreatedAt.IsZero() { payload["created_at"] = contact.CreatedAt.Unix() } if includeInboxes { payload["contact_inboxes"] = []any{} if db != nil { var contactInboxes []model.ContactInbox if err := db.WithContext(ctx).Preload("Inbox").Where("contact_id = ?", contact.ID).Order("id ASC").Find(&contactInboxes).Error; err == nil { items := make([]any, 0, len(contactInboxes)) for i := range contactInboxes { items = append(items, serializeContactInbox(&contactInboxes[i])) } payload["contact_inboxes"] = items } } } return payload } func serializeCompanyContact(ctx context.Context, db *gorm.DB, contact *model.Contact, currentCompanyID uint) map[string]any { payload := serializeCRMContact(ctx, db, contact, false) payload["company_id"] = contact.CompanyID payload["linked_to_current_company"] = contact.CompanyID != nil && *contact.CompanyID == currentCompanyID payload["company"] = nil if db != nil && contact.CompanyID != nil { var company model.Company if err := db.WithContext(ctx).First(&company, *contact.CompanyID).Error; err == nil { payload["company"] = serializeCompany(ctx, db, &company) } } return payload } func serializeContactInbox(contactInbox *model.ContactInbox) map[string]any { return map[string]any{ "source_id": contactInbox.SourceID, "inbox": serializeInboxSlim(&contactInbox.Inbox), } } func serializeContactInboxShell(contactInbox *model.ContactInbox) map[string]any { if contactInbox == nil { return map[string]any{"inbox": nil, "source_id": nil} } return map[string]any{"inbox": contactInbox.Inbox, "source_id": contactInbox.SourceID} } func serializeInboxSlim(inbox *model.Inbox) map[string]any { if inbox == nil || inbox.ID == 0 { return map[string]any{} } return map[string]any{ "id": inbox.ID, "name": inbox.Name, "channel_type": inbox.ChannelType, "account_id": inbox.AccountID, } } func companyListResponse(ctx context.Context, db *gorm.DB, companies []model.Company, total int64, page int) map[string]any { payload := make([]any, 0, len(companies)) for i := range companies { payload = append(payload, serializeCompany(ctx, db, &companies[i])) } return map[string]any{ "meta": chatwootCompanyMeta{TotalCount: total, Page: page}, "payload": payload, } } func companyPayloadResponse(ctx context.Context, db *gorm.DB, company *model.Company) map[string]any { payload := serializeCompany(ctx, db, company) return map[string]any{"payload": payload} } func serializeCompany(ctx context.Context, db *gorm.DB, company *model.Company) map[string]any { return map[string]any{ "id": company.ID, "name": company.Name, "contacts_count": companyContactsCount(ctx, db, company), "domain": company.Domain, "description": company.Description, "custom_attributes": jsonObject(company.CustomAttributes), "avatar_url": company.FaviconURL, "last_activity_at": unixTimePtr(company.LastActivityAt), "created_at": company.CreatedAt.Unix(), "updated_at": company.UpdatedAt.Unix(), } } func companyContactsResponse(ctx context.Context, db *gorm.DB, companyID uint, contacts []model.Contact, total int64, page int) map[string]any { payload := make([]any, 0, len(contacts)) for i := range contacts { payload = append(payload, serializeCompanyContact(ctx, db, &contacts[i], companyID)) } return map[string]any{ "meta": chatwootCompanyMeta{TotalCount: total, Page: page}, "payload": payload, } } func companyNotesResponse(ctx context.Context, db *gorm.DB, notes []model.CompanyNote, accountID uint) map[string]any { payload := make([]any, 0, len(notes)) for i := range notes { payload = append(payload, serializeCompanyNote(ctx, db, ¬es[i], accountID)) } return map[string]any{"payload": payload} } func contactNotesResponse(notes []model.Note) []any { payload := make([]any, 0, len(notes)) for i := range notes { payload = append(payload, serializeContactNote(¬es[i])) } return payload } func serializeContactNote(note *model.Note) map[string]any { item := map[string]any{ "id": note.ID, "content": note.Content, "account_id": note.AccountID, "contact_id": note.ContactID, "created_at": note.CreatedAt.Unix(), "updated_at": note.UpdatedAt.Unix(), } if note.UserID != nil { item["user_id"] = *note.UserID } if note.User != nil && note.User.ID != 0 { item["user"] = serializeUser(note.User, note.AccountID) } return item } func serializeCompanyNote(ctx context.Context, db *gorm.DB, note *model.CompanyNote, accountID uint) map[string]any { item := map[string]any{ "id": note.ID, "content": note.Content, "company_id": note.CompanyID, "user_id": note.UserID, "created_at": note.CreatedAt.Unix(), "updated_at": note.UpdatedAt.Unix(), } if note.User.ID != 0 { item["user"] = serializeUser(¬e.User, accountID) } else if db != nil && note.UserID != 0 { item["user"] = serializeUserFromDB(ctx, db, note.UserID, accountID) } return item } func companyContactsCount(ctx context.Context, db *gorm.DB, company *model.Company) int64 { if db == nil || company == nil || company.ID == 0 { return 0 } var count int64 _ = db.WithContext(ctx).Model(&model.Contact{}).Where("account_id = ? AND company_id = ?", company.AccountID, company.ID).Count(&count).Error return count } func unixTimePtr(value *time.Time) any { if value == nil { return nil } return value.Unix() }