diff --git a/packages/nodes-base/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.ts b/packages/nodes-base/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.ts index 2e6017b296..52413c0b7e 100644 --- a/packages/nodes-base/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.ts +++ b/packages/nodes-base/credentials/GoogleFirebaseRealtimeDatabaseOAuth2Api.credentials.ts @@ -23,5 +23,25 @@ export class GoogleFirebaseRealtimeDatabaseOAuth2Api implements ICredentialType type: 'hidden', default: scopes.join(' '), }, + { + displayName: 'Region', + name: 'region', + type: 'options', + default: 'firebaseio.com', + options: [ + { + name: 'us-central1', + value: 'firebaseio.com', + }, + { + name: 'europe-west1', + value: 'europe-west1.firebasedatabase.app', + }, + { + name: 'asia-southeast1', + value: 'asia-southeast1.firebasedatabase.app', + }, + ], + }, ]; } diff --git a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/GenericFunctions.ts b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/GenericFunctions.ts index acb50b22f4..3a70524f24 100644 --- a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/GenericFunctions.ts +++ b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/GenericFunctions.ts @@ -9,11 +9,13 @@ import { } from 'n8n-core'; import { - IDataObject, NodeApiError, + IDataObject, JsonObject, NodeApiError, } from 'n8n-workflow'; export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleFunctions | ILoadOptionsFunctions, projectId: string, method: string, resource: string, body: any = {}, qs: IDataObject = {}, headers: IDataObject = {}, uri: string | null = null): Promise { // tslint:disable-line:no-any + const { region } = await this.getCredentials('googleFirebaseRealtimeDatabaseOAuth2Api') as IDataObject; + const options: OptionsWithUrl = { headers: { 'Content-Type': 'application/json', @@ -21,9 +23,10 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF method, body, qs, - url: uri || `https://${projectId}.firebaseio.com/${resource}.json`, + url: uri || `https://${projectId}.${region}/${resource}.json`, json: true, }; + try { if (Object.keys(headers).length !== 0) { options.headers = Object.assign({}, options.headers, headers); @@ -34,7 +37,7 @@ export async function googleApiRequest(this: IExecuteFunctions | IExecuteSingleF return await this.helpers.requestOAuth2!.call(this, 'googleFirebaseRealtimeDatabaseOAuth2Api', options); } catch (error) { - throw new NodeApiError(this.getNode(), error); + throw new NodeApiError(this.getNode(), error as JsonObject); } } diff --git a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/RealtimeDatabase.node.ts b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/RealtimeDatabase.node.ts index 023d2b1a80..cd7cd66ded 100644 --- a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/RealtimeDatabase.node.ts +++ b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/RealtimeDatabase.node.ts @@ -9,6 +9,7 @@ import { INodePropertyOptions, INodeType, INodeTypeDescription, + JsonObject, NodeApiError, NodeOperationError, } from 'n8n-workflow'; @@ -22,7 +23,7 @@ export class RealtimeDatabase implements INodeType { description: INodeTypeDescription = { displayName: 'Google Cloud Realtime Database', name: 'googleFirebaseRealtimeDatabase', - icon: 'file:googleFirebaseRealtimeDatabase.png', + icon: 'file:googleFirebaseRealtimeDatabase.svg', group: ['input'], version: 1, subtitle: '={{$parameter["operation"]}}', @@ -53,6 +54,7 @@ export class RealtimeDatabase implements INodeType { displayName: 'Operation', name: 'operation', type: 'options', + noDataExpression: true, options: [ { name: 'Create', @@ -81,7 +83,6 @@ export class RealtimeDatabase implements INodeType { }, ], default: 'create', - description: 'The operation to perform.', required: true, }, { @@ -89,9 +90,28 @@ export class RealtimeDatabase implements INodeType { name: 'path', type: 'string', default: '', - placeholder: '/app/users', - description: 'Object path on database. With leading slash. Do not append .json.', + placeholder: 'e.g. /app/users', + description: 'Object path on database. Do not append .json.', required: true, + displayOptions: { + hide: { + 'operation': [ 'get' ], + }, + }, + }, + { + displayName: 'Object Path', + name: 'path', + type: 'string', + default: '', + placeholder: 'e.g. /app/users', + description: 'Object path on database. Do not append .json.', + hint: 'Leave blank to get a whole database object', + displayOptions: { + show: { + 'operation': [ 'get' ], + }, + }, }, { displayName: 'Columns / Attributes', @@ -121,7 +141,7 @@ export class RealtimeDatabase implements INodeType { ): Promise { const projects = await googleApiRequestAllItems.call( this, - 'projects', + '', 'GET', 'results', {}, @@ -129,14 +149,23 @@ export class RealtimeDatabase implements INodeType { {}, 'https://firebase.googleapis.com/v1beta1/projects', ); - const returnData = projects.map((o: IDataObject) => ({ name: o.projectId, value: o.projectId })) as INodePropertyOptions[]; + + const returnData = projects + // select only realtime database projects + .filter((project: IDataObject) => (project.resources as IDataObject).realtimeDatabaseInstance ) + .map((project: IDataObject) => ( + { + name: project.projectId, + value: (project.resources as IDataObject).realtimeDatabaseInstance, + } + )) as INodePropertyOptions[]; + return returnData; }, }, }; async execute(this: IExecuteFunctions): Promise { - const items = this.getInputData(); const returnData: IDataObject[] = []; const length = (items.length as unknown) as number; @@ -144,6 +173,7 @@ export class RealtimeDatabase implements INodeType { const operation = this.getNodeParameter('operation', 0) as string; //https://firebase.google.com/docs/reference/rest/database + if (['push', 'create', 'update'].includes(operation) && items.length === 1 && Object.keys(items[0].json).length === 0) { throw new NodeOperationError(this.getNode(), `The ${operation} operation needs input data`); } @@ -151,6 +181,7 @@ export class RealtimeDatabase implements INodeType { for (let i = 0; i < length; i++) { try { const projectId = this.getNodeParameter('projectId', i) as string; + let method = 'GET', attributes = ''; const document: IDataObject = {}; if (operation === 'create') { @@ -194,7 +225,7 @@ export class RealtimeDatabase implements INodeType { } } catch (error) { if (this.continueOnFail()) { - returnData.push({ error: error.message }); + returnData.push({ error: (error as JsonObject).message }); continue; } throw error; diff --git a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.png b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.png deleted file mode 100644 index a956676107..0000000000 Binary files a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.png and /dev/null differ diff --git a/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.svg b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.svg new file mode 100644 index 0000000000..feec452fc2 --- /dev/null +++ b/packages/nodes-base/nodes/Google/Firebase/RealtimeDatabase/googleFirebaseRealtimeDatabase.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +