Angular 2 + Firebase Push Function - javascript

I currently have completed a tutorial which reads/writes to a Firebase using Angular2.
Need some help with the below function within the firebase.service.ts
addListing(listing){
let storageRef = firebase.storage().ref();
for (let selectedFile of [(<HTMLInputElement>document.getElementById('image')).files[0]]){
let path = `/${this.folder}/${selectedFile.name}`;
let iRef = storageRef.child(path);
iRef.put(selectedFile).then((snapshot) => {
listing.image = selectedFile.name;
listing.path = path;
return this.listings.push(listing);
});
}
}
Code that runs the function
Within the add-listing.component.html file
<form (submit)="onAddSubmit()">
Within the add-listing.component.ts file
onAddSubmit(){
let listing = {
title:this.title,
city:this.city,
owner:this.owner,
bedrooms:this.bedrooms,
price:this.price,
type:this.type
}
this.firebaseService.addListing(listing);
this.router.navigate(['listings']);
}
This all works correctly - however I want to change the function to allow data to be pushed to the database without having to upload a image or file - currently the function wont run unless a image is included in the form.
Thanks for all your help.

Related

Get the file path where user downloaded a file

I currently have a function that prompts the user to download a JSON file:
function downloadObjectAsJson (exportObj, exportName) {
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(exportObj))
let downloadAnchorNode = document.createElement('a')
downloadAnchorNode.setAttribute('href', dataStr)
downloadAnchorNode.setAttribute('download', exportName + '.json')
document.body.appendChild(downloadAnchorNode) // required for firefox
downloadAnchorNode.click()
downloadAnchorNode.remove()
}
Is there a way to get the path the user selected to download this file to? Just need it to be displayed on the UI.
There are some API available that somehow allows access to the client file system like this, which lists down all the files in the selected directory:
async function listFilesInDirectory () {
const dirHandle = await window.showDirectoryPicker()
const promises = []
for await (const entry of dirHandle.values()) {
if (entry.kind !== 'file') {
break
}
promises.push(entry.getFile().then((file) => `${file.name} (${file.size})`))
}
console.log(await Promise.all(promises))
}
So I thought there might be some way to also get the path selected by the user when saving files.
Any other suggestions/means are welcome.

Trying to import all google sheets files within a folder to a spreadsheet, all column headers are the same

