mirror of
https://github.com/dadosfera/maestro.git
synced 2026-09-01 20:28:17 +00:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b736cddf07 | ||
|
|
007f3911ff |
@@ -1,12 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
.git
|
||||
*.log
|
||||
npm-debug.log*
|
||||
.DS_Store
|
||||
.env
|
||||
.env.*
|
||||
coverage
|
||||
.nyc_output
|
||||
*.tgz
|
||||
!protospack.tgz
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
FROM node:22-alpine AS base_image
|
||||
FROM node:20-alpine AS base_image
|
||||
RUN npm install -g npm@latest
|
||||
|
||||
FROM base_image AS build_base
|
||||
|
||||
@@ -48,9 +48,6 @@ spec:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
{{- end }}
|
||||
env:
|
||||
# Auth Provider Configuration (cognito or keycloak)
|
||||
- name: AUTH_PROVIDER
|
||||
value: {{ .Values.maestro.auth_provider | default "cognito" | quote }}
|
||||
- name: AWS_IDENTITY_POOL_ID
|
||||
value: {{ .Values.maestro.aws_identity_pool_id }}
|
||||
- name: AWS_REGION
|
||||
@@ -111,8 +108,6 @@ spec:
|
||||
value: "{{ .Values.maestro.redis_tls }}"
|
||||
- name: PLATFORM_API_URL
|
||||
value: {{ .Values.maestro.platform_api_url }}
|
||||
- name: STORAGE_EXPLORER_API_URL
|
||||
value: {{ .Values.maestro.storage_explorer_api_url | quote }}
|
||||
- name: JWT_PRIVATE_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
|
||||
@@ -27,9 +27,6 @@ resources:
|
||||
cpu: 2000m
|
||||
memory: 2Gi
|
||||
maestro:
|
||||
# Auth provider: "cognito" (default) or "keycloak"
|
||||
# Note: maestro doesn't connect to Keycloak directly, only duc does
|
||||
auth_provider: "cognito"
|
||||
aws_identity_pool_id: "us-east-1_Mrezsw9Sn"
|
||||
duc_url: duc.dadosfera.ai
|
||||
in_factory_url: in-factory.dadosfera.ai
|
||||
@@ -47,7 +44,6 @@ maestro:
|
||||
open_customer_id: f239718a-a271-4ef9-ae7e-02a2f0f3aa6e
|
||||
open_group_id: 401573bb-334f-44b2-b30e-88d4cea31ae9
|
||||
platform_api_url: https://oz8v2zid1e.execute-api.us-east-1.amazonaws.com
|
||||
storage_explorer_api_url: "https://storage-explorer-{customer_id}.prd.dadosfera.ai/api"
|
||||
dedicated_proxy: ""
|
||||
restricted_ip: ""
|
||||
redis_host: "aaapzppmlyamkocqwstpo7zvopczyyiyuy6xzm2g6c5k4mq3a66be4a-0.redis.sa-saopaulo-1.oci.oraclecloud.com"
|
||||
|
||||
+15
-813
@@ -213,7 +213,14 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
@@ -5454,66 +5461,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/customers/{id}/organization-info": {
|
||||
"get": {
|
||||
"operationId": "CustomersController_getOrganizationInfo",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Organization information"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Customers"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"put": {
|
||||
"operationId": "CustomersController_updateOrganizationInfo",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Organization information updated"
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Customers"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/catalog/data-asset/share/{id}": {
|
||||
"get": {
|
||||
"operationId": "ShareController_getShareDataAsset",
|
||||
@@ -7767,748 +7714,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/tables/validate-name": {
|
||||
"post": {
|
||||
"operationId": "StorageExplorerController_validateTableName",
|
||||
"summary": "Validate table name in PostgreSQL and Snowflake",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/tables": {
|
||||
"post": {
|
||||
"operationId": "StorageExplorerController_createTable",
|
||||
"summary": "Create a new table",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_listTables",
|
||||
"summary": "List all tables with pagination",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "page",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/tables/{tableId}": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_getTable",
|
||||
"summary": "Get table details by ID",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tableId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/tables/{tableId}/datasets/{datasetId}": {
|
||||
"post": {
|
||||
"operationId": "StorageExplorerController_linkDatasetToTable",
|
||||
"summary": "Link a dataset to a table",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tableId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "datasetId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/tables/{tableId}/datasets": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_getTableDatasets",
|
||||
"summary": "Get all datasets linked to a table",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tableId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/tables/{tableId}/schema": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_getTableSchema",
|
||||
"summary": "Get table schema",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tableId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/tables/{tableId}/validate-compatibility/{datasetId}": {
|
||||
"post": {
|
||||
"operationId": "StorageExplorerController_validateSchemaCompatibility",
|
||||
"summary": "Validate schema compatibility between table and dataset",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "tableId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "datasetId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/datasets/{datasetId}/preview": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_getDatasetPreview",
|
||||
"summary": "Get dataset preview data",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "datasetId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/datasets/{datasetId}/schema": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_getDatasetSchema",
|
||||
"summary": "Get dataset schema information",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "datasetId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "force_refresh",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/datasets/upload/{uploadId}": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_listDatasetsByUpload",
|
||||
"summary": "List all datasets for a specific upload",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "uploadId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/datasets/{datasetId}/refresh-schema": {
|
||||
"put": {
|
||||
"operationId": "StorageExplorerController_refreshDatasetSchema",
|
||||
"summary": "Refresh dataset schema with new parsing options (Excel)",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "datasetId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/storage/uploads/history": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_listFileExplorerUploads",
|
||||
"summary": "List file explorer uploads with pagination",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "page",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "folder_path",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/storage/browse": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_browseStorage",
|
||||
"summary": "Browse folders and files in storage",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "path",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/storage/upload/batch": {
|
||||
"post": {
|
||||
"operationId": "StorageExplorerController_batchUpload",
|
||||
"summary": "Upload multiple files to storage",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/storage/folder/create": {
|
||||
"post": {
|
||||
"operationId": "StorageExplorerController_createFolder",
|
||||
"summary": "Create a new folder in storage",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/storage/download": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_downloadFile",
|
||||
"summary": "Download a file from storage",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "file_path",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/storage/link-to-table": {
|
||||
"post": {
|
||||
"operationId": "StorageExplorerController_linkFileToTable",
|
||||
"summary": "Link an existing file in storage to a table",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/storage-explorer/storage/metadata": {
|
||||
"get": {
|
||||
"operationId": "StorageExplorerController_getFileMetadata",
|
||||
"summary": "Get detailed file metadata",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "file_path",
|
||||
"required": true,
|
||||
"in": "query",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Storage Explorer"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"operationId": "HealthController_check",
|
||||
@@ -8964,7 +8169,7 @@
|
||||
"companyName": {
|
||||
"type": "string"
|
||||
},
|
||||
"personalSite": {
|
||||
"companySite": {
|
||||
"type": "string"
|
||||
},
|
||||
"mfaStatus": {
|
||||
@@ -8987,9 +8192,6 @@
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"authProvider": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -9002,7 +8204,7 @@
|
||||
"hierarchy",
|
||||
"bio",
|
||||
"companyName",
|
||||
"personalSite",
|
||||
"companySite",
|
||||
"mfaStatus",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
@@ -9142,7 +8344,7 @@
|
||||
"companyName": {
|
||||
"type": "string"
|
||||
},
|
||||
"personalSite": {
|
||||
"companySite": {
|
||||
"type": "string"
|
||||
},
|
||||
"customer": {
|
||||
@@ -9174,7 +8376,7 @@
|
||||
"hierarchy",
|
||||
"bio",
|
||||
"companyName",
|
||||
"personalSite",
|
||||
"companySite",
|
||||
"mfaStatus",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
@@ -9318,7 +8520,7 @@
|
||||
"bio": {
|
||||
"type": "string"
|
||||
},
|
||||
"personalSite": {
|
||||
"companySite": {
|
||||
"type": "string"
|
||||
},
|
||||
"companyName": {
|
||||
@@ -9370,7 +8572,7 @@
|
||||
"companyName": {
|
||||
"type": "string"
|
||||
},
|
||||
"personalSite": {
|
||||
"companySite": {
|
||||
"type": "string"
|
||||
},
|
||||
"mfaStatus": {
|
||||
@@ -9398,7 +8600,7 @@
|
||||
"hierarchy",
|
||||
"bio",
|
||||
"companyName",
|
||||
"personalSite",
|
||||
"companySite",
|
||||
"mfaStatus",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
|
||||
Generated
+5
-4
@@ -17,7 +17,7 @@
|
||||
"@aws-sdk/signature-v4": "^3.370.0",
|
||||
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
||||
"@dadosfera/protospack": "2.5.3",
|
||||
"@dadosfera/protospack-v2": "^3.38.0-beta.26",
|
||||
"@dadosfera/protospack-v2": "3.38.0-beta.19",
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
"@grpc/proto-loader": "^0.7.9",
|
||||
"@nestjs/cli": "^9.5.0",
|
||||
@@ -1744,9 +1744,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@dadosfera/protospack-v2": {
|
||||
"version": "3.38.0-beta.26",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.38.0-beta.26.tgz",
|
||||
"integrity": "sha512-N8NS7+djLGy0wJXk00+4oupqd/wBIQ1f+YBBhK2y9x4guFXYK1KWIrPZhPj+gaU8g2KNkqKoT7SnE9PXNxlLSQ==",
|
||||
"version": "3.38.0-beta.19",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.38.0-beta.19.tgz",
|
||||
"integrity": "sha512-qevGunl1IKv4POa2hhXNaDpqlh/bvnq5Hxo6534OHYPZ//S+XcRZgTrxFnylK3+uoROM8epF3Mey5GwynxY7Tw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
"rxjs": "^7.5.5"
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
"@aws-sdk/signature-v4": "^3.370.0",
|
||||
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
||||
"@dadosfera/protospack": "2.5.3",
|
||||
"@dadosfera/protospack-v2": "^3.38.0-beta.26",
|
||||
"@dadosfera/protospack-v2": "3.38.0-beta.19",
|
||||
"@grpc/grpc-js": "^1.9.3",
|
||||
"@grpc/proto-loader": "^0.7.9",
|
||||
"@nestjs/cli": "^9.5.0",
|
||||
|
||||
@@ -34,7 +34,6 @@ import { AssignModule } from './modules/assign/assign.module';
|
||||
import { ShareMetadataModule } from './modules/share-metadata/share-metadata.module';
|
||||
import { ApiKeyModule } from './modules/api-key/api-key.module';
|
||||
import { PlatformApiModule } from './modules/platform-api/platform-api.module';
|
||||
import { StorageExplorerModule } from './modules/storage-explorer/storage-explorer.module';
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
@@ -76,7 +75,6 @@ import { StorageExplorerModule } from './modules/storage-explorer/storage-explor
|
||||
IdentityProviderModule,
|
||||
NetworkPolicyModule,
|
||||
PlatformApiModule,
|
||||
StorageExplorerModule,
|
||||
//Always leave HealthModule last, so it is on the bottom of swagger
|
||||
HealthModule,
|
||||
],
|
||||
|
||||
@@ -668,35 +668,6 @@ export const PERMISSIONS_GROUPS = {
|
||||
},
|
||||
},
|
||||
},
|
||||
STORAGE_EXPLORER: {
|
||||
title: {
|
||||
'pt-br': 'Storage Explorer',
|
||||
'en-us': 'Storage Explorer',
|
||||
'es-es': 'Storage Explorer',
|
||||
},
|
||||
permissions: {
|
||||
READ: {
|
||||
seqid: 51,
|
||||
claim: 'storage-explorer:read',
|
||||
usage: PermissionUsages.PUBLIC,
|
||||
name: {
|
||||
'pt-br': 'Ler dados do Storage Explorer',
|
||||
'en-us': 'Read Storage Explorer data',
|
||||
'es-es': 'Leer datos del Storage Explorer',
|
||||
},
|
||||
},
|
||||
WRITE: {
|
||||
seqid: 52,
|
||||
claim: 'storage-explorer:write',
|
||||
usage: PermissionUsages.PUBLIC,
|
||||
name: {
|
||||
'pt-br': 'Escrever dados no Storage Explorer',
|
||||
'en-us': 'Write Storage Explorer data',
|
||||
'es-es': 'Escribir datos en Storage Explorer',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
export interface DadosferaModule {
|
||||
name: string;
|
||||
|
||||
@@ -190,14 +190,13 @@ export class AuthController {
|
||||
) {
|
||||
this.logger.info('/auth - change-password');
|
||||
|
||||
const { oldPassword, newPassword, totpCode } = body;
|
||||
const { oldPassword, newPassword } = body;
|
||||
const { authorization: accessToken } = headers;
|
||||
|
||||
return this.authClient.changePassword({
|
||||
accessToken,
|
||||
oldPassword,
|
||||
newPassword,
|
||||
totpCode,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -215,8 +214,7 @@ export class AuthController {
|
||||
|
||||
const { username } = body;
|
||||
|
||||
await this.authClient.resetPassword({ username }, metadata);
|
||||
return { authProvider: process.env.AUTH_PROVIDER || 'cognito' };
|
||||
return this.authClient.resetPassword({ username }, metadata);
|
||||
}
|
||||
|
||||
@ApiInternalOnlyEndpoint()
|
||||
|
||||
@@ -143,7 +143,6 @@ export class AuthClientService implements OnModuleInit {
|
||||
accessToken,
|
||||
oldPassword,
|
||||
newPassword,
|
||||
totpCode,
|
||||
}: AuthChangePasswordRequest) {
|
||||
this.logger.info('ChangePassword');
|
||||
|
||||
@@ -152,7 +151,6 @@ export class AuthClientService implements OnModuleInit {
|
||||
accessToken,
|
||||
oldPassword,
|
||||
newPassword,
|
||||
totpCode,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -136,32 +136,4 @@ export class CustomersController {
|
||||
const result = await this.customersService.getAccessDashboardUrl(user.customer_name, metadata);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Get(':id/organization-info')
|
||||
@Authenticated()
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
|
||||
@ApiOkResponse({ description: 'Organization information' })
|
||||
async getOrganizationInfo(@Param('id') id: string) {
|
||||
this.logger.info('getOrganizationInfo', { id });
|
||||
return this.customersService.getOrganizationInfo(id);
|
||||
}
|
||||
|
||||
@Put(':id/organization-info')
|
||||
@Authenticated()
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiOkResponse({ description: 'Organization information updated' })
|
||||
async updateOrganizationInfo(
|
||||
@Param('id') id: string,
|
||||
@Body() body: {
|
||||
companyName: string;
|
||||
companySite: string;
|
||||
domain: string;
|
||||
cnpj: string;
|
||||
description: string;
|
||||
},
|
||||
) {
|
||||
return this.customersService.updateOrganizationInfo(id, body);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -223,57 +223,4 @@ export class CustomersService implements OnModuleInit {
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
async updateOrganizationInfo(
|
||||
customerId: string,
|
||||
data: {
|
||||
companyName: string;
|
||||
companySite: string;
|
||||
domain: string;
|
||||
cnpj: string;
|
||||
description: string;
|
||||
},
|
||||
) {
|
||||
try {
|
||||
const result = await lastValueFrom(
|
||||
this.customerService.OrganizationUpdate({
|
||||
customerId,
|
||||
companyName: data.companyName || '',
|
||||
companySite: data.companySite || '',
|
||||
domain: data.domain || '',
|
||||
cnpj: data.cnpj || '',
|
||||
description: data.description || '',
|
||||
}),
|
||||
);
|
||||
|
||||
return result;
|
||||
} catch (err) {
|
||||
if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND)
|
||||
throw new HttpException(err.details, HttpStatus.NOT_FOUND);
|
||||
else throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async getOrganizationInfo(customerId: string) {
|
||||
try {
|
||||
const customerResponse = await lastValueFrom(
|
||||
this.customerService.CustomerFindOneById({ id: customerId })
|
||||
);
|
||||
|
||||
const customer = customerResponse.customer;
|
||||
|
||||
return {
|
||||
companyName: customer.companyName || '',
|
||||
companySite: customer.companySite || '',
|
||||
domain: customer.domain || '',
|
||||
cnpj: customer.cnpj || '',
|
||||
description: customer.description || ''
|
||||
};
|
||||
} catch (err) {
|
||||
if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND)
|
||||
throw new HttpException(err.details, HttpStatus.NOT_FOUND);
|
||||
else throw err;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||
|
||||
export class OrganizationUpdateRequest {
|
||||
@ApiProperty()
|
||||
name: string;
|
||||
@ApiPropertyOptional()
|
||||
companySite: string;
|
||||
@ApiProperty()
|
||||
domain: string;
|
||||
@ApiPropertyOptional()
|
||||
info: string;
|
||||
@ApiPropertyOptional()
|
||||
cnpj: string;
|
||||
}
|
||||
|
||||
export class OrganizationResponse {
|
||||
@ApiProperty()
|
||||
name: string;
|
||||
@ApiPropertyOptional()
|
||||
companySite: string;
|
||||
@ApiProperty()
|
||||
domain: string;
|
||||
@ApiPropertyOptional()
|
||||
info: string;
|
||||
@ApiPropertyOptional()
|
||||
cnpj: string;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
export const STORAGE_EXPLORER_CONFIG = {
|
||||
getUrl: (customerId: string): string => {
|
||||
const urlTemplate = process.env.STORAGE_EXPLORER_API_URL;
|
||||
if (!urlTemplate) {
|
||||
throw new Error('STORAGE_EXPLORER_API_URL environment variable is not set');
|
||||
}
|
||||
// Replace {customer_id} placeholder with actual customer ID
|
||||
// For local: http://172.17.0.1:8000/api (no placeholder)
|
||||
// For prod: https://storage-explorer-{customer_id}.stg.dadosfera.ai/api
|
||||
return urlTemplate.replace('{customer_id}', customerId);
|
||||
},
|
||||
timeout: parseInt(process.env.STORAGE_EXPLORER_TIMEOUT || '30000', 10),
|
||||
};
|
||||
@@ -1,350 +0,0 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Put,
|
||||
Delete,
|
||||
Param,
|
||||
Body,
|
||||
Query,
|
||||
Inject,
|
||||
UseInterceptors,
|
||||
UploadedFiles,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiConsumes } from '@nestjs/swagger';
|
||||
import { FilesInterceptor } from '@nestjs/platform-express';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import FormData from 'form-data';
|
||||
|
||||
import {
|
||||
Authenticated,
|
||||
RequireAllPermissions,
|
||||
} from '../../decorators/authentication.decorator';
|
||||
import { User, RequestUser } from '../../decorators/user.decorator';
|
||||
import { StorageExplorerService } from './storage-explorer.service';
|
||||
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
|
||||
|
||||
@ApiTags('Storage Explorer')
|
||||
@Controller('storage-explorer')
|
||||
@Authenticated()
|
||||
export class StorageExplorerController {
|
||||
private logger: any;
|
||||
|
||||
constructor(
|
||||
private readonly storageExplorerService: StorageExplorerService,
|
||||
@Inject(DadosferaLogger) dadosferaLogger: DadosferaLogger,
|
||||
) {
|
||||
this.logger = dadosferaLogger.logger;
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// TABLE OPERATIONS
|
||||
// ============================================
|
||||
|
||||
@ApiOperation({ summary: 'Validate table name in PostgreSQL and Snowflake' })
|
||||
@Post('tables/validate-name')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.WRITE)
|
||||
async validateTableName(
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'POST',
|
||||
'/tables/validate-name',
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Create a new table' })
|
||||
@Post('tables')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.WRITE)
|
||||
async createTable(
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'POST',
|
||||
'/tables/',
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'List all tables with pagination' })
|
||||
@Get('tables')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async listTables(
|
||||
@Query('page') page: number,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
'/tables/',
|
||||
user,
|
||||
undefined,
|
||||
{ page },
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get table details by ID' })
|
||||
@Get('tables/:tableId')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async getTable(
|
||||
@Param('tableId') tableId: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
`/tables/${tableId}`,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Link a dataset to a table' })
|
||||
@Post('tables/:tableId/datasets/:datasetId')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.WRITE)
|
||||
async linkDatasetToTable(
|
||||
@Param('tableId') tableId: string,
|
||||
@Param('datasetId') datasetId: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'POST',
|
||||
`/tables/${tableId}/datasets/${datasetId}`,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get all datasets linked to a table' })
|
||||
@Get('tables/:tableId/datasets')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async getTableDatasets(
|
||||
@Param('tableId') tableId: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
`/tables/${tableId}/datasets`,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get table schema' })
|
||||
@Get('tables/:tableId/schema')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async getTableSchema(
|
||||
@Param('tableId') tableId: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
`/tables/${tableId}/schema`,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Validate schema compatibility between table and dataset' })
|
||||
@Post('tables/:tableId/validate-compatibility/:datasetId')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async validateSchemaCompatibility(
|
||||
@Param('tableId') tableId: string,
|
||||
@Param('datasetId') datasetId: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'POST',
|
||||
`/tables/${tableId}/validate-compatibility/${datasetId}`,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// DATASET OPERATIONS
|
||||
// ============================================
|
||||
|
||||
@ApiOperation({ summary: 'Get dataset preview data' })
|
||||
@Get('datasets/:datasetId/preview')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async getDatasetPreview(
|
||||
@Param('datasetId') datasetId: string,
|
||||
@Query('limit') limit: number,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
`/datasets/${datasetId}/preview`,
|
||||
user,
|
||||
undefined,
|
||||
{ limit },
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get dataset schema information' })
|
||||
@Get('datasets/:datasetId/schema')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async getDatasetSchema(
|
||||
@Param('datasetId') datasetId: string,
|
||||
@Query('force_refresh') forceRefresh: boolean,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
`/datasets/${datasetId}/schema`,
|
||||
user,
|
||||
undefined,
|
||||
{ force_refresh: forceRefresh },
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'List all datasets for a specific upload' })
|
||||
@Get('datasets/upload/:uploadId')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async listDatasetsByUpload(
|
||||
@Param('uploadId') uploadId: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
`/datasets/upload/${uploadId}`,
|
||||
user,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Refresh dataset schema with new parsing options (Excel)' })
|
||||
@Put('datasets/:datasetId/refresh-schema')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.WRITE)
|
||||
async refreshDatasetSchema(
|
||||
@Param('datasetId') datasetId: string,
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'PUT',
|
||||
`/datasets/${datasetId}/refresh-schema`,
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
// ============================================
|
||||
// STORAGE OPERATIONS
|
||||
// ============================================
|
||||
|
||||
@ApiOperation({ summary: 'List file explorer uploads with pagination' })
|
||||
@Get('storage/uploads/history')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async listFileExplorerUploads(
|
||||
@Query('page') page: number,
|
||||
@Query('limit') limit: number,
|
||||
@Query('folder_path') folderPath: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
'/storage/uploads/history',
|
||||
user,
|
||||
undefined,
|
||||
{ page, limit, folder_path: folderPath },
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Browse folders and files in storage' })
|
||||
@Get('storage/browse')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async browseStorage(
|
||||
@Query('path') path: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
'/storage/browse',
|
||||
user,
|
||||
undefined,
|
||||
{ path },
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Upload multiple files to storage' })
|
||||
@Post('storage/upload/batch')
|
||||
@ApiConsumes('multipart/form-data')
|
||||
@UseInterceptors(FilesInterceptor('files'))
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.WRITE)
|
||||
async batchUpload(
|
||||
@UploadedFiles() files: Array<Express.Multer.File>,
|
||||
@Body('folder_path') folderPath: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
// Create FormData to forward files to storage-explorer API
|
||||
const formData = new FormData();
|
||||
|
||||
// Add files
|
||||
if (files && files.length > 0) {
|
||||
files.forEach((file) => {
|
||||
formData.append('files', file.buffer, {
|
||||
filename: file.originalname,
|
||||
contentType: file.mimetype,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Add folder_path
|
||||
if (folderPath) {
|
||||
formData.append('folder_path', folderPath);
|
||||
}
|
||||
|
||||
return this.storageExplorerService.proxyFormData(
|
||||
'POST',
|
||||
'/storage/upload/batch',
|
||||
user,
|
||||
formData,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Create a new folder in storage' })
|
||||
@Post('storage/folder/create')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.WRITE)
|
||||
async createFolder(
|
||||
@Body() body: any,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'POST',
|
||||
'/storage/folder/create',
|
||||
user,
|
||||
body,
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Download a file from storage' })
|
||||
@Get('storage/download')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async downloadFile(
|
||||
@Query('file_path') filePath: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
'/storage/download',
|
||||
user,
|
||||
undefined,
|
||||
{ file_path: filePath },
|
||||
);
|
||||
}
|
||||
|
||||
@ApiOperation({ summary: 'Get detailed file metadata' })
|
||||
@Get('storage/metadata')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.STORAGE_EXPLORER.permissions.READ)
|
||||
async getFileMetadata(
|
||||
@Query('file_path') filePath: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
return this.storageExplorerService.proxy(
|
||||
'GET',
|
||||
'/storage/metadata',
|
||||
user,
|
||||
undefined,
|
||||
{ file_path: filePath },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
|
||||
import { StorageExplorerController } from './storage-explorer.controller';
|
||||
import { StorageExplorerService } from './storage-explorer.service';
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [StorageExplorerController],
|
||||
providers: [StorageExplorerService, DadosferaLogger],
|
||||
exports: [StorageExplorerService],
|
||||
})
|
||||
export class StorageExplorerModule {}
|
||||
@@ -1,178 +0,0 @@
|
||||
import { Injectable, Inject, HttpException } from '@nestjs/common';
|
||||
import axios, { AxiosResponse, Method } from 'axios';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
|
||||
import { RequestUser } from '../../decorators/user.decorator';
|
||||
import { STORAGE_EXPLORER_CONFIG } from './storage-explorer.config';
|
||||
|
||||
@Injectable()
|
||||
export class StorageExplorerService {
|
||||
private logger: any;
|
||||
|
||||
constructor(
|
||||
@Inject(DadosferaLogger) dadosferaLogger: DadosferaLogger,
|
||||
) {
|
||||
this.logger = dadosferaLogger.logger;
|
||||
}
|
||||
|
||||
async proxy(
|
||||
method: string,
|
||||
path: string,
|
||||
user: RequestUser,
|
||||
body?: any,
|
||||
query?: Record<string, any>,
|
||||
): Promise<any> {
|
||||
// Validate customer_id is present for multi-tenant isolation
|
||||
if (!user.customer_id) {
|
||||
throw new HttpException('Customer ID is required for storage operations', 400);
|
||||
}
|
||||
|
||||
// Get customer-specific storage-explorer URL
|
||||
const baseUrl = STORAGE_EXPLORER_CONFIG.getUrl(user.customer_id);
|
||||
const url = new URL(`${baseUrl}${path}`);
|
||||
|
||||
// Add query params
|
||||
if (query) {
|
||||
Object.entries(query).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null) {
|
||||
url.searchParams.set(key, String(value));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
'content-type': 'application/json',
|
||||
};
|
||||
|
||||
this.logger.info('Proxying request to storage-explorer', {
|
||||
method: method.toUpperCase(),
|
||||
path,
|
||||
customer_id: user.customer_id,
|
||||
storage_url: baseUrl,
|
||||
user_id: user.user_id,
|
||||
});
|
||||
|
||||
try {
|
||||
const response: AxiosResponse = await axios({
|
||||
method: method as Method,
|
||||
url: url.href,
|
||||
headers,
|
||||
data: body,
|
||||
timeout: STORAGE_EXPLORER_CONFIG.timeout,
|
||||
validateStatus: () => true, // Don't throw on non-2xx
|
||||
});
|
||||
|
||||
// Propagate non-2xx responses as HttpExceptions
|
||||
if (response.status >= 400) {
|
||||
throw new HttpException(response.data, response.status);
|
||||
}
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.logger.error('Storage Explorer API proxy error', {
|
||||
error: error.message,
|
||||
status: error.response?.status,
|
||||
path,
|
||||
storage_url: baseUrl,
|
||||
method: method.toUpperCase(),
|
||||
});
|
||||
|
||||
if (error instanceof HttpException) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (error.response) {
|
||||
throw new HttpException(error.response.data, error.response.status);
|
||||
}
|
||||
|
||||
if (error.code === 'ECONNREFUSED') {
|
||||
throw new HttpException('Storage Explorer API service unavailable', 503);
|
||||
}
|
||||
|
||||
if (error.code === 'ETIMEDOUT' || error.code === 'ECONNABORTED') {
|
||||
throw new HttpException('Storage Explorer API request timeout', 504);
|
||||
}
|
||||
|
||||
throw new HttpException('Internal server error', 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy with file upload support (multipart/form-data)
|
||||
*/
|
||||
async proxyFormData(
|
||||
method: string,
|
||||
path: string,
|
||||
user: RequestUser,
|
||||
formData: any,
|
||||
query?: Record<string, any>,
|
||||
): Promise<any> {
|
||||
// Validate customer_id is present for multi-tenant isolation
|
||||
if (!user.customer_id) {
|
||||
throw new HttpException('Customer ID is required for storage operations', 400);
|
||||
}
|
||||
|
||||
// Get customer-specific storage-explorer URL
|
||||
const baseUrl = STORAGE_EXPLORER_CONFIG.getUrl(user.customer_id);
|
||||
const url = new URL(`${baseUrl}${path}`);
|
||||
|
||||
// Add query params
|
||||
if (query) {
|
||||
Object.entries(query).forEach(([key, value]) => {
|
||||
if (value !== undefined && value !== null) {
|
||||
url.searchParams.set(key, String(value));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
// Let axios set Content-Type for multipart/form-data with boundary
|
||||
...formData.getHeaders?.(),
|
||||
};
|
||||
|
||||
this.logger.info('Proxying form data request to storage-explorer', {
|
||||
method: method.toUpperCase(),
|
||||
path,
|
||||
customer_id: user.customer_id,
|
||||
storage_url: baseUrl,
|
||||
user_id: user.user_id,
|
||||
});
|
||||
|
||||
try {
|
||||
const response: AxiosResponse = await axios({
|
||||
method: method as Method,
|
||||
url: url.href,
|
||||
headers,
|
||||
data: formData,
|
||||
timeout: STORAGE_EXPLORER_CONFIG.timeout,
|
||||
maxContentLength: Infinity,
|
||||
maxBodyLength: Infinity,
|
||||
validateStatus: () => true,
|
||||
});
|
||||
|
||||
if (response.status >= 400) {
|
||||
throw new HttpException(response.data, response.status);
|
||||
}
|
||||
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
this.logger.error('Storage Explorer API form data proxy error', {
|
||||
error: error.message,
|
||||
status: error.response?.status,
|
||||
path,
|
||||
storage_url: baseUrl,
|
||||
method: method.toUpperCase(),
|
||||
});
|
||||
|
||||
if (error instanceof HttpException) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (error.response) {
|
||||
throw new HttpException(error.response.data, error.response.status);
|
||||
}
|
||||
|
||||
throw new HttpException('Internal server error', 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ export class User {
|
||||
@ApiProperty()
|
||||
companyName?: string;
|
||||
@ApiProperty()
|
||||
personalSite?: string;
|
||||
companySite?: string;
|
||||
@ApiPropertyOptional()
|
||||
customer?: Customer;
|
||||
@ApiProperty()
|
||||
@@ -64,8 +64,6 @@ export class UserNoRolesAndCustomer extends OmitType(UserNoRoles, [
|
||||
export class IUserByCustomer extends OmitType(User, ['customer']) {
|
||||
@ApiPropertyOptional()
|
||||
permissions?: string[];
|
||||
@ApiPropertyOptional()
|
||||
authProvider?: string;
|
||||
}
|
||||
|
||||
export class CreateUserReq {
|
||||
@@ -119,7 +117,7 @@ export class UpdateUserReq {
|
||||
@ApiPropertyOptional()
|
||||
bio?: string;
|
||||
@ApiPropertyOptional()
|
||||
personalSite?: string;
|
||||
companySite?: string;
|
||||
@ApiPropertyOptional()
|
||||
companyName?: string;
|
||||
@ApiPropertyOptional()
|
||||
|
||||
@@ -125,7 +125,6 @@ export class UsersService implements OnModuleInit {
|
||||
return { permissions };
|
||||
});
|
||||
res.user.permissions = permissions;
|
||||
res.user.authProvider = process.env.AUTH_PROVIDER || 'cognito';
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -163,7 +162,7 @@ export class UsersService implements OnModuleInit {
|
||||
name: updateUserDTO.name,
|
||||
bio: updateUserDTO.bio,
|
||||
companyName: updateUserDTO.companyName,
|
||||
personalSite: updateUserDTO.personalSite,
|
||||
companySite: updateUserDTO.companySite,
|
||||
customerId,
|
||||
id,
|
||||
metabaseUserId: undefined,
|
||||
|
||||
@@ -14,7 +14,10 @@ export class ValidationPipe implements PipeTransform<any> {
|
||||
return value;
|
||||
}
|
||||
const object = plainToInstance(metatype, value);
|
||||
const errors = await validate(object);
|
||||
const errors = await validate(object, {
|
||||
forbidUnknownValues: false,
|
||||
whitelist: true,
|
||||
});
|
||||
if (errors.length > 0) {
|
||||
const errorMessages = errors.map((err) => err.constraints);
|
||||
throw new BadRequestException(errorMessages);
|
||||
|
||||
Reference in New Issue
Block a user