Skip to content

Instantly share code, notes, and snippets.

@aymenjegham
Last active May 23, 2019 09:30
Show Gist options
  • Save aymenjegham/21754b07d1ca3eb70584365993b94aa1 to your computer and use it in GitHub Desktop.
Save aymenjegham/21754b07d1ca3eb70584365993b94aa1 to your computer and use it in GitHub Desktop.
Firebase function example for notification and backend operations
const functions = require('firebase-functions');
let admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const actionTypeNewLike = "new_like";
const actionTypeNewComment = "new_comment";
const actionTypeNewPost = "new_post";
const notificationTitle = "Notification";
const actionTypeNewmember = "new_member_activated";
const actionTypemoderator = "new_moderator_activated";
const actionTypemoderatornotif ="new_reclamation_sent";
const actionTypeusernotif ="reclamation_modified";
const actionTypenewmembernotif ="new_member_joined";
const followingPosDbValue = "following_post";
const followingPosDbKey = "followingPostsIds";
const followingsDbKey = "followings";
const followersDbKey = "followers";
const followingDbKey = "follow";
const postsTopic = "postsTopic";
const THUMB_MEDIUM_SIZE = 1024; //px
const THUMB_SMALL_SIZE = 100; //px
const THUMB_MEDIUM_DIR = "medium";
const THUMB_SMALL_DIR = "small";
//const gcs = require('@google-cloud/storage')();
const {Storage} = require('@google-cloud/storage');
const storage = new Storage();
const path = require('path');
const sharp = require('sharp');
const os = require('os');
const fs = require('fs');
exports.getTime = functions.https.onCall((data,context)=>{
return Date.now()
})
exports.sendNotificationmoderator = functions.database.ref('/profiles/{userId}/type').onWrite((change, context) => {
const userid = context.params.userId;
const getDeviceTokensTask = admin.database().ref(`/profiles/${userid}/notificationTokens`).once('value');
const getAuthorLikeUrl= admin.database().ref(`/profiles/${userid}/photoUrl`).once('value');
const gettypestatus= admin.database().ref(`/profiles/${userid}/type`).once('value');
return Promise.all([getDeviceTokensTask, getAuthorLikeUrl,gettypestatus]).then(results => {
const tokensSnapshot = results[0];
const likeAuthorphotourl = results[1].val();
const statusactivity = results[2].val();
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.',getDeviceTokensTask);
}
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.',statusactivity);
// Create a notification
const payload = {
data: {
actionType: actionTypemoderator,
title: notificationTitle,
body: `Bienvenue à Syndic Spig,votre compte moderateur à éte activée`,
icon: likeAuthorphotourl,//post.val().imagePath,
statuactivity:statusactivity.toString(),
},
};
// Listing all tokens.
const tokens = Object.keys(tokensSnapshot.val());
console.log('tokens:', tokens[0]);
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
});
});
exports.sendTicketNotificationToModerator = functions.database.ref('/Tickets/{residence}/{userid}/{ticket}').onCreate((change, context) => {
const userid = context.params.userid;
const residence = context.params.residence;
const getModId= admin.database().ref(`/moderators/${residence}`).once('value');
const getAuthorUrl= admin.database().ref(`/profiles/${userid}/photoUrl`).once('value');
return Promise.all([getModId,getAuthorUrl]).then(results => {
const residenceval = results[0]; //.val();
const authorimage = results[1].val();
if (!residenceval.hasChildren()) {
return console.log('There are no notification tokens to send to.',getModId);
}
console.log('There are', residenceval.numChildren(), 'tokens to send notifications to.');
// Create a notification
const payload = {
data: {
actionType: actionTypemoderatornotif,
title: notificationTitle,
body: `Une nouvelle reclamation a été envoyée`,
icon: authorimage,
},
};
const tokens = Object.keys(residenceval.val());
console.log('tokens:', tokens[0]);
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(residenceval.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
});
});
exports.sendNewUserNotificationToModerator = functions.database.ref('/profiles/{userid}/residence/').onCreate((change, context) => {
const userid = context.params.userid;
const residencev = change.val();
const getresidence = admin.database().ref(`/profiles/${userid}/residence`).once('value');
const getModId= admin.database().ref(`/moderators/${residencev}`).once('value');
const getAuthorUrl= admin.database().ref(`/profiles/${userid}/photoUrl`).once('value');
return Promise.all([getresidence,getModId,getAuthorUrl]).then(results => {
const residencevalue = results[0].val();
const residenceval = results[1];//.val();
const authorimage = results[2].val();
if (!residenceval.hasChildren()) {
return console.log('There are no notification tokens to send to.', residencev);
}
console.log('There are', residenceval.numChildren(), 'tokens to send notifications to.');
// Create a notification
const payload = {
data: {
actionType: actionTypenewmembernotif,
title: notificationTitle,
body: `nouvel utilisateur a rejoint`,
icon: authorimage,
},
};
const tokens = Object.keys(residenceval.val());
console.log('tokens:', tokens[0]);
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(residenceval.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
});
});
exports.sendTicketNotificationToUser = functions.database.ref('/Tickets/{residence}/{userid}/{ticket}/state').onUpdate((change, context) => {
const userid = context.params.userid;
const residence = context.params.residence;
const ticket = context.params.ticket;
const getDeviceTokensTask = admin.database().ref(`/profiles/${userid}/notificationTokens`).once('value');
const getvalue= admin.database().ref(`/Tickets/${residence}/${userid}/${ticket}/state`).once('value');
return Promise.all([getDeviceTokensTask,getvalue]).then(results => {
const tokensnopshot = results[0];
const valueofstatu = results[1].val();
if (!tokensnopshot.hasChildren()) {
return console.log('There are no notification tokens to send to.',getDeviceTokensTask);
}
console.log('There are', tokensnopshot,valueofstatu,change);
const tokens = Object.keys(tokensnopshot.val());
console.log('tokens:', tokens[0]);
// Create a notification
const payload = {
data: {
actionType: actionTypeusernotif,
title: notificationTitle,
body: `statue de reclamation modifiée`,
// icon: authorimage,
},
};
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
});
});
exports.sendTicketcommentaddNotificationToUser = functions.database.ref('/Tickets/{residence}/{userid}/{ticket}/comment').onUpdate((change, context) => {
const userid = context.params.userid;
const residence = context.params.residence;
const ticket = context.params.ticket;
const getDeviceTokensTask = admin.database().ref(`/profiles/${userid}/notificationTokens`).once('value');
const getvalue= admin.database().ref(`/Tickets/${residence}/${userid}/${ticket}/state`).once('value');
return Promise.all([getDeviceTokensTask,getvalue]).then(results => {
const tokensnopshot = results[0];
const valueofstatu = results[1].val();
if (!tokensnopshot.hasChildren()) {
return console.log('There are no notification tokens to send to.',getDeviceTokensTask);
}
console.log('There are', tokensnopshot,valueofstatu,change);
const tokens = Object.keys(tokensnopshot.val());
console.log('tokens:', tokens[0]);
// Create a notification
const payload = {
data: {
actionType: actionTypeusernotif,
title: notificationTitle,
body: `une réponse est ajoutée`,
// icon: authorimage,
},
};
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
});
});
exports.sendNotification = functions.database.ref('/profiles/{userId}/active').onWrite((change, context) => {
//const receiverId = change.after.child('active').val();
// console.log("receiverId: ", receiverId);//receiverId);
//get the message
//const message = change.after.child('username').val();
//console.log("message: ", message);
const userid = context.params.userId;
const getDeviceTokensTask = admin.database().ref(`/profiles/${userid}/notificationTokens`).once('value');
const getAuthorLikeUrl= admin.database().ref(`/profiles/${userid}/photoUrl`).once('value');
const getactivestatus= admin.database().ref(`/profiles/${userid}/active`).once('value');
return Promise.all([getDeviceTokensTask, getAuthorLikeUrl,getactivestatus]).then(results => {
const tokensSnapshot = results[0];
const likeAuthorphotourl = results[1].val();
const statusactivity = results[2].val();
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.',getDeviceTokensTask);
}
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.',statusactivity);
// Create a notification
const payload = {
data: {
actionType: actionTypeNewmember,
title: notificationTitle,
body: `Bienvenue à Syndic Spig,votre compte à éte activée`,
icon: likeAuthorphotourl,//post.val().imagePath,
statuactivity:statusactivity.toString(),
},
};
// Listing all tokens.
const tokens = Object.keys(tokensSnapshot.val());
console.log('tokens:', tokens[0]);
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
});
//console.log('message: ');
//const payload = {
//data: {
//data_type: "direct_message",
//title: "Open Up",
//message: message,
//}
//};
//return admin.messaging().sendToDevice("doM-ilq4kes:APA91bHaiJzJb052b1jXZUFRjXDKTuz12eIa-1cerJAQX-YEmufYZLxv35jPiRnhIa-jGlPU793QeOCpV_riH6zZLlYmUT32hCnrXMIwJHMN_wrrnD3a1UY5_O-QBGnviEnr4GvE6qNu", payload);
});
exports.pushNotificationLikes = functions.database.ref('/post-likes/{postId}/{authorId}/{likeId}').onCreate((snap, context) => {
console.log('New like was added');
const likeAuthorId = context.params.authorId;
const postId = context.params.postId;
// Get liked post.
const getPostTask = admin.database().ref(`/posts/${postId}`).once('value');
return getPostTask.then(post => {
if (likeAuthorId === post.val().authorId) {
console.log('User liked own post');
return 'User liked own post';
}
// Get the list of device notification tokens.
const getDeviceTokensTask = admin.database().ref(`/profiles/${post.val().authorId}/notificationTokens`).once('value');
console.log('getDeviceTokensTask path: ', `/profiles/${post.val().authorId}/notificationTokens`);
// Get like author.
const getLikeAuthorProfileTask = admin.database().ref(`/profiles/${likeAuthorId}`).once('value');
// Get author photo url.
const getAuthorLikeUrl= admin.database().ref(`/profiles/${likeAuthorId}/photoUrl`).once('value');
console.log('photo url: ', `/profiles/${likeAuthorId}/photoUrl`);
return Promise.all([getDeviceTokensTask, getLikeAuthorProfileTask,getAuthorLikeUrl]).then(results => {
const tokensSnapshot = results[0];
const likeAuthorProfile = results[1].val();
const likeAuthorphotourl = results[2].val();
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
return console.log('There are no notification tokens to send to.');
}
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
console.log('Fetched like Author profile', likeAuthorProfile);
// Create a notification
const payload = {
data: {
actionType: actionTypeNewLike,
title: notificationTitle,
body: `${likeAuthorProfile.username} a aimé votre publication`,
icon: likeAuthorphotourl,//post.val().imagePath,
postId: postId,
},
};
// Listing all tokens.
const tokens = Object.keys(tokensSnapshot.val());
console.log('tokens:', tokens[0]);
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
})
});
exports.pushNotificationComments = functions.database.ref('/post-comments/{postId}/{commentId}').onCreate((snap, context) => {
const commentId = context.params.commentId;
const postId = context.params.postId;
const comment = snap.val();
console.log('New comment was added, id: ', postId);
// Get the commented post .
const getPostTask = admin.database().ref(`/posts/${postId}`).once('value');
return getPostTask.then(post => {
// Get the list of device notification tokens.
const getDeviceTokensTask = admin.database().ref(`/profiles/${post.val().authorId}/notificationTokens`).once('value');
console.log('getDeviceTokensTask path: ', `/profiles/${post.val().authorId}/notificationTokens`);
// Get post author.
const getCommentAuthorProfileTask = admin.database().ref(`/profiles/${comment.authorId}`).once('value');
console.log('getCommentAuthorProfileTask path: ', `/profiles/${comment.authorId}`);
// Get author photo url.
const getAuthorPhotoUrl= admin.database().ref(`/profiles/${comment.authorId}/photoUrl`).once('value');
console.log('photo url: ', `/profiles/${comment.authorId}/photoUrl`);
return Promise.all([getDeviceTokensTask, getCommentAuthorProfileTask,getAuthorPhotoUrl]).then(results => {
const tokensSnapshot = results[0];
const commentAuthorProfile = results[1].val();
const AuthorUrlPhoto = results[2].val();
if (commentAuthorProfile.id === post.val().authorId) {
console.log('User commented own post');
return 'User commented own post';
}
// Check if there are any device tokens.
if (!tokensSnapshot.hasChildren()) {
console.log('There are no notification tokens to send to.');
return 'There are no notification tokens to send to.';
}
console.log('There are', tokensSnapshot.numChildren(), 'tokens to send notifications to.');
console.log('photo url is :', AuthorUrlPhoto);
// Create a notification
const payload = {
data: {
actionType: actionTypeNewComment,
title: notificationTitle,
body: `${commentAuthorProfile.username} a ajouté un commentaire`,
icon: AuthorUrlPhoto,//post.val().imagePath,
postId: postId,
},
};
// Listing all tokens.
const tokens = Object.keys(tokensSnapshot.val());
console.log('tokens:', tokens[0]);
// Send notifications to all tokens.
return admin.messaging().sendToDevice(tokens, payload).then(response => {
// For each message check if there was an error.
const tokensToRemove = [];
response.results.forEach((result, index) => {
const error = result.error;
if (error) {
console.error('Failure sending notification to', tokens[index], error);
// Cleanup the tokens who are not registered anymore.
if (error.code === 'messaging/invalid-registration-token' ||
error.code === 'messaging/registration-token-not-registered') {
tokensToRemove.push(tokensSnapshot.ref.child(tokens[index]).remove());
}
}
});
return Promise.all(tokensToRemove);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
});
}).catch((fallback) => {
console.error('Failure getPostTask', fallback);
})
});
exports.pushNotificationNewPost = functions.database.ref('/posts/{postId}').onCreate((snap, context) => {
const postId = context.params.postId;
const getresidenceTask = admin.database().ref(`/posts/${postId}/residence`).once('value');
console.log('New post was created');
// Get post authorID.
const getAuthorIdTask = admin.database().ref(`/posts/${postId}/authorId`).once('value');
// return getAuthorIdTask.then(authorId => {
// console.log('post author id', authorId.val());
return Promise.all([getAuthorIdTask, getresidenceTask]).then(results => {
const authorSnapshot = results[0];
const residence = results[1]
// Create a notification
const payload = {
data: {
actionType: actionTypeNewPost,
postId: postId,
authorId: authorSnapshot.val(),
residencei: residence.val()
},
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToTopic(postsTopic, payload).then(response => {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent info about new post :", response);
return response;
})
.catch(error => {
console.log("Error sending info about new post:", error);
});
}).catch(fallback => {
console.error('Failure getPostTask', fallback);
});
});
exports.addNewPostToFollowers = functions.database.ref('/posts/{postId}').onCreate((snap, context) => {
const postId = context.params.postId;
console.log('New post was created');
// Get post authorID.
const getAuthorIdTask = admin.database().ref(`/posts/${postId}/authorId`).once('value');
return getAuthorIdTask.then(authorId => {
console.log('post author id', authorId.val());
// Get followers ids.
return admin.database().ref().child(followingDbKey).child(authorId.val()).child(followersDbKey).once('value', function(snapshot) {
snapshot.forEach(function (childSnapshot) {
let followerId = childSnapshot.val().profileId;
console.log('setNewPostValuesToFollower', "followerId:", followerId, "postId:", postId);
admin.database().ref().child(followingPosDbKey).child(followerId).child(postId).set({
postId:postId
});
});
}).catch(fallback => {
console.error('Failure get followers ids', fallback);
});
}).catch(fallback => {
console.error('Failure getPostTask', fallback);
});
});
exports.removePostFromFollowingList = functions.database.ref('/posts/{postId}').onDelete((snap, context) => {
const postId = context.params.postId;
const authorId = snap.val().authorId;
// Get followers ids.
return admin.database().ref().child(followingDbKey).child(authorId).child(followersDbKey).once('value', function(snapshot) {
snapshot.forEach(function (childSnapshot) {
let followerId = childSnapshot.val().profileId;
admin.database().ref().child(followingPosDbKey).child(followerId).child(postId).remove();
console.log('remove post if from following list for followerId:', followerId, "postId:", postId);
});
}).catch(fallback => {
console.error('Failure get followers ids', fallback);
});
});
exports.generateThumbnail = functions.storage.object().onFinalize((object) => {
const fileBucket = object.bucket; // The Storage bucket that contains the origin file.
const filePath = object.name; // File path in the bucket.
const contentType = object.contentType; // File content type.
const generateThumbsPromises = generateThumbnailsGeneral(fileBucket, filePath, contentType);
if(generateThumbsPromises !== null) {
return generateThumbsPromises.then(() => {
console.log('Thumbnail created successfully');
return null;
})
} else {
return null;
}
});
function generateThumbnailsGeneral(fileBucket, filePath, contentType) {
console.log("fileBucket", fileBucket);
console.log("filePath", filePath);
console.log("contentType", contentType);
// Exit if this is triggered on a file that is not an image.
if (!contentType.startsWith('image/')) {
console.log('This is not an image.');
return null;
}
// Get the dir name.
const dirname = path.dirname(filePath);
if (dirname.includes(THUMB_MEDIUM_DIR) || dirname.includes(THUMB_SMALL_DIR)) {
console.log('Already scaled.');
return null;
}
// Download file from bucket.
const fileName = path.basename(filePath);
const tempFilePath = path.join(os.tmpdir(), fileName);
const bucket = storage.bucket(fileBucket);
return bucket.file(filePath)
.download({
destination: tempFilePath
})
.then(() => {
console.log('download origin file successfully');
const mediumThumbPromise = createThumb(fileName, filePath, tempFilePath, THUMB_MEDIUM_DIR, THUMB_MEDIUM_SIZE, bucket);
const smallThumbPromise = createThumb(fileName, filePath, tempFilePath, THUMB_SMALL_DIR, THUMB_SMALL_SIZE, bucket);
return Promise.all([mediumThumbPromise, smallThumbPromise])
})
.then(() => {
fs.unlinkSync(tempFilePath);
console.log(`removing origimal temp file complete`);
return null;
});
}
function createThumb(fileName, originFilePath, tempFilePath, thumbDir, size, bucket) {
const newFileTemp = path.join(os.tmpdir(), `${fileName}_${size}_tmp.jpg`);
const newFilePath = path.join(path.dirname(originFilePath), thumbDir, fileName);
return sharp(tempFilePath)
.resize(size, size)
.toFile(newFileTemp)
.then(info => {
console.log(`resize ${size} complete, filePath = ${newFilePath}`);
return bucket.upload(newFileTemp, {
destination: newFilePath
})
})
.then(() => {
fs.unlinkSync(newFileTemp);
console.log(`removing thumb temp file for size ${size} px is complete`);
return null;
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment