mirror of
https://github.com/dadosfera/maestro.git
synced 2026-08-31 19:58:21 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1149a4d52 | ||
|
|
4c6f4bfd84 | ||
|
|
9caf3dc67f | ||
|
|
635c4da48c | ||
|
|
44bb205483 | ||
|
|
edb4622684 | ||
|
|
abb46d78da | ||
|
|
04fdc0368a | ||
|
|
50d76622c5 | ||
|
|
238f56cb76 | ||
|
|
e721d6f5f5 | ||
|
|
44df13e820 | ||
|
|
1fd0f79dd5 | ||
|
|
1b92371737 | ||
|
|
bf5b3484a1 | ||
|
|
eb1e248d4b | ||
|
|
0827414051 | ||
|
|
081986607b | ||
|
|
189080199a | ||
|
|
55281e3965 | ||
|
|
db8a6175e8 | ||
|
|
7b0d4dd5bc | ||
|
|
6fd277ef3a | ||
|
|
7b25bfdb69 | ||
|
|
2abc19c589 | ||
|
|
faf6b1df75 | ||
|
|
422be4a422 | ||
|
|
da136e0ef0 | ||
|
|
737cc9b8ea | ||
|
|
23f6b179fd | ||
|
|
03e451c21d | ||
|
|
2646e3e4f6 |
+287
-13
@@ -241,7 +241,16 @@
|
||||
},
|
||||
"get": {
|
||||
"operationId": "ConnectionController_getConnectionDetails",
|
||||
"parameters": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
@@ -449,7 +458,16 @@
|
||||
"/inputs/{id}": {
|
||||
"get": {
|
||||
"operationId": "InputsController_findOne",
|
||||
"parameters": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
@@ -646,6 +664,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -678,6 +704,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -710,6 +744,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -749,6 +791,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -786,6 +836,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -823,6 +881,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -985,6 +1051,14 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shared",
|
||||
"required": true,
|
||||
@@ -1025,6 +1099,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
@@ -1125,6 +1207,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1167,6 +1257,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1209,6 +1307,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -1402,6 +1508,108 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/catalog/dataset-catalog-task": {
|
||||
"post": {
|
||||
"operationId": "CatalogController_triggerCatalog",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "dadosfera-lang",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"enum": [
|
||||
"pt-br",
|
||||
"en-us"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TriggerCatalogReq"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TriggerCatalogRes"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Catalog"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/catalog/dataset-catalog-task/{session}": {
|
||||
"get": {
|
||||
"operationId": "CatalogController_getCatalogTask",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "dadosfera-lang",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"enum": [
|
||||
"pt-br",
|
||||
"en-us"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "session",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetDatasetCatalogTaskRes"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Catalog"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/oauth/hubspot": {
|
||||
"get": {
|
||||
"operationId": "OauthController_oauthHubspot",
|
||||
@@ -1544,24 +1752,16 @@
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"title": "Maestro - fix/upload-files",
|
||||
"title": "Maestro - feature/customer-links",
|
||||
"description": "This is the Maestro API",
|
||||
"version": "1.0.0",
|
||||
"contact": {}
|
||||
},
|
||||
"tags": [],
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://maestro.stg.dadosfera.ai",
|
||||
"description": "Ambiente STG"
|
||||
},
|
||||
{
|
||||
"url": "https://maestro-2.stg.dadosfera.ai",
|
||||
"description": "Ambiente STG2"
|
||||
},
|
||||
{
|
||||
"url": "https://maestro.dadosfera.ai",
|
||||
"description": "Ambiente PRD"
|
||||
"description": "Dadosfera API"
|
||||
}
|
||||
],
|
||||
"components": {
|
||||
@@ -1612,6 +1812,12 @@
|
||||
},
|
||||
"scheduleLimit": {
|
||||
"type": "string"
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -1619,7 +1825,8 @@
|
||||
"id",
|
||||
"name",
|
||||
"tier",
|
||||
"scheduleLimit"
|
||||
"scheduleLimit",
|
||||
"links"
|
||||
]
|
||||
},
|
||||
"AuthUser": {
|
||||
@@ -2850,6 +3057,73 @@
|
||||
"required": [
|
||||
"comment"
|
||||
]
|
||||
},
|
||||
"TriggerCatalogReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"table_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the table on Snowflake",
|
||||
"example": "TB__4DXSD4_TEST"
|
||||
},
|
||||
"table_schema": {
|
||||
"type": "string",
|
||||
"description": "Schema where the asset is located. If not set defaults to \"PUBLIC\""
|
||||
},
|
||||
"pipeline_id": {
|
||||
"type": "string",
|
||||
"description": "Id of the pipeline that generated the asset."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"table_name"
|
||||
]
|
||||
},
|
||||
"TriggerCatalogRes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"session": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"session"
|
||||
]
|
||||
},
|
||||
"GetDatasetCatalogTaskRes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"customer_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"session_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"table_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_by": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"created_at",
|
||||
"customer_name",
|
||||
"session_id",
|
||||
"status",
|
||||
"table_name",
|
||||
"updated_at",
|
||||
"updated_by"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+435
-21
@@ -690,7 +690,16 @@
|
||||
},
|
||||
"get": {
|
||||
"operationId": "ConnectionController_getConnectionDetails",
|
||||
"parameters": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
@@ -2574,7 +2583,16 @@
|
||||
"/inputs/{id}": {
|
||||
"get": {
|
||||
"operationId": "InputsController_findOne",
|
||||
"parameters": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
@@ -2819,6 +2837,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -2851,6 +2877,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -2883,6 +2917,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -2922,6 +2964,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -2959,6 +3009,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -2999,6 +3057,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3036,6 +3102,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3217,6 +3291,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3247,7 +3329,16 @@
|
||||
"summary": "",
|
||||
"deprecated": true,
|
||||
"description": "This method is deprecated. Please use route /pipelinesV2/start/:id instead",
|
||||
"parameters": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
@@ -3279,7 +3370,16 @@
|
||||
"summary": "",
|
||||
"deprecated": true,
|
||||
"description": "This method is deprecated. Please use route /pipelinesV2/:id/status instead",
|
||||
"parameters": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
@@ -3350,7 +3450,16 @@
|
||||
"/transformations/{id}": {
|
||||
"get": {
|
||||
"operationId": "TransformationsController_findOne",
|
||||
"parameters": [],
|
||||
"parameters": [
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
@@ -3658,6 +3767,14 @@
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shared",
|
||||
"required": true,
|
||||
@@ -3698,6 +3815,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
@@ -3798,6 +3923,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3833,6 +3966,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3875,6 +4016,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3917,6 +4066,14 @@
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -4190,6 +4347,108 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/catalog/dataset-catalog-task": {
|
||||
"post": {
|
||||
"operationId": "CatalogController_triggerCatalog",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "dadosfera-lang",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"enum": [
|
||||
"pt-br",
|
||||
"en-us"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TriggerCatalogReq"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"201": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/TriggerCatalogRes"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Catalog"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/catalog/dataset-catalog-task/{session}": {
|
||||
"get": {
|
||||
"operationId": "CatalogController_getCatalogTask",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "dadosfera-lang",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"enum": [
|
||||
"pt-br",
|
||||
"en-us"
|
||||
],
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "session",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetDatasetCatalogTaskRes"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Catalog"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/terms-of-use/token": {
|
||||
"get": {
|
||||
"operationId": "TermsOfUseController_getToken",
|
||||
@@ -4700,6 +4959,72 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/customers/{id}/links": {
|
||||
"get": {
|
||||
"operationId": "CustomersController_getCustomerLinks",
|
||||
"parameters": [],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CustomerLinksResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Customers"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"put": {
|
||||
"operationId": "CustomersController_setCustomerLinks",
|
||||
"parameters": [],
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/CustomerDto"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Customers"
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"access-token": []
|
||||
},
|
||||
{
|
||||
"access-token": []
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/health": {
|
||||
"get": {
|
||||
"operationId": "HealthController_check",
|
||||
@@ -4716,26 +5041,13 @@
|
||||
}
|
||||
},
|
||||
"info": {
|
||||
"title": "Maestro - fix/upload-files",
|
||||
"title": "Maestro - feature/customer-links",
|
||||
"description": "This is the Maestro API",
|
||||
"version": "1.0.0",
|
||||
"contact": {}
|
||||
},
|
||||
"tags": [],
|
||||
"servers": [
|
||||
{
|
||||
"url": "https://maestro.stg.dadosfera.ai",
|
||||
"description": "Ambiente STG"
|
||||
},
|
||||
{
|
||||
"url": "https://maestro-2.stg.dadosfera.ai",
|
||||
"description": "Ambiente STG2"
|
||||
},
|
||||
{
|
||||
"url": "https://maestro.dadosfera.ai",
|
||||
"description": "Ambiente PRD"
|
||||
}
|
||||
],
|
||||
"servers": [],
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"access-token": {
|
||||
@@ -4784,6 +5096,12 @@
|
||||
},
|
||||
"scheduleLimit": {
|
||||
"type": "string"
|
||||
},
|
||||
"links": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
@@ -4791,7 +5109,8 @@
|
||||
"id",
|
||||
"name",
|
||||
"tier",
|
||||
"scheduleLimit"
|
||||
"scheduleLimit",
|
||||
"links"
|
||||
]
|
||||
},
|
||||
"AuthUser": {
|
||||
@@ -7096,6 +7415,73 @@
|
||||
"comment"
|
||||
]
|
||||
},
|
||||
"TriggerCatalogReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"table_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the table on Snowflake",
|
||||
"example": "TB__4DXSD4_TEST"
|
||||
},
|
||||
"table_schema": {
|
||||
"type": "string",
|
||||
"description": "Schema where the asset is located. If not set defaults to \"PUBLIC\""
|
||||
},
|
||||
"pipeline_id": {
|
||||
"type": "string",
|
||||
"description": "Id of the pipeline that generated the asset."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"table_name"
|
||||
]
|
||||
},
|
||||
"TriggerCatalogRes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"session": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"session"
|
||||
]
|
||||
},
|
||||
"GetDatasetCatalogTaskRes": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"created_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"customer_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"session_id": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"table_name": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
"type": "string"
|
||||
},
|
||||
"updated_by": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"created_at",
|
||||
"customer_name",
|
||||
"session_id",
|
||||
"status",
|
||||
"table_name",
|
||||
"updated_at",
|
||||
"updated_by"
|
||||
]
|
||||
},
|
||||
"ConnectionTestPingReq": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -7389,6 +7775,34 @@
|
||||
"content",
|
||||
"tags"
|
||||
]
|
||||
},
|
||||
"CustomerLinksResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"links": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"links"
|
||||
]
|
||||
},
|
||||
"CustomerDto": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"links": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"links"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+32
-23
@@ -12,7 +12,7 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-secrets-manager": "^3.112.0",
|
||||
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
||||
"@dadosfera/protospack-v2": "3.29.1",
|
||||
"@dadosfera/protospack-v2": "3.30.0",
|
||||
"@grpc/grpc-js": "^1.6.7",
|
||||
"@grpc/proto-loader": "^0.6.13",
|
||||
"@nestjs/common": "^8.4.7",
|
||||
@@ -1727,9 +1727,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@dadosfera/protospack-v2": {
|
||||
"version": "3.29.1",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.29.1.tgz",
|
||||
"integrity": "sha512-uVswwXltdG0aX8cYVSFPRcROPWjOlW5bJGFfn5RNodKyHeBiTVDWBB3/YgocKrWV4mYBSbZ11ctBzjSAOkf/0Q==",
|
||||
"version": "3.30.0",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.30.0.tgz",
|
||||
"integrity": "sha512-00wqZyZmjd6rMECga2S3Ow0dk6c5fZoWd6Th+Ajofq6q/kycTU66p/5xdf0sPf//WyXMGCXasqGSZa0h9i01vg==",
|
||||
"dependencies": {
|
||||
"@grpc/grpc-js": "^1.6.7",
|
||||
"rxjs": "^7.5.5",
|
||||
@@ -4495,9 +4495,10 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cookiejar": {
|
||||
"version": "2.1.3",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
|
||||
"integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
@@ -7759,9 +7760,10 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/json5": {
|
||||
"version": "2.2.1",
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"json5": "lib/cli.js"
|
||||
},
|
||||
@@ -7968,9 +7970,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
"version": "1.28.0",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz",
|
||||
"integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ==",
|
||||
"version": "1.28.1",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz",
|
||||
"integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
@@ -10384,9 +10386,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tsconfig-paths/node_modules/json5": {
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.0"
|
||||
},
|
||||
@@ -12284,9 +12287,9 @@
|
||||
}
|
||||
},
|
||||
"@dadosfera/protospack-v2": {
|
||||
"version": "3.29.1",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.29.1.tgz",
|
||||
"integrity": "sha512-uVswwXltdG0aX8cYVSFPRcROPWjOlW5bJGFfn5RNodKyHeBiTVDWBB3/YgocKrWV4mYBSbZ11ctBzjSAOkf/0Q==",
|
||||
"version": "3.30.0",
|
||||
"resolved": "https://dadosfera-611330257153.d.codeartifact.us-east-1.amazonaws.com:443/npm/dadosfera-npm/@dadosfera/protospack-v2/-/protospack-v2-3.30.0.tgz",
|
||||
"integrity": "sha512-00wqZyZmjd6rMECga2S3Ow0dk6c5fZoWd6Th+Ajofq6q/kycTU66p/5xdf0sPf//WyXMGCXasqGSZa0h9i01vg==",
|
||||
"requires": {
|
||||
"@grpc/grpc-js": "^1.6.7",
|
||||
"rxjs": "^7.5.5",
|
||||
@@ -14190,7 +14193,9 @@
|
||||
"version": "1.0.6"
|
||||
},
|
||||
"cookiejar": {
|
||||
"version": "2.1.3",
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz",
|
||||
"integrity": "sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==",
|
||||
"dev": true
|
||||
},
|
||||
"core-util-is": {
|
||||
@@ -16399,7 +16404,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"json5": {
|
||||
"version": "2.2.1",
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
|
||||
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
|
||||
"dev": true
|
||||
},
|
||||
"jsonc-parser": {
|
||||
@@ -16548,9 +16555,9 @@
|
||||
}
|
||||
},
|
||||
"luxon": {
|
||||
"version": "1.28.0",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz",
|
||||
"integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ=="
|
||||
"version": "1.28.1",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.1.tgz",
|
||||
"integrity": "sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw=="
|
||||
},
|
||||
"macos-release": {
|
||||
"version": "2.5.0",
|
||||
@@ -18138,7 +18145,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"json5": {
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "^1.2.0"
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-secrets-manager": "^3.112.0",
|
||||
"@dadosfera/dadosfera-logs": "^1.0.0-beta.4",
|
||||
"@dadosfera/protospack-v2": "3.29.1",
|
||||
"@dadosfera/protospack-v2": "3.31.0",
|
||||
"@grpc/grpc-js": "^1.6.7",
|
||||
"@grpc/proto-loader": "^0.6.13",
|
||||
"@nestjs/common": "^8.4.7",
|
||||
|
||||
@@ -25,6 +25,7 @@ import { ConfigModule } from '@nestjs/config';
|
||||
import { PipelinesV2Module } from './modules/pipelinesV2/pipelines.module';
|
||||
import { ProductboardModule } from './modules/productboard/productboard.module';
|
||||
import { MixpanelModule } from './modules/mixpanel/mixpanel.module';
|
||||
import { CustomersModule } from './modules/customers/customers.module';
|
||||
|
||||
@Module({
|
||||
controllers: [],
|
||||
@@ -56,6 +57,7 @@ import { MixpanelModule } from './modules/mixpanel/mixpanel.module';
|
||||
OauthModule,
|
||||
ProductboardModule,
|
||||
MixpanelModule,
|
||||
CustomersModule,
|
||||
//Always leave HealthModule last, so it is on the bottom of swagger
|
||||
HealthModule,
|
||||
],
|
||||
|
||||
@@ -44,7 +44,7 @@ class NoClassAuthController {
|
||||
@Get('has-all-permissions')
|
||||
@RequireAllPermissions(
|
||||
PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN,
|
||||
PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE,
|
||||
PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE,
|
||||
)
|
||||
async hasAllPermissions(@Body() body) {
|
||||
return { body };
|
||||
@@ -53,7 +53,7 @@ class NoClassAuthController {
|
||||
@Get('has-some-permission')
|
||||
@RequireSomePermission(
|
||||
PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN,
|
||||
PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE,
|
||||
PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE,
|
||||
)
|
||||
async hasSomePermission(@Body() body) {
|
||||
return { body };
|
||||
@@ -62,7 +62,7 @@ class NoClassAuthController {
|
||||
|
||||
@Controller('class-auth-condition')
|
||||
@AuthenticateCondition((req) => req.get('x-on-class') === 'ok')
|
||||
@RequireSomePermission(PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE)
|
||||
@RequireSomePermission(PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE)
|
||||
class ClassAuthConditionController {
|
||||
@Get('body')
|
||||
async getBody(@Body() body) {
|
||||
@@ -444,13 +444,13 @@ describe('authentication.guard', () => {
|
||||
NoClassAuthTest(tokenZ, ['zendesk']);
|
||||
ClassAuthConditionTest(tokenZ, ['zendesk']);
|
||||
|
||||
const tokenM = CreateToken([PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE]);
|
||||
const tokenM = CreateToken([PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE]);
|
||||
NoClassAuthTest(tokenM, ['metabase']);
|
||||
ClassAuthConditionTest(tokenM, ['metabase']);
|
||||
|
||||
const tokenZM = CreateToken([
|
||||
PERMISSIONS_GROUPS.ZENDESK.permissions.OPEN,
|
||||
PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE,
|
||||
PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE,
|
||||
]);
|
||||
NoClassAuthTest(tokenZM, ['zendesk', 'metabase']);
|
||||
ClassAuthConditionTest(tokenZM, ['zendesk', 'metabase']);
|
||||
|
||||
@@ -346,6 +346,16 @@ export const PERMISSIONS_GROUPS = {
|
||||
'es-es': 'Acceder al Módulo de Incorporación de Activos',
|
||||
},
|
||||
},
|
||||
TRIGGER_CATALOG_TASK: {
|
||||
seqid: 45,
|
||||
claim: 'catalog:trigger-task',
|
||||
usage: PermissionUsages.INTERNAL,
|
||||
name: {
|
||||
'pt-br': 'Executar a catalogação de um ativo',
|
||||
'en-us': 'Trigger an asset cataloging',
|
||||
'es-es': 'Realizar el listado de un activo',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -439,7 +449,7 @@ export const PERMISSIONS_GROUPS = {
|
||||
},
|
||||
},
|
||||
|
||||
ANALYZE: {
|
||||
DATAVIZ: {
|
||||
title: {
|
||||
'pt-br': 'Analisar | Visualização',
|
||||
'en-us': 'Analyze | Visualization',
|
||||
@@ -456,6 +466,15 @@ export const PERMISSIONS_GROUPS = {
|
||||
'es-es': 'Acceso Metabase',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
INTELLIGENCE: {
|
||||
title: {
|
||||
'pt-br': 'Analisar | Inteligência',
|
||||
'en-us': 'Analyze | Intelligence',
|
||||
'es-es': 'Analizar | Inteligencia',
|
||||
},
|
||||
permissions: {
|
||||
INTELLIGENCE: {
|
||||
seqid: 31,
|
||||
claim: 'intelligence:open',
|
||||
@@ -577,7 +596,8 @@ export const DADOSFERA_MODULES: Array<DadosferaModule> = [
|
||||
name: 'Intelligence Module',
|
||||
description: 'Orchest Module',
|
||||
key: 'intelligence',
|
||||
permissionSeqId: PERMISSIONS_GROUPS.ANALYZE.permissions.INTELLIGENCE.seqid,
|
||||
permissionSeqId:
|
||||
PERMISSIONS_GROUPS.INTELLIGENCE.permissions.INTELLIGENCE.seqid,
|
||||
},
|
||||
{
|
||||
name: 'Proccessing Module',
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('user.decorator', () => {
|
||||
const fakeUserPayload = {
|
||||
user_id: 'd50d33c7-6c2b-463c-861f-e21667e7c125',
|
||||
username: 'super.admin',
|
||||
permissions: [PERMISSIONS_GROUPS.ANALYZE.permissions.METABASE].map(
|
||||
permissions: [PERMISSIONS_GROUPS.DATAVIZ.permissions.METABASE].map(
|
||||
({ seqid }) => seqid,
|
||||
),
|
||||
customer_id: '9d18e8ae-24b9-41a3-9e8f-a25ce57555b11',
|
||||
|
||||
+7
-6
@@ -42,7 +42,7 @@ function configureSwagger(app: INestApplication) {
|
||||
}
|
||||
const swaggerTitle = branchName ? `Maestro - ${branchName}` : 'Maestro';
|
||||
|
||||
const config = new DocumentBuilder()
|
||||
const swaggerConfig = new DocumentBuilder()
|
||||
.setTitle(swaggerTitle)
|
||||
.setDescription('Documentation for Maestro gateway')
|
||||
.addSecurity('access-token', {
|
||||
@@ -50,11 +50,12 @@ function configureSwagger(app: INestApplication) {
|
||||
name: 'Authorization',
|
||||
in: 'header',
|
||||
})
|
||||
.setDescription('This is the Maestro API')
|
||||
.addServer('https://maestro.stg.dadosfera.ai', 'Ambiente STG')
|
||||
.addServer('https://maestro-2.stg.dadosfera.ai', 'Ambiente STG2')
|
||||
.addServer('https://maestro.dadosfera.ai', 'Ambiente PRD')
|
||||
.build();
|
||||
.setDescription('This is the Maestro API');
|
||||
|
||||
if (process.env.INTERNAL_SWAGGER !== 'true')
|
||||
swaggerConfig.addServer('https://maestro.dadosfera.ai', 'Dadosfera API');
|
||||
|
||||
const config = swaggerConfig.build();
|
||||
|
||||
const document = SwaggerModule.createDocument(app, config);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Link } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities';
|
||||
import {
|
||||
AuthSignInRequest,
|
||||
AuthSignInResponse,
|
||||
@@ -74,6 +75,8 @@ export class AuthCustomer {
|
||||
tier: string;
|
||||
@ApiProperty()
|
||||
scheduleLimit: string;
|
||||
@ApiProperty()
|
||||
links: Link[];
|
||||
}
|
||||
|
||||
export class AuthSignInReq implements AuthSignInRequest {
|
||||
|
||||
@@ -14,9 +14,15 @@ import {
|
||||
Query,
|
||||
UseFilters,
|
||||
} from '@nestjs/common';
|
||||
import { ApiHeaders, ApiTags } from '@nestjs/swagger';
|
||||
import {
|
||||
ApiCreatedResponse,
|
||||
ApiHeaders,
|
||||
ApiOkResponse,
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import {
|
||||
Authenticated,
|
||||
RequireAllPermissions,
|
||||
RequireSomePermission,
|
||||
} from '../../decorators/authentication.decorator';
|
||||
import { PERMISSIONS_GROUPS } from '../../authentication/permissions.enum';
|
||||
@@ -25,6 +31,7 @@ import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { PackTheMetadata } from 'src/utils/ PackTheMetadata';
|
||||
import { RequestUser, User } from 'src/decorators/user.decorator';
|
||||
import {
|
||||
GetDatasetCatalogTaskRes,
|
||||
ICatalogAllRequest,
|
||||
ICatalogAllResponse,
|
||||
IColumnsMetadataResponse,
|
||||
@@ -35,6 +42,8 @@ import {
|
||||
IOneDataAsset,
|
||||
IPreviewResponse,
|
||||
IUpdateDataRequest,
|
||||
TriggerCatalogReq,
|
||||
TriggerCatalogRes,
|
||||
} from './dtos';
|
||||
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
|
||||
import { Language } from 'src/decorators/language.decorator';
|
||||
@@ -180,7 +189,7 @@ export class CatalogController {
|
||||
)
|
||||
async getDataAsset(
|
||||
@User() user: RequestUser,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
@Query('shared') shared?: 'true',
|
||||
) {
|
||||
const { username, user_id, customer_id, customer_name, permissions } = user;
|
||||
@@ -196,7 +205,7 @@ export class CatalogController {
|
||||
let has_permission = false;
|
||||
const metadata = PackTheMetadata({
|
||||
username,
|
||||
user_id: undefined,
|
||||
user_id,
|
||||
customer_id,
|
||||
customer_name,
|
||||
});
|
||||
@@ -237,7 +246,7 @@ export class CatalogController {
|
||||
async getDataAssetRls(
|
||||
@User() user: RequestUser,
|
||||
@Headers() headers,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
const { username, user_id, customer_id, customer_name, permissions } = user;
|
||||
|
||||
@@ -292,7 +301,7 @@ export class CatalogController {
|
||||
async getDataAssetColumnsMetadata(
|
||||
@User() user: RequestUser,
|
||||
@Language() language: LanguageEnum,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
): Promise<IColumnsMetadataResponse> {
|
||||
const { customer_name, customer_id, user_id, username } = user;
|
||||
|
||||
@@ -323,7 +332,7 @@ export class CatalogController {
|
||||
async getDataAssetPreview(
|
||||
@User() user: RequestUser,
|
||||
@Language() language: LanguageEnum,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
): Promise<IPreviewResponse> {
|
||||
const { customer_name, customer_id, user_id, username } = user;
|
||||
|
||||
@@ -353,7 +362,7 @@ export class CatalogController {
|
||||
async getDataAssetDocs(
|
||||
@User() user: RequestUser,
|
||||
@Language() language: LanguageEnum,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
): Promise<IDocsResponse> {
|
||||
const { customer_name, customer_id, user_id, username } = user;
|
||||
|
||||
@@ -383,7 +392,7 @@ export class CatalogController {
|
||||
async updateDataAsset(
|
||||
@User() user: RequestUser,
|
||||
@Language() language: LanguageEnum,
|
||||
@Param('id') data_asset_id,
|
||||
@Param('id') data_asset_id: string,
|
||||
@Body() body: IUpdateDataRequest,
|
||||
): Promise<IOneDataAsset> {
|
||||
const { customer_id, customer_name, user_id, username } = user;
|
||||
@@ -579,4 +588,49 @@ export class CatalogController {
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@Post('dataset-catalog-task')
|
||||
@RequireAllPermissions(
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.TRIGGER_CATALOG_TASK,
|
||||
)
|
||||
@ApiCreatedResponse({ type: TriggerCatalogRes })
|
||||
async triggerCatalog(
|
||||
@User() user: RequestUser,
|
||||
@Body() body: TriggerCatalogReq,
|
||||
) {
|
||||
const { customer_id, customer_name, user_id, username } = user;
|
||||
const metadata = PackTheMetadata({
|
||||
customer_id,
|
||||
customer_name,
|
||||
user_id,
|
||||
username,
|
||||
});
|
||||
const session = await this.catalogService.triggerCatalog(body, metadata);
|
||||
|
||||
return { session };
|
||||
}
|
||||
|
||||
@Get('dataset-catalog-task/:session')
|
||||
@RequireAllPermissions(
|
||||
PERMISSIONS_GROUPS.CATALOG.permissions.TRIGGER_CATALOG_TASK,
|
||||
)
|
||||
@ApiOkResponse({ type: GetDatasetCatalogTaskRes })
|
||||
async getCatalogTask(
|
||||
@User() user: RequestUser,
|
||||
@Param('session') session: string,
|
||||
) {
|
||||
const { customer_id, customer_name, user_id, username } = user;
|
||||
const metadata = PackTheMetadata({
|
||||
customer_id,
|
||||
customer_name,
|
||||
user_id,
|
||||
username,
|
||||
});
|
||||
const response = await this.catalogService.getDatasetCatalogTask(
|
||||
session,
|
||||
metadata,
|
||||
);
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import { CatalogClientConfiguration } from './catalog-client';
|
||||
import { UsersService } from '../users/users.service';
|
||||
import { RolesService } from '../roles/roles.service';
|
||||
import { Metadata } from '@grpc/grpc-js';
|
||||
import { IUpdateDataRequest } from './dtos';
|
||||
import { IUpdateDataRequest, TriggerCatalogReq } from './dtos';
|
||||
|
||||
class CatalogService implements OnModuleInit {
|
||||
catalogReadService: ReadService.CatalogReadServices;
|
||||
@@ -333,6 +333,18 @@ class CatalogService implements OnModuleInit {
|
||||
} as typeof data_asset;
|
||||
});
|
||||
}
|
||||
async triggerCatalog(data: TriggerCatalogReq, metadata: Metadata) {
|
||||
const { session } = await lastValueFrom(
|
||||
this.catalogWriteService.TriggerDatasetCataloging(data, metadata),
|
||||
);
|
||||
return session;
|
||||
}
|
||||
async getDatasetCatalogTask(session: string, metadata: Metadata) {
|
||||
const res = await lastValueFrom(
|
||||
this.catalogReadService.GetDatasetCatalogTask({ session }, metadata),
|
||||
);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
export { CatalogService };
|
||||
|
||||
@@ -271,3 +271,44 @@ export class IColumnsMetadataResponse {
|
||||
@ApiProperty({ type: [IColumnMetadata] })
|
||||
columns_metadata: IColumnMetadata[];
|
||||
}
|
||||
|
||||
export class TriggerCatalogReq {
|
||||
@ApiProperty({
|
||||
description: 'Name of the table on Snowflake',
|
||||
example: 'TB__4DXSD4_TEST',
|
||||
})
|
||||
table_name: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description:
|
||||
'Schema where the asset is located. If not set defaults to "PUBLIC"',
|
||||
})
|
||||
table_schema?: string;
|
||||
|
||||
@ApiPropertyOptional({
|
||||
description: 'Id of the pipeline that generated the asset.',
|
||||
})
|
||||
pipeline_id: string;
|
||||
}
|
||||
|
||||
export class TriggerCatalogRes {
|
||||
@ApiProperty()
|
||||
session: string;
|
||||
}
|
||||
|
||||
export class GetDatasetCatalogTaskRes {
|
||||
@ApiProperty()
|
||||
created_at: string;
|
||||
@ApiProperty()
|
||||
customer_name: string;
|
||||
@ApiProperty()
|
||||
session_id: string;
|
||||
@ApiProperty()
|
||||
status: string;
|
||||
@ApiProperty()
|
||||
table_name: string;
|
||||
@ApiProperty()
|
||||
updated_at: string;
|
||||
@ApiProperty()
|
||||
updated_by: string;
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ export class ConnectionController {
|
||||
async getConnectionDetails(
|
||||
@Language() language: LanguageEnum,
|
||||
@User() user: RequestUser,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
@Query() queries,
|
||||
): Promise<ConnectionDetailsRes> {
|
||||
this.logger.info('/connections - Get Connection Details');
|
||||
|
||||
@@ -273,16 +273,13 @@ export class ConnectorController {
|
||||
@Param('plugin') plugin: string,
|
||||
@Query('version') version: string,
|
||||
) {
|
||||
this.logger.info('/upload - Upload Connector Route');
|
||||
this.logger.info('DELETE /:plugin - Delete Connector Route');
|
||||
|
||||
const response: any = await this.connectorClientService.deleteConnector(
|
||||
const response = await this.connectorClientService.deleteConnector(
|
||||
plugin,
|
||||
version,
|
||||
);
|
||||
|
||||
return {
|
||||
message: response.message || 'ok',
|
||||
connector: { ...JSON.parse(response.connector) },
|
||||
};
|
||||
return { message: response.message, connector: response.connector };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { IdResponse } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
Inject,
|
||||
Param,
|
||||
Put,
|
||||
UseFilters,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags } from '@nestjs/swagger';
|
||||
import { PERMISSIONS_GROUPS } from 'src/authentication/permissions.enum';
|
||||
import {
|
||||
Authenticated,
|
||||
RequireAllPermissions,
|
||||
} from 'src/decorators/authentication.decorator';
|
||||
import { ApiInternalOnlyController } from 'src/decorators/swagger.decorator';
|
||||
import { GrpcToHttpExceptionFilter } from 'src/error/grpc-to-http-exception.filter';
|
||||
import { CustomersService } from './customers.service';
|
||||
import { CustomerDto, CustomerLinksResponse } from './dtos/customers';
|
||||
|
||||
@ApiInternalOnlyController()
|
||||
@ApiTags('Customers')
|
||||
@Controller('customers')
|
||||
@Authenticated()
|
||||
@UseFilters(GrpcToHttpExceptionFilter)
|
||||
export class CustomersController {
|
||||
logger: DadosferaLogger;
|
||||
|
||||
constructor(
|
||||
@Inject(DadosferaLogger)
|
||||
dadosferaLogger: DadosferaLogger,
|
||||
private customersService: CustomersService,
|
||||
) {
|
||||
this.logger = dadosferaLogger.logger;
|
||||
}
|
||||
|
||||
@Get(':id/links')
|
||||
async getCustomerLinks(@Param('id') id): Promise<CustomerLinksResponse> {
|
||||
this.logger.info('getCustomerLinks', { id });
|
||||
const links = await this.customersService.getLinks(id);
|
||||
return { links };
|
||||
}
|
||||
|
||||
@Put(':id/links')
|
||||
@RequireAllPermissions(PERMISSIONS_GROUPS.USERS.permissions.ADMIN)
|
||||
setCustomerLinks(
|
||||
@Body() body: CustomerDto,
|
||||
@Param('id') id,
|
||||
): Promise<IdResponse> {
|
||||
const { links } = body;
|
||||
this.logger.info('setCustomerLinks', { id, links });
|
||||
return this.customersService.setLinks(id, links);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DadosferaLogger } from '@dadosfera/dadosfera-logs';
|
||||
import { ClientsModule } from '@nestjs/microservices';
|
||||
import { DucClient } from '../duc/client.config';
|
||||
import { CustomersController } from './customers.controller';
|
||||
import { CustomersService } from './customers.service';
|
||||
|
||||
const client = new DucClient();
|
||||
|
||||
@Module({
|
||||
imports: [ClientsModule.register([client.providerOptions])],
|
||||
controllers: [CustomersController],
|
||||
providers: [CustomersService, DadosferaLogger],
|
||||
exports: [CustomersService],
|
||||
})
|
||||
export class CustomersModule {}
|
||||
@@ -0,0 +1,63 @@
|
||||
import {
|
||||
OnModuleInit,
|
||||
Inject,
|
||||
Injectable,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
} from '@nestjs/common';
|
||||
|
||||
import { firstValueFrom, lastValueFrom } from 'rxjs';
|
||||
import { Link } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities';
|
||||
import { DucClient } from '../duc/client.config';
|
||||
import { ClientGrpc } from '@nestjs/microservices';
|
||||
import { ProtoServices } from '@dadosfera/protospack-v2/dist/lib/Duc';
|
||||
import { CustomerUpdateRequest } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/messages';
|
||||
import { CustomersProtoService } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/write-service';
|
||||
import ErrorCodes from 'src/utils/errorCodes';
|
||||
|
||||
@Injectable()
|
||||
export class CustomersService implements OnModuleInit {
|
||||
private customerService: CustomersProtoService;
|
||||
|
||||
constructor(
|
||||
@Inject(DucClient.name) private readonly grpcClient: ClientGrpc,
|
||||
) {}
|
||||
|
||||
onModuleInit() {
|
||||
this.customerService = this.grpcClient.getService<CustomersProtoService>(
|
||||
ProtoServices.CustomersProtoService,
|
||||
);
|
||||
}
|
||||
|
||||
async getLinks(customerId: string) {
|
||||
try {
|
||||
const result = await lastValueFrom(
|
||||
this.customerService.CustomerFindOneById({ id: customerId }),
|
||||
);
|
||||
return result.customer?.links || [];
|
||||
} catch (err) {
|
||||
if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND)
|
||||
throw new HttpException(err.details, HttpStatus.NOT_FOUND);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async setLinks(customerId: string, links: Link[]) {
|
||||
if (!customerId || !links) {
|
||||
throw new HttpException(null, HttpStatus.BAD_REQUEST);
|
||||
}
|
||||
|
||||
try {
|
||||
return await firstValueFrom(
|
||||
this.customerService.CustomerUpdate({
|
||||
id: customerId,
|
||||
links,
|
||||
} as CustomerUpdateRequest),
|
||||
);
|
||||
} catch (err) {
|
||||
if (err.details === ErrorCodes.CUSTOMER.NOT_FOUND)
|
||||
throw new HttpException(err.details, HttpStatus.NOT_FOUND);
|
||||
else throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Link } from '@dadosfera/protospack-v2/dist/lib/Duc/interfaces/entities';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CustomerDto {
|
||||
@ApiProperty()
|
||||
links: Link[];
|
||||
}
|
||||
|
||||
export class CustomerLinksResponse {
|
||||
@ApiProperty()
|
||||
links: Link[];
|
||||
}
|
||||
@@ -123,8 +123,7 @@ export class InputsController {
|
||||
}
|
||||
|
||||
@Get('/:id')
|
||||
async findOne(@Body() body, @Param() params) {
|
||||
const { id } = params;
|
||||
async findOne(@Body() body, @Param('id') id: string) {
|
||||
this.logger.info(`/input/${id} - ON FIND ONE ROUTE`, {
|
||||
user: body.info.user_id,
|
||||
customer: body.info.customer,
|
||||
|
||||
@@ -17,7 +17,7 @@ export class HubspotStrategy extends PassportStrategy(Strategy) {
|
||||
clientSecret: oauthSecrets.hubspot.client_secret,
|
||||
callbackURL: oauthSecrets.hubspot.redirect_uri,
|
||||
scope:
|
||||
'automation business-intelligence oauth forms integration-sync sales-email-read crm.lists.read crm.objects.contacts.read crm.schemas.contacts.read crm.objects.companies.read crm.objects.deals.read crm.schemas.companies.read crm.schemas.deals.read crm.objects.owners.read crm.objects.quotes.read crm.schemas.quotes.read crm.objects.line_items.read crm.schemas.line_items.read',
|
||||
'tickets automation business-intelligence oauth forms integration-sync sales-email-read crm.lists.read crm.objects.contacts.read crm.schemas.contacts.read crm.objects.companies.read crm.objects.deals.read crm.schemas.companies.read crm.schemas.deals.read crm.objects.owners.read crm.objects.quotes.read crm.schemas.quotes.read crm.objects.line_items.read crm.schemas.line_items.read',
|
||||
passReqToCallback: true,
|
||||
},
|
||||
(accessToken, refreshToken, tokenInfo, profile, done) => {
|
||||
|
||||
@@ -49,8 +49,7 @@ export class PipelinesController {
|
||||
description:
|
||||
'This method is deprecated. Please use route /pipelinesV2/start/:id instead',
|
||||
})
|
||||
async activate(@Param() params, @Body() body) {
|
||||
const { id } = params;
|
||||
async activate(@Param('id') id: string, @Body() body) {
|
||||
const { info } = body;
|
||||
|
||||
this.logger.info(
|
||||
@@ -72,8 +71,7 @@ export class PipelinesController {
|
||||
description:
|
||||
'This method is deprecated. Please use route /pipelinesV2/:id/status instead',
|
||||
})
|
||||
async getPipelineStatus(@Body() body, @Param() params) {
|
||||
const { id } = params;
|
||||
async getPipelineStatus(@Body() body, @Param('id') id: string) {
|
||||
body.id = id;
|
||||
|
||||
this.logger.info(
|
||||
|
||||
@@ -170,7 +170,7 @@ export class PipelinesController {
|
||||
async getPipelineproperties(
|
||||
@Language() language: LanguageEnum,
|
||||
@User() user: RequestUser,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
this.logger.info('PipelinesController - getPipelineproperties', { user });
|
||||
const metadata = PackTheMetadata({ ...user, language: language });
|
||||
@@ -181,7 +181,7 @@ export class PipelinesController {
|
||||
async getPipelineObjects(
|
||||
@Language() language: LanguageEnum,
|
||||
@User() user: RequestUser,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
) {
|
||||
this.logger.info('PipelinesController - getPipelineObjects', { user });
|
||||
const metadata = PackTheMetadata({ ...user, language: language });
|
||||
@@ -189,8 +189,7 @@ export class PipelinesController {
|
||||
}
|
||||
|
||||
@Get(':id/status')
|
||||
async getPipelineStatus(@Body() body, @Param() params) {
|
||||
const { id } = params;
|
||||
async getPipelineStatus(@Body() body, @Param('id') id: string) {
|
||||
body.id = id;
|
||||
|
||||
this.logger.info(
|
||||
@@ -210,7 +209,7 @@ export class PipelinesController {
|
||||
async findOne(
|
||||
@Language() language: LanguageEnum,
|
||||
@User() user: RequestUser,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
): Promise<Messages.PipelineV2FindOneResponse> {
|
||||
this.logger.info('PipelinesController - findOne', { user });
|
||||
|
||||
@@ -251,7 +250,7 @@ export class PipelinesController {
|
||||
async update(
|
||||
@Language() language: LanguageEnum,
|
||||
@Body() updatePipelineDto,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
this.logger.info('PipelinesController - update', { user });
|
||||
@@ -290,7 +289,7 @@ export class PipelinesController {
|
||||
async updateDeprecated(
|
||||
@Language() language: LanguageEnum,
|
||||
@Body() updatePipelineDto,
|
||||
@Param('id') id,
|
||||
@Param('id') id: string,
|
||||
@User() user: RequestUser,
|
||||
) {
|
||||
this.logger.info('PipelinesController - put', { user });
|
||||
@@ -302,9 +301,8 @@ export class PipelinesController {
|
||||
@Delete(':id')
|
||||
@ApiNoContentResponse()
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
async delete(@Param() params, @User() user: RequestUser) {
|
||||
async delete(@Param('id') id: string, @User() user: RequestUser) {
|
||||
this.logger.info('PipelinesController - delete', { user });
|
||||
const { id } = params;
|
||||
const metadata = PackTheMetadata({
|
||||
customer_id: user.customer_id,
|
||||
customer_name: user.customer_name,
|
||||
@@ -416,8 +414,7 @@ export class PipelinesController {
|
||||
|
||||
@ApiInternalOnlyEndpoint()
|
||||
@Post('start/:id')
|
||||
async activate(@Param() params, @Body() body) {
|
||||
const { id } = params;
|
||||
async activate(@Param('id') id: string, @Body() body) {
|
||||
const { info } = body;
|
||||
|
||||
this.logger.info(
|
||||
|
||||
@@ -233,15 +233,23 @@ export class PipelinesService implements OnModuleInit {
|
||||
const config_controls = (connector.config_controls || []).filter(
|
||||
(config_control) => {
|
||||
const path: string = config_control.name;
|
||||
|
||||
if (!objHasPath({ object: { properties }, path })) return false;
|
||||
|
||||
const default_value = getObjValueFromPath({
|
||||
let default_value = getObjValueFromPath({
|
||||
object: { properties },
|
||||
path,
|
||||
});
|
||||
if (default_value != undefined)
|
||||
|
||||
if (default_value != undefined) {
|
||||
if (
|
||||
path === 'properties.spreadsheet_id' &&
|
||||
typeof default_value === 'string'
|
||||
)
|
||||
default_value = 'https://docs.google.com/spreadsheets/d/'.concat(
|
||||
default_value,
|
||||
);
|
||||
config_control.default_value = default_value;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
@@ -251,7 +259,7 @@ export class PipelinesService implements OnModuleInit {
|
||||
pipeline: {
|
||||
...pipeline,
|
||||
config_controls,
|
||||
properties: properties,
|
||||
properties,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -72,8 +72,7 @@ export class TransformationsController {
|
||||
|
||||
@Get('/:id')
|
||||
@RequireSomePermission(pipelinePermissions.GET)
|
||||
async findOne(@Body() data, @Param() params) {
|
||||
const { id } = params;
|
||||
async findOne(@Body() data, @Param('id') id: string) {
|
||||
this.logger.info(`/transformation/${id} - ON Find One ROUTE`, {
|
||||
user: data.info.user_id,
|
||||
customer: data.info.customer,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
export function getObjValueFromPath<T>(data: { object: T; path: string }): T {
|
||||
export function getObjValueFromPath<T extends object>(data: {
|
||||
object: T;
|
||||
path: string;
|
||||
}): any {
|
||||
const { object, path } = data;
|
||||
const keys = path.split('.');
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ export const CUSTOMER = {
|
||||
INVALID_ID: 'CUSTOMER.INVALID_ID',
|
||||
NOT_FOUND: 'CUSTOMER.NOT_FOUND',
|
||||
ALREADY_EXISTS: 'CUSTOMER.ALREADY_EXISTS',
|
||||
BAD_REQUEST: 'CUSTOMER.BAD_REQUEST',
|
||||
};
|
||||
const TERMS_OF_USE = {
|
||||
UP_TO_DATE: 'TERMS_OF_USE.UP_TO_DATE',
|
||||
|
||||
Reference in New Issue
Block a user