@@ -4,6 +4,9 @@ const UtilsHelper = require('../helpers/utilsHelper');
4
4
const ChallengeHelper = require ( '../helpers/challengeHelper' ) ;
5
5
const RecaptchaHelper = require ( '../helpers/recaptchaHelper' ) ;
6
6
const { Op } = require ( 'sequelize' ) ;
7
+ const dayjs = require ( 'dayjs' ) ;
8
+ // json2csv
9
+ const { Parser } = require ( 'json2csv' ) ;
7
10
8
11
exports . fetch = async ( req , res ) => {
9
12
try {
@@ -356,6 +359,9 @@ exports.statsChartCountByDimension = async (req, res) => {
356
359
for ( const city of cities ) {
357
360
const cityData = {
358
361
name : city . name ,
362
+ label : {
363
+ show : true ,
364
+ } ,
359
365
value : dimensions . map (
360
366
( dimension ) => challengeCounts [ city . id ] ?. [ dimension . id ] || 0
361
367
) ,
@@ -370,44 +376,185 @@ exports.statsChartCountByDimension = async (req, res) => {
370
376
}
371
377
} ;
372
378
379
+
380
+ exports . statsCountByDimensionBar = async ( req , res ) => {
381
+ try {
382
+ const cityId = req . params . cityId || null ;
383
+ // Initialize radar data structure
384
+
385
+ const results = await ChallengeHelper . getChallengesStatsByDimensionBar ( ) ;
386
+
387
+ const outputJson = JSON . parse ( JSON . stringify ( results ) ) ;
388
+
389
+ // convert percentage to float
390
+ for ( let i = 0 ; i < outputJson . length ; i ++ ) {
391
+ outputJson [ i ] . percentage = parseFloat ( outputJson [ i ] . percentage ) ;
392
+ }
393
+
394
+ return res . status ( 200 ) . json ( outputJson ) ;
395
+ } catch ( error ) {
396
+ console . error ( error ) ;
397
+ return res . status ( 500 ) . json ( { message : msg . error . default } ) ;
398
+ }
399
+ } ;
400
+
373
401
exports . statsChartCountBySubdivision = async ( req , res ) => {
374
402
try {
375
403
const cityId = req . params . cityId || null ;
376
404
const countBySubdivisions = [ ] ;
377
405
378
406
// count how many challenges per subdivision per city
379
407
// challenge.subdivision.id , challenge.subdivision.name, challenge.subdivision.city.id, count
380
- const countOfChallengesPerSubdivision = await models . Challenge . findAll ( {
381
- attributes : [
382
- [ models . sequelize . col ( "subdivision.id" ) , "subdivisionId" ] ,
383
- [ models . sequelize . col ( "subdivision.name" ) , "subdivisionName" ] ,
384
- [ models . sequelize . col ( "subdivision.type" ) , "subdivisionType" ] ,
385
- [ models . sequelize . col ( "subdivision.city.id" ) , "cityId" ] ,
386
- [ models . sequelize . col ( "subdivision.city.name" ) , "cityName" ] ,
387
- [ models . sequelize . fn ( "COUNT" , "subdivisionId" ) , "count" ] ,
388
- ] ,
389
- group : [ "subdivisionId" ] ,
408
+ // const countOfChallengesPerSubdivision = await models.Challenge.findAll({
409
+ // attributes: [
410
+ // [models.sequelize.col("subdivision.id"), "subdivisionId"],
411
+ // [models.sequelize.col("subdivision.name"), "subdivisionName"],
412
+ // [models.sequelize.col("subdivision.type"), "subdivisionType"],
413
+ // [models.sequelize.col("subdivision.city.id"), "cityId"],
414
+ // [models.sequelize.col("subdivision.city.name"), "cityName"],
415
+ // [models.sequelize.fn("COUNT", "subdivisionId"), "count"],
416
+ // ],
417
+ // group: ["subdivisionId"],
418
+ // include: [
419
+ // {
420
+ // model: models.Subdivision,
421
+ // as: "subdivision",
422
+ // where: cityId ? { cityId } : {},
423
+ // attributes: [],
424
+ // include: [
425
+ // {
426
+ // model: models.City,
427
+ // as: "city",
428
+ // where: cityId ? { id: cityId } : {},
429
+ // attributes: [],
430
+ // },
431
+ // ],
432
+ // },
433
+ // ],
434
+ // });
435
+
436
+ const countOfChallengesPerSubdivision = await ChallengeHelper . getChallengesCountBySubdivision ( cityId ) ;
437
+
438
+ return res . status ( 200 ) . json ( countOfChallengesPerSubdivision ) ;
439
+ } catch ( error ) {
440
+ console . error ( error ) ;
441
+ return res . status ( 500 ) . json ( { message : msg . error . default } ) ;
442
+ }
443
+ } ;
444
+
445
+ exports . downloadChallengesCsv = async ( req , res ) => {
446
+ try {
447
+
448
+ const recaptchaResponse = req . body . recaptchaResponse ;
449
+
450
+ // if the user is an admin, we don't need to validate the recaptcha
451
+ if ( RecaptchaHelper . requiresRecaptcha ( req . user ) ) {
452
+ // validate the recaptcha
453
+ const recaptchaValidation = await RecaptchaHelper . verifyRecaptcha ( recaptchaResponse ) ;
454
+ if ( ! recaptchaValidation ) {
455
+ return res . status ( 400 ) . json ( { message : 'Error en la validación del recaptcha' } ) ;
456
+ }
457
+ }
458
+
459
+ const challenges = await models . Challenge . findAll ( {
390
460
include : [
391
461
{
392
462
model : models . Subdivision ,
393
- as : "subdivision" ,
394
- where : cityId ? { cityId } : { } ,
395
- attributes : [ ] ,
463
+ as : 'subdivision' ,
464
+ attributes : [ 'id' , 'type' , 'name' ] ,
396
465
include : [
397
466
{
398
467
model : models . City ,
399
- as : "city" ,
400
- where : cityId ? { id : cityId } : { } ,
401
- attributes : [ ] ,
402
- } ,
403
- ] ,
468
+ as : 'city' ,
469
+ attributes : [ 'id' , 'name' ] ,
470
+ }
471
+ ]
472
+ } ,
473
+ {
474
+ model : models . Dimension ,
475
+ as : 'dimension' ,
476
+ attributes : [ 'id' , 'name' ] ,
404
477
} ,
405
478
] ,
406
479
} ) ;
407
480
408
- return res . status ( 200 ) . json ( countOfChallengesPerSubdivision ) ;
481
+ const fields = [
482
+ {
483
+ label : 'reporteId' ,
484
+ value : 'id' ,
485
+ } ,
486
+ {
487
+ label : 'fuente' ,
488
+ value : 'source' ,
489
+ } ,
490
+ {
491
+ label : 'fechaCreacion' ,
492
+ value : ( row ) => dayjs ( row . createdAt ) . toISOString ( ) ,
493
+ } ,
494
+ {
495
+ label : 'ciudadId' ,
496
+ value : 'subdivision.city.id' ,
497
+ } ,
498
+ {
499
+ label : 'ciudadNombre' ,
500
+ value : 'subdivision.city.name' ,
501
+ } ,
502
+ {
503
+ label : 'subdivisionId' ,
504
+ value : 'subdivision.id'
505
+ } ,
506
+ {
507
+ label : 'subdivisionNombre' ,
508
+ value : 'subdivision.name' ,
509
+ } ,
510
+ {
511
+ label : 'subdivisionTipo' ,
512
+ value : 'subdivision.type' ,
513
+ } ,
514
+ {
515
+ label : 'ejeTematicoId' ,
516
+ value : 'dimension.id' ,
517
+ } ,
518
+ {
519
+ label : 'ejeTematicoNombre' ,
520
+ value : 'dimension.name' ,
521
+ } ,
522
+ {
523
+ label : 'latitude' ,
524
+ value : ( row ) => row . latitude ? row . latitude . toString ( ) : null
525
+ } ,
526
+ {
527
+ label : 'longitude' ,
528
+ value : ( row ) => row . longitude ? row . longitude . toString ( ) : null
529
+ } ,
530
+ {
531
+ label : 'necesidadesYDesafios' ,
532
+ value : 'needsAndChallenges' ,
533
+ } ,
534
+ {
535
+ label : 'propuesta' ,
536
+ value : 'proposal'
537
+ } ,
538
+ {
539
+ label : 'enPalabras' ,
540
+ value : 'inWords' ,
541
+ } ,
542
+ ]
543
+
544
+ const opts = { fields, defaultValue : 'NULL' } ;
545
+
546
+ const parser = new Parser ( opts ) ;
547
+
548
+ const csv = parser . parse ( challenges ) ;
549
+
550
+ const timestamp = dayjs ( ) . format ( 'YYYYMMDD_HHmmss' ) ;
551
+ const filename = `${ timestamp } _desafios_export.csv` ;
552
+
553
+ res . setHeader ( 'Content-disposition' , `attachment; filename=${ filename } ` ) ;
554
+ res . set ( 'Content-Type' , 'text/csv' ) ;
555
+ res . status ( 200 ) . send ( csv ) ;
409
556
} catch ( error ) {
410
- console . error ( error ) ;
411
- return res . status ( 500 ) . json ( { message : msg . error . default } ) ;
557
+ console . error ( error )
558
+ return res . status ( 500 ) . json ( { message : msg . error . default } )
412
559
}
413
- } ;
560
+ }
0 commit comments