219 lines
4.3 KiB
Go
219 lines
4.3 KiB
Go
package contact
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/frenocorp/pop/internal/config"
|
|
)
|
|
|
|
type ContactManager struct {
|
|
mu sync.Mutex
|
|
configDir string
|
|
contactsFile string
|
|
}
|
|
|
|
func NewContactManager() *ContactManager {
|
|
cfg := config.NewConfigManager()
|
|
configDir := cfg.ConfigDir()
|
|
return &ContactManager{
|
|
configDir: configDir,
|
|
contactsFile: filepath.Join(configDir, "contacts.json"),
|
|
}
|
|
}
|
|
|
|
func (m *ContactManager) List(req ListContactsRequest) (*ListContactsResponse, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
contacts, err := m.loadContacts()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var filtered []Contact
|
|
for _, c := range contacts {
|
|
if req.Search != "" {
|
|
search := req.Search
|
|
if !contains(c.Email, search) && !contains(c.Name, search) {
|
|
continue
|
|
}
|
|
}
|
|
if req.IsFavorite != nil && *req.IsFavorite != c.IsFavorite {
|
|
continue
|
|
}
|
|
filtered = append(filtered, c)
|
|
}
|
|
|
|
start := req.Page * req.PageSize
|
|
end := start + req.PageSize
|
|
if start > len(filtered) {
|
|
start = len(filtered)
|
|
}
|
|
if end > len(filtered) {
|
|
end = len(filtered)
|
|
}
|
|
|
|
return &ListContactsResponse{
|
|
Total: len(filtered),
|
|
Contacts: filtered[start:end],
|
|
}, nil
|
|
}
|
|
|
|
func (m *ContactManager) Create(req CreateContactRequest) (*Contact, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
contacts, err := m.loadContacts()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
id := fmt.Sprintf("contact_%d", time.Now().UnixNano())
|
|
contact := Contact{
|
|
ID: id,
|
|
Email: req.Email,
|
|
Name: req.Name,
|
|
Phone: req.Phone,
|
|
Address: req.Address,
|
|
Notes: req.Notes,
|
|
IsFavorite: req.IsFavorite,
|
|
CustomFields: req.CustomFields,
|
|
CreatedAt: time.Now(),
|
|
UpdatedAt: time.Now(),
|
|
}
|
|
|
|
contacts = append(contacts, contact)
|
|
if err := m.saveContacts(contacts); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &contact, nil
|
|
}
|
|
|
|
func (m *ContactManager) Get(id string) (*Contact, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
contacts, err := m.loadContacts()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, c := range contacts {
|
|
if c.ID == id {
|
|
return &c, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("contact not found: %s", id)
|
|
}
|
|
|
|
func (m *ContactManager) Update(id string, req UpdateContactRequest) (*Contact, error) {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
contacts, err := m.loadContacts()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for i, c := range contacts {
|
|
if c.ID == id {
|
|
if req.Email != nil {
|
|
c.Email = *req.Email
|
|
}
|
|
if req.Name != nil {
|
|
c.Name = *req.Name
|
|
}
|
|
if req.Phone != nil {
|
|
c.Phone = *req.Phone
|
|
}
|
|
if req.Address != nil {
|
|
c.Address = *req.Address
|
|
}
|
|
if req.Notes != nil {
|
|
c.Notes = *req.Notes
|
|
}
|
|
if req.IsFavorite != nil {
|
|
c.IsFavorite = *req.IsFavorite
|
|
}
|
|
if req.CustomFields != nil {
|
|
c.CustomFields = req.CustomFields
|
|
}
|
|
c.UpdatedAt = time.Now()
|
|
contacts[i] = c
|
|
|
|
if err := m.saveContacts(contacts); err != nil {
|
|
return nil, err
|
|
}
|
|
return &c, nil
|
|
}
|
|
}
|
|
|
|
return nil, fmt.Errorf("contact not found: %s", id)
|
|
}
|
|
|
|
func (m *ContactManager) Delete(id string) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
contacts, err := m.loadContacts()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for i, c := range contacts {
|
|
if c.ID == id {
|
|
contacts = append(contacts[:i], contacts[i+1:]...)
|
|
return m.saveContacts(contacts)
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("contact not found: %s", id)
|
|
}
|
|
|
|
func (m *ContactManager) loadContacts() ([]Contact, error) {
|
|
data, err := os.ReadFile(m.contactsFile)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return []Contact{}, nil
|
|
}
|
|
return nil, err
|
|
}
|
|
|
|
var contacts []Contact
|
|
if err := json.Unmarshal(data, &contacts); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return contacts, nil
|
|
}
|
|
|
|
func (m *ContactManager) saveContacts(contacts []Contact) error {
|
|
if err := os.MkdirAll(m.configDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
|
|
data, err := json.MarshalIndent(contacts, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.WriteFile(m.contactsFile, data, 0600)
|
|
}
|
|
|
|
func contains(s, substr string) bool {
|
|
return len(s) >= len(substr) && (s == substr || len(s) > 0 && len(substr) > 0 &&
|
|
(s[:len(substr)] == substr || s[len(s)-len(substr):] == substr ||
|
|
findSubstring(s, substr)))
|
|
}
|
|
|
|
func findSubstring(s, substr string) bool {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|