Compare commits

..

6 Commits

39 changed files with 746 additions and 466 deletions

View File

@@ -0,0 +1,116 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create Cloud Firestore document',
key: 'createCloudFirestoreDocument',
description: 'Creates a new document within a Cloud Firestore collection.',
arguments: [
{
label: 'Collection',
key: 'collectionId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listFirestoreCollections',
},
],
},
},
{
label: 'Convert Numerics',
key: 'convertNumerics',
type: 'dropdown',
required: false,
description:
"If any value represents a valid numerical value, whether it's an integer or a floating-point number, this field directs the database to store it as a numeric data type instead of a string.",
variables: true,
options: [
{ label: 'Yes', value: true },
{ label: 'No', value: false },
],
},
{
label: 'Document ID',
key: 'documentId',
type: 'string',
required: false,
description:
'The document ID to use for this document. If not specified, an ID will be assigned.',
variables: true,
},
{
label: 'Document Data',
key: 'documentData',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Key',
key: 'key',
type: 'string',
required: false,
variables: true,
},
{
label: 'Value',
key: 'value',
type: 'string',
required: false,
variables: true,
},
],
},
],
async run($) {
const projectId = $.auth.data.projectId;
const { collectionId, documentId, documentData, convertNumerics } =
$.step.parameters;
const documentDataObject = documentData.reduce((result, entry) => {
const key = entry.key?.toLowerCase();
const value = entry.value;
const isNumber = !isNaN(parseFloat(value));
if (key && value) {
const formattedValue =
convertNumerics && isNumber
? { integerValue: parseFloat(value) }
: { stringValue: value };
return {
...result,
[key]: formattedValue,
};
}
return result;
}, {});
const body = {
fields: documentDataObject,
};
const { data } = await $.http.post(
`/v1/projects/${projectId}/databases/(default)/documents/${collectionId}?documentId=${documentId}`,
body,
{
additionalProperties: {
setFirestoreBaseUrl: true,
},
}
);
$.setActionItem({
raw: data,
});
},
});

View File

@@ -0,0 +1,100 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Create Firebase Realtime Database Record',
key: 'createFirebaseRealtimeDatabaseRecord',
description: 'Creates a child object within your Firebase Realtime Database.',
arguments: [
{
label: 'Path',
key: 'path',
type: 'string',
required: true,
description:
"Indicate the path to the key of the object where the child objects to be queried are located, for example, 'foo/bar/here'.",
variables: true,
},
{
label: 'Convert Numerics',
key: 'convertNumerics',
type: 'dropdown',
required: false,
description:
"If any value represents a valid numerical value, whether it's an integer or a floating-point number, this field directs the database to store it as a numeric data type instead of a string.",
variables: true,
options: [
{ label: 'Yes', value: true },
{ label: 'No', value: false },
],
},
{
label: 'New ID',
key: 'newId',
type: 'string',
required: false,
description:
'The key to use for this object, or leave it blank for Firebase to create one automatically.',
variables: true,
},
{
label: 'Data',
key: 'childData',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'Key',
key: 'key',
type: 'string',
required: false,
variables: true,
},
{
label: 'Value',
key: 'value',
type: 'string',
required: false,
variables: true,
},
],
},
],
async run($) {
let path = $.step.parameters.path;
const { convertNumerics, newId, childData } = $.step.parameters;
if (newId) {
path = `${path}/${newId}.json`;
} else {
path = `${path}.json`;
}
const formattedChildObjectData = childData.reduce((result, entry) => {
const key = entry?.key;
const value = entry?.value;
const isNumber = !isNaN(parseFloat(value));
if (isNumber && convertNumerics) {
result[key] = parseFloat(value);
} else {
result[key] = value;
}
return result;
}, {});
const body = formattedChildObjectData;
const { data } = await $.http.post(path, body, {
additionalProperties: {
setFirestoreBaseUrl: false,
},
});
$.setActionItem({
raw: data,
});
},
});

