Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion backend/src/dal/sqliteCampaignRepository.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-check
import Database from 'better-sqlite3';

Check warning on line 2 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / backend

'Database' is defined but never used

Check warning on line 2 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / Backend — lint, typecheck, test

'Database' is defined but never used

/** @returns {boolean} */
export function isFts5Available(db) {
Expand Down Expand Up @@ -86,7 +86,17 @@
}
}

function parseTranslationsFromRow(row) {
try {
const parsed = JSON.parse(row.translations ?? '{}');
return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
} catch {
return {};
}
}

function rowToCampaign(row) {
const rawTranslations = parseTranslationsFromRow(row);
const campaign = {
id: String(row.id),
name: row.name,
Expand All @@ -107,8 +117,9 @@
status: row.status ?? 'draft',
createdAt: row.created_at,
updatedAt: row.updated_at ?? row.created_at,
available_locales: Object.keys(rawTranslations),
_rawTranslations: rawTranslations,
};
// Keep the computed status for backward compatibility with time-based status
campaign.computedStatus = computeCampaignStatus(campaign);
return campaign;
}
Expand Down Expand Up @@ -409,11 +420,11 @@
overrides.description !== undefined ? overrides.description : source.description;
const clonedRewardPerAction =
overrides.rewardPerAction !== undefined ? overrides.rewardPerAction : source.rewardPerAction;
const clonedCategory =

Check warning on line 423 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / backend

'clonedCategory' is assigned a value but never used

Check warning on line 423 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / Backend — lint, typecheck, test

'clonedCategory' is assigned a value but never used
overrides.category !== undefined ? overrides.category : source.category || null;
const clonedImageUrl =

Check warning on line 425 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / backend

'clonedImageUrl' is assigned a value but never used

Check warning on line 425 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / Backend — lint, typecheck, test

'clonedImageUrl' is assigned a value but never used
overrides.imageUrl !== undefined ? overrides.imageUrl : source.imageUrl || null;
const clonedTags = overrides.tags !== undefined ? overrides.tags : source.tags || null;

Check warning on line 427 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / backend

'clonedTags' is assigned a value but never used

Check warning on line 427 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / Backend — lint, typecheck, test

'clonedTags' is assigned a value but never used

const createdAt = new Date().toISOString();
const info = db
Expand Down Expand Up @@ -503,6 +514,46 @@
return getById(id);
}

/** @param {string | number} id @returns {Record<string, { name?: string, description?: string }>} */
function getTranslations(id) {
const row = db.prepare('SELECT translations FROM campaigns WHERE id = ?').get(Number(id));
if (!row) return {};
return parseTranslationsFromRow(row);
}

/**
* @param {string | number} id
* @param {string} locale
* @param {{ name?: string, description?: string }} data
*/
function upsertTranslation(id, locale, data) {
const current = getTranslations(id);
const updated = { ...current, [locale]: { ...data } };
const updatedAt = new Date().toISOString();
db.prepare('UPDATE campaigns SET translations = ?, updated_at = ? WHERE id = ?').run(
JSON.stringify(updated),
updatedAt,
Number(id),
);
}

/**
* @param {string | number} id
* @param {string} locale
*/
function deleteTranslation(id, locale) {
const current = getTranslations(id);
if (!(locale in current)) return false;
const { [locale]: _removed, ...rest } = current;

Check warning on line 547 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / backend

'_removed' is assigned a value but never used

Check warning on line 547 in backend/src/dal/sqliteCampaignRepository.js

View workflow job for this annotation

GitHub Actions / Backend — lint, typecheck, test

'_removed' is assigned a value but never used
const updatedAt = new Date().toISOString();
db.prepare('UPDATE campaigns SET translations = ?, updated_at = ? WHERE id = ?').run(
JSON.stringify(rest),
updatedAt,
Number(id),
);
return true;
}

return {
list,
listCategories,
Expand All @@ -515,6 +566,9 @@
clone,
publish,
archive,
getTranslations,
upsertTranslation,
deleteTranslation,
ftsAvailable,
};
}
16 changes: 16 additions & 0 deletions backend/src/db/migrations/027_campaign_translations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const version = 27;
export const description = 'Add translations JSON column to campaigns';

export function up(db) {
const columns = db.prepare('PRAGMA table_info(campaigns)').all();
const columnNames = new Set(columns.map((col) => col.name));

if (!columnNames.has('translations')) {
db.exec("ALTER TABLE campaigns ADD COLUMN translations TEXT NOT NULL DEFAULT '{}'");
}
}

export function down(db) {
// SQLite does not support DROP COLUMN in older versions; left as no-op.
void db;
}
Loading
Loading