261 lines
5.4 KiB
Go
261 lines
5.4 KiB
Go
package cache
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
)
|
|
|
|
// PreferenceSavedCity represents a user's saved city preference.
|
|
type PreferenceSavedCity struct {
|
|
CityCode string `json:"city_code"`
|
|
Name string `json:"name"`
|
|
}
|
|
|
|
// PreferenceSearchHistory represents a user's search history entry.
|
|
type PreferenceSearchHistory struct {
|
|
Query string `json:"query"`
|
|
FromCity string `json:"from_city"`
|
|
ToCity string `json:"to_city"`
|
|
Date string `json:"date"`
|
|
CreatedAt int64 `json:"created_at"`
|
|
}
|
|
|
|
// Preferences represents user preferences storage.
|
|
// It provides methods for managing saved cities and search history.
|
|
type Preferences struct {
|
|
store Cache
|
|
}
|
|
|
|
// NewPreferences creates a new Preferences instance with the given cache store.
|
|
func NewPreferences(store Cache) *Preferences {
|
|
return &Preferences{store: store}
|
|
}
|
|
|
|
// GetSavedCities returns the user's saved cities.
|
|
func (p *Preferences) GetSavedCities(ctx context.Context, userID string) ([]PreferenceSavedCity, error) {
|
|
data, err := p.store.Get(ctx, &CacheKey{
|
|
Kind: "prefs:saved_city:" + userID,
|
|
Code: userID,
|
|
From: "",
|
|
To: "",
|
|
Date: "",
|
|
Request: "",
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if data == nil {
|
|
return []PreferenceSavedCity{}, nil
|
|
}
|
|
|
|
var cities []PreferenceSavedCity
|
|
if err := json.Unmarshal(data, &cities); err != nil {
|
|
return nil, err
|
|
}
|
|
return cities, nil
|
|
}
|
|
|
|
// AddSavedCity adds a city to the user's saved cities.
|
|
func (p *Preferences) AddSavedCity(ctx context.Context, userID, cityCode, cityName string) error {
|
|
|
|
// Load existing cities
|
|
cities, err := p.GetSavedCities(ctx, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Check if city already exists
|
|
exists := false
|
|
for i, c := range cities {
|
|
if c.CityCode == cityCode {
|
|
cities[i].Name = cityName
|
|
exists = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if !exists {
|
|
// Add new city
|
|
cities = append(cities, PreferenceSavedCity{
|
|
CityCode: cityCode,
|
|
Name: cityName,
|
|
})
|
|
}
|
|
|
|
// Store back to cache
|
|
data, err := json.Marshal(cities)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
cacheKey := &CacheKey{
|
|
Kind: "prefs:saved_city:" + userID,
|
|
Code: userID,
|
|
From: "",
|
|
To: "",
|
|
Date: "",
|
|
Request: "",
|
|
}
|
|
if err := p.store.Set(ctx, cacheKey, data, PreferenceTTL); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RemoveSavedCity removes a city from the user's saved cities.
|
|
func (p *Preferences) RemoveSavedCity(ctx context.Context, userID, cityCode string) error {
|
|
// Load existing cities
|
|
cities, err := p.GetSavedCities(ctx, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Remove the city
|
|
var result []PreferenceSavedCity
|
|
for _, c := range cities {
|
|
if c.CityCode != cityCode {
|
|
result = append(result, c)
|
|
}
|
|
}
|
|
|
|
if len(result) == 0 {
|
|
// If no cities left, delete the key
|
|
key := &CacheKey{
|
|
Kind: "prefs:saved_city:" + userID,
|
|
Code: userID,
|
|
}
|
|
return p.store.Delete(ctx, key)
|
|
}
|
|
|
|
// Store back
|
|
data, err := json.Marshal(result)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
key := &CacheKey{
|
|
Kind: "prefs:saved_city:" + userID,
|
|
Code: userID,
|
|
}
|
|
return p.store.Set(ctx, key, data, PreferenceTTL)
|
|
}
|
|
|
|
// GetSearchHistory returns the user's search history.
|
|
func (p *Preferences) GetSearchHistory(ctx context.Context, userID string) ([]PreferenceSearchHistory, error) {
|
|
key := &CacheKey{
|
|
Kind: "prefs:search_history:" + userID,
|
|
Code: userID,
|
|
From: "",
|
|
To: "",
|
|
Date: "",
|
|
Request: "",
|
|
}
|
|
|
|
data, err := p.store.Get(ctx, key)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if data == nil {
|
|
return []PreferenceSearchHistory{}, nil
|
|
}
|
|
|
|
var history []PreferenceSearchHistory
|
|
if err := json.Unmarshal(data, &history); err != nil {
|
|
return nil, err
|
|
}
|
|
return history, nil
|
|
}
|
|
|
|
// AddSearchHistory adds a search to the user's history.
|
|
func (p *Preferences) AddSearchHistory(ctx context.Context, userID, fromCity, toCity, date string) error {
|
|
key := &CacheKey{
|
|
Kind: "prefs:search_history:" + userID,
|
|
Code: userID,
|
|
From: "",
|
|
To: "",
|
|
Date: "",
|
|
Request: "",
|
|
}
|
|
|
|
// Load existing history
|
|
history, err := p.GetSearchHistory(ctx, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Add new entry at the beginning (most recent first)
|
|
history = append([]PreferenceSearchHistory{
|
|
{
|
|
Query: fromCity + "→" + toCity,
|
|
FromCity: fromCity,
|
|
ToCity: toCity,
|
|
Date: date,
|
|
CreatedAt: time.Now().Unix(),
|
|
},
|
|
}, history...)
|
|
|
|
// Keep only last 50 searches
|
|
if len(history) > 50 {
|
|
history = history[:50]
|
|
}
|
|
|
|
// Store back to cache
|
|
data, err := json.Marshal(history)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := p.store.Set(ctx, key, data, PreferenceTTL); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// RemoveOldSearchHistory removes search entries older than the given age.
|
|
func (p *Preferences) RemoveOldSearchHistory(ctx context.Context, userID string, maxAgeSeconds int64) error {
|
|
key := &CacheKey{
|
|
Kind: "prefs:search_history:" + userID,
|
|
Code: userID,
|
|
From: "",
|
|
To: "",
|
|
Date: "",
|
|
Request: "",
|
|
}
|
|
|
|
history, err := p.GetSearchHistory(ctx, userID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Filter out old entries
|
|
var recent []PreferenceSearchHistory
|
|
now := time.Now().Unix()
|
|
for _, entry := range history {
|
|
if entry.CreatedAt >= now-maxAgeSeconds {
|
|
recent = append(recent, entry)
|
|
}
|
|
}
|
|
|
|
if len(recent) == len(history) {
|
|
// No entries removed
|
|
return nil
|
|
}
|
|
|
|
// Store back
|
|
data, err := json.Marshal(recent)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := p.store.Set(ctx, key, data, PreferenceTTL); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|