I'm using Google Cloud Functions (GCF) to schedule posts on Instagram (an app similar to Hootsuite). I just integrated local notifications and I want to add the ID (generated automatically by my "notificationManager") to the post (data sent to Google Cloud).
Basically, the way that it works is the app sends the data to GCF and GCF is responsible for adding the elements to Firestore Database, but after many failed attempts, I cannot seem to figure out how to add an additional value. My goal is to add the element "notificationIdentifier", but for some reason, GCF won't register it (I can't even see it in the logs!).
Here's what's in GCF:
/* eslint-disable max-len */
/* eslint-disable */
const functions = require("firebase-functions");
const admin = require("firebase-admin");
const express = require("express");
const bodyParser = require("body-parser");
const axios = require("axios");
const FACEBOOK_GRAPH_API_VERSION = "v11.0";
const FACEBOOK_APP_ID = Undisclosed APP_ID;
const FACEBOOK_APP_SECRET = Undisclosed APP_SECRET;
// // Create and Deploy Your First Cloud Functions
// // https://firebase.google.com/docs/functions/write-firebase-functions
//
admin.initializeApp();
const app = express();
const main = express();
const db = admin.firestore();
/**
* publish Instagram Media Object.
* #param {string} container_id instagram media object creation id.
* #param {string} accessToken user access token.
* #return {Promise} Returns container status
*/
async function getContainerStatus(container_id, accessToken) {
let status = "IN PROGRESS";
let response;
try {
response = await axios.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${container_id}`,
{
params: {
access_token: accessToken,
fields: "status_code",
},
}
);
} catch (error) {
console.log(error);
return "ERROR";
}
// console.log(response.data.status_code, "status");
status = response.data.status_code;
return status;
}
/**
* Get LongLive Token Expire in 60 days.
* #param {string} accessToken user access token.
* #return {Promise} Return Long Live token.
*/
function getLongLiveToken(accessToken) {
return new Promise((resolve, reject) => {
axios
.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/oauth/access_token`,
{
params: {
grant_type: "fb_exchange_token",
client_id: FACEBOOK_APP_ID,
client_secret: FACEBOOK_APP_SECRET,
fb_exchange_token: accessToken,
},
}
)
.then((response) => {
resolve(response.data.access_token);
})
.catch((error) => {
reject(error);
});
});
}
/**
* Get Facebook Pages.
* #param {string} accessToken user access token.
* #return {Promise} Returns the facebook pages result.
*/
function getFacebookPages(accessToken) {
return new Promise((resolve, reject) => {
axios
.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/me/accounts`,
{
params: {
access_token: accessToken,
},
}
)
.then((response) => {
const data = response.data.data;
resolve(data);
})
.catch((error) => {
reject(error);
});
});
}
/**
* Get Instagram Account From Facebook Pages.
* #param {string} accessToken user access token.
* #param {string} pageId Page ID.
* #return {Promise} Returns the Instagram Account Id.
*/
function getInstagramAccountId(accessToken, pageId) {
return new Promise((resolve, reject) => {
axios
.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${pageId}`,
{
params: {
access_token: accessToken,
fields: "instagram_business_account",
},
}
)
.then((response) => {
if (response.data.instagram_business_account) {
resolve({
id: response.data.instagram_business_account.id,
});
} else {
resolve({ error: "No instagram Business Account" });
}
})
.catch((error) => {
reject(error);
});
});
}
/**
* Get Facebook Profile.
* #param {string} accessToken user access token.
* #return {Promise} Returns the Facebook Account Profile.
*/
function getFacebookProfile(accessToken) {
return new Promise((resolve, reject) => {
axios
.get(`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/me`, {
params: {
access_token: accessToken,
fields: "name,picture,email",
},
})
.then((response) => {
resolve({
picture: response.data.picture.data.url,
name: response.data.name,
email: response.data.email,
facebookUserId: response.data.id,
});
})
.catch((error) => {
reject(error);
});
});
}
/**
* Get Instagram Profile.
* #param {string} accessToken user access token.
* #param {string} instagramAccountId Instagram Account ID.
* #return {Promise} Returns the Instagram Account Profile.
*/
function getInstagramProfile(accessToken, instagramAccountId) {
return new Promise((resolve, reject) => {
axios
.get(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${instagramAccountId}`,
{
params: {
access_token: accessToken,
fields: "name,username,profile_picture_url",
},
}
)
.then((response) => {
resolve(response.data);
})
.catch((error) => {
reject(error);
});
});
}
/**
* Create Instagram Media Object.
* #param {string} accessToken user access token.
* #param {string} instagramAccountId Instagram Account ID.
* #param {string} caption caption.
* #param {string} mediaType Instagram Account ID.
* #param {string} mediaUrl media url
* #return {Promise} Returns created Instagram Media ID.
*/
function createInstagramMedia(
accessToken,
instagramAccountId,
caption,
mediaType,
mediaUrl,
tags,
) {
return new Promise((resolve, reject) => {
const params = {
access_token: accessToken,
caption: caption,
};
let user_tags = [];
if(tags != null) {
for (let i = 0; i < tags.length; i++) {
const user_tag = {
"username": tags[i],
"x": Math.random(),
"y": Math.random()
}
user_tags.push(user_tag);
}
}
if (mediaType == "PICTURE") {
params["image_url"] = mediaUrl;
if(tags != null) {
params["user_tags"] = user_tags;
}
} else if (mediaType == "VIDEO") {
params["video_url"] = mediaUrl;
params["media_type"] = "VIDEO";
} else {
reject({ message: "Unknow media!" });
return;
}
axios
.post(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${instagramAccountId}/media`,
params
)
.then(async (response) => {
const container_id = response.data.id;
let container_status = "IN_PROGRESS";
while (container_status == "IN_PROGRESS") {
container_status = await getContainerStatus(
container_id,
accessToken
);
console.log(container_status, "Container status");
}
// resolve(response.data);
if (container_status == "ERROR") {
reject({ error: "Container error!" });
} else {
resolve(response.data);
}
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}
/**
* publish Instagram Media Object.
* #param {string} accessToken user access token.
* #param {string} instagramAcctId instagram media object creation id.
* #param {string} mediaObjectId instagram media object creation id.
* #return {Promise} Returns the Instagram Account Profile.
*/
function publishMedia(accessToken, instagramAcctId, mediaObjectId) {
console.log(accessToken, " --> ", instagramAcctId, " --> ", mediaObjectId);
return new Promise((resolve, reject) => {
axios
.post(
`https://graph.facebook.com/${FACEBOOK_GRAPH_API_VERSION}/${instagramAcctId}/media_publish`,
{
access_token: accessToken,
creation_id: mediaObjectId,
}
)
.then((response) => {
resolve(response.data);
})
.catch((error) => {
console.log(error);
reject(error);
});
});
}
/**
* Facebook Login with uuid
* body params {uuid, accessToken}
*/
app.post("/register", async (req, res) => {
const uuid = req.body.uuid;
const accessToken = req.body.accessToken;
const instagramAccts = [];
let longLiveToken, userData, pages;
try {
longLiveToken = await getLongLiveToken(accessToken);
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to create LongLive Token",
});
}
try {
userData = await getFacebookProfile(accessToken);
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Facebook profile",
});
}
try {
pages = await getFacebookPages(accessToken);
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Facebook pages",
});
}
if (pages.length > 0) {
for (let i = 0; i < pages.length; i++) {
try {
const data = await getInstagramAccountId(accessToken, pages[i].id);
if (!data.error) {
const igProfile = await getInstagramProfile(accessToken, data.id);
// const tags = await db
// .collection("tags")
// .where("tag", igProfile["username"])
// .get();
// if (tags.docs.length < 1) {
// await db.collection("tags").add({
// tag: igProfile["username"],
// });
// }
igProfile["isActive"] = true;
if (i == 0) {
igProfile["isPrimary"] = true;
} else {
igProfile["isPrimary"] = false;
}
instagramAccts.push(igProfile);
}
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Instagram accounts",
});
}
}
}
try {
await db.collection("users").doc(uuid).set({
longLiveToken: longLiveToken,
picture: userData.picture,
name: userData.name,
email: userData.email,
facebookUserId: userData.facebookUserId,
accessToken: accessToken,
uuid: uuid,
instagramAccts: instagramAccts,
});
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to save user info to firestore",
});
}
return res.status(200).json({
message: "Success",
instagramAccts: instagramAccts,
});
});
app.post("/getInstagramAccounts", async (req, res) => {
const uuid = req.body.uuid;
const user = await db.collection("users").doc(uuid).get();
const userData = user.data();
const accessToken = userData.longLiveToken;
const instagramAccts = [];
let pages;
try {
pages = await getFacebookPages(accessToken);
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Facebook pages",
});
}
if (pages.length > 0) {
for (let i = 0; i < pages.length; i++) {
try {
const data = await getInstagramAccountId(accessToken, pages[i].id);
if (!data.error) {
const igProfile = await getInstagramProfile(accessToken, data.id);
if (i == 0) {
igProfile["isActive"] = true;
} else {
igProfile["isActive"] = false;
}
instagramAccts.push(igProfile);
}
} catch (error) {
console.log(error);
return res.status(400).json({
error: "Failed to get Instagram accounts",
});
}
}
}
try {
await db
.collection("users")
.doc(uuid)
.update({ instagramAccts: instagramAccts });
} catch (error) {
console.log(error);
return res.status(500).json({
error: "Failed to update instagram accounts",
});
}
return res.status(200).json({ instagramAccts: instagramAccts });
});
/**
* Schedule Instagram Media Object to publish.
* body params {time, mediaType, uuid, media, instagramAcctId}
*/
app.post("/schedule", async (req, res) => {
const uuid = req.body.uuid;
const time = req.body.time;
const mediaType = req.body.mediaType;
const media = req.body.media; // url string array
const tags = req.body.tags; // array of strings
const longitude = req.body.longitude;
const latitude = req.body.latitude;
const instagramAcctId = req.body.instagramAcctId;
const caption = req.body.caption;
const thumbnail = req.body.thumbnail;
const timeStamp = req.body.timeStamp;
const notificationIdentifier = req.notificationIdentifier;
try {
const postData = await db.collection("posts").add({
uuid: uuid,
time: time,
mediaType: mediaType,
media: media,
instagramAcctId: instagramAcctId,
published: false,
caption: caption,
tags: tags ? tags : null,
thumbnail: thumbnail ? thumbnail : null,
longitude: longitude,
latitude: latitude,
timeStamp: timeStamp,
notificationIdentifier: notificationIdentifier ? notificationIdentifier : null,
});
const ref = await postData.get();
await db.collection("posts").doc(ref.id).update({ id: ref.id });
res.status(200).json({
message: "Success!",
});
} catch (error) {
console.log(error);
res.status(500).json(error.message);
}
});
app.post("/update-schedule", async (req, res) => {
const id = req.body.id;
const time = req.body.time;
const tags = req.body.tags; // array of strings
const longitude = req.body.longitude;
const latitude = req.body.latitude;
const instagramAcctId = req.body.instagramAcctId;
const caption = req.body.caption;
const timeStamp = req.body.timeStamp;
const notificationIdentifier = req.body.notificationIdentifier;
const updateData = {};
if (time) {
updateData["time"] = time;
}
if (tags) {
updateData["tags"] = tags;
}
if (longitude) {
updateData["longitude"] = longitude;
}
if (latitude) {
updateData["latitude"] = latitude;
}
if (instagramAcctId) {
updateData["instagramAcctId"] = instagramAcctId;
}
if (caption) {
updateData["caption"] = caption;
}
if (timeStamp) {
updateData["timeStamp"] = timeStamp;
}
if (notificationID) {
updateData["notificationIdentifier"] = notificationIdentifier;
}
try {
await db.collection("posts").doc(id).update(updateData);
res.status(200).json({
message: "Update success!",
});
} catch (error) {
console.log(error);
res.status(500).json(error.message);
}
});
app.post("/remove-schedule", async (req, res) => {
const id = req.body.id;
try {
const postData = await db.collection("posts").doc(id).get();
if (postData.exists) {
await db.collection("posts").doc(id).delete();
res.status(200).json({
message: "Remove success!",
});
} else {
res.status(400).json({
message: "There is no such post!",
});
}
} catch (error) {
console.log(error);
res.status(500).json(error.message);
}
});
app.post("/get-posts-by-date", async (req, res) => {
const uuid = req.body.uuid;
let posts_by_date = [];
try {
const posts = await db
.collection("posts")
.where("published", "==", false)
.where("uuid", "==", uuid)
.orderBy("time")
.get();
for (let i = 0; i < posts.docs.length; i++) {
const postData = posts.docs[i].data();
console.log(new Date(postData["time"]).toLocaleDateString());
const localDate = new Date(postData["time"]).toLocaleDateString();
if (posts_by_date[localDate]) {
posts_by_date[localDate].push(postData);
} else {
posts_by_date[localDate] = [];
posts_by_date[localDate].push(postData);
}
}
console.log(posts_by_date, "posts by date");
return res.status(200).json({
posts: posts_by_date,
});
} catch (error) {
console.log(error);
return res.status(500).json(error.message);
}
});
exports.scheduledFunction = functions.pubsub
.schedule("* * * * *")
.onRun((context) => {
console.log("This will be run every 1 minute!");
db.collection("posts")
.where("published", "==", false)
.get()
.then((querySnapshot) => {
querySnapshot.forEach(async (doc) => {
console.log(doc.id, " => ", doc.data());
const post = doc.data();
const now = new Date();
const publishDate = new Date(post.time);
if (publishDate <= now) {
//publish media object.
const uuid = post.uuid;
const userRef = await db.collection("users").doc(uuid).get();
const user = userRef.data();
const longLiveToken = user.longLiveToken;
const instagramAcctId = post.instagramAcctId;
const medias = post.media;
//const notificationIdentifier = post.notificationIdentifier;
for (let i = 0; i < medias.length; i++) {
try {
const mediaObjects = await createInstagramMedia(
longLiveToken,
instagramAcctId,
post.caption,
post.mediaType,
medias[i],
post.tags,
// notificationIdentifier
);
const mediaObjectId = mediaObjects.id;
await publishMedia(
longLiveToken,
instagramAcctId,
mediaObjectId
);
} catch (error) {
console.log(error);
return;
}
}
await db
.collection("posts")
.doc(doc.id)
.update({ published: true });
}
});
})
.catch((error) => {
console.log("Error getting documents: ", error);
});
return null;
});
main.use("/v1", app);
main.use(bodyParser.json());
main.use(bodyParser.urlencoded({ extended: true }));
exports.api = functions.https.onRequest(main);
and this is how the data is sent:
private func schedulePost(uuid: String, time: Date, mediaType: String, media: [String], caption: String, tags:[String], location: CLLocation?, thumbImageUrl: String) {
var newCap: [String] = []
newCap.append(caption)
newCap.insert(contentsOf: tags, at: newCap.endIndex)
let newCaption = newCap.joined(separator: " ")
print (newCaption)
AuthManager.shared.loadUser()
guard let instagramAccountId = AuthManager.shared.currentUser?.id else {return}
let timeStamp = NSDate().timeIntervalSince1970
if !self.TrueStory {
StoryManager().addNewTask("POST", "Post", time, self.ImageURL)
print("Scheduled Post" + self.ImageURL)
// let notificationID = notificationIdentifier
//tags.insert(caption, at: tags.firstIndex)
let param = ["uuid": uuid, "time": time, "mediaType": mediaType, "media": media, "instagramAcctId": instagramAccountId, "caption": newCaption, "tags": "", "latitude": location?.coordinate.latitude ?? "", "longitude":location?.coordinate.longitude ?? "", "thumbnail":thumbImageUrl, "timeStamp":timeStamp, "notificationIdentifier":notificationIdentifier] as [String : Any]
print ("The PARAMS are: ")
print (param)
ServerApi.shared.scheduleIGPosts(param: param, success: {response in
print(response)
ProgressHUD.dismiss()
AppManager.shared.isPostScheduled = true
AppManager.shared.showNext()
// NotificationCenter.default.post(name: .PostWasSuccessfullyScheduled, object: nil, userInfo: ["posted": true])
}, failure: {(error) in
print(error)
self.showAlert(error.description)
ProgressHUD.dismiss()
})
} else if self.TrueStory {
StoryManager().addNewTask("STORY", "Story", time, self.ImageURL)
print("Scheduled Story" + self.ImageURL)
// let notificationID = notificationIdentifier
let param = ["uuid": uuid, "time": time, "mediaType": mediaType, "media": media, "instagramAcctId": instagramAccountId, "caption": caption, "tags": "", "latitude": location?.coordinate.latitude ?? "", "longitude":location?.coordinate.longitude ?? "", "thumbnail":thumbImageUrl, "timeStamp":timeStamp, "notificationIdentifier":notificationIdentifier] as [String : Any]
// "notificationID":notificationIdentifier
ServerApi.shared.scheduleIGPosts(param: param, success: {response in
print(response)
ProgressHUD.dismiss()
AppManager.shared.isPostScheduled = true
AppManager.shared.showNext()
// NotificationCenter.default.post(name: .PostWasSuccessfullyScheduled, object: nil, userInfo: ["posted": true])
}, failure: {(error) in
print(error)
self.showAlert(error.description)
ProgressHUD.dismiss()
})
}
}
And the "ScheduleIGPost" function for your entertainment:
import Foundation
import SwiftyJSON
import Alamofire
struct AppUrls {
static let baseUrl = URL that I wont disclose
static let registerIGAccounts = baseUrl + "register"
static let scheduleIGPosts = baseUrl + "schedule"
static let updateIGPosts = baseUrl + "update-schedule"
static let removeIGPosts = baseUrl + "remove-schedule"
}
class ServerApi {
static let shared = ServerApi()
func scheduleIGPosts(param: [String: Any], success: #escaping(JSON) -> Void, failure: #escaping(JSON) -> Void) {
ApiWrapper.requestPOSTURLWithoutToken(AppUrls.scheduleIGPosts, params: param, success: {(response) in
print(JSON(response))
success(JSON(response))
}, failure: { (error) in
let err = JSON(error)
print(err)
failure(err)
})
}
I did check and see if "param" included "notificationIdentifier" when sending to GCF and it does, but if I check the logs in GCF, I can see everything that's supposed to be except for "notificationIdentifier". And when I replace, for example, "tags" with the "notificationIdentifier", then it works.
I'm unsure if Firestore/Firebase has a limit of elements or not and why this behaviour is happening. To be honest, I couldn't find much information online.
Feel free to ask any questions if I was unclear, as I tend to be!
This was solved quite simply, the app is using a Cloud Function called "API" which is used before accessing the "Schedule" function. So changed the values (or rather added the values) and everything is working fine now.
i am using ionic 5 & capacitor.
For some reason, the readAsDataURL isnt working and it isnt showing me an error message either.
the path & file name seem fine, they are :
filePath: file:///storage/emulated/0/Android/data/io.ionic.starter/cache/1763816379-cropped.jpg
path : file:///storage/emulated/0/Android/data/io.ionic.starter/cache/
fileName: 1763816379-cropped.jpg
showCroppedImage(ImagePath) {
var filePath = ImagePath;
let fileName = filePath.split("/").pop();
let path = filePath.substring(0, filePath.lastIndexOf("/") + 1);
alert(filePath);
alert(fileName);
alert(path);
alert("works till here");
this.file
.readAsDataURL(path, fileName)
.then((base64) => {
alert(base64);
})
.catch((err) => {
console.log(err);
alert(err);
});
}
this.file.createFile(
this.file.externalDataDirectory,
"base64string.txt",
true
);
this.file.readAsText(this.file.externalDataDirectory, "base64string.txt");
this.blob = new Blob([this.base64string]);
this.file
.writeFile(
this.file.externalDataDirectory,
"base64string.txt",
this.blob,
{ replace: true, append: false }
)
.then(() => {
alert("File saved in internal storage/android/data/io.starter.ionic/");
});
}
Earlier, my file was getting saved in an internal directory which was not accessible by a user. So i used the externalDataDirectory function, which fixed my issue. It stores the file in an external directory which is accessible by the user.
The file is stored in "internal storage/android/data/#app_id#/"
I ended up sorting the problem for my application and I have included it below:
/** #desc crop the selected image */
async cropImage(fileUrl: any) {
this.show_spinner = true;
await this.ionLoader.showLoader('Cropping Image...');
this.crop.crop(fileUrl, {
quality: 75,
targetHeight: 320,
targetWidth: 240
})
.then(
async (newImage) => {
this.show_spinner = false;
await this.ionLoader.hideLoader();
this.showCroppedImage(newImage.split('?')[0]);
},
async (error: IonicResultMessageInterface) => {
this.show_spinner = false;
await this.ionLoader.hideLoader();
console.error('Error cropping image', error);
console.log(error);
this.setUserProfileImage();
this.toasterService.showToast(error.message, 'failure');
}
);
}
/** #desc show the image after it has been cropped */
async showCroppedImage(ImagePath: string) {
console.log(ImagePath);
this.show_spinner = true;
const copyPath = ImagePath;
const splitPath = copyPath.split('/');
const imageName = splitPath[splitPath.length - 1];
const file_ext = imageName.substr(imageName.lastIndexOf('.') + 1);
try {
const base64 = await Filesystem.readFile({ path: ImagePath});
if (base64) {
console.log(base64);
this.userImageUrl = 'data:image/' + file_ext + ';base64,' + base64.data;
this.show_spinner = false;
await this.updateProfilePictureMethod();
} else {
this.show_spinner = false;
console.log('Error in the showCroppedImage File method');
console.log('Unexpected Error');
this.setUserProfileImage();
this.toasterService.showToast('Unexpected Error Occurred in the showCroppedImage File', 'failure');
}
} catch (error) {
this.show_spinner = false;
console.log('Error in the showCroppedImage File method');
console.log('Unexpected Error');
this.setUserProfileImage();
this.toasterService.showToast(error.message, 'failure');
}
}
I am trying to upload an image to Firebase Storage, however, ref.putfile() leads to the error in the tittle
I didn't find any appropriate resource related to this error
This is where I get image from user:
openPicker = () => {
// More info on all the options is below in the API Reference... just some common use cases shown here
const options = {
title: 'Fotoğraf Seç',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ', response.customButton);
}
else {
const source = { uri: response.uri}
this.setState({
imageMessageSrc: source
});
this.uploadImage();
}
});
}
Then I try to uploadImage to firebase
uploadImage = () => {
console.log("Here");
const filename = this.randIDGenerator// Generate unique name
firebase
.storage()
.ref(`${firebase.auth().currentUser.uid}/sentPictures/${filename}`)
.putFile(this.state.imageMessageSrc)
.then(() => {
console.log("Here1");
})
.catch((error) => {
console.log(error);
})
When I delete putFile, error is gone, but obviously nothing happens to database.
Problem is related to the difference between filePath and fileUri. So, the solution is as below:
openPicker = () => {
const options = {
title: 'Fotoğraf Seç',
storageOptions: {
skipBackup: true,
path: 'images',
allowsEditing: true,
},
};
ImagePicker.showImagePicker(options, (response) => {
console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
}
else if (response.error) {
console.log('ImagePicker Error: ', response.error);
}
else if (response.customButton) {
console.log('User tapped custom button: ',response.customButton);
}
else {
var path = '';
if (Platform.OS == 'ios')
path = response.uri.toString();
else {
path = response.path.toString();
}
const image= {
image: response.uri.toString(),
path: path
};
this.uploadImage(image);
}
});
}
uploadImage = (image) => {
firebase.storage().ref(uploadUrl).putFile(image.path);
}
I realized that Firebase Storage putFile function doesn't work with image uri, instead it should be supplied with filePath. I used uri of this image to directly show image on the screen even before upload.
I am using the Jquery file upload basic-plus.html. I am not sure How to use the Resumable uploading functionality in the below code.
I see something like this according to the documentation but not sure How to use that with the basic-plus.html
$('#fileupload').fileupload({
maxChunkSize: 10000000, // 10 MB
add: function (e, data) {
var that = this;
$.getJSON('server/php/', {file: data.files[0].name}, function (result) {
var file = result.file;
data.uploadedBytes = file && file.size;
$.blueimp.fileupload.prototype
.options.add.call(that, e, data);
});
}
});
I tried something like below. But didn't work.
basic-plus.html
$(function () {
'use strict';
// Change this to the location of your server-side upload handler:
var url = window.location.hostname === 'blueimp.github.io' ?
'//jquery-file-upload.appspot.com/' : 'server/php/',
uploadButton = $('<button/>')
.addClass('btn btn-primary')
.prop('disabled', true)
.text('Processing...')
.on('click', function () {
var $this = $(this),
data = $this.data();
$.getJSON('server/php/', {file: data.files[0].name}, function (result) {
console.log('come here');
console.log(result);
var file = result.file;
data.uploadedBytes = file && file.size;
//$.blueimp.fileupload.prototype.options.add.call($this, data);
});
$this
.off('click')
.text('Abort')
.on('click', function () {
$this.remove();
data.abort();
});
data.submit().always(function () {
$this.remove();
});
});
$('#fileupload').fileupload({
url: url,
dataType: 'json',
autoUpload: false,
//multipart: false,
acceptFileTypes: /(\.|\/)(avi|flv|wmv|mpg|mp4|mov|3gp|m4v)$/i,
maxFileSize: 969932800, // 900 MB
maxChunkSize: 2000000, // 2 MB
// Enable image resizing, except for Android and Opera,
// which actually support image resizing, but fail to
// send Blob objects via XHR requests:
disableImageResize: /Android(?!.*Chrome)|Opera/
.test(window.navigator.userAgent),
previewMaxWidth: 100,
previewMaxHeight: 100,
previewCrop: true,
}).on('fileuploadadd', function (e, data) {
data.context = $('<div/>').appendTo('#files');
$.each(data.files, function (index, file) {
var node = $('<p/>').append($('<span/>').text(file.name));
console.log(node);
if (!index) {
node
.append('<br>')
.append(uploadButton.clone(true).data(data));
}
node.appendTo(data.context);
});
}).on('fileuploadprocessalways', function (e, data) {
var index = data.index,
file = data.files[index],
node = $(data.context.children()[index]);
if (file.preview) {
node
.prepend('<br>')
.prepend(file.preview);
}
if (file.error) {
node
.append('<br>')
.append($('<span class="text-danger"/>').text(file.error));
}
if (index + 1 === data.files.length) {
data.context.find('button')
.text('Upload')
.prop('disabled', !!data.files.error);
}
}).on('fileuploadprogressall', function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress .progress-bar').css(
'width',
progress + '%'
);
}).on('fileuploaddone', function (e, data) {
$.each(data.result.files, function (index, file) {
if (file.url) {
var link = $('<a>')
.attr('target', '_blank')
.prop('href', file.url);
$(data.context.children()[index])
.wrap(link);
} else if (file.error) {
var error = $('<span class="text-danger"/>').text(file.error);
$(data.context.children()[index])
.append('<br>')
.append(error);
}
});
}).on('fileuploadfail', function (e, data) {
$.each(data.files, function (index) {
var error = $('<span class="text-danger"/>').text('File upload failed.');
$(data.context.children()[index])
.append('<br>')
.append(error);
});
}).prop('disabled', !$.support.fileInput)
.parent().addClass($.support.fileInput ? undefined : 'disabled');
});
I am having a problem taking a picture and uploading it to an S3 bucket when using FILE_URI for the camera.DestinationType. When using this same process with the DATA_URL DestinationType it works fine.
When using FILE_URI the file that gets uploaded to the S3 bucket says it's corrupt. I did notice the file size is much smaller (~100B) than an actual image.
Here are the versions I am using:
Ionic Framework 3.9.2 and cordova-plugin-camera 4.0.2
Here is the code I'm using:
const options: CameraOptions = {
quality: 100,
correctOrientation: true,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE,
sourceType: this.camera.PictureSourceType.CAMERA,
}
this.camera.getPicture(options).then((imageData) => {
console.log(imageData);
let base64data = 'data:image/jpeg;base64,' + imageData;
this.bigImg = base64data;
// imageData is either a base64 encoded string or a file URI
// If it's base64:
this.selectedPhoto = this.dataURItoBlob(this.bigImg);
}, (err) => {
// Handle error
console.log("Get Image Error: " + err);
});
this.sub = AWS.config.credentials.identityId;
let uploadMessage = "Uploading Image...";
let photoName = "testPic";
this.upload(this.selectedPhoto, uploadMessage, photoName)
.then(data => {
// Change active page to list
this.navCtrl.setRoot(TabsPage).then(() => {
});
});
dataURItoBlob(dataURI) {
// code adapted from: http://stackoverflow.com/questions/33486352/cant-upload-image-to-aws-s3-from-ionic-camera
let binary = atob(dataURI.split(',')[1]);
let array = [];
for (let i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/jpeg'});
};
upload(selectedPhoto, uploadMessage, photoName) {
return new Promise((resolve, reject) => {
let loading = this.loadingCtrl.create({
content: uploadMessage
});
loading.present();
if (selectedPhoto) {
this.s3.upload({
'Key': 'protected/' + this.sub + '/' + photoName,
'Body': selectedPhoto,
'ContentType': 'image/jpeg'
}).promise().then((data) => {
this.data2 = data;
console.log('upload complete:', JSON.stringify(data));
loading.dismiss();
resolve(data);
}, err => {
console.log('upload failed....', JSON.stringify(err));
loading.dismiss();
reject(err);
});
} else {
loading.dismiss();
reject("upload failed");
}
});