160 lines
5.7 KiB
Go
160 lines
5.7 KiB
Go
package inquiry
|
|
|
|
import (
|
|
"tm/pkg/response"
|
|
"tm/pkg/security"
|
|
|
|
"github.com/asaskevich/govalidator"
|
|
)
|
|
|
|
// Inquiry DTOs
|
|
|
|
// CreateInquiryForm represents the data required to create a new inquiry
|
|
type CreateInquiryForm struct {
|
|
FullName string `json:"full_name" valid:"required,length(2|100)" example:"John Doe"` // Full name of the inquirer
|
|
CompanyName string `json:"company_name" valid:"required,length(2|100)" example:"Opplens"` // Company name
|
|
WorkEmail string `json:"work_email" valid:"required,email" example:"info@opplens.com"` // Work email address
|
|
PhoneNumber string `json:"phone_number" valid:"required,length(10|20)" example:"+1234567890"` // Phone number
|
|
}
|
|
|
|
// UpdateInquiryStatusForm represents the data required to update inquiry status
|
|
type UpdateInquiryStatusForm struct {
|
|
Status string `json:"status" valid:"required,in(pending|reviewed|approved|rejected)" example:"reviewed"` // New status
|
|
Reason string `json:"reason" valid:"required,length(5|500)" example:"Initial review completed"` // Reason for status change
|
|
Description string `json:"description" valid:"optional,length(0|1000)" example:"Additional notes about the review"` // Optional description
|
|
}
|
|
|
|
// SearchInquiriesForm represents search and filter parameters for inquiries
|
|
type SearchInquiriesForm struct {
|
|
Search *string `query:"q" valid:"optional"` // Search term for full name, company name, or email
|
|
Status *string `query:"status" valid:"optional,in(pending|reviewed|approved|rejected)"` // Filter by status
|
|
Limit *int `query:"limit" valid:"optional,range(1|100)"` // Limit results
|
|
Offset *int `query:"offset" valid:"optional,min(0)"` // Offset results
|
|
SortBy *string `query:"sort_by" valid:"optional,in(full_name|company_name|work_email|status|created_at)"` // Sort field
|
|
SortOrder *string `query:"sort_order" valid:"optional,in(asc|desc)"` // Sort order
|
|
}
|
|
|
|
// Response DTOs
|
|
|
|
// StatusHistoryResponse represents status history in API responses
|
|
type StatusHistoryResponse struct {
|
|
Status string `json:"status"`
|
|
Reason string `json:"reason"`
|
|
ChangedAt int64 `json:"changed_at"`
|
|
Description string `json:"description"`
|
|
}
|
|
|
|
// InquiryResponse represents the inquiry data in API responses
|
|
type InquiryResponse struct {
|
|
ID string `json:"id"`
|
|
FullName string `json:"full_name"`
|
|
CompanyName string `json:"company_name"`
|
|
WorkEmail string `json:"work_email"`
|
|
PhoneNumber string `json:"phone_number"`
|
|
Status string `json:"status"`
|
|
StatusHistory []StatusHistoryResponse `json:"status_history"`
|
|
CreatedAt int64 `json:"created_at"`
|
|
UpdatedAt int64 `json:"updated_at"`
|
|
}
|
|
|
|
// InquiryListResponse represents a paginated list of inquiries
|
|
type InquiryListResponse struct {
|
|
Inquiries []*InquiryResponse `json:"inquiries"`
|
|
Meta *response.Meta `json:"meta"`
|
|
}
|
|
|
|
// Helper function to convert Inquiry to InquiryResponse
|
|
func (i *Inquiry) ToResponse() *InquiryResponse {
|
|
// Convert status history
|
|
var statusHistoryResponses []StatusHistoryResponse
|
|
for _, history := range i.StatusHistory {
|
|
statusHistoryResponses = append(statusHistoryResponses, StatusHistoryResponse{
|
|
Status: history.Status,
|
|
Reason: history.Reason,
|
|
ChangedAt: history.ChangedAt,
|
|
Description: history.Description,
|
|
})
|
|
}
|
|
|
|
return &InquiryResponse{
|
|
ID: i.ID.Hex(),
|
|
FullName: i.FullName,
|
|
CompanyName: i.CompanyName,
|
|
WorkEmail: i.WorkEmail,
|
|
PhoneNumber: i.PhoneNumber,
|
|
Status: i.Status,
|
|
StatusHistory: statusHistoryResponses,
|
|
CreatedAt: i.CreatedAt,
|
|
UpdatedAt: i.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
// ValidateAndSanitize validates and sanitizes the form
|
|
func (f *CreateInquiryForm) ValidateAndSanitize(xssPolicy *security.XSSPolicy) error {
|
|
var err error
|
|
|
|
// Sanitize and validate FullName
|
|
f.FullName, err = xssPolicy.ValidateAndSanitizeInput(f.FullName, "text")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Sanitize and validate CompanyName
|
|
f.CompanyName, err = xssPolicy.ValidateAndSanitizeInput(f.CompanyName, "text")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Sanitize and validate WorkEmail (email validation is separate)
|
|
f.WorkEmail, err = xssPolicy.ValidateAndSanitizeInput(f.WorkEmail, "email")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Sanitize and validate PhoneNumber
|
|
f.PhoneNumber, err = xssPolicy.ValidateAndSanitizeInput(f.PhoneNumber, "phone")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Standard govalidator validation
|
|
_, err = govalidator.ValidateStruct(f)
|
|
return err
|
|
}
|
|
|
|
// ValidateAndSanitize validates and sanitizes the status update form
|
|
func (f *UpdateInquiryStatusForm) ValidateAndSanitize(xssPolicy *security.XSSPolicy) error {
|
|
var err error
|
|
|
|
// Sanitize Reason
|
|
f.Reason, err = xssPolicy.ValidateAndSanitizeInput(f.Reason, "text")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Sanitize Description
|
|
f.Description, err = xssPolicy.ValidateAndSanitizeInput(f.Description, "html")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Standard govalidator validation
|
|
_, err = govalidator.ValidateStruct(f)
|
|
return err
|
|
}
|
|
|
|
// ValidateAndSanitize validates and sanitizes the search form
|
|
func (f *SearchInquiriesForm) ValidateAndSanitize(xssPolicy *security.XSSPolicy) error {
|
|
if f.Search != nil {
|
|
sanitized, err := xssPolicy.ValidateAndSanitizeInput(*f.Search, "text")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*f.Search = sanitized
|
|
}
|
|
|
|
// Standard govalidator validation
|
|
_, err := govalidator.ValidateStruct(f)
|
|
return err
|
|
}
|