package persistence import ( domain "RenewCMS/internal/domain/localization" "RenewCMS/internal/infrastructure/persistence/mappers" entity "RenewCMS/internal/infrastructure/persistence/models" "slices" "gorm.io/gorm" ) type LocalizationRepository struct { db *gorm.DB } func NewLocalizationRepository(db *gorm.DB) *LocalizationRepository { return &LocalizationRepository{db} } type languageTotal struct { Lang string Total int } func (l *LocalizationRepository) Rows(siteID uint32) ([]domain.Row, error) { var found []entity.SiteLanguage if err := l.db.Where("site_id = ?", siteID).Order("lang ASC").Find(&found).Error; err != nil { return nil, err } rows := make([]domain.Row, 0, len(found)) for _, row := range found { rows = append(rows, mappers.LocalizationRowToDomain(row)) } return rows, nil } func (l *LocalizationRepository) ConfirmedSites() (map[uint32]bool, error) { var ids []uint32 err := l.db.Model(&entity.SiteLanguage{}).Where("is_default = ? AND confirmed = ?", true, true).Distinct().Pluck("site_id", &ids).Error if err != nil { return nil, err } confirmed := make(map[uint32]bool, len(ids)) for _, id := range ids { confirmed[id] = true } return confirmed, nil } func (l *LocalizationRepository) VersionCounts(siteID uint32) (map[string]domain.VersionCount, error) { totals, err := l.countByLanguage(l.db.Where("site_id = ?", siteID)) if err != nil { return nil, err } published, err := l.countByLanguage(l.db.Where("site_id = ? AND is_online = ?", siteID, true)) if err != nil { return nil, err } trashed, err := l.countByLanguage(l.db.Unscoped().Where("site_id = ? AND deleted_at IS NOT NULL", siteID)) if err != nil { return nil, err } counts := make(map[string]domain.VersionCount, len(totals)) for lang, total := range totals { counts[lang] = domain.VersionCount{Total: total, Published: published[lang]} } for lang, count := range trashed { kept := counts[lang] kept.Trashed = count counts[lang] = kept } return counts, nil } func (l *LocalizationRepository) countByLanguage(scope *gorm.DB) (map[string]int, error) { var totals []languageTotal err := scope.Model(&entity.Article{}).Select("lang, COUNT(*) AS total").Group("lang").Scan(&totals).Error if err != nil { return nil, err } counted := make(map[string]int, len(totals)) for _, total := range totals { counted[total.Lang] = total.Total } return counted, nil } func (l *LocalizationRepository) Replace(siteID uint32, rows []domain.Row) error { existing, err := l.Rows(siteID) if err != nil { return err } known := make(map[string]domain.Row, len(existing)) for _, row := range existing { known[row.Tag] = row } wanted := make([]string, 0, len(rows)) for _, row := range rows { wanted = append(wanted, row.Tag) } for _, row := range existing { if !slices.Contains(wanted, row.Tag) { if err := l.db.Where("site_id = ? AND lang = ?", siteID, row.Tag).Delete(&entity.SiteLanguage{}).Error; err != nil { return err } } } if err := l.clearOtherDefaults(siteID, rows); err != nil { return err } for _, row := range rows { if err := l.save(siteID, row, known); err != nil { return err } } return nil } func (l *LocalizationRepository) clearOtherDefaults(siteID uint32, rows []domain.Row) error { for _, row := range rows { if row.IsDefault { return l.db.Model(&entity.SiteLanguage{}).Where("site_id = ? AND is_default = ? AND lang <> ?", siteID, true, row.Tag).UpdateColumn("is_default", false).Error } } return nil } func (l *LocalizationRepository) save(siteID uint32, row domain.Row, known map[string]domain.Row) error { before, exists := known[row.Tag] if !exists { model := mappers.LocalizationRowToModel(siteID, row) return l.db.Create(&model).Error } if before.Equal(row) { return nil } changes := map[string]any{"is_default": row.IsDefault, "enabled": row.Enabled, "confirmed": row.Confirmed, "social_locale": row.SocialLocale} return l.db.Model(&entity.SiteLanguage{}).Where("site_id = ? AND lang = ?", siteID, row.Tag).Updates(changes).Error } func (l *LocalizationRepository) ConfirmSetup(siteID uint32, tag string) error { if err := l.db.Where("site_id = ? AND confirmed = ?", siteID, false).Delete(&entity.SiteLanguage{}).Error; err != nil { return err } confirmed := entity.SiteLanguage{SiteID: siteID, Lang: tag, IsDefault: true, Enabled: true, Confirmed: true} return l.db.Create(&confirmed).Error } var _ domain.Repository = &LocalizationRepository{}