@data-fair/catalog-onegeo-suite 0.1.4 → 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 CHANGED
@@ -1,5 +1,5 @@
1
1
  import type CatalogPlugin from '@data-fair/types-catalogs'
2
- import { importConfigSchema, configSchema, assertConfigValid, type OneGeoSuiteConfig } from '#types'
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
  }
@@ -11,7 +11,6 @@ export const capabilities = [
11
11
  'pagination',
12
12
 
13
13
  'import',
14
- 'importConfig',
15
14
 
16
15
  ] satisfies Capability[]
17
16
 
package/lib/imports.ts CHANGED
@@ -4,65 +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
- export const getResource = async ({ catalogConfig, importConfig, resourceId, tmpDir, log }: GetResourceContext<OneGeoSuiteConfig>): ReturnType<CatalogPlugin['getResource']> => {
8
- let format: string = importConfig.format
9
- let service: string = importConfig.service
10
- const catalog = (await axios.get(new URL(`fr/indexer/elastic/_search/?q=_id:${resourceId}`, catalogConfig.url).href)).data.hits.hits[0]
11
- if (!format) {
12
- if (!service) {
13
- const links = catalog._source['metadata-fr'].link.filter((x: any) => { return apiList.includes(x.service) && x.formats.find((y: string) => { return formatsList.includes(y) }) })
14
- service = sortList(links.map((x: Link) => x.service), apiList)[0]
15
- }
16
- format = sortList(catalog._source['metadata-fr'].link.find((x: Link) => { return x.service === service && x.formats.find((y: string) => { return formatsList.includes(y) }) }).formats, formatsList)[0]
17
- }
18
-
19
- if (!catalog) {
20
- throw Error(`resource ${service} not found for ${resourceId} in ${catalogConfig.url}`)
21
- }
22
-
23
- // filter links by format and service
24
- const source: Link = catalog._source['metadata-fr'].link.find((x: Link) => {
25
- return x.service === service || x.url === service
26
- })
27
-
28
- // table of format for make WFS url
29
- const wfsTable: Record<string, string> = {
30
- CSV: 'csv',
31
- JSON: 'application/json',
32
- GeoJSON: 'application/json',
33
- 'Shapefile (zip)': 'SHAPE-ZIP',
34
- 'SHAPE-ZIP': 'SHAPE-ZIP',
35
- KML: 'kml',
36
- }
37
- // table of format
38
- const extensionTable: Record<string, string> = {
39
- CSV: '.csv',
40
- GeoJSON: '.geojson',
41
- JSON: '.json',
42
- 'Shapefile (zip)': '.zip',
43
- 'SHAPE-ZIP': '.zip',
44
- KML: '.kml',
45
- 'Excel non structuré': '.xlsx',
46
- 'Microsoft Excel': '.xls',
47
- }
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
+ }
48
16
 
49
- let downloadUrl: string
50
- if (source.service === 'WS') {
51
- downloadUrl = `${source.url}/${source.name}/all${extensionTable[format]}`
52
- } else if (source.service === undefined) {
53
- downloadUrl = `${source.url}`
54
- } else if (source.service === 'WFS') {
55
- downloadUrl = `${source.url}?SERVICE=WFS&VERSION=2.0.0&request=GetFeature&typename=${source.name}&outputFormat=${wfsTable[format]}&startIndex=0&sortby=gid`
56
- } else {
57
- downloadUrl = `${source.url}`
58
- }
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
+ }
59
28
 