View File

@@ -0,0 +1,53 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Find Cloud Firestore document',
key: 'findCloudFirestoreDocument',
description: 'Finds a document within a collection.',
arguments: [
{
label: 'Collection',
key: 'collectionId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listFirestoreCollections',
},
],
},
},
{
label: 'Document ID',
key: 'documentId',
type: 'string',
required: true,
description: '',
variables: true,
},
],
async run($) {
const projectId = $.auth.data.projectId;
const { collectionId, documentId } = $.step.parameters;
const { data } = await $.http.get(
`/v1/projects/${projectId}/databases/(default)/documents/${collectionId}/${documentId}`,
{
additionalProperties: {
setFirestoreBaseUrl: true,
},
}
);
$.setActionItem({
raw: data,
});
},
});

View File

@@ -0,0 +1,9 @@
import createCloudFirestoreDocument from './create-cloud-firestore-document/index.js';
import createFirebaseRealtimeDatabaseRecord from './create-firebase-realtime-database-record/index.js';
import findCloudFirestoreDocument from './find-cloud-firestore-document/index.js';
export default [
createCloudFirestoreDocument,
createFirebaseRealtimeDatabaseRecord,
findCloudFirestoreDocument,
];

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -11,7 +11,7 @@ export default {
type: 'string',
required: true,
readOnly: true,
value: '{WEB_APP_URL}/app/gmail/connections/add',
value: '{WEB_APP_URL}/app/firebase/connections/add',
placeholder: null,
description:
'When asked to input a redirect URL in Google Cloud, enter the URL above.',
@@ -39,6 +39,29 @@ export default {
description: null,
clickToCopy: false,
},
{
key: 'projectId',
label: 'Project ID',
type: 'string',
required: true,
readOnly: false,
value: null,
placeholder: null,
description: 'The project id of your Firebase project',
clickToCopy: false,
},
{
key: 'realtimeDatabaseId',
label: 'Realtime Database Domain',
type: 'string',
required: false,
readOnly: false,
value: null,
placeholder: null,
description:
'If you want to use Realtime Database, please provide the domain of your Realtime Database (https://{{domain}}.firebaseio.com)',
clickToCopy: false,
},
],
generateAuthUrl,

View File

@@ -12,7 +12,12 @@ const refreshToken = async ($) => {
const { data } = await $.http.post(
'https://oauth2.googleapis.com/token',
params.toString()
params.toString(),
{
additionalProperties: {
skipAddingAuthHeader: true,
},
}
);
await $.auth.set({

View File

@@ -5,13 +5,21 @@ const verifyCredentials = async ($) => {
(field) => field.key == 'oAuthRedirectUrl'
);
const redirectUri = oauthRedirectUrlField.value;
const { data } = await $.http.post(`https://oauth2.googleapis.com/token`, {
client_id: $.auth.data.clientId,
client_secret: $.auth.data.clientSecret,
code: $.auth.data.code,
grant_type: 'authorization_code',
redirect_uri: redirectUri,
});
const { data } = await $.http.post(
`https://oauth2.googleapis.com/token`,
{
client_id: $.auth.data.clientId,
client_secret: $.auth.data.clientSecret,
code: $.auth.data.code,
grant_type: 'authorization_code',
redirect_uri: redirectUri,
},
{
additionalProperties: {
skipAddingAuthHeader: true,
},
}
);
await $.auth.set({
accessToken: data.access_token,
@@ -36,7 +44,6 @@ const verifyCredentials = async ($) => {
refreshToken: data.refresh_token,
resourceName: currentUser.resourceName,
screenName: `${displayName} - ${email}`,
userId: email,
});
};

View File

@@ -1,6 +1,7 @@
const authScope = [
'https://www.googleapis.com/auth/gmail.compose',
'https://www.googleapis.com/auth/gmail.modify',
'https://www.googleapis.com/auth/datastore',
'https://www.googleapis.com/auth/firebase.database',
'https://www.googleapis.com/auth/datastore',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
];

View File

@@ -1,6 +1,11 @@
const getCurrentUser = async ($) => {
const { data: currentUser } = await $.http.get(
'https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses'
'https://people.googleapis.com/v1/people/me?personFields=names,emailAddresses',
{
additionalProperties: {
skipAddingAuthHeader: true,
},
}
);
return currentUser;
};

View File

@@ -0,0 +1,16 @@
const setBaseUrl = ($, requestConfig) => {
const realtimeDatabaseId = $.auth.data.realtimeDatabaseId;
if (requestConfig.additionalProperties?.skipAddingAuthHeader)
return requestConfig;
if (requestConfig.additionalProperties?.setFirestoreBaseUrl) {
requestConfig.baseURL = 'https://firestore.googleapis.com';
} else {
requestConfig.baseURL = `https://${realtimeDatabaseId}.firebaseio.com`;
}
return requestConfig;
};
export default setBaseUrl;

View File

@@ -0,0 +1,3 @@
import listFirestoreCollections from './list-firestore-collections/index.js';
export default [listFirestoreCollections];

View File

@@ -0,0 +1,32 @@
export default {
name: 'List firestore collections',
key: 'listFirestoreCollections',
async run($) {
const firestoreCollections = {
data: [],
};
const projectId = $.auth.data.projectId;
const { data } = await $.http.post(
`/v1/projects/${projectId}/databases/(default)/documents:listCollectionIds`,
null,
{
additionalProperties: {
setFirestoreBaseUrl: true,
},
}
);
if (data.collectionIds?.length) {
for (const collectionId of data.collectionIds) {
firestoreCollections.data.push({
value: collectionId,
name: collectionId,
});
}
}
return firestoreCollections;
},
};

View File

@@ -1,20 +1,21 @@
import defineApp from '../../helpers/define-app.js';
import addAuthHeader from './common/add-auth-header.js';
import auth from './auth/index.js';
import setBaseUrl from './common/set-base-url.js';
import triggers from './triggers/index.js';
import dynamicData from './dynamic-data/index.js';
import actions from './actions/index.js';
export default defineApp({
name: 'Gmail',
key: 'gmail',
baseUrl: 'https://mail.google.com',
apiBaseUrl: 'https://gmail.googleapis.com',
iconUrl: '{BASE_URL}/apps/gmail/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/gmail/connection',
primaryColor: 'ea4335',
name: 'Firebase',
key: 'firebase',
baseUrl: 'https://firebase.google.com',
apiBaseUrl: '',
iconUrl: '{BASE_URL}/apps/firebase/assets/favicon.svg',
authDocUrl: 'https://automatisch.io/docs/apps/firebase/connection',
primaryColor: 'FFA000',
supportsConnections: true,
beforeRequest: [addAuthHeader],
beforeRequest: [setBaseUrl, addAuthHeader],
auth,
triggers,
dynamicData,

View File

@@ -0,0 +1,7 @@
import newChildObjectInFirebaseRealtimeDatabase from './new-child-object-in-a-firebase-realtime-database/index.js';
import newDocumentsWithinFirestoreCollection from './new-documents-within-firestore-collection/index.js';
export default [
newChildObjectInFirebaseRealtimeDatabase,
newDocumentsWithinFirestoreCollection,
];

View File

@@ -0,0 +1,75 @@
import Crypto from 'crypto';
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New child object in a firebase realtime database',
key: 'newChildObjectInFirebaseRealtimeDatabase',
pollInterval: 15,
description:
'Triggers when a new child object is generated within a specific path.',
arguments: [
{
label: 'Path',
key: 'path',
type: 'string',
required: true,
description:
"Indicate the path to the key of the object where the child objects to be queried are located, for example, 'foo/bar/here.json'.",
variables: true,
},
{
label: 'Order',
key: 'order',
type: 'string',
required: false,
description:
'The key or path of the child that should be utilized for comparing objects/records. If unspecified, the order of $key is used.',
variables: true,
},
{
label: 'Location of newest objects',
key: 'locationOfNewestObjects',
type: 'dropdown',
required: false,
description:
'Specifies whether the new 100 records are positioned at the "top" or the "bottom" of the ordering. If left unspecified, the assumption is that the bottom/last result represents the "newest objects" (limitToLast).',
variables: true,
options: [
{ label: 'Top of results', value: 'limitToFirst' },
{ label: 'Bottom of results', value: 'limitToLast' },
],
},
],
async run($) {
const { path, order, locationOfNewestObjects } = $.step.parameters;
const params = {};
if (order) {
params.orderBy = `"${order}"`;
}
if (locationOfNewestObjects) {
params[`${locationOfNewestObjects}`] = 100;
}
const { data } = await $.http.get(path, {
params,
additionalProperties: {
setFirestoreBaseUrl: false,
},
});
if (!data) {
return;
}
$.pushTriggerItem({
raw: data,
meta: {
internalId: Crypto.randomUUID(),
},
});
},
});

View File

@@ -0,0 +1,66 @@
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New documents within a firestore collection',
key: 'newDocumentsWithinFirestoreCollection',
pollInterval: 15,
description:
'Triggers when a new document is added within a Cloud Firestore collection.',
arguments: [
{
label: 'Collection',
key: 'collectionId',
type: 'dropdown',
required: true,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listFirestoreCollections',
},
],
},
},
],
async run($) {
const projectId = $.auth.data.projectId;
const collectionId = $.step.parameters.collectionId;
const params = {
pageSize: 100,
pageToken: undefined,
};
do {
const { data } = await $.http.get(
`/v1/projects/${projectId}/databases/(default)/documents/${collectionId}`,
{
params,
additionalProperties: {
setFirestoreBaseUrl: true,
},
}
);
params.pageToken = data.nextPageToken;
if (!data?.documents?.length) {
return;
}
for (const document of data.documents) {
const nameParts = document.name.split('/');
const id = nameParts[nameParts.length - 1];
$.pushTriggerItem({
raw: document,
meta: {
internalId: id,
},
});
}
} while (params.pageToken);
},
});

