150 lines
3.9 KiB
Go
150 lines
3.9 KiB
Go
package repository
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"time"
|
|
|
|
"fncConvertGui/internal/crypto"
|
|
"fncConvertGui/internal/models"
|
|
)
|
|
|
|
// CustomerRepository handles customer CRUD with field-level encryption.
|
|
type CustomerRepository struct {
|
|
db *sql.DB
|
|
enc *crypto.Encryptor
|
|
}
|
|
|
|
// NewCustomerRepository creates a new repository.
|
|
func NewCustomerRepository(db *sql.DB, enc *crypto.Encryptor) *CustomerRepository {
|
|
return &CustomerRepository{db: db, enc: enc}
|
|
}
|
|
|
|
// Create inserts a new customer, encrypting sensitive fields.
|
|
func (r *CustomerRepository) Create(c *models.Customer) (int64, error) {
|
|
encName, err := r.enc.Encrypt([]byte(c.Name))
|
|
if err != nil {
|
|
return 0, fmt.Errorf("encrypt name: %w", err)
|
|
}
|
|
encEmail, err := r.enc.Encrypt([]byte(c.Email))
|
|
if err != nil {
|
|
return 0, fmt.Errorf("encrypt email: %w", err)
|
|
}
|
|
encPhone, err := r.enc.Encrypt([]byte(c.Phone))
|
|
if err != nil {
|
|
return 0, fmt.Errorf("encrypt phone: %w", err)
|
|
}
|
|
|
|
now := time.Now()
|
|
res, err := r.db.Exec(
|
|
`INSERT INTO customers (name, email, phone, company, created_at, updated_at)
|
|
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
encName, encEmail, encPhone, c.Company, now, now,
|
|
)
|
|
if err != nil {
|
|
return 0, fmt.Errorf("insert: %w", err)
|
|
}
|
|
return res.LastInsertId()
|
|
}
|
|
|
|
// GetByID fetches a customer by ID, decrypting sensitive fields.
|
|
func (r *CustomerRepository) GetByID(id int64) (*models.Customer, error) {
|
|
var c models.Customer
|
|
var encName, encEmail, encPhone []byte
|
|
|
|
err := r.db.QueryRow(
|
|
`SELECT id, name, email, phone, company, created_at, updated_at
|
|
FROM customers WHERE id = ?`, id,
|
|
).Scan(&c.ID, &encName, &encEmail, &encPhone, &c.Company, &c.CreatedAt, &c.UpdatedAt)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("query: %w", err)
|
|
}
|
|
|
|
name, err := r.enc.Decrypt(encName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decrypt name: %w", err)
|
|
}
|
|
email, err := r.enc.Decrypt(encEmail)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decrypt email: %w", err)
|
|
}
|
|
phone, err := r.enc.Decrypt(encPhone)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decrypt phone: %w", err)
|
|
}
|
|
|
|
c.Name = string(name)
|
|
c.Email = string(email)
|
|
c.Phone = string(phone)
|
|
return &c, nil
|
|
}
|
|
|
|
// List returns all customers with decrypted fields for list views.
|
|
func (r *CustomerRepository) List() ([]models.CustomerListItem, error) {
|
|
rows, err := r.db.Query(
|
|
`SELECT id, name, email, company FROM customers ORDER BY id DESC`)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("query: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var items []models.CustomerListItem
|
|
for rows.Next() {
|
|
var item models.CustomerListItem
|
|
var encName, encEmail []byte
|
|
|
|
if err := rows.Scan(&item.ID, &encName, &encEmail, &item.Company); err != nil {
|
|
return nil, fmt.Errorf("scan: %w", err)
|
|
}
|
|
|
|
name, err := r.enc.Decrypt(encName)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decrypt name: %w", err)
|
|
}
|
|
email, err := r.enc.Decrypt(encEmail)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decrypt email: %w", err)
|
|
}
|
|
|
|
item.Name = string(name)
|
|
item.Email = string(email)
|
|
items = append(items, item)
|
|
}
|
|
return items, rows.Err()
|
|
}
|
|
|
|
// Update modifies an existing customer, re-encrypting sensitive fields.
|
|
func (r *CustomerRepository) Update(c *models.Customer) error {
|
|
encName, err := r.enc.Encrypt([]byte(c.Name))
|
|
if err != nil {
|
|
return fmt.Errorf("encrypt name: %w", err)
|
|
}
|
|
encEmail, err := r.enc.Encrypt([]byte(c.Email))
|
|
if err != nil {
|
|
return fmt.Errorf("encrypt email: %w", err)
|
|
}
|
|
encPhone, err := r.enc.Encrypt([]byte(c.Phone))
|
|
if err != nil {
|
|
return fmt.Errorf("encrypt phone: %w", err)
|
|
}
|
|
|
|
_, err = r.db.Exec(
|
|
`UPDATE customers SET name=?, email=?, phone=?, company=?, updated_at=?
|
|
WHERE id=?`,
|
|
encName, encEmail, encPhone, c.Company, time.Now(), c.ID,
|
|
)
|
|
if err != nil {
|
|
return fmt.Errorf("update: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Delete removes a customer by ID.
|
|
func (r *CustomerRepository) Delete(id int64) error {
|
|
_, err := r.db.Exec(`DELETE FROM customers WHERE id = ?`, id)
|
|
if err != nil {
|
|
return fmt.Errorf("delete: %w", err)
|
|
}
|
|
return nil
|
|
}
|