I need to be able to take all files from a a folder within drive and input the data into the spreadsheet. I am also creating a Menu Tab so I can just Run the script without going to editor. It would be great if I can create a way enter names of existing folder name without always going to the script in order to take out that extra step. This is the script I am using. I really need assistance with this.
function importTimesheets() {
var spreadsheets = DriveApp.
getFolderById("").
getFilesByType(MimeType.GOOGLE_SHEETS);
var data = [];
while (spreadsheets.hasNext()) {
var currentSpreadsheet = SpreadsheetApp.openById(spreadsheets.next().getId());
data = data.concat(currentSpreadsheet
.getSheetByName('Timesheet')
.getRange("A3:L10")
.getValues()
);
}
SpreadsheetApp.
getActiveSheet().
getRange(1, 1, data.length, data[0].length).
setValues(data);
}
function onOpen() {
var ui = SpreadsheetApp.getUi();
ui.createMenu('Generate Timesheets')
.addItem('Generate', 'importTimesheets')
As far as I understand you are trying to find a solution for this line of code, whereby you currently have to enter the Id manually.
DriveApp.getFolderById("")
My suggestions would be to prompt the user for the folder Id, because prompting for the folder name may cause errors if more than one folder has the same name. My suggestion is implemented as follows:
const folderId = SpreadsheetApp.getUi().prompt("Please enter the Folder Id").getResponseText()
const folder = DriveApp.getFolderById(folderId)
You could also use the Google File/Folder picker, as described here to search and select the folder.
Try this:
var level=0;
function getFnF(folder = DriveApp.getRootFolder()) {
const ss=SpreadsheetApp.getActive();
const sh=ss.getSheetByName('Sheet1')
const files=folder.getFilesByType(MimeType.GOOGLE_SHEETS);
while(files.hasNext()) {
let file=files.next();
let firg=sh.getRange(sh.getLastRow() + 1,level + 1);
firg.setValue(Utilities.formatString('File: %s', file.getName()));//need editing
}
const subfolders=folder.getFolders()
while(subfolders.hasNext()) {
let subfolder=subfolders.next();
let forg=sh.getRange(sh.getLastRow() + 1,level + 1);
forg.setValue(Utilities.formatString('Fldr: %s', subfolder.getName()));//needs editing
level++;
getFnF(subfolder);
}
level--;
}
function runThisFirst() {
let r = SpreadsheetApp.getUi().prompt('Folder id','Enter Folder Id',SpreadsheetApp.getUi().ButtonSet.OK);
let folder = DriveApp.getFolderById(r.getResponseText())
getFnF(folder);
}

How to delete a file using cloud function JavaScript firebase?

I wanted to delete the file from storage when a data node is deleted from the realtime database. the name of the file to be deleted is taken before deleted. The name of the file is saved in the node in child named "imageTitle". The code works fine before implementing the file delete code. I mean the nodes get deleted perfectly.
When I implement the file delete code the rest doesn't work, but there is no any errors. The code after file delete doesn't work. I dunno why.
This is for an academic final project.
There's a folder named images in the bucket, and the file I need to delete is in there. The file name is taken from the child in the node which is to be deleted in the realtime database named imageTitle:
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
exports.changetime = functions.database.ref('/posts/{pushId}')
.onCreate((snapshot, context) => {
const editDate = Date.now()
datas = snapshot.val();
return snapshot.ref.update({editDate})
})
const CUT_OFF_TIME = 1 * 60 * 1000;
/**
* This database triggered function will check for child nodes that are older than the
* cut-off time. Each child needs to have a `timestamp` attribute.
*/
exports.deleteOldItems = functions.database.ref('/posts/{pushId}').onWrite(async (change,
context) => {
const ref = change.after.ref.parent; // reference to the parent
const now = Date.now();
const id = context.params.pushId;
const cutoff = now - CUT_OFF_TIME;
const oldItemsQuery = ref.orderByChild('createdDate').endAt(cutoff);
const snapshot = await oldItemsQuery.once('value');
const getImageTitle = admin.database().ref(`/posts/${id}/imageTitle`).once('value');
return getImageTitle.then(imageTitle => {
console.log('post author id', imageTitle.val());
const imageName = imageTitle.val();
const filePath = 'images/' + imageName;
const path = `images/${imageName}`;
const bucket = app.storage().bucket();
return bucket.file(path).delete().then(() =>{
console.log(`File deleted successfully in path: ${imageName}`)
/* The problem is here. the code doesn't work after file.delete function. no errors. but doesn't work
if I remove that piece of code the other codes work fine. I mean the realtime database nodes get deleted and updated perfectly */
const updates = {};
snapshot.forEach(child => {
updates[child.key] = null;
if(updates[child.key] == null){
admin.database().ref(/post-likes/+id).remove();
}
})
return ref.update(updates);
});
});
[my storage looks like this][1]});
There's a folder named images in the bucket, and the file I need to delete is in there. The file name is taken from the child in the node which id to be deleted in the realtime database imageTitle:
enter image description here
I think this is the problem:
const filePath = 'images/' + imageName;
const path = `images/${imageName}`;
You should be using filePath not path in your bucket reference. const path = `images/${imageName}`; is wild-card syntax used when querying, not when assigning variables....think you stayed in 'Dart' mode here:-). Not sure what path contains, therefore, but console.log it to see.
Here is some code that I use to delete images from my storage bucket that works perfectly. First, a couple of things to check (best done using console.log, never assume you know what is in the variable), and do:
Ensure imageName, filePath, path and bucket contain what they should contain.
Include the .catch block in your code to check if there actually is an error
I am not clear if console.log(`File deleted successfully in path: ${imageName}`) is executing but if it isn't then your file.delete must be throwing an error which the catch block should trap.
The code snippet:
const oldProfileImagePath = "profileImages/" + authenticatedUserId + "/" + oldProfileImageName;
return bucket.file(oldProfileImagePath).delete()
.then(function () {
console.info("Old Profile Image: " + oldProfileImagePath + " deleted!");
})
.catch(function (error) {
console.error("Remove Old Profile Image: " + oldProfileImagePath +
" failed with " + error.message)
});

How to get uploaded image link in Firebase Cloud Function? [duplicate]

This question already has answers here:
Get Download URL from file uploaded with Cloud Functions for Firebase
(25 answers)
Closed 4 years ago.
I have a cloud function that generates a set of resized images for every image uploaded. This is triggered with the onFinalize() hook.
Cloud Function to resize an uploaded image:
export const onImageUpload = functions
.runWith({
timeoutSeconds: 120,
memory: '1GB'
})
.storage
.object()
.onFinalize(async object => {
const bucket = admin.storage().bucket(object.bucket)
const filePath = object.name
const fileName = filePath.split('/').pop()
const bucketDir = dirname(filePath)
const workingDir = join(tmpdir(), 'resizes')
const tmpFilePath = join(workingDir, fileName)
if (fileName.includes('resize#') || !object.contentType.includes('image')) {
return false
}
await fs.ensureDir(workingDir)
await bucket.file(filePath).download({
destination: tmpFilePath
})
const sizes = [
500,
1000
]
const uploadPromises = sizes.map(async size => {
const resizeName = `resize#${size}_${fileName}`
const resizePath = join(workingDir, resizeName)
await sharp(tmpFilePath)
.resize(size, null)
.toFile(resizePath)
return bucket.upload(resizePath, {
destination: join(bucketDir, resizeName)
})
})
// I need to now update my Firestore database with the public URL.
// ...but how do I get that here?
await Promise.all(uploadPromises)
return fs.remove(workingDir)
})
That's all well and good and it works, but I also need to somehow retrieve the public URL for each of these images, in order to write the values into my Firestore.
I can do this on the frontend using getDownloadURL(), but I'm not sure how to do it from within a Cloud Function from the newly generated images.
As I see it, this needs to happen on the backend anyway, as my frontend has no way of knowing when the images have been processed.
Only works on the client:
const storageRef = firebase.storage().ref()
const url = await storageRef.child(`images/${image.name}`).getDownloadURL()
Any ideas?
Answer (with caveats):
This question was technically answered correctly by #sergio below, but I just wanted to point out some additional things that need doing before it can work.
It appears that the 'expires' parameter of getSignedUrl() has to be a number according to TypeScript. So, to make it work I had to pass a future date represented as an epoch (milliseconds) like 3589660800000.
I needed to pass credentials to admin.initializeApp() in order to use this method. You need to generate a service account key in your Firebase admin. See here: https://firebase.google.com/docs/admin/setup?authuser=1
Hope this helps someone else out too.
I believe the promises returned from bucket upload contain a reference to the File, which then you can use to obtain a signed URL.
Something like (not tested):
const data = await bucket.upload(resizePath, { destination: join(bucketDir, resizeName) });
const file = data[0];
const signedUrlData = await file.getSignedUrl({ action: 'read', expires: '03-17-2025'});
const url = signedUrlData[0];

Loop through array of file urls and download each one with React

I'm trying to do what I 'thought' would be a simple task. I have an array of URLs that I'd like to loop through and download on to the client machine when the user clicks a button.
Right now I have a parent component that contains the button and an array of the urls (in the state) that I'd like to loop through and download. For some reason, the way I'm doing it now only downloads one of the files, not all of the contents of the array.
Any idea how to do this correctly within React?
handleDownload(event){
var downloadUrls = this.state.downloadUrls;
downloadUrls.forEach(function (value) {
console.log('yo '+value)
const response = {
file: value,
};
window.location.href = response.file;
})
}
I would use setTimeout to wait a little bit between downloading each files.
handleDownload(event){
var downloadUrls = this.state.downloadUrls.slice();
downloadUrls.forEach(function (value, idx) {
const response = {
file: value,
};
setTimeout(() => {
window.location.href = response.file;
}, idx * 100)
})
}
In Chrome, this will also prompt the permission asking for multiple files download.

Categories

Resources