View File

@@ -1,3 +0,0 @@
import sendEmail from './send-email/index.js';
export default [sendEmail];

View File

@@ -1,234 +0,0 @@
import defineAction from '../../../../helpers/define-action.js';
export default defineAction({
name: 'Send email',
key: 'sendEmail',
description: 'Send a new email message.',
arguments: [
{
label: 'TOs',
key: 'tos',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'To',
key: 'to',
type: 'string',
required: false,
variables: true,
},
],
},
{
label: 'CCs',
key: 'ccs',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'CC',
key: 'cc',
type: 'string',
required: false,
variables: true,
},
],
},
{
label: 'BCCs',
key: 'bccs',
type: 'dynamic',
required: false,
description: '',
fields: [
{
label: 'BCC',
key: 'bcc',
type: 'string',
required: false,
variables: true,
},
],
},
{
label: 'From',
key: 'from',
type: 'dropdown',
required: false,
description:
'Select an email address or alias from your Gmail Account. Defaults to the primary email address.',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listEmails',
},
],
},
},
{
label: 'From Name',
key: 'fromName',
type: 'string',
required: false,
description: '',
variables: true,
},
{
label: 'Reply To',
key: 'replyTo',
type: 'string',
required: false,
description: 'Specify a single reply address other than your own.',
variables: true,
},
{
label: 'Subject',
key: 'subject',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'Body Type',
key: 'bodyType',
type: 'dropdown',
required: false,
description: '',
variables: true,
options: [
{
label: 'plain',
value: 'plain',
},
{
label: 'html',
value: 'html',
},
],
},
{
label: 'Body',
key: 'emailBody',
type: 'string',
required: true,
description: '',
variables: true,
},
{
label: 'Signature',
key: 'signature',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listSignatures',
},
],
},
},
{
label: 'Label',
key: 'labelId',
type: 'dropdown',
required: false,
description: '',
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listLabels',
},
],
},
},
],
async run($) {
const {
tos,
ccs,
bccs,
from,
fromName,
replyTo,
subject,
bodyType,
emailBody,
signature,
labelId,
} = $.step.parameters;
const userId = $.auth.data.userId;
const allTos = tos?.map((entry) => entry.to);
const allCcs = ccs?.map((entry) => entry.cc);
const allBccs = bccs?.map((entry) => entry.bcc);
const contentType =
bodyType === 'html'
? 'text/html; charset="UTF-8"'
: 'text/plain; charset="UTF-8"';
const email =
'From: ' +
fromName +
' <' +
from +
'>' +
'\r\n' +
'Reply-To: ' +
replyTo +
'\r\n' +
'To: ' +
allTos.join(',') +
'\r\n' +
'Cc: ' +
allCcs.join(',') +
'\r\n' +
'Bcc: ' +
allBccs.join(',') +
'\r\n' +
'Subject: ' +
subject +
'\r\n' +
'Content-Type: ' +
contentType +
'\r\n' +
'\r\n' +
emailBody +
'\r\n' +
'\r\n' +
signature;
const base64EncodedEmailBody = Buffer.from(email).toString('base64');
const body = {
labelIds: [labelId],
raw: base64EncodedEmailBody,
};
const { data } = await $.http.post(
`/gmail/v1/users/${userId}/messages/send`,
body
);
$.setActionItem({
raw: data,
});
},
});

