initial setup for google firebase integration

This commit is contained in:
Maurits Lourens 2022-03-08 17:31:36 +01:00
parent f7de7ed349
commit e9405a1802
9 changed files with 317 additions and 2 deletions

View File

@ -0,0 +1,54 @@
<script>
export let width = "100"
export let height = "100"
</script>
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="23 6 469 132"
{width}
{height}
>
<defs id="defs202">
<linearGradient id="a" x1="-3.49%" x2="100.83%" y1="17.02%" y2="92.9%">
<stop offset="0%" stop-color="#fff" stop-opacity=".1" id="stop192" />
<stop offset="14%" stop-color="#fff" stop-opacity=".08" id="stop194" />
<stop offset="61%" stop-color="#fff" stop-opacity=".02" id="stop196" />
<stop offset="100%" stop-color="#fff" stop-opacity="0" id="stop198" />
</linearGradient>
<path
id="b"
d="M106.687 35.2742c-.186-1.0977-.967-2-2.0244-2.338s-2.2148-.057-3.0002.73L86.2473 49.166l-12.12-23.1455c-.5133-.9786-1.525-1.5914-2.6273-1.5914s-2.114.6128-2.6273 1.5914l-6.6277 12.656L45.62 7.5726c-.603-1.1297-1.8588-1.746-3.118-1.5297s-2.2394 1.216-2.4335 2.4827L24 111.701l42.9727 24.1654c2.6985 1.5113 5.985 1.5113 8.6836 0L119 111.701l-12.313-76.427z"
/>
</defs>
<g id="g305" transform="matrix(2.9011579,0,0,2.9011579,43.533284,-135.93685)">
<path
fill="#ffa000"
d="M 23.8266,111.7182 39.9588,8.4901 c 0.1972,-1.266 1.1818,-2.264 2.445,-2.4786 1.2632,-0.2146 2.522,0.4028 3.126,1.5327 L 62.2133,38.6615 68.8633,26 c 0.515,-0.979 1.5303,-1.592 2.6366,-1.592 1.1063,0 2.1215,0.613 2.6366,1.592 l 45.0227,85.718 H 23.8266 Z"
id="path204"
/>
<path
fill="#f57c00"
d="M 79.566,71.5074 62.2124,38.6472 23.8334,111.7187 Z"
id="path206"
/>
<path
fill="#ffca28"
d="m 119.1666,111.7187 -12.356,-76.4603 c -0.1867,-1.098 -0.9703,-2 -2.0315,-2.34 -1.0612,-0.34 -2.2226,-0.057 -3.0107,0.7302 l -77.935,78.069 43.1234,24.1834 c 2.708,1.512 6.006,1.512 8.714,0 l 43.4958,-24.1834 z"
id="path208"
/>
<path
fill="#ffffff"
fill-opacity="0.2"
d="m 106.8105,35.2584 c -0.1867,-1.098 -0.9703,-2 -2.0315,-2.34 -1.0612,-0.34 -2.2226,-0.057 -3.0107,0.7302 L 86.3,49.1562 74.1365,26 c -0.515,-0.979 -1.5303,-1.592 -2.6366,-1.592 -1.1063,0 -2.1215,0.613 -2.6366,1.592 L 62.2133,38.6615 45.529,7.5447 C 44.924,6.4145 43.6637,5.7981 42.399,6.0143 41.1343,6.2305 40.153,7.231 39.958,8.498 L 23.8333,111.7187 h -0.052 l 0.052,0.0596 0.4245,0.2085 77.488,-77.5775 c 0.7877,-0.7915 1.952,-1.076 3.016,-0.737 1.064,0.339 1.849,1.2445 2.0338,2.3457 l 12.2518,75.775 0.1192,-0.0745 -12.356,-76.4603 z M 23.9748,111.5772 39.9655,9.228 c 0.1948,-1.267 1.1784,-2.2675 2.442,-2.4837 1.2636,-0.2162 2.524,0.4 3.13,1.5304 L 62.22,39.392 68.87,26.7305 c 0.515,-0.979 1.5303,-1.592 2.6366,-1.592 1.1063,0 2.1215,0.613 2.6366,1.592 l 11.9167,22.664 -62.0858,62.1827 z"
id="path210"
/>
<path
fill="#a52714"
opacity="0.2"
d="m 75.6708,135.1722 c -2.708,1.512 -6.006,1.512 -8.714,0 l -43.0192,-24.1162 -0.1043,0.663 43.1234,24.176 c 2.708,1.512 6.006,1.512 8.714,0 l 43.4958,-24.176 -0.1117,-0.6852 -43.384,24.1387 z"
id="path212"
/>
</g>
</svg>

