1
+ import { toAPIError } from '@shared/errors/APIError' ;
1
2
import { decodeOrThrowRequest } from '@shared/endpoints/helper' ;
2
- import * as foodUtils from '@shared/utils/food.utils' ;
3
- import endpoints , {
4
- ListMetadataResponse ,
5
- } from '@tktrex/shared/endpoints/v2/metadata.endpoints' ;
3
+ import endpoints from '@tktrex/shared/endpoints/v2/metadata.endpoints' ;
6
4
import createDebug from 'debug' ;
5
+ import * as A from 'fp-ts/Array' ;
6
+ import { pipe } from 'fp-ts/lib/function' ;
7
+ import * as TE from 'fp-ts/TaskEither' ;
8
+ import * as E from 'fp-ts/lib/Either' ;
9
+ import { toTKMetadata } from '../io/metadata.io' ;
7
10
import _ from 'lodash' ;
8
11
import * as automo from '../lib/automo' ;
12
+ import { throwTE } from '@shared/utils/task.utils' ;
13
+ import { AppError } from '@shared/errors/AppError' ;
14
+ import moment from 'moment' ;
15
+ import CSV from '../lib/CSV' ;
16
+ import { ListMetadataOutput } from '@tktrex/shared/models/http/metadata/output/ListMetadata.output' ;
17
+ import { ListMetadataQuery } from '@tktrex/shared/models/http/metadata/query/ListMetadata.query' ;
9
18
10
19
const debug = createDebug ( 'routes:public' ) ;
11
20
12
21
// This variables is used as cap in every readLimit below
13
22
const PUBLIC_AMOUNT_ELEMS = 100 ;
14
23
15
- const listMetadata = async (
16
- req : any
17
- ) : Promise < { json : ListMetadataResponse } > => {
24
+ type ListMetadataResponse =
25
+ | { json : ListMetadataOutput }
26
+ | { headers : any ; text : string } ;
27
+
28
+ const listMetadata = async ( req : any ) : Promise < ListMetadataResponse > => {
29
+ const { query } = decodeOrThrowRequest (
30
+ endpoints . ListMetadata ,
31
+ req
32
+ ) as any as {
33
+ query : ListMetadataQuery ;
34
+ } ;
35
+
36
+ debug ( 'Filter metadata with query %O' , query ) ;
37
+
18
38
const {
19
- query : {
20
- researchTag,
21
- experimentId,
22
- publicKey,
23
- nature,
24
- amount = PUBLIC_AMOUNT_ELEMS ,
25
- skip = 0 ,
26
- } ,
27
- } = decodeOrThrowRequest ( endpoints . ListMetadata , req ) ;
39
+ researchTag,
40
+ experimentId,
41
+ publicKey,
42
+ nature,
43
+ amount = PUBLIC_AMOUNT_ELEMS ,
44
+ skip = 0 ,
45
+ format,
46
+ } = query ;
47
+
48
+ debug ( 'Filter metadata with query %O' , query ) ;
28
49
29
50
const filter = { } as any ;
30
51
if ( publicKey ) {
@@ -36,29 +57,71 @@ const listMetadata = async (
36
57
if ( researchTag ) {
37
58
filter . researchTag = researchTag ;
38
59
}
60
+
39
61
if ( nature ) {
40
62
filter [ 'nature.type' ] = nature ;
63
+ switch ( nature ) {
64
+ case 'search' : {
65
+ const { query : q } = query ;
66
+ if ( q ) {
67
+ filter . query = {
68
+ $regex : q ,
69
+ } ;
70
+ }
71
+ break ;
72
+ }
73
+ }
41
74
}
42
75
43
76
debug ( 'Filtering metadata for %O (%d, %d)' , filter , amount , skip ) ;
44
77
45
- const metadata = await automo
46
- . getMetadataByFilter ( filter , {
47
- amount,
48
- skip,
49
- } )
50
- . then ( ( { totals, data } ) => ( {
51
- totals,
52
- data : data . map ( ( { publicKey, _id, id, ...m } ) => ( {
53
- ...m ,
54
- id : id . substring ( 0 , 10 ) ,
55
- supporter : foodUtils . string2Food ( publicKey ) ,
56
- } ) ) ,
57
- } ) ) ;
58
-
59
- debug ( 'Fetched %d evidences of %d' , _ . size ( metadata . data ) , metadata . totals ) ;
60
-
61
- return { json : metadata } ;
78
+ return pipe (
79
+ TE . tryCatch (
80
+ ( ) =>
81
+ automo . getMetadataByFilter ( filter , {
82
+ amount,
83
+ skip,
84
+ } ) ,
85
+ toAPIError
86
+ ) ,
87
+ TE . chain ( ( { totals, data } ) => {
88
+ debug ( 'Metadata by %O, %d evidences' , filter , _ . size ( data ) ) ;
89
+ return pipe (
90
+ data . map ( toTKMetadata ) ,
91
+ A . sequence ( E . Applicative ) ,
92
+ E . map ( ( d ) => ( { data : d , totals } ) ) ,
93
+ TE . fromEither
94
+ ) ;
95
+ } ) ,
96
+ TE . chain ( ( metadata ) : TE . TaskEither < AppError , ListMetadataResponse > => {
97
+ if ( format === 'csv' ) {
98
+ const csv = CSV . produceCSVv1 ( metadata . data ) ;
99
+ let filename = `metadata` ;
100
+ filename += experimentId ? `-experiment-${ experimentId } ` : '' ;
101
+ filename += researchTag ? `-research_tag-${ researchTag } ` : '' ;
102
+ filename += '-' + moment ( ) . format ( 'YY-MM-DD' ) + '.csv' ;
103
+
104
+ debug (
105
+ 'VideoCSV: produced %d bytes, returning %s' ,
106
+ _ . size ( csv ) ,
107
+ filename
108
+ ) ;
109
+
110
+ // if (!_.size(csv)) return { text: 'Error, Zorry: 🤷' };
111
+
112
+ return TE . right ( {
113
+ headers : {
114
+ 'Content-Type' : 'csv/text' ,
115
+ 'Content-Disposition' : `attachment; filename=${ filename } ` ,
116
+ } ,
117
+ text : csv ,
118
+ } ) ;
119
+ }
120
+
121
+ return TE . right ( { json : metadata } ) ;
122
+ } ) ,
123
+ throwTE
124
+ ) ;
62
125
} ;
63
126
64
127
export { listMetadata } ;
0 commit comments