View File

@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 49.4 512 399.42">
<g fill="none" fill-rule="evenodd">
<g fill-rule="nonzero">
<path fill="#4285f4" d="M34.91 448.818h81.454V251L0 163.727V413.91c0 19.287 15.622 34.91 34.91 34.91z"/>
<path fill="#34a853" d="M395.636 448.818h81.455c19.287 0 34.909-15.622 34.909-34.909V163.727L395.636 251z"/>
<path fill="#fbbc04" d="M395.636 99.727V251L512 163.727v-46.545c0-43.142-49.25-67.782-83.782-41.891z"/>
</g>
<path fill="#ea4335" d="M116.364 251V99.727L256 204.455 395.636 99.727V251L256 355.727z"/>
<path fill="#c5221f" fill-rule="nonzero" d="M0 117.182v46.545L116.364 251V99.727L83.782 75.291C49.25 49.4 0 74.04 0 117.18z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 720 B

View File

@@ -1,5 +0,0 @@
import listEmails from './list-emails/index.js';
import listLabels from './list-labels/index.js';
import listSignatures from './list-signatures/index.js';
export default [listEmails, listLabels, listSignatures];

View File

@@ -1,23 +0,0 @@
import getCurrentUser from '../../common/get-current-user.js';
export default {
name: 'List emails',
key: 'listEmails',
async run($) {
const emails = {
data: [],
};
const currentUser = await getCurrentUser($);
for (const emailAddress of currentUser.emailAddresses) {
emails.data.push({
value: emailAddress.value,
name: emailAddress.value,
});
}
return emails;
},
};

View File

@@ -1,22 +0,0 @@
export default {
name: 'List labels',
key: 'listLabels',
async run($) {
const labels = {
data: [],
};
const userId = $.auth.data.userId;
const { data } = await $.http.get(`/gmail/v1/users/${userId}/labels`);
for (const label of data.labels) {
labels.data.push({
value: label.id,
name: label.name,
});
}
return labels;
},
};

View File

@@ -1,24 +0,0 @@
export default {
name: 'List signatures',
key: 'listSignatures',
async run($) {
const signatures = {
data: [],
};
const userId = $.auth.data.userId;
const { data } = await $.http.get(
`/gmail/v1/users/${userId}/settings/sendAs`
);
for (const sendAs of data.sendAs) {
signatures.data.push({
value: sendAs.signature,
name: sendAs.sendAsEmail,
});
}
return signatures;
},
};

