Files
tm_back/internal/inquiry/repository.go
T
n.nakhostin 5d721705b7 Update MongoDB Driver and Configuration for Company Entities
- Updated the MongoDB driver from v1.17.4 to v2.3.0, ensuring compatibility with the latest features and improvements.
- Refactored company-related entity and repository files to utilize the new driver, replacing `primitive.ObjectID` with `bson.ObjectID` for ID handling.
- Adjusted the configuration in `.drone.yml` to include the `main` branch in the trigger settings, enhancing CI/CD pipeline flexibility.
2025-09-09 18:53:39 +03:30

287 lines
8.0 KiB
Go

package inquiry
import (
"context"
"errors"
"time"
"tm/pkg/logger"
orm "tm/pkg/mongo"
"tm/pkg/response"
"go.mongodb.org/mongo-driver/v2/bson"
)
// Repository defines methods for inquiry data access
type Repository interface {
Create(ctx context.Context, inquiry *Inquiry) error
GetByID(ctx context.Context, id string) (*Inquiry, error)
UpdateStatus(ctx context.Context, id string, status, reason, changedBy, description string) error
Search(ctx context.Context, form *SearchInquiriesForm, pagination *response.Pagination) ([]Inquiry, int64, error)
Delete(ctx context.Context, id string) error
CheckPendingInquiry(ctx context.Context, email string) (*Inquiry, error)
CheckPendingInquiryByPhone(ctx context.Context, phone string) (*Inquiry, error)
}
// inquiryRepository implements the Repository interface using the MongoDB ORM
type inquiryRepository struct {
ormRepo orm.Repository[Inquiry]
logger logger.Logger
}
// NewInquiryRepository creates a new inquiry repository
func NewInquiryRepository(mongoManager *orm.ConnectionManager, logger logger.Logger) Repository {
// Create indexes using the ORM's index management
indexes := []orm.Index{
*orm.CreateTextIndex("search_idx", "full_name", "company_name", "work_email"),
*orm.NewIndex("company_name_idx", bson.D{bson.E{Key: "company_name", Value: 1}}),
*orm.NewIndex("work_email_idx", bson.D{bson.E{Key: "work_email", Value: 1}}),
*orm.NewIndex("phone_number_idx", bson.D{bson.E{Key: "phone_number", Value: 1}}),
*orm.NewIndex("status_idx", bson.D{bson.E{Key: "status", Value: 1}}),
*orm.NewIndex("created_at_idx", bson.D{bson.E{Key: "created_at", Value: -1}}),
// Compound index for duplicate prevention
*orm.NewIndex("email_status_idx", bson.D{
bson.E{Key: "work_email", Value: 1},
bson.E{Key: "status", Value: 1},
}),
*orm.NewIndex("phone_status_idx", bson.D{
bson.E{Key: "phone_number", Value: 1},
bson.E{Key: "status", Value: 1},
}),
}
// Create indexes
err := mongoManager.CreateIndexes("inquiries", indexes)
if err != nil {
logger.Warn("Failed to create inquiry indexes", map[string]interface{}{
"error": err.Error(),
})
}
// Create ORM repository
ormRepo := orm.NewRepository[Inquiry](mongoManager.GetCollection("inquiries"), logger)
return &inquiryRepository{
ormRepo: ormRepo,
logger: logger,
}
}
// Create creates a new inquiry
func (r *inquiryRepository) Create(ctx context.Context, inquiry *Inquiry) error {
// Set created timestamp using Unix timestamp
now := time.Now().Unix()
inquiry.SetCreatedAt(now)
inquiry.SetUpdatedAt(now)
// Set initial status to pending
inquiry.Status = StatusPending
// Add initial status change to history
inquiry.AddStatusChange(StatusPending, "Inquiry submitted", "system", "Initial inquiry submission")
// Use ORM to create inquiry
err := r.ormRepo.Create(ctx, inquiry)
if err != nil {
r.logger.Error("Failed to create inquiry", map[string]interface{}{
"error": err.Error(),
"work_email": inquiry.WorkEmail,
"company_name": inquiry.CompanyName,
})
return err
}
r.logger.Info("Inquiry created successfully", map[string]interface{}{
"inquiry_id": inquiry.ID,
"work_email": inquiry.WorkEmail,
"company_name": inquiry.CompanyName,
"status": inquiry.Status,
})
return nil
}
// GetByID retrieves an inquiry by ID
func (r *inquiryRepository) GetByID(ctx context.Context, id string) (*Inquiry, error) {
inquiry, err := r.ormRepo.FindByID(ctx, id)
if err != nil {
if errors.Is(err, orm.ErrDocumentNotFound) {
return nil, errors.New("inquiry not found")
}
r.logger.Error("Failed to get inquiry by ID", map[string]interface{}{
"error": err.Error(),
"inquiry_id": id,
})
return nil, err
}
return inquiry, nil
}
// UpdateStatus updates the status of an inquiry
func (r *inquiryRepository) UpdateStatus(ctx context.Context, id string, status, reason, changedBy, description string) error {
// Get inquiry first
inquiry, err := r.GetByID(ctx, id)
if err != nil {
return err
}
// Add status change to history
inquiry.AddStatusChange(status, reason, changedBy, description)
// Update in database - use the correct Update method signature
err = r.ormRepo.Update(ctx, inquiry)
if err != nil {
r.logger.Error("Failed to update inquiry status", map[string]interface{}{
"error": err.Error(),
"inquiry_id": id,
"new_status": status,
})
return err
}
r.logger.Info("Inquiry status updated successfully", map[string]interface{}{
"inquiry_id": id,
"old_status": inquiry.StatusHistory[len(inquiry.StatusHistory)-2].Status, // Previous status
"new_status": status,
"changed_by": changedBy,
})
return nil
}
// CheckPendingInquiry checks if there's a pending inquiry for the given email
func (r *inquiryRepository) CheckPendingInquiry(ctx context.Context, email string) (*Inquiry, error) {
filter := bson.M{
"work_email": email,
"status": bson.M{"$in": []string{StatusPending, StatusReviewed}},
}
pagination := orm.NewPaginationBuilder().
Limit(1).
SortBy("created_at", "desc").
Build()
result, err := r.ormRepo.FindAll(ctx, filter, pagination)
if err != nil {
r.logger.Error("Failed to check pending inquiry by email", map[string]interface{}{
"error": err.Error(),
"work_email": email,
})
return nil, err
}
if len(result.Items) > 0 {
return &result.Items[0], nil
}
return nil, nil
}
// CheckPendingInquiryByPhone checks if there's a pending inquiry for the given phone number
func (r *inquiryRepository) CheckPendingInquiryByPhone(ctx context.Context, phone string) (*Inquiry, error) {
filter := bson.M{
"phone_number": phone,
"status": bson.M{"$in": []string{StatusPending, StatusReviewed}},
}
pagination := orm.NewPaginationBuilder().
Limit(1).
SortBy("created_at", "desc").
Build()
result, err := r.ormRepo.FindAll(ctx, filter, pagination)
if err != nil {
r.logger.Error("Failed to check pending inquiry by phone", map[string]interface{}{
"error": err.Error(),
"phone_number": phone,
})
return nil, err
}
if len(result.Items) > 0 {
return &result.Items[0], nil
}
return nil, nil
}
// Search retrieves inquiries with pagination and filters
func (r *inquiryRepository) Search(ctx context.Context, form *SearchInquiriesForm, pagination *response.Pagination) ([]Inquiry, int64, error) {
filter := bson.M{}
// Add search filter
if form.Search != nil {
filter["$or"] = bson.A{
bson.M{"full_name": bson.M{"$regex": form.Search, "$options": "i"}},
bson.M{"company_name": bson.M{"$regex": form.Search, "$options": "i"}},
bson.M{"work_email": bson.M{"$regex": form.Search, "$options": "i"}},
}
}
// Add status filter
if form.Status != nil {
filter["status"] = *form.Status
}
// Build sort
sort := "created_at"
if pagination.SortBy != "" {
sort = pagination.SortBy
}
sortOrder := "desc"
if pagination.SortOrder != "" {
sortOrder = pagination.SortOrder
}
// Build pagination
paginationBuilder := orm.NewPaginationBuilder().
Limit(pagination.Limit).
Skip(pagination.Offset).
SortBy(sort, sortOrder).
Build()
// Use ORM to find inquiries
result, err := r.ormRepo.FindAll(ctx, filter, paginationBuilder)
if err != nil {
r.logger.Error("Failed to search inquiries", map[string]interface{}{
"error": err.Error(),
})
return nil, 0, err
}
return result.Items, result.TotalCount, nil
}
// Delete deletes an inquiry
func (r *inquiryRepository) Delete(ctx context.Context, id string) error {
// Get inquiry first to ensure it exists
_, err := r.GetByID(ctx, id)
if err != nil {
r.logger.Error("Failed to delete inquiry", map[string]interface{}{
"error": err.Error(),
"inquiry_id": id,
})
if errors.Is(err, orm.ErrDocumentNotFound) {
return errors.New("inquiry not found")
}
return err
}
// Delete in database
err = r.ormRepo.Delete(ctx, id)
if err != nil {
r.logger.Error("Failed to delete inquiry", map[string]interface{}{
"error": err.Error(),
"inquiry_id": id,
})
return err
}
r.logger.Info("Inquiry deleted successfully", map[string]interface{}{
"inquiry_id": id,
})
return nil
}