@data-fair/catalog-onegeo-suite 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.ts +1 -2
- package/lib/capabilities.ts +0 -1
- package/lib/imports.ts +83 -79
- package/lib/list.ts +6 -6
- package/package.json +1 -1
- package/types/index.ts +0 -1
- package/types/importConfig/index.ts +0 -1
- package/types/importConfig/schema.json +0 -67
package/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type CatalogPlugin from '@data-fair/types-catalogs'
|
|
2
|
-
import {
|
|
2
|
+
import { configSchema, assertConfigValid, type OneGeoSuiteConfig } from '#types'
|
|
3
3
|
import { type OneGeoCapabilities, capabilities } from './lib/capabilities.ts'
|
|
4
4
|
import i18n from './lib/i18n.ts'
|
|
5
5
|
|
|
@@ -30,7 +30,6 @@ const plugin: CatalogPlugin<OneGeoSuiteConfig, OneGeoCapabilities> = {
|
|
|
30
30
|
capabilities
|
|
31
31
|
},
|
|
32
32
|
|
|
33
|
-
importConfigSchema,
|
|
34
33
|
configSchema,
|
|
35
34
|
assertConfigValid
|
|
36
35
|
}
|
package/lib/capabilities.ts
CHANGED
package/lib/imports.ts
CHANGED
|
@@ -4,74 +4,38 @@ import { apiList, formatsList, sortList } from './list.ts'
|
|
|
4
4
|
|
|
5
5
|
import axios from '@data-fair/lib-node/axios.js'
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
format = sortList(catalog._source['metadata-fr'].link.find((x: Link) => { return (x.service === service || x.url === service) && x.formats.find((y: string) => { return formatsList.includes(y) }) }).formats, formatsList)[0]
|
|
17
|
-
if (!format) throw Error(`resource not found for service ${service}`)
|
|
18
|
-
} else {
|
|
19
|
-
if (!service) {
|
|
20
|
-
const links = catalog._source['metadata-fr'].link.filter((x: Link) => { return x.formats.includes(format) })
|
|
21
|
-
service = sortList(links.map((x: Link) => x.service), apiList)[0]
|
|
22
|
-
if (!service) throw Error(`resource not found for format ${format}`)
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
if (!catalog) throw Error(`resource not found for ${resourceId} in ${catalogConfig.url}`)
|
|
27
|
-
if (!service) throw Error('resource not found')
|
|
28
|
-
if (!format) throw Error(`resource not found for service ${service}`)
|
|
29
|
-
|
|
30
|
-
// filter links by format and service
|
|
31
|
-
const source: Link = catalog._source['metadata-fr'].link.find((x: Link) => {
|
|
32
|
-
return x.service === service || x.url === service
|
|
33
|
-
})
|
|
34
|
-
if (!source) throw Error('resource not found')
|
|
35
|
-
// table of format for make WFS url
|
|
36
|
-
const wfsTable: Record<string, string> = {
|
|
37
|
-
CSV: 'csv',
|
|
38
|
-
JSON: 'application/json',
|
|
39
|
-
GeoJSON: 'application/json',
|
|
40
|
-
'Shapefile (zip)': 'SHAPE-ZIP',
|
|
41
|
-
'SHAPE-ZIP': 'SHAPE-ZIP',
|
|
42
|
-
KML: 'kml',
|
|
43
|
-
}
|
|
44
|
-
// table of format
|
|
45
|
-
const extensionTable: Record<string, string> = {
|
|
46
|
-
CSV: '.csv',
|
|
47
|
-
GeoJSON: '.geojson',
|
|
48
|
-
JSON: '.json',
|
|
49
|
-
'Shapefile (zip)': '.zip',
|
|
50
|
-
'SHAPE-ZIP': '.zip',
|
|
51
|
-
KML: '.kml',
|
|
52
|
-
'Excel non structuré': '.xlsx',
|
|
53
|
-
'Microsoft Excel': '.xls',
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let downloadUrl: string
|
|
57
|
-
if (source.service === 'WS') {
|
|
58
|
-
if (extensionTable[format] === undefined) throw Error(`Format ${format} not valid for ${service}`)
|
|
59
|
-
downloadUrl = `${source.url}/${source.name}/all${extensionTable[format]}`
|
|
60
|
-
} else if (source.service === undefined) {
|
|
61
|
-
downloadUrl = `${source.url}`
|
|
62
|
-
} else if (source.service === 'WFS') {
|
|
63
|
-
if (wfsTable[format] === undefined) throw Error(`Format ${format} not valid for ${service}`)
|
|
64
|
-
downloadUrl = `${source.url}?SERVICE=WFS&VERSION=2.0.0&request=GetFeature&typename=${source.name}&outputFormat=${wfsTable[format]}&startIndex=0&sortby=gid`
|
|
65
|
-
} else {
|
|
66
|
-
downloadUrl = `${source.url}`
|
|
67
|
-
}
|
|
7
|
+
// table of format -> extension
|
|
8
|
+
const wfsTable: Record<string, string> = {
|
|
9
|
+
CSV: 'csv',
|
|
10
|
+
JSON: 'application/json',
|
|
11
|
+
GeoJSON: 'application/json',
|
|
12
|
+
'Shapefile (zip)': 'SHAPE-ZIP',
|
|
13
|
+
'SHAPE-ZIP': 'SHAPE-ZIP',
|
|
14
|
+
KML: 'kml',
|
|
15
|
+
}
|
|
68
16
|
|
|
69
|
-
|
|
17
|
+
// table of format -> extension
|
|
18
|
+
const extensionTable: Record<string, string> = {
|
|
19
|
+
CSV: '.csv',
|
|
20
|
+
GeoJSON: '.geojson',
|
|
21
|
+
JSON: '.json',
|
|
22
|
+
'Shapefile (zip)': '.zip',
|
|
23
|
+
'SHAPE-ZIP': '.zip',
|
|
24
|
+
KML: '.kml',
|
|
25
|
+
'Excel non structuré': '.xlsx',
|
|
26
|
+
'Microsoft Excel': '.xls',
|
|
27
|
+
}
|
|
70
28
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
29
|
+
export const getResource = async ({
|
|
30
|
+
catalogConfig,
|
|
31
|
+
resourceId,
|
|
32
|
+
tmpDir,
|
|
33
|
+
log
|
|
34
|
+
}: GetResourceContext<OneGeoSuiteConfig>): ReturnType<CatalogPlugin['getResource']> => {
|
|
35
|
+
const catalog = (await axios.get(new URL(`fr/indexer/elastic/_search/?q=uuid.keyword:${resourceId}%20AND%20is_metadata:true`, catalogConfig.url).href)).data.hits.hits[0]
|
|
36
|
+
if (!catalog) throw Error(`resource not found for ${resourceId} in ${catalogConfig.url}`)
|
|
74
37
|
|
|
38
|
+
// get origine url
|
|
75
39
|
const axiosPortail = axios.create({
|
|
76
40
|
validateStatus: function (status) {
|
|
77
41
|
return status >= 200 && status < 500
|
|
@@ -86,19 +50,57 @@ export const getResource = async ({ catalogConfig, importConfig, resourceId, tmp
|
|
|
86
50
|
}
|
|
87
51
|
const origin = portail ? `${catalogConfig.url}/${portail}/jeux-de-donnees/${catalog._source.slug}/info` : ''
|
|
88
52
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
responseType: 'stream',
|
|
53
|
+
const links: Link[] = catalog._source['metadata-fr'].link.filter((x: Link) => {
|
|
54
|
+
return apiList.includes(x.service) && x.formats.find((y: string) => {
|
|
55
|
+
return formatsList.includes(y)
|
|
93
56
|
})
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
// list all url possible
|
|
60
|
+
let downloadUrls: { url: string, format: string, service: string | undefined, description: string | undefined }[] = []
|
|
61
|
+
|
|
62
|
+
for (const link of links) {
|
|
63
|
+
const formats = link.formats.filter((f: string) => {
|
|
64
|
+
return formatsList.includes(f)
|
|
65
|
+
})
|
|
66
|
+
for (const format of formats) {
|
|
67
|
+
if (link.service === 'WS' && extensionTable[format]) {
|
|
68
|
+
downloadUrls.push({ url: `${link.url}/${link.name}/all${extensionTable[format]}`, format, service: link.service, description: link.description })
|
|
69
|
+
} else if (link.service === undefined) {
|
|
70
|
+
downloadUrls.push({ url: `${link.url}`, format, service: link.service, description: link.description })
|
|
71
|
+
} else if (link.service === 'WFS' && wfsTable[format]) {
|
|
72
|
+
downloadUrls.push({ url: `${link.url}?SERVICE=WFS&VERSION=2.0.0&request=GetFeature&typename=${link.name}&outputFormat=${wfsTable[format]}`, format, service: link.service, description: link.description })
|
|
73
|
+
}
|
|
97
74
|
}
|
|
75
|
+
}
|
|
76
|
+
downloadUrls = sortList(downloadUrls, apiList, (x: any) => { return x.service })
|
|
77
|
+
downloadUrls = sortList(downloadUrls, formatsList, (x: any) => { return x.format })
|
|
98
78
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
79
|
+
// Download the resource
|
|
80
|
+
const fs = await import('node:fs')
|
|
81
|
+
const path = await import('path')
|
|
82
|
+
let response
|
|
83
|
+
let format: string
|
|
84
|
+
let description: string | undefined
|
|
85
|
+
|
|
86
|
+
for (const downloadUrl of downloadUrls) {
|
|
87
|
+
await log.step(`Downloading the file ${downloadUrl.url}; format: ${downloadUrl.format}; service: ${downloadUrl.service}`)
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
response = await axios.get(downloadUrl.url, {
|
|
91
|
+
responseType: 'stream',
|
|
92
|
+
})
|
|
93
|
+
if (response.headers['content-type'] === 'text/html') {
|
|
94
|
+
response = undefined
|
|
95
|
+
throw Error('return HTML page')
|
|
96
|
+
}
|
|
97
|
+
format = downloadUrl.format
|
|
98
|
+
description = downloadUrl.description
|
|
99
|
+
await log.info(`Get file with ${downloadUrl.url} successfully! ${response.status}`)
|
|
100
|
+
} catch (e) {
|
|
101
|
+
await log.warning(`Downloading fail with this url: ${downloadUrl}; ${e}`)
|
|
102
|
+
}
|
|
103
|
+
if (response) break
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
if (!response) {
|
|
@@ -106,7 +108,7 @@ export const getResource = async ({ catalogConfig, importConfig, resourceId, tmp
|
|
|
106
108
|
}
|
|
107
109
|
|
|
108
110
|
// Create a filename
|
|
109
|
-
const fileName = catalog._source.slug + extensionTable[format]
|
|
111
|
+
const fileName = catalog._source.slug + extensionTable[format!]
|
|
110
112
|
const filePath = path.join(tmpDir, fileName)
|
|
111
113
|
await log.info(`Downloading resource to ${fileName}`)
|
|
112
114
|
|
|
@@ -149,9 +151,9 @@ export const getResource = async ({ catalogConfig, importConfig, resourceId, tmp
|
|
|
149
151
|
id: resourceId,
|
|
150
152
|
slug: catalog._source.slug,
|
|
151
153
|
title: catalog._source['metadata-fr'].title,
|
|
152
|
-
description:
|
|
154
|
+
description: description ?? catalog._source['metadata-fr'].abstratc,
|
|
153
155
|
filePath,
|
|
154
|
-
format
|
|
156
|
+
format: format!,
|
|
155
157
|
frequency,
|
|
156
158
|
license: {
|
|
157
159
|
href: '',
|
|
@@ -159,7 +161,9 @@ export const getResource = async ({ catalogConfig, importConfig, resourceId, tmp
|
|
|
159
161
|
},
|
|
160
162
|
keywords: catalog._source['metadata-fr'].keyword,
|
|
161
163
|
updatedAt: catalog._source['metadata-fr'].lastUpdateDate ?? undefined,
|
|
162
|
-
image: catalog._source['metadata-fr'].image.find((x: { type: string, url: string | null }) => {
|
|
164
|
+
image: catalog._source['metadata-fr'].image.find((x: { type: string, url: string | null }) => {
|
|
165
|
+
return x.type === 'thumbnail' && !!x.url
|
|
166
|
+
})?.url ?? null,
|
|
163
167
|
origin
|
|
164
168
|
}
|
|
165
169
|
}
|
package/lib/list.ts
CHANGED
|
@@ -7,7 +7,7 @@ type ResourceList = Awaited<ReturnType<CatalogPlugin['list']>>['results']
|
|
|
7
7
|
|
|
8
8
|
export const apiList: Array<string | undefined> = ['WS', 'WFS', undefined]
|
|
9
9
|
export const formatsList = [
|
|
10
|
-
'
|
|
10
|
+
'GeoJSON', 'SHAPE-ZIP', 'Shapefile (zip)', 'CSV', 'JSON', 'Excel non structuré', 'Microsoft Excel', 'KML']
|
|
11
11
|
|
|
12
12
|
const extensionTable: Record<string, string> = {
|
|
13
13
|
CSV: '.csv',
|
|
@@ -20,10 +20,10 @@ const extensionTable: Record<string, string> = {
|
|
|
20
20
|
'Microsoft Excel': '.xls',
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export const sortList = (formats: any[], reference: any[]) => {
|
|
23
|
+
export const sortList = (formats: any[], reference: any[], func = (x: any) => { return x }) => {
|
|
24
24
|
return [...formats].sort((a, b) =>
|
|
25
|
-
(reference.indexOf(a) === -1 ? reference.length : reference.indexOf(a)) -
|
|
26
|
-
(reference.indexOf(b) === -1 ? reference.length : reference.indexOf(b))
|
|
25
|
+
(reference.indexOf(func(a)) === -1 ? reference.length : reference.indexOf(func(a))) -
|
|
26
|
+
(reference.indexOf(func(b)) === -1 ? reference.length : reference.indexOf(func(b)))
|
|
27
27
|
)
|
|
28
28
|
}
|
|
29
29
|
const baseReqDataset = (input: string = '*', size: number = 500, from: number = 1) => {
|
|
@@ -47,7 +47,7 @@ const baseReqDataset = (input: string = '*', size: number = 500, from: number =
|
|
|
47
47
|
}
|
|
48
48
|
}]
|
|
49
49
|
}
|
|
50
|
-
}, { term: { is_metadata: true } }, { term: { 'editorial-metadata.
|
|
50
|
+
}, { term: { is_metadata: true } }, { term: { 'editorial-metadata.defaultPermissionLevel': 3 } }, {
|
|
51
51
|
bool: {
|
|
52
52
|
should: [
|
|
53
53
|
...apiList.filter((x: any) => { return x }).map((x: any) => { return { term: { 'metadata-fr.link.service.keyword': x } } }),
|
|
@@ -87,7 +87,7 @@ const countReq = (input: string = '*') => {
|
|
|
87
87
|
}
|
|
88
88
|
}]
|
|
89
89
|
}
|
|
90
|
-
}, { term: { is_metadata: true } }, { term: { 'editorial-metadata.
|
|
90
|
+
}, { term: { is_metadata: true } }, { term: { 'editorial-metadata.defaultPermissionLevel': 3 } }, {
|
|
91
91
|
bool: {
|
|
92
92
|
should: [
|
|
93
93
|
...apiList.filter((x: any) => x).map((x: any) => ({ term: { 'metadata-fr.link.service.keyword': x } })),
|
package/package.json
CHANGED
package/types/index.ts
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './.type/index.js'
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$id": "https://github.com/data-fair/catalog-onegeo-suite/import-config",
|
|
3
|
-
"x-exports": [
|
|
4
|
-
"schema"
|
|
5
|
-
],
|
|
6
|
-
"title": "ImportConfig",
|
|
7
|
-
"type": "object",
|
|
8
|
-
"additionalProperties": false,
|
|
9
|
-
"required": [],
|
|
10
|
-
"properties": {
|
|
11
|
-
"service": {
|
|
12
|
-
"type": "string",
|
|
13
|
-
"title": "Web Service",
|
|
14
|
-
"x-i18n-title": {
|
|
15
|
-
"fr": "Service Web"
|
|
16
|
-
},
|
|
17
|
-
"description": "This resource is available from multiple sources (web services, local files). Select the source you want to use for the import.",
|
|
18
|
-
"x-i18n-description": {
|
|
19
|
-
"fr": "Cette ressource est disponible via plusieurs sources (services web, fichiers locaux). Sélectionnez la source que vous souhaitez utiliser pour l'import."
|
|
20
|
-
},
|
|
21
|
-
"layout": {
|
|
22
|
-
"cols": 6,
|
|
23
|
-
"getItems": {
|
|
24
|
-
"url": "${context.catalogConfig.url}/fr/indexer/elastic/_search/?q=uuid.keyword:${context.resourceId}%20AND%20is_metadata:true",
|
|
25
|
-
"itemsResults": "(function() { const links = data.hits.hits[0]._source['metadata-fr'].link; return links.filter(l => l.formats.find(f => ['CSV', 'Excel non structuré', 'Microsoft Excel','ZIP', 'Shapefile (zip)', 'SHAPE-ZIP', 'GeoJSON', 'JSON', 'KML'].includes(f)) && ['WS', 'WFS', undefined].includes(l.service)).map((l, i) => [l, i] ); })()",
|
|
26
|
-
"itemTitle": "item[0].service?? 'Local N°' + (item[1] + 1)",
|
|
27
|
-
"itemValue": "item[0].service?? item[0].url"
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"format": {
|
|
32
|
-
"type": "string",
|
|
33
|
-
"title": "Format",
|
|
34
|
-
"description": "Import format, if no service is set, the possible formats are unknown.",
|
|
35
|
-
"x-i18n-description": {
|
|
36
|
-
"fr": "Format d’importation, si aucun service n’est défini, les formats possibles sont inconnus."
|
|
37
|
-
},
|
|
38
|
-
"layout": {
|
|
39
|
-
"if": "parent.data.service != null",
|
|
40
|
-
"cols": 6,
|
|
41
|
-
"getItems": {
|
|
42
|
-
"url": "${context.catalogConfig.url}/fr/indexer/elastic/_search/?q=${parent.data.service}&q=uuid.keyword:${context.resourceId}%20AND%20is_metadata:true",
|
|
43
|
-
"itemsResults": "(function(){ const service = data.hits.hits[0]._source['metadata-fr'].link.find(x => x.service === parent.data.service || x.url === parent.data.service); let formats = service.formats; if (['WS', 'WFS'].includes(service.service) && !formats.includes('CSV')) {formats.push('CSV');} return formats.filter(f => ['CSV', 'Excel non structuré', 'Microsoft Excel','ZIP', 'Shapefile (zip)', 'SHAPE-ZIP', 'GeoJSON', 'JSON', 'KML'].includes(f));})()"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
|
-
"format2": {
|
|
48
|
-
"type": "string",
|
|
49
|
-
"title": "Format",
|
|
50
|
-
"description": "Import format, if no service is set, the possible formats are unknown.",
|
|
51
|
-
"x-i18n-description": {
|
|
52
|
-
"fr": "Format d’importation, si aucun service n’est défini, les formats possibles sont inconnus."
|
|
53
|
-
},
|
|
54
|
-
"layout": {
|
|
55
|
-
"if": "parent.data.service == null",
|
|
56
|
-
"cols": 6,
|
|
57
|
-
"getItems": {
|
|
58
|
-
"url": "https://httpbin.org/get",
|
|
59
|
-
"itemsResults": "(function(){return ['CSV', 'Excel non structuré', 'Microsoft Excel','ZIP', 'Shapefile (zip)', 'SHAPE-ZIP', 'GeoJSON', 'JSON', 'KML']})()"
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
"layout": {
|
|
65
|
-
"title": null
|
|
66
|
-
}
|
|
67
|
-
}
|