View File

@@ -1,3 +0,0 @@
import newEmails from './new-emails/index.js';
export default [newEmails];

View File

@@ -1,68 +0,0 @@
import defineTrigger from '../../../../helpers/define-trigger.js';
export default defineTrigger({
name: 'New emails',
key: 'newEmails',
pollInterval: 15,
description:
'Triggers when a new email is received in the specified mailbox.',
arguments: [
{
label: 'Label',
key: 'labelId',
type: 'dropdown',
required: false,
description:
"If you don't choose a label, this Zap will trigger for all emails, including Drafts.",
variables: true,
source: {
type: 'query',
name: 'getDynamicData',
arguments: [
{
name: 'key',
value: 'listLabels',
},
],
},
},
],
async run($) {
const userId = $.auth.data.userId;
const labelId = $.step.parameters.labelId;
const params = {
maxResults: 500,
pageToken: undefined,
};
if (labelId) {
params.labelIds = labelId;
}
do {
const { data } = await $.http.get(`/gmail/v1/users/${userId}/messages`, {
params,
});
params.pageToken = data.nextPageToken;
if (!data?.messages?.length) {
return;
}
for (const message of data.messages) {
const { data: messageData } = await $.http.get(
`/gmail/v1/users/${userId}/messages/${message.id}`
);
$.pushTriggerItem({
raw: messageData,
meta: {
internalId: messageData.id,
},
});
}
} while (params.pageToken);
},
});

View File

