diff --git a/award-definitions/dld-40m.json b/award-definitions/dld-40m.json new file mode 100644 index 0000000..df172c9 --- /dev/null +++ b/award-definitions/dld-40m.json @@ -0,0 +1,19 @@ +{ + "id": "dld-40m", + "name": "DLD 40m", + "description": "Confirm 100 unique DOKs on 40m", + "caption": "Contact and confirm stations with 100 unique DOKs (DARC Ortsverband Kennung) on the 40m band. Only DCL-confirmed QSOs with valid DOK information on 40m count toward this award.", + "category": "darc", + "rules": { + "type": "dok", + "target": 100, + "confirmationType": "dcl", + "displayField": "darcDok", + "filters": { + "operator": "AND", + "filters": [ + { "field": "band", "operator": "eq", "value": "40m" } + ] + } + } +} diff --git a/award-definitions/dld-80m-cw.json b/award-definitions/dld-80m-cw.json new file mode 100644 index 0000000..895b7f4 --- /dev/null +++ b/award-definitions/dld-80m-cw.json @@ -0,0 +1,20 @@ +{ + "id": "dld-80m-cw", + "name": "DLD 80m CW", + "description": "Confirm 100 unique DOKs on 80m using CW", + "caption": "Contact and confirm stations with 100 unique DOKs (DARC Ortsverband Kennung) on the 80m band using CW mode. Only DCL-confirmed QSOs with valid DOK information on 80m CW count toward this award.", + "category": "darc", + "rules": { + "type": "dok", + "target": 100, + "confirmationType": "dcl", + "displayField": "darcDok", + "filters": { + "operator": "AND", + "filters": [ + { "field": "band", "operator": "eq", "value": "80m" }, + { "field": "mode", "operator": "eq", "value": "CW" } + ] + } + } +} diff --git a/award-definitions/dld-80m.json b/award-definitions/dld-80m.json new file mode 100644 index 0000000..cd47894 --- /dev/null +++ b/award-definitions/dld-80m.json @@ -0,0 +1,19 @@ +{ + "id": "dld-80m", + "name": "DLD 80m", + "description": "Confirm 100 unique DOKs on 80m", + "caption": "Contact and confirm stations with 100 unique DOKs (DARC Ortsverband Kennung) on the 80m band. Only DCL-confirmed QSOs with valid DOK information on 80m count toward this award.", + "category": "darc", + "rules": { + "type": "dok", + "target": 100, + "confirmationType": "dcl", + "displayField": "darcDok", + "filters": { + "operator": "AND", + "filters": [ + { "field": "band", "operator": "eq", "value": "80m" } + ] + } + } +} diff --git a/award-definitions/dld-cw.json b/award-definitions/dld-cw.json new file mode 100644 index 0000000..9288367 --- /dev/null +++ b/award-definitions/dld-cw.json @@ -0,0 +1,19 @@ +{ + "id": "dld-cw", + "name": "DLD CW", + "description": "Confirm 100 unique DOKs using CW mode", + "caption": "Contact and confirm stations with 100 unique DOKs (DARC Ortsverband Kennung) using CW (Morse code). Each unique DOK on CW counts separately. Only DCL-confirmed QSOs with valid DOK information count toward this award.", + "category": "darc", + "rules": { + "type": "dok", + "target": 100, + "confirmationType": "dcl", + "displayField": "darcDok", + "filters": { + "operator": "AND", + "filters": [ + { "field": "mode", "operator": "eq", "value": "CW" } + ] + } + } +} diff --git a/src/backend/services/awards.service.js b/src/backend/services/awards.service.js index 0423bcd..cd20d1b 100644 --- a/src/backend/services/awards.service.js +++ b/src/backend/services/awards.service.js @@ -27,6 +27,10 @@ function loadAwardDefinitions() { 'sat-rs44.json', 'special-stations.json', 'dld.json', + 'dld-80m.json', + 'dld-40m.json', + 'dld-cw.json', + 'dld-80m-cw.json', ]; for (const file of files) { @@ -173,9 +177,9 @@ export async function calculateAwardProgress(userId, award, options = {}) { async function calculateDOKAwardProgress(userId, award, options = {}) { const { includeDetails = false } = options; const { rules } = award; - const { target, displayField } = rules; + const { target, displayField, filters } = rules; - logger.debug('Calculating DOK-based award progress', { userId, awardId: award.id, target }); + logger.debug('Calculating DOK-based award progress', { userId, awardId: award.id, target, hasFilters: !!filters }); // Get all QSOs for user const allQSOs = await db @@ -185,10 +189,17 @@ async function calculateDOKAwardProgress(userId, award, options = {}) { logger.debug('Total QSOs for user', { count: allQSOs.length }); + // Apply filters if defined + let filteredQSOs = allQSOs; + if (filters) { + filteredQSOs = applyFilters(allQSOs, filters); + logger.debug('QSOs after DOK award filters', { count: filteredQSOs.length }); + } + // Track unique (DOK, band, mode) combinations const dokCombinations = new Map(); // Key: "DOK/band/mode" -> detail object - for (const qso of allQSOs) { + for (const qso of filteredQSOs) { const dok = qso.darcDok; if (!dok) continue; // Skip QSOs without DOK