When connecting to the internet for the first time, the proclamations table is empty. If the user navigates to Settings -> Proclamations, then the sync.SyncProclamations function is called. After this function returns, the ProclamationOptions screen queries the database for proclamations which returns an empty list. Even though the database was updated, the ProclamationOptions screen's instance of the database connection was returning empty.
119 lines
3.2 KiB
Go
119 lines
3.2 KiB
Go
package sync
|
|
|
|
import (
|
|
"regexp"
|
|
|
|
"gorm.io/gorm"
|
|
"gorm.io/gorm/clause"
|
|
"rhemawavetech.com/rhemawave/internal/db"
|
|
"rhemawavetech.com/rhemawave/internal/logger"
|
|
"rhemawavetech.com/rhemawave/internal/netreq"
|
|
)
|
|
|
|
var htmlRegex = regexp.MustCompile(`<[^>]*>`)
|
|
|
|
// SyncProclamations fetches data from the API, cleans it, and updates the local DB.
|
|
// It returns the slice of proclamations so the UI can update immediately.
|
|
func SyncProclamations(database *gorm.DB) ([]db.Proclamation, error) {
|
|
fullURL := "https://portal.rhemawavetech.com/api/v1/proclamations"
|
|
logger.Debug("Syncronizing proclamations. URL: %s", fullURL)
|
|
|
|
proclamations, err := netreq.GetJSON[db.Proclamation](fullURL)
|
|
if err != nil {
|
|
// If we're offline or API is down, we log it but don't crash.
|
|
// The UI can still use whatever is currently in the DB.
|
|
logger.Error("Proclamation sync failed, skipping update: %v", err)
|
|
return nil, err
|
|
}
|
|
logger.Debug("Request Granted")
|
|
|
|
for i := range proclamations {
|
|
proclamations[i].Content = htmlRegex.ReplaceAllString(proclamations[i].Content, "")
|
|
}
|
|
|
|
var storedProclamationSettings []db.Proclamation
|
|
database.Select("ID", "Selected").Find(&storedProclamationSettings)
|
|
// [ID]Selected
|
|
stash := make(map[string]bool)
|
|
for _, row := range storedProclamationSettings {
|
|
stash[row.ID] = row.Selected
|
|
}
|
|
|
|
for i := range proclamations {
|
|
proclamations[i].Selected = stash[proclamations[i].ID]
|
|
}
|
|
|
|
err = database.Transaction(func(tx *gorm.DB) error {
|
|
ids := make([]string, len(proclamations))
|
|
for i, p := range proclamations {
|
|
ids[i] = p.ID
|
|
}
|
|
|
|
if len(ids) == 0 {
|
|
// API returned nothing → DB should be empty
|
|
if err := tx.Where("1 = 1").Delete(&db.Proclamation{}).Error; err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
// Remove anything not in API
|
|
if err := tx.Where("id NOT IN ?", ids).Delete(&db.Proclamation{}).Error; err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Upsert (preserve Selected automatically)
|
|
if err := tx.Clauses(clause.OnConflict{
|
|
Columns: []clause.Column{{Name: "id"}},
|
|
DoUpdates: clause.AssignmentColumns([]string{
|
|
"name",
|
|
"content",
|
|
"solfeggio_frequency_id",
|
|
"category_id",
|
|
"available",
|
|
"price",
|
|
}),
|
|
}).Create(&proclamations).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
})
|
|
|
|
logger.Debug("Proclamations stored to database")
|
|
|
|
if err != nil {
|
|
logger.Error("Failed to save synced proclamations: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
logger.Info("Successfully synced proclamations: %d", len(proclamations))
|
|
return proclamations, nil
|
|
}
|
|
|
|
func SyncCategories(database *gorm.DB) ([]db.ProclamationCategory, error) {
|
|
fullURL := "https://portal.rhemawavetech.com/api/v1/categories"
|
|
categories, err := netreq.GetJSON[db.ProclamationCategory](fullURL)
|
|
if err != nil {
|
|
logger.Error("Category sync failed, skipping update: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
err = database.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Where("1 = 1").Delete(&db.ProclamationCategory{}).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Save(&categories).Error; err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
})
|
|
|
|
if err != nil {
|
|
logger.Error("failed to sync proclamation categories: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
logger.Info("Successfully synced proclamation categories: %d", len(categories))
|
|
return categories, nil
|
|
}
|