@@ -95,6 +95,16 @@ export default defineConfig({
{ text: 'Connection', link: '/apps/filter/connection' },
],
},
{
text: 'Firebase',
collapsible: true,
collapsed: true,
items: [
{ text: 'Actions', link: '/apps/firebase/actions' },
{ text: 'Triggers', link: '/apps/firebase/triggers' },
{ text: 'Connection', link: '/apps/firebase/connection' },
],
},
{
text: 'Flickr',
collapsible: true,
@@ -141,16 +151,6 @@ export default defineConfig({
{ text: 'Connection', link: '/apps/gitlab/connection' },
],
},
{
text: 'Gmail',
collapsible: true,
collapsed: true,
items: [
{ text: 'Triggers', link: '/apps/gmail/triggers' },
{ text: 'Connection', link: '/apps/gmail/connection' },
{ text: 'Actions', link: '/apps/gmail/actions' },
],
},
{
text: 'Google Calendar',
collapsible: true,

View File

@@ -0,0 +1,16 @@
---
favicon: /favicons/firebase.svg
items:
- name: Create Cloud Firestore document
desc: Creates a new document within a Cloud Firestore collection.
- name: Create Firebase Realtime Database Record
desc: Creates a child object within your Firebase Realtime Database.
- name: Find Cloud Firestore document
desc: Finds a document within a collection.
---
<script setup>
import CustomListing from '../../components/CustomListing.vue'
</script>
<CustomListing />

View File

@@ -1,7 +1,7 @@
# Gmail
# Firebase
:::info
This page explains the steps you need to follow to set up the Gmail
This page explains the steps you need to follow to set up the Firebase
connection in Automatisch. If any of the steps are outdated, please let us know!
:::
@@ -9,9 +9,9 @@ connection in Automatisch. If any of the steps are outdated, please let us know!
2. Click on the project drop-down menu at the top of the page, and click on the **New Project** button.
3. Enter a name for your project and click on the **Create** button.
4. Go to [API Library](https://console.cloud.google.com/apis/library) in Google Cloud console.
5. Search for **People API** in the search bar and click on it.
5. Search for **Cloud Firestore API** in the search bar and click on it.
6. Click on the **Enable** button to enable the API.
7. Repeat steps 5 and 6 for the **Gmail API**
7. Repeat steps 5 and 6 for the **Firebase Realtime Database API and People API**
8. Go to [OAuth consent screen](https://console.cloud.google.com/apis/credentials/consent) in Google Cloud console.
9. Select **External** here for starting your app in testing mode at first. Click on the **Create** button.
10. Fill **App Name**, **User Support Email**, and **Developer Contact Information**. Click on the **Save and Continue** button.
@@ -24,5 +24,8 @@ connection in Automatisch. If any of the steps are outdated, please let us know!
17. Copy **OAuth Redirect URL** from Automatisch to **Authorized redirect URIs** field, and click on the **Create** button.
18. Copy the **Your Client ID** value from the following popup to the `Client ID` field on Automatisch.
19. Copy the **Your Client Secret** value from the following popup to the `Client Secret` field on Automatisch.
20. Click **Submit** button on Automatisch.
21. Congrats! Start using your new Gmail connection within the flows.
20. Login to your [Firebase account](https://firebase.google.com/) and go to your project (please create a new project if you don't already have one).
21. Click on the gear icon next to **Project Overview** and go to **Project settings**.
22. Copy the **Project ID** value to the `Project ID` field on Automatisch.
23. Click **Submit** button on Automatisch.
24. Congrats! Start using your new Firebase connection within the flows.

View File

@@ -0,0 +1,14 @@
---
favicon: /favicons/firebase.svg
items:
- name: New child object in a firebase realtime database
desc: Triggers when a new child object is generated within a specific path.
- name: New documents within a firestore collection
desc: Triggers when a new document is added within a Cloud Firestore collection.
---
<script setup>
import CustomListing from '../../components/CustomListing.vue'
</script>
<CustomListing />

View File

@@ -1,12 +0,0 @@
---
favicon: /favicons/gmail.svg
items:
- name: Send email
desc: Send a new email message.
---
<script setup>
import CustomListing from '../../components/CustomListing.vue'
</script>
<CustomListing />

View File

@@ -1,12 +0,0 @@
---
favicon: /favicons/gmail.svg
items:
- name: New emails
desc: Triggers when a new email is received in the specified mailbox.
---
<script setup>
import CustomListing from '../../components/CustomListing.vue'
</script>
<CustomListing />

View File

@@ -9,12 +9,12 @@ The following integrations are currently supported by Automatisch.
- [Discord](/apps/discord/actions)
- [Dropbox](/apps/dropbox/actions)
- [Filter](/apps/filter/actions)
- [Firebase](/apps/firebase/triggers)
- [Flickr](/apps/flickr/triggers)
- [Formatter](/apps/formatter/actions)
- [Ghost](/apps/ghost/triggers)
- [GitHub](/apps/github/triggers)
- [GitLab](/apps/gitlab/triggers)
- [Gmail](/apps/gmail/triggers)
- [Google Calendar](/apps/google-calendar/triggers)
- [Google Drive](/apps/google-drive/triggers)
- [Google Forms](/apps/google-forms/triggers)

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -1,11 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 49.4 512 399.42">
<g fill="none" fill-rule="evenodd">
<g fill-rule="nonzero">
<path fill="#4285f4" d="M34.91 448.818h81.454V251L0 163.727V413.91c0 19.287 15.622 34.91 34.91 34.91z"/>
<path fill="#34a853" d="M395.636 448.818h81.455c19.287 0 34.909-15.622 34.909-34.909V163.727L395.636 251z"/>
<path fill="#fbbc04" d="M395.636 99.727V251L512 163.727v-46.545c0-43.142-49.25-67.782-83.782-41.891z"/>
</g>
<path fill="#ea4335" d="M116.364 251V99.727L256 204.455 395.636 99.727V251L256 355.727z"/>
<path fill="#c5221f" fill-rule="nonzero" d="M0 117.182v46.545L116.364 251V99.727L83.782 75.291C49.25 49.4 0 74.04 0 117.18z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 720 B