60
- await log.step(`Downloading the file ${downloadUrl}`)
61
-
62
- // Download the resource
63
- const fs = await import('node:fs')
64
- const path = await import('path')
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}`)
65
37
 
38
+ // get origine url
66
39
  const axiosPortail = axios.create({
67
40
  validateStatus: function (status) {
68
41
  return status >= 200 && status < 500
@@ -77,19 +50,57 @@ export const getResource = async ({ catalogConfig, importConfig, resourceId, tmp
77
50
  }
78
51
  const origin = portail ? `${catalogConfig.url}/${portail}/jeux-de-donnees/${catalog._source.slug}/info` : ''
79
52
 
80
- let response
81
- try {
82
- response = await axios.get(downloadUrl, {
83
- 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)
56
+ })
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)
84
65
  })
85
- if (response.headers['content-type'] === 'text/html') {
86
- response = undefined
87
- throw Error('return HTML page')
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
+ }
88
74
  }
75
+ }
76
+ downloadUrls = sortList(downloadUrls, apiList, (x: any) => { return x.service })
77
+ downloadUrls = sortList(downloadUrls, formatsList, (x: any) => { return x.format })
89
78
 
90
- await log.info(`Get file with ${downloadUrl} successfully! ${response.status}`)
91
- } catch (e) {
92
- await log.warning(`Get file fail with this url: ${downloadUrl}; ${e}`)
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
93
104
  }
94
105
 
95
106
  if (!response) {
@@ -97,7 +108,7 @@ export const getResource = async ({ catalogConfig, importConfig, resourceId, tmp
97
108
  }
98
109
 
99
110
  // Create a filename
100
- const fileName = catalog._source.slug + extensionTable[format]
111
+ const fileName = catalog._source.slug + extensionTable[format!]
101
112
  const filePath = path.join(tmpDir, fileName)
102
113
  await log.info(`Downloading resource to ${fileName}`)
103
114
 
@@ -140,9 +151,9 @@ export const getResource = async ({ catalogConfig, importConfig, resourceId, tmp
140
151
  id: resourceId,
141
152
  slug: catalog._source.slug,
142
153
  title: catalog._source['metadata-fr'].title,
143
- description: source.description ?? catalog._source['metadata-fr'].abstratc,
154
+ description: description ?? catalog._source['metadata-fr'].abstratc,
144
155
  filePath,
145
- format,
156
+ format: format!,
146
157
  frequency,
147
158
  license: {
148
159
  href: '',
@@ -150,7 +161,9 @@ export const getResource = async ({ catalogConfig, importConfig, resourceId, tmp
150
161
  },
151
162
  keywords: catalog._source['metadata-fr'].keyword,
152
163
  updatedAt: catalog._source['metadata-fr'].lastUpdateDate ?? undefined,
153
- image: catalog._source['metadata-fr'].image.find((x: { type: string, url: string | null }) => { return x.type === 'thumbnail' && !!x.url })?.url ?? 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,
154
167
  origin
155
168
  }
156
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
- 'CSV', 'Excel non structuré', 'Microsoft Excel', 'Shapefile (zip)', 'SHAPE-ZIP', 'GeoJSON', 'JSON', 'KML']
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,13 +20,13 @@ 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
- const baseReqDataset = (input: string = '*', size: number = 100, from: number = 1) => {
29
+ const baseReqDataset = (input: string = '*', size: number = 500, from: number = 1) => {
30
30
  return {
31
31
  from: (from - 1) * size,
32
32
  size: Math.min(size, 10000),
@@ -47,7 +47,7 @@ const baseReqDataset = (input: string = '*', size: number = 100, from: number =
47
47
  }
48
48
  }]
49
49
  }
50
- }, { term: { is_metadata: true } }, {
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 } }, {
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 } })),
@@ -121,7 +121,13 @@ const countReq = (input: string = '*') => {
121
121
  export const list = async ({ catalogConfig, params }: ListContext<OneGeoSuiteConfig, OneGeoCapabilities>): ReturnType<CatalogPlugin['list']> => {
122
122
  const url = catalogConfig.url
123
123
  const listResources = async (params: Record<any, any>) => {
124
- const catalogs = (await axios.post(new URL('fr/indexer/elastic/_search/', url).href, baseReqDataset(params.q || '*', params.size, params.page))).data.hits.hits
124
+ let catalogs
125
+ try {
126
+ catalogs = (await axios.post(new URL('fr/indexer/elastic/_search/', url).href, baseReqDataset(params.q || '*', params.size, params.page))).data.hits.hits
127
+ } catch (e) {
128
+ // @ts-ignore
129
+ throw Error(`Axios error: ${e?.status ?? ''} ${e?.message}`)
130
+ }
125
131
  const count = (await axios.post(new URL('fr/indexer/elastic/_search/', url).href, countReq(params.q))).data.aggregations.unique_datasets.value
126
132
  const res = []
127
133
 
@@ -151,7 +157,7 @@ export const list = async ({ catalogConfig, params }: ListContext<OneGeoSuiteCon
151
157
  formats = formats.map(x => extensionTable[x]?.slice(1) ?? x)
152
158
 
153
159
  res.push({
154
- id: `${catalog._id}`,
160
+ id: `${catalog._source.uuid}`,
155
161
  title: catalog._source['metadata-fr'].title,
156
162
  description: sources[0].description,
157
163
  format: formats.slice(0, 3).join(', ') + (formats.length ? '..' : ''),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@data-fair/catalog-onegeo-suite",
3
3
  "description": "OneGeoSuite plugin for the Data Fair catalogs service.",
4
- "version": "0.1.4",
4
+ "version": "0.1.8",
5
5
  "main": "index.ts",
6
6
  "type": "module",
7
7
  "scripts": {
@@ -29,8 +29,8 @@ export const schema = {
29
29
  "layout": {
30
30
  "cols": 6,
31
31
  "getItems": {
32
- "url": "${context.catalogConfig.url}/fr/indexer/elastic/_search/?q=_id:${context.resourceId}",
33
- "itemsResults": "(function() { const links = data.hits.hits[0]._source['metadata-fr'].link; return links.filter(l => l.formats.find(f => ['CSV', 'ODS', 'Excel non structuré', 'Microsoft Excel','ZIP', 'Shapefile (zip)', 'GeoJSON', 'JSON', 'XML', 'GML', 'KML'].includes(f)) || ['WS', 'AFS', 'WFS'].includes(l.service)).map((l, i) => [l, i] ); })()",
32
+ "url": "${context.catalogConfig.url}/fr/indexer/elastic/_search/?q=uuid.keyword:${context.resourceId}%20AND%20is_metadata:true",
33
+ "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] ); })()",
34
34
  "itemTitle": "item[0].service?? 'Local N°' + (item[1] + 1)",
35
35
  "itemValue": "item[0].service?? item[0].url"
36
36
  }
@@ -39,12 +39,32 @@ export const schema = {
39
39
  "format": {
40
40
  "type": "string",
41
41
  "title": "Format",
42
+ "description": "Import format, if no service is set, the possible formats are unknown.",
43
+ "x-i18n-description": {
44
+ "fr": "Format d’importation, si aucun service n’est défini, les formats possibles sont inconnus."
45
+ },
42
46
  "layout": {
43
47
  "if": "parent.data.service != null",
44
48
  "cols": 6,
45
49
  "getItems": {
46
- "url": "${context.catalogConfig.url}/fr/indexer/elastic/_search/?q=${parent.data.service}&q=_id:${context.resourceId}",
47
- "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', 'AFS'].includes(service.service) && !formats.includes('CSV')) {formats.push('CSV');} return formats; })()"
50
+ "url": "${context.catalogConfig.url}/fr/indexer/elastic/_search/?q=${parent.data.service}&q=uuid.keyword:${context.resourceId}%20AND%20is_metadata:true",
51
+ "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));})()"
52
+ }
53
+ }
54
+ },
55
+ "format2": {
56
+ "type": "string",
57
+ "title": "Format",
58
+ "description": "Import format, if no service is set, the possible formats are unknown.",
59
+ "x-i18n-description": {
60
+ "fr": "Format d’importation, si aucun service n’est défini, les formats possibles sont inconnus."
61
+ },
62
+ "layout": {
63
+ "if": "parent.data.service == null",
64
+ "cols": 6,
65
+ "getItems": {
66
+ "url": "https://httpbin.org/get",
67
+ "itemsResults": "(function(){return ['CSV', 'Excel non structuré', 'Microsoft Excel','ZIP', 'Shapefile (zip)', 'SHAPE-ZIP', 'GeoJSON', 'JSON', 'KML']})()"
48
68
  }
49
69
  }
50
70
  }
package/types/index.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  export { schema as configSchema, assertValid as assertConfigValid, type OneGeoSuiteConfig } from './catalogConfig/index.ts'
2
- export { schema as importConfigSchema } from './importConfig/index.ts'
3
2
 
4
3
  export type Link = {
5
4
  _main: boolean,
@@ -1 +0,0 @@
1
- export * from './.type/index.js'
@@ -1,47 +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=_id:${context.resourceId}",
25
- "itemsResults": "(function() { const links = data.hits.hits[0]._source['metadata-fr'].link; return links.filter(l => l.formats.find(f => ['CSV', 'ODS', 'Excel non structuré', 'Microsoft Excel','ZIP', 'Shapefile (zip)', 'GeoJSON', 'JSON', 'XML', 'GML', 'KML'].includes(f)) || ['WS', 'AFS', 'WFS'].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
- "layout": {
35
- "if": "parent.data.service != null",
36
- "cols": 6,
37
- "getItems": {
38
- "url": "${context.catalogConfig.url}/fr/indexer/elastic/_search/?q=${parent.data.service}&q=_id:${context.resourceId}",
39
- "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', 'AFS'].includes(service.service) && !formats.includes('CSV')) {formats.push('CSV');} return formats; })()"
40
- }
41
- }
42
- }
43
- },
44
- "layout": {
45
- "title": null
46
- }
47
- }