Firestore Recursive Delete via Firebase Admin SDK Local Node Server - node.js

I'm building a Firebase Admin SDK local nodejs server to which I'm trying to add recursive delete functionality. The examples I've been able to find, such as:
https://firebase.google.com/docs/firestore/solutions/delete-collections
use firebase-functions and appear to require an auth token, which all seems applicable when using the Firebase SDK rather than the Firebase Admin SDK.
Here is my code, which I know isn't the way it can be done, but it hopefully conveys what I am attempting to do. Any leads would be greatly appreciated.
const firebaseTools = require('firebase-tools');
async function recursiveDocumentDelete(fsDb, docRefPath) {
const collRefPath = extractCollRefPath(docRefPath);
const docId = extractDocId(docRefPath);
try {
const docToBeDeleted = await fsDb.collection(collRefPath).doc(docId).get();
if (docToBeDeleted.exists) {
recursiveDeleteFn = firebaseTools.functions().httpsCallable('recursiveDelete');
const recursiveDeleteResponse = await recursiveDeleteFn({ path: docRefPath })
console.log(`Document with ID ${docId} in the ${collRefPath} collection/subcollection, and all of its decendants, were successfully deleted at ${recursiveDeleteResponse.writeTime.toDate()}!`);
return JSON.stringify(recursiveDeleteResponse);
} else {
console.log(`Document with ID ${docId} in the ${collRefPath} collection/subcollection was not found`);
}
} catch(err) {
console.log(err);
}
}

Related

how to upload firebase images to web using local emulator?

I'm trying to upload some images to a firebase storage bucket,
and trying to run the code locally in the firebase emulator.
With most examples I'll get an error like:
"Unhandled error FirebaseError: Firebase: Need to provide options, when not being deployed to hosting via source.
(app/no-options). at initializeApp
I tried this: https://firebase.google.com/docs/admin/setup
const defaultApp = initializeApp({ credential: applicationDefault() })
Which may or not be working.
I think this creates an authed app (maybe?) but if I later use
const storage = getStorage() I get the same auth error.
So next, I tried using the defaultApp for next steps, like:
const storage = defaultApp.storage();
that doesn't error, but it returns something different from getStorage, that I can't seem to use for other needed things like getting a ref
as per examples https://firebase.google.com/docs/storage/web/upload-files
So it's not clear how to upload files to firebase from the local simulator.
my full function looks like this:
import cuid from "cuid";
import {
getStorage,
ref,
uploadBytes,
uploadBytesResumable,
getDownloadURL
} from "firebase/storage";
import { admin, defaultApp } from '../utils/firebaseInit'
export function saveToBucket(url: string): string {
const normalStorage = getStorage() // Gets a FirebaseStorage instance for the given Firebase app. but NOT AUTHED
const defaultStorage = defaultApp.storage(); // Gets the default FirebaseStorage instance.
const storageRef = ref(normalStorage)
const bucketPath = `personas-out/img-${cuid()}.jpg`
const bucket = defaultStorage.bucket();
// const bucketRef = bucket.ref(); // Property 'ref' does not exist on type 'Bucket'.ts(2339)
const metadata = {
contentType: 'image/jpeg'
};
const imageRef = ref(storageRef, bucketPath);
const file = new File([url], bucketPath, {
type: "image/jpeg",
});
// will happen in the background?
uploadBytesResumable(imageRef, file, metadata)
.then((snapshot: any) => {
console.log('Uploaded', snapshot);
});
return bucketPath
}
You're not supposed to use the Firebase client SDK (firebase/storage) in nodejs code. The client SDKs are meant to work in a browser only. For nodejs code that runs on a backend (which is what you're doing when you deploy to Cloud Functions), you should use the Firebase Admin SDK. The API it exposes for Storage is essentially a thin wrapper around the Google Cloud Storage nodejs library.

Listing Business Accounts under Google My Business API

I have authenticated against a Google Account and trying to fetch the Businesses on that account using the Google My Business API.
I can't seem to find any samples on how to do that using the Google NodeJS Client Libraries.
Here is what I tried:
async fetchGoogleMyBusinessAccounts() {
console.log(`Fetching GMB Accounts`);
let authCredentials= ...
const oauth2Client = initOAuth2Client(platform, authCredentials);
google.options({ auth: oauth2Client });
let gmbAccountManagement = google.mybusinessaccountmanagement(); //There seems to be an issue on this line
try {
let myBusinessAccounts = await gmbAccountManagement.accounts.list();
console.log(`Connected Accounts = ${JSON.stringify(myBusinessAccounts, null, 2)}`);
} catch (e) {
console.log(`Error Listing GMB Accounts`);
}
}
But the error I keep getting is:
Argument error: Accepts only string or object
I can't seem to figure out how what might be wrong and how best to get about this.
Any insights would be really appreciated.
I think you may be missing the API version:
const mybusinessaccountmanagement = google.mybusinessaccountmanagement('v1');

Using Firebase Cloud Functions to fan out data

