@@ -32,12 +32,12 @@ interface PolitProResponse {
3232
3333const PARTY_NAME_MAP : Record < string , string > = {
3434 'CDU/CSU' : 'CDU/CSU' ,
35- ' AfD' : 'AfD' ,
36- ' SPD' : 'SPD' ,
37- ' Grüne' : 'GRÜNE' ,
38- ' Linke' : 'DIE LINKE' ,
39- ' BSW' : 'BSW' ,
40- ' FDP' : 'FDP' ,
35+ AfD : 'AfD' ,
36+ SPD : 'SPD' ,
37+ Grüne : 'GRÜNE' ,
38+ Linke : 'DIE LINKE' ,
39+ BSW : 'BSW' ,
40+ FDP : 'FDP' ,
4141} ;
4242
4343async function fetchPolitPro ( parliament : string , year : number ) : Promise < PolitProResponse | null > {
@@ -110,7 +110,7 @@ export interface PolitProPollData extends PollData {
110110function toExtendedPollData (
111111 data : PolitProResponse ,
112112 parliament : string ,
113- institutePolls ?: PollResult [ ] ,
113+ institutePolls ?: PollResult [ ]
114114) : PolitProPollData {
115115 const base = toPollData ( data , parliament ) ;
116116
@@ -121,7 +121,9 @@ function toExtendedPollData(
121121 }
122122
123123 const useInstitutePolls = institutePolls && institutePolls . length > 0 ;
124- log . info ( `[toExtendedPollData] Branch: ${ useInstitutePolls ? `institutePolls (${ institutePolls ! . length } )` : `base.polls (${ base . polls . length } )` } ` ) ;
124+ log . info (
125+ `[toExtendedPollData] Branch: ${ useInstitutePolls ? `institutePolls (${ institutePolls ! . length } )` : `base.polls (${ base . polls . length } )` } `
126+ ) ;
125127
126128 return {
127129 ...base ,
@@ -160,7 +162,9 @@ async function scrapeInstitutePolls(parliament: string): Promise<PollResult[]> {
160162 log . info ( `[scrapeInstitutePolls] Found ${ pollListItems . length } .poll-list-item elements` ) ;
161163
162164 if ( pollListItems . length === 0 ) {
163- log . warn ( `[scrapeInstitutePolls] No .poll-list-item elements found — HTML snippet (first 500 chars): ${ html . slice ( 0 , 500 ) } ` ) ;
165+ log . warn (
166+ `[scrapeInstitutePolls] No .poll-list-item elements found — HTML snippet (first 500 chars): ${ html . slice ( 0 , 500 ) } `
167+ ) ;
164168 }
165169
166170 const polls : PollResult [ ] = [ ] ;
@@ -171,23 +175,36 @@ async function scrapeInstitutePolls(parliament: string): Promise<PollResult[]> {
171175 if ( ! institute ) return ;
172176
173177 const parties : Record < string , number | null > = { } ;
174- $ ( el ) . find ( '.horizontal-parties-list-item' ) . each ( ( _ , partyEl ) => {
175- const name = $ ( partyEl ) . attr ( 'title' ) ;
176- const val = $ ( partyEl ) . find ( '.list-horizontal-value' ) . text ( ) . trim ( ) ;
177- if ( name && val ) {
178- const partyName = PARTY_NAME_MAP [ name ] || name ;
179- parties [ partyName ] = parseFloat ( val ) || null ;
180- }
181- } ) ;
178+ $ ( el )
179+ . find ( '.horizontal-parties-list-item' )
180+ . each ( ( _ , partyEl ) => {
181+ const name = $ ( partyEl ) . attr ( 'title' ) ;
182+ const val = $ ( partyEl ) . find ( '.list-horizontal-value' ) . text ( ) . trim ( ) ;
183+ if ( name && val ) {
184+ const partyName = PARTY_NAME_MAP [ name ] || name ;
185+ parties [ partyName ] = parseFloat ( val ) || null ;
186+ }
187+ } ) ;
182188
183189 polls . push ( { institute, date, parties } ) ;
184190 } ) ;
185191
186192 log . info ( `[scrapeInstitutePolls] Parsed ${ polls . length } institute polls for ${ parliament } ` ) ;
187193 if ( polls . length > 0 ) {
188- log . info ( `[scrapeInstitutePolls] First 2 polls:` , polls . slice ( 0 , 2 ) . map ( ( p ) => ( { institute : p . institute , date : p . date , partyCount : Object . keys ( p . parties ) . length } ) ) ) ;
194+ log . info (
195+ `[scrapeInstitutePolls] First 2 polls:` ,
196+ polls
197+ . slice ( 0 , 2 )
198+ . map ( ( p ) => ( {
199+ institute : p . institute ,
200+ date : p . date ,
201+ partyCount : Object . keys ( p . parties ) . length ,
202+ } ) )
203+ ) ;
189204 } else {
190- log . warn ( `[scrapeInstitutePolls] 0 institute polls parsed despite ${ pollListItems . length } DOM elements` ) ;
205+ log . warn (
206+ `[scrapeInstitutePolls] 0 institute polls parsed despite ${ pollListItems . length } DOM elements`
207+ ) ;
191208 }
192209 return polls ;
193210 } catch ( error ) {
@@ -197,15 +214,22 @@ async function scrapeInstitutePolls(parliament: string): Promise<PollResult[]> {
197214}
198215
199216export async function getPolitProPolls (
200- parliament = 'deutschland' ,
217+ parliament = 'deutschland'
201218) : Promise < PolitProPollData | null > {
219+ if ( ! VALID_PARLIAMENT_IDS . has ( parliament ) ) {
220+ log . warn ( `[getPolitProPolls] Invalid parliament ID: ${ parliament } ` ) ;
221+ return null ;
222+ }
223+
202224 const cacheKey = `monitor:politpro:${ parliament } ` ;
203225
204226 try {
205227 const cached = await redisClient . get ( cacheKey ) ;
206228 if ( cached ) {
207229 const parsed = JSON . parse ( cached ) as PolitProPollData ;
208- log . info ( `[getPolitProPolls] Cache hit (${ parliament } ): ${ parsed . polls . length } polls, first poll date: ${ parsed . polls [ 0 ] ?. date ?? 'none' } , institute: ${ parsed . polls [ 0 ] ?. institute ?? 'none' } ` ) ;
230+ log . info (
231+ `[getPolitProPolls] Cache hit (${ parliament } ): ${ parsed . polls . length } polls, first poll date: ${ parsed . polls [ 0 ] ?. date ?? 'none' } , institute: ${ parsed . polls [ 0 ] ?. institute ?? 'none' } `
232+ ) ;
209233 return parsed ;
210234 }
211235 } catch {
@@ -221,13 +245,15 @@ export async function getPolitProPolls(
221245
222246 log . info ( `[getPolitProPolls] Institute polls found: ${ institutePolls . length } for ${ parliament } ` ) ;
223247 if ( institutePolls . length === 0 ) {
224- log . warn ( `[getPolitProPolls] No institute polls scraped — will fall back to API interpolated data` ) ;
248+ log . warn (
249+ `[getPolitProPolls] No institute polls scraped — will fall back to API interpolated data`
250+ ) ;
225251 }
226252
227253 const result = toExtendedPollData ( data , parliament , institutePolls ) ;
228254
229255 log . info (
230- `[getPolitProPolls] Final result (${ parliament } ): ${ result . polls . length } polls, ${ Object . keys ( result . average ) . length } parties` ,
256+ `[getPolitProPolls] Final result (${ parliament } ): ${ result . polls . length } polls, ${ Object . keys ( result . average ) . length } parties`
231257 ) ;
232258
233259 try {
@@ -259,3 +285,5 @@ export const POLITPRO_PARLIAMENTS = [
259285 { id : 'schleswig-holstein' , name : 'Schleswig-Holstein' } ,
260286 { id : 'thueringen' , name : 'Thüringen' } ,
261287] as const ;
288+
289+ const VALID_PARLIAMENT_IDS : Set < string > = new Set ( POLITPRO_PARLIAMENTS . map ( ( p ) => p . id ) ) ;
0 commit comments