View File

@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="23 6 469 132"
width="100"
height="100"
version="1.1"
id="svg216"
sodipodi:docname="firebase.svg"
inkscape:version="1.1.2 (b8e25be8, 2022-02-05)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview218"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
showgrid="false"
inkscape:zoom="7.19"
inkscape:cx="50"
inkscape:cy="51.668985"
inkscape:window-width="1296"
inkscape:window-height="969"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="0"
inkscape:current-layer="svg216" />
<defs
id="defs202">
<linearGradient
id="a"
x1="-3.49%"
x2="100.83%"
y1="17.02%"
y2="92.9%">
<stop
offset="0%"
stop-color="#fff"
stop-opacity=".1"
id="stop192" />
<stop
offset="14%"
stop-color="#fff"
stop-opacity=".08"
id="stop194" />
<stop
offset="61%"
stop-color="#fff"
stop-opacity=".02"
id="stop196" />
<stop
offset="100%"
stop-color="#fff"
stop-opacity="0"
id="stop198" />
</linearGradient>
<path
id="b"
d="M106.687 35.2742c-.186-1.0977-.967-2-2.0244-2.338s-2.2148-.057-3.0002.73L86.2473 49.166l-12.12-23.1455c-.5133-.9786-1.525-1.5914-2.6273-1.5914s-2.114.6128-2.6273 1.5914l-6.6277 12.656L45.62 7.5726c-.603-1.1297-1.8588-1.746-3.118-1.5297s-2.2394 1.216-2.4335 2.4827L24 111.701l42.9727 24.1654c2.6985 1.5113 5.985 1.5113 8.6836 0L119 111.701l-12.313-76.427z" />
</defs>
<g
id="g305"
transform="matrix(2.9011579,0,0,2.9011579,43.533284,-135.93685)">
<path
fill="#ffa000"
d="M 23.8266,111.7182 39.9588,8.4901 c 0.1972,-1.266 1.1818,-2.264 2.445,-2.4786 1.2632,-0.2146 2.522,0.4028 3.126,1.5327 L 62.2133,38.6615 68.8633,26 c 0.515,-0.979 1.5303,-1.592 2.6366,-1.592 1.1063,0 2.1215,0.613 2.6366,1.592 l 45.0227,85.718 H 23.8266 Z"
id="path204" />
<path
fill="#f57c00"
d="M 79.566,71.5074 62.2124,38.6472 23.8334,111.7187 Z"
id="path206" />
<path
fill="#ffca28"
d="m 119.1666,111.7187 -12.356,-76.4603 c -0.1867,-1.098 -0.9703,-2 -2.0315,-2.34 -1.0612,-0.34 -2.2226,-0.057 -3.0107,0.7302 l -77.935,78.069 43.1234,24.1834 c 2.708,1.512 6.006,1.512 8.714,0 l 43.4958,-24.1834 z"
id="path208" />
<path
fill="#ffffff"
fill-opacity="0.2"
d="m 106.8105,35.2584 c -0.1867,-1.098 -0.9703,-2 -2.0315,-2.34 -1.0612,-0.34 -2.2226,-0.057 -3.0107,0.7302 L 86.3,49.1562 74.1365,26 c -0.515,-0.979 -1.5303,-1.592 -2.6366,-1.592 -1.1063,0 -2.1215,0.613 -2.6366,1.592 L 62.2133,38.6615 45.529,7.5447 C 44.924,6.4145 43.6637,5.7981 42.399,6.0143 41.1343,6.2305 40.153,7.231 39.958,8.498 L 23.8333,111.7187 h -0.052 l 0.052,0.0596 0.4245,0.2085 77.488,-77.5775 c 0.7877,-0.7915 1.952,-1.076 3.016,-0.737 1.064,0.339 1.849,1.2445 2.0338,2.3457 l 12.2518,75.775 0.1192,-0.0745 -12.356,-76.4603 z M 23.9748,111.5772 39.9655,9.228 c 0.1948,-1.267 1.1784,-2.2675 2.442,-2.4837 1.2636,-0.2162 2.524,0.4 3.13,1.5304 L 62.22,39.392 68.87,26.7305 c 0.515,-0.979 1.5303,-1.592 2.6366,-1.592 1.1063,0 2.1215,0.613 2.6366,1.592 l 11.9167,22.664 -62.0858,62.1827 z"
id="path210" />
<path
fill="#a52714"
opacity="0.2"
d="m 75.6708,135.1722 c -2.708,1.512 -6.006,1.512 -8.714,0 l -43.0192,-24.1162 -0.1043,0.663 43.1234,24.176 c 2.708,1.512 6.006,1.512 8.714,0 l 43.4958,-24.176 -0.1117,-0.6852 -43.384,24.1387 z"
id="path212" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -12,6 +12,7 @@ import Rest from "./Rest.svelte"
import Budibase from "./Budibase.svelte" import Budibase from "./Budibase.svelte"
import Oracle from "./Oracle.svelte" import Oracle from "./Oracle.svelte"
import GoogleSheets from "./GoogleSheets.svelte" import GoogleSheets from "./GoogleSheets.svelte"
import Firebase from "./Firebase.svelte"
export default { export default {
BUDIBASE: Budibase, BUDIBASE: Budibase,
@ -28,4 +29,5 @@ export default {
REST: Rest, REST: Rest,
ORACLE: Oracle, ORACLE: Oracle,
GOOGLE_SHEETS: GoogleSheets, GOOGLE_SHEETS: GoogleSheets,
FIREBASE: Firebase,
} }

View File

@ -178,6 +178,7 @@ export const IntegrationTypes = {
ORACLE: "ORACLE", ORACLE: "ORACLE",
INTERNAL: "INTERNAL", INTERNAL: "INTERNAL",
GOOGLE_SHEETS: "GOOGLE_SHEETS", GOOGLE_SHEETS: "GOOGLE_SHEETS",
FIREBASE: "FIREBASE",
} }
export const IntegrationNames = { export const IntegrationNames = {
@ -195,6 +196,7 @@ export const IntegrationNames = {
[IntegrationTypes.ORACLE]: "Oracle", [IntegrationTypes.ORACLE]: "Oracle",
[IntegrationTypes.INTERNAL]: "Internal", [IntegrationTypes.INTERNAL]: "Internal",
[IntegrationTypes.GOOGLE_SHEETS]: "Google Sheets", [IntegrationTypes.GOOGLE_SHEETS]: "Google Sheets",
[IntegrationTypes.FIREBASE]: "Firebase",
} }
export const SchemaTypeOptions = [ export const SchemaTypeOptions = [

View File

@ -77,6 +77,7 @@
"@bull-board/api": "^3.7.0", "@bull-board/api": "^3.7.0",
"@bull-board/koa": "^3.7.0", "@bull-board/koa": "^3.7.0",
"@elastic/elasticsearch": "7.10.0", "@elastic/elasticsearch": "7.10.0",
"@google-cloud/firestore": "^5.0.2",
"@koa/router": "8.0.0", "@koa/router": "8.0.0",
"@sendgrid/mail": "7.1.1", "@sendgrid/mail": "7.1.1",
"@sentry/node": "^6.0.0", "@sentry/node": "^6.0.0",

View File

@ -29,7 +29,7 @@ function getApiLimitPerSecond(): number {
return parseInt(env.API_REQ_LIMIT_PER_SEC) return parseInt(env.API_REQ_LIMIT_PER_SEC)
} }
if (!env.isTest()) { /*if (!env.isTest()) {
const REDIS_OPTS = getRedisOptions() const REDIS_OPTS = getRedisOptions()
RateLimit.defaultOptions({ RateLimit.defaultOptions({
store: new Stores.Redis({ store: new Stores.Redis({
@ -42,7 +42,7 @@ if (!env.isTest()) {
database: 1, database: 1,
}), }),
}) })
} }*/
// rate limiting, allows for 2 requests per second // rate limiting, allows for 2 requests per second
const limiter = RateLimit.middleware({ const limiter = RateLimit.middleware({
interval: { sec: 1 }, interval: { sec: 1 },

View File

@ -48,6 +48,7 @@ export enum SourceNames {
REST = "REST", REST = "REST",
ORACLE = "ORACLE", ORACLE = "ORACLE",
GOOGLE_SHEETS = "GOOGLE_SHEETS", GOOGLE_SHEETS = "GOOGLE_SHEETS",
FIREBASE = "FIREBASE",
} }
export enum IncludeRelationships { export enum IncludeRelationships {

View File

@ -0,0 +1,161 @@
import {
DatasourceFieldTypes,
Integration,
QueryTypes,
} from "../definitions/datasource"
import { IntegrationBase } from "./base/IntegrationBase"
import { Firestore, WhereFilterOp } from "@google-cloud/firestore"
module Firebase {
interface FirebaseConfig {
email: string
privateKey: string
projectId: string
}
const SCHEMA: Integration = {
docs: "https://firebase.google.com/docs/firestore/quickstart",
friendlyName: "Firestore",
description:
"Cloud Firestore is a flexible, scalable database for mobile, web, and server development from Firebase and Google Cloud.",
datasource: {
email: {
type: DatasourceFieldTypes.STRING,
required: true,
},
privateKey: {
type: DatasourceFieldTypes.STRING,
required: true,
},
projectId: {
type: DatasourceFieldTypes.STRING,
required: true,
},
},
query: {
create: {
type: QueryTypes.JSON,
},
read: {
type: QueryTypes.JSON,
},
update: {
type: QueryTypes.JSON,
},
delete: {
type: QueryTypes.JSON,
},
},
extra: {
collection: {
displayName: "Collection",
type: DatasourceFieldTypes.STRING,
required: true,
},
filter: {
displayName: "Filter query",
type: DatasourceFieldTypes.LIST,
required: false,
data: {
read: [
"==",
"<",
"<=",
"==",
"!=",
">=",
">",
"array-contains",
"in",
"not-in",
"array-contains-any",
],
},
},
queryValue: {
displayName: "Query value",
type: DatasourceFieldTypes.STRING,
required: false,
},
},
}
class FirebaseIntegration implements IntegrationBase {
private config: FirebaseConfig
private db: Firestore
constructor(config: FirebaseConfig) {
this.config = config
this.db = new Firestore({
projectId: config.projectId,
credential: {
clientEmail: config.email,
privateKey: config.privateKey,
},
})
}
async create(query: { json: object; extra: { [key: string]: string } }) {
try {
return await this.db.collection(query.extra.collection).add(query.json)
} catch (err) {
console.error("Error writing to Firestore", err)
throw err
}
}
async read(query: {
field: string
opStr: WhereFilterOp
value: any
extra: { [key: string]: string }
}) {
try {
const snapshot = await this.db
.collection(query.extra.collection)
.where(query.field, query.opStr, query.value)
.get()
const result: any[] = []
snapshot.forEach(doc => result.push(doc.data()))
return result
} catch (err) {
console.error("Error querying Firestore", err)
throw err
}
}
async update(query: {
id: string
json: object
extra: { [key: string]: string }
}) {
try {
return await this.db
.collection(query.extra.collection)
.doc(query.id)
.update(query.json)
} catch (err) {
console.error("Error writing to mongodb", err)
throw err
}
}
async delete(query: { id: string; extra: { [key: string]: string } }) {
try {
return await this.db
.collection(query.extra.collection)
.doc(query.id)
.delete()
} catch (err) {
console.error("Error writing to mongodb", err)
throw err
}
}
}
module.exports = {
schema: SCHEMA,
integration: FirebaseIntegration,
}
}

View File

@ -10,6 +10,7 @@ const mysql = require("./mysql")
const arangodb = require("./arangodb") const arangodb = require("./arangodb")
const rest = require("./rest") const rest = require("./rest")
const googlesheets = require("./googlesheets") const googlesheets = require("./googlesheets")
const firebase = require("./firebase")
const { SourceNames } = require("../definitions/datasource") const { SourceNames } = require("../definitions/datasource")
const environment = require("../environment") const environment = require("../environment")
@ -25,6 +26,7 @@ const DEFINITIONS = {
[SourceNames.MYSQL]: mysql.schema, [SourceNames.MYSQL]: mysql.schema,
[SourceNames.ARANGODB]: arangodb.schema, [SourceNames.ARANGODB]: arangodb.schema,
[SourceNames.REST]: rest.schema, [SourceNames.REST]: rest.schema,
[SourceNames.FIREBASE]: firebase.schema,
} }
const INTEGRATIONS = { const INTEGRATIONS = {
@ -39,6 +41,7 @@ const INTEGRATIONS = {
[SourceNames.MYSQL]: mysql.integration, [SourceNames.MYSQL]: mysql.integration,
[SourceNames.ARANGODB]: arangodb.integration, [SourceNames.ARANGODB]: arangodb.integration,
[SourceNames.REST]: rest.integration, [SourceNames.REST]: rest.integration,
[SourceNames.FIREBASE]: firebase.integration,
} }
// optionally add oracle integration if the oracle binary can be installed // optionally add oracle integration if the oracle binary can be installed