I'm extremely new to using Firebase cloud functions, and I am struggling to find the error in my code. It is supposed to trigger on a firestore write and then copy that document into all of the user's feeds who follow that user who posted.
My current code is below:
exports.fanOutPosts = functions.firestore
.document('posts/{postId}')
.onCreate((snap, context) => {
var db = admin.firestore();
const post = snap.data();
const userID = post['author'];
const postCollectionRef = db.collection('friends').document(userID).collection('followers');
return postCollectionRef.get()
.then(querySnapshot => {
if (querySnapshot.empty) {
return null;
} else {
const promises = []
querySnapshot.forEach(doc => {
promises.push(db.collection('feeds').document(doc.key).collection('posts').document(post.key).update(data));
});
return Promise.all(promises);
}
});
});
So this successfully deploys to Firebase, but it receives this error when a document is created:
TypeError: db.collection(...).document is not a function
at exports.fanOutPosts.functions.firestore.document.onCreate (/workspace/index.js:22:60)
Line 22 is const postCollectionRef = db.collection('friends').document(userID).collection('followers');
I am unsure why this line is causing errors with the .get, but if anyone could point me in the right direction it would be much appreciated!
Given that this is the nodejs API, you'll want to use doc() instead of document(). Other languages might use document().
I found this info via the Admin SDK on CollectionReference https://googleapis.dev/nodejs/firestore/latest/CollectionReference.html
According to the reference, the collection should be defined as the following:
const postCollectionRef = db.collection(`friends/${userId}/followers`);
Using template literals will allow you to dynamically add variables into the collection ref.
I would also take a look into the else logic to use template literals within your return statement.

Google Calendar API and Service Account permission error

I'm trying to integrate the Google Calendar API in my app.
So far i've managed to do this:
Created a new project on Cloud Platform
Enabled Calendar API
Added a new service account with role: Owner
Generated jwt.json
Granted domain-wide for that service account
Shared a calendar with that service account (modify rights)
Enabled in the GSuite the option for everyone out of the organisation to modify the events
Now, my code on node.js looks like this:
const { JWT } = require('google-auth-library');
const client = new JWT(
keys.client_email,
null,
keys.private_key,
['https://www.googleapis.com/auth/calendar']
);
const url = `https://dns.googleapis.com/dns/v1/projects/${keys.project_id}`;
const rest = await client.request({url});
console.log(rest);
The error I get is:
Sending 500 ("Server Error") response:
Error: Insufficient Permission
Anyone has any ideea? This gets frustrating.
How about this modification?
I think that in your script, the endpoint and/or scope might be not correct.
Pattern 1:
In this pattern, your endpoint of https://dns.googleapis.com/dns/v1/projects/${keys.project_id} is used.
Modified script:
const { JWT } = require("google-auth-library");
const keys = require("###"); // Please set the filename of credential file of the service account.
async function main() {
const calendarId = "ip15lduoirvpitbgc4ppm777ag#group.calendar.google.com";
const client = new JWT(keys.client_email, null, keys.private_key, [
'https://www.googleapis.com/auth/cloud-platform' // <--- Modified
]);
const url = `https://dns.googleapis.com/dns/v1/projects/${keys.project_id}`;
const res = await client.request({ url });
console.log(res.data);
}
main().catch(console.error);
In this case, it is required to enable Cloud DNS API at API console. And it is required to pay. Please be careful with this.
I thought that the reason of your error message of Insufficient Permission might be this.
Pattern 2:
In this pattern, as a sample situation, the event list is retrieved from the calendar shared with the service account. If the calendar can be used with the service account, the event list is returned. By this, I think that you can confirm whether the script works.
Modified script:
const { JWT } = require("google-auth-library");
const keys = require("###"); // Please set the filename of credential file of the service account.
async function main() {
const calendarId = "###"; // Please set the calendar ID.
const client = new JWT(keys.client_email, null, keys.private_key, [
"https://www.googleapis.com/auth/calendar"
]);
const url = `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events`; // <--- Modified
const res = await client.request({ url });
console.log(res.data);
}
main().catch(console.error);
Note:
This modified script supposes that you are using google-auth-library-nodejs of the latest version.
Reference:
JSON Web Tokens in google-auth-library-nodejs

Access Error while accessing Azure API from NodeJS

I am trying to use Azure News Search in my NodeJS App. The code for the router is here:
const CognitiveServicesCredentials = require('ms-rest-azure').CognitiveServicesCredentials;
let credentials = new CognitiveServicesCredentials('apikey');
let search_term = 'Winter Olympics'
const NewsSearchAPIClient = require('azure-cognitiveservices-newssearch');
let client = new NewsSearchAPIClient(credentials);
client.newsOperations.search(search_term).then((result) => {
console.log(result.value);
}).catch((err) => {
throw err;
});
I get an error:
Access denied due to invalid subscription key or wrong API endpoint. Make sure to provide a valid key for an active subscription and use a correct regional API endpoint for your resource.
I made sure my API key is correct. The code sample is straight from Azure's Quickstart quide. There is no mention of the endpoint there. I feel like I am missing something but can't figure out what.
Thanks in advance for any guidance.
Try this to specify your endpoint :
const CognitiveServicesCredentials = require('ms-rest-azure').CognitiveServicesCredentials;
let credentials = new CognitiveServicesCredentials('<api key>');
let search_term = 'Winter Olympics'
const NewsSearchAPIClient = require('azure-cognitiveservices-newssearch');
let client = new NewsSearchAPIClient(credentials,{"endpoint":"<endpoint url>"});
client.newsOperations.search(search_term,{"count":1}).then((result) => {
console.log(result.value);
}).catch((err) => {
console.log(err);
throw err;
});
Result :
Hope it helps .

Resources