Merge branch 'T-954157790482076-User-can-upload-a-photo-to-each-profile'

This commit is contained in:
Okechi Onyeje 2019-01-14 18:01:12 -05:00
commit 0b432b99f7
5 changed files with 128 additions and 48 deletions

View File

@ -50,6 +50,13 @@
}
}
},
"buckets": {
"profile": "tagfer-inc_profile-images"
},
"imageFormat": {
"image/jpeg": "jpg",
"image/png": "png"
},
"dbPath": {
"users": "users",
"profiles": "profiles"

View File

@ -27,6 +27,7 @@ function router(app) {
// Profile Endpoints
app.post('/profiles/:profileNumber', ProfileHandlers.updateUserProfile);
app.get('/profiles/:profileNumber', ProfileHandlers.getUserProfile);
app.put('/profiles/uploadImage/:profileNumber', ProfileHandlers.updateUserProfileImage);
}
module.exports = router;

View File

@ -1,4 +1,6 @@
const database = require('firebase-admin').database();
const utils = require('../utils/utils');
const appConfig = require('../../config/app.json');
/**
* Blind initializing function for a new user's default profile
@ -6,8 +8,8 @@ const database = require('firebase-admin').database();
* @param {string} tagferId
*/
function createInitialProfiles(profileObj, tagferId) {
//persist profile data to firebase
return database.ref(`/profiles/${tagferId}/profile1`).set(profileObj);
//persist profile data to firebase
return database.ref(`/profiles/${tagferId}/profile1`).set(profileObj);
}
/**
@ -18,8 +20,8 @@ function createInitialProfiles(profileObj, tagferId) {
* @returns {Boolean} Boolean result of whether the
*/
function updateProfile(profileObj, profileNumber, tagferId) {
//persist profile data to firebase
return database.ref(`/profiles/${tagferId}/profile${profileNumber}`).set(profileObj);
//persist profile data to firebase
return database.ref(`/profiles/${tagferId}/profile${profileNumber}`).set(profileObj);
}
/**
@ -29,13 +31,32 @@ function updateProfile(profileObj, profileNumber, tagferId) {
* @returns {Object} Profile object containg information for a specific user's profile
*/
function getProfile(profileNumber, tagferId) {
return database.ref(`/profiles/${tagferId}/profile${profileNumber}`).once('value').then(function(snapshot) {
return (snapshot.exists() ? snapshot.val() : {});
});
return database.ref(`/profiles/${tagferId}/profile${profileNumber}`).once('value').then(function (snapshot) {
return (snapshot.exists() ? snapshot.val() : {});
});
}
/**
* Updates a user's profile image
* @param {object} profileImageData JSON object containing all image data for a profile captured from the frontend
* @param {number} profileNumber Number used to identify which profile a user wants to update/add image to
* @param {string} tagferId tagferId obtained by extracting from authorization header
* @returns {object} Object containing a Promise that contains the result of uploading profile image, and the image url | {promise, imageURL}
*/
async function updateProfileImage(profileImageData, profileNumber, tagferId) {
//persist profile image data to firebase storage
try {
const downloadURL = await utils.uploadImage(profileImageData, `${tagferId}-profile${profileNumber}`, appConfig.buckets.profile);
return { promise: database.ref(`/profiles/${tagferId}/profile${profileNumber}/photoURL`).set(downloadURL), imageURL: downloadURL };
} catch (error) {
throw error;
}
}
module.exports = {
updateProfile,
createInitialProfiles,
getProfile
updateProfile,
createInitialProfiles,
updateProfileImage,
getProfile
};

View File

@ -1,9 +1,8 @@
const profileDao = require('./dao');
const authDao = require('../auth/dao');
const utils = require('../utils/utils');
const errors = require('../../config/errors');
const errors = require('../../config/errors');
const http = require('../../config/http');
const _ = require('lodash');
// Handlers
/**
@ -13,44 +12,69 @@ const _ = require('lodash');
* @param {Object} res {result: Boolean} | {error: String}
*/
async function updateUserProfile(req, res) {
const profileObj = req.body;
const profileNumber = req.params.profileNumber;
const profileObj = req.body;
const profileNumber = req.params.profileNumber;
if (!utils.isProfileNumberValid(profileNumber, res)) {
return;
}
const sessionId = utils.getSessionIdFromAuthHeader(req, res);
try {
const tagferId = authDao.getSession(sessionId).tagferId;
profileDao.updateProfile(profileObj, profileNumber, tagferId).then( () => {
res.status(http.CREATED).json({})
}).catch( (error) => {
res.status(http.INTERNAL_SERVER_ERROR).json({error: errors.APP_FIREBASE_DATABASE_ERROR})
});
} catch (error) {
res.status(http.UNAUTHORIZED).json({error})
}
if (!utils.isProfileNumberValid(profileNumber, res)) {
return;
}
const sessionId = utils.getSessionIdFromAuthHeader(req, res);
try {
const tagferId = authDao.getSession(sessionId).tagferId;
profileDao.updateProfile(profileObj, profileNumber, tagferId).then(() => {
res.status(http.CREATED).json({});
}).catch((error) => {
res.status(http.INTERNAL_SERVER_ERROR).json({ error: errors.APP_FIREBASE_DATABASE_ERROR });
});
} catch (error) {
res.status(http.UNAUTHORIZED).json({ error });
}
}
/**
* Endpoints: PUT profiles/uploadImage/:profileNumber
* Updates user's profile with a profile image based on profile number given.
* This endpoint is called seperately in order to add an image to a profile.
* @param {Object} req {profileNumber}
* @param {Object} res
*/
async function updateUserProfileImage(req, res) {
const profileImageObj = req.body;
const sessionId = utils.getSessionIdFromAuthHeader(req, res);
try {
const tagferId = authDao.getSession(sessionId).tagferId;
const result = await profileDao.updateProfileImage(profileImageObj, req.params.profileNumber, tagferId);
result.promise.then(() => {
res.status(http.OK).json({ imageURL: result.imageURL });
}).catch((error) => {
res.status(http.INTERNAL_SERVER_ERROR).json({ error });
});
} catch (error) {
res.status(http.BAD_REQUEST).json({ error });
}
}
async function getUserProfile(req, res) {
const profileNumber = req.params.profileNumber;
if (!utils.isProfileNumberValid(profileNumber)) {
return;
}
const sessionId = utils.getSessionIdFromAuthHeader(req, res);
try {
const tagferId = authDao.getSession(sessionId).tagferId;
profileDao.getProfile(profileNumber,tagferId).then((profile) => {
res.status(http.OK).json({profile})
}).catch(error => {
res.status(http.INTERNAL_SERVER_ERROR).json({error: error.code})
})
} catch (error) {
res.status(http.UNAUTHORIZED).json({ error })
}
const profileNumber = req.params.profileNumber;
if (!utils.isProfileNumberValid(profileNumber)) {
return;
}
const sessionId = utils.getSessionIdFromAuthHeader(req, res);
try {
const tagferId = authDao.getSession(sessionId).tagferId;
profileDao.getProfile(profileNumber, tagferId).then((profile) => {
res.status(http.OK).json({ profile });
}).catch(error => {
res.status(http.INTERNAL_SERVER_ERROR).json({ error: error.code });
});
} catch (error) {
res.status(http.UNAUTHORIZED).json({ error });
}
}
module.exports = {
updateUserProfile,
getUserProfile
}
updateUserProfile,
updateUserProfileImage,
getUserProfile
};

View File

@ -1,9 +1,9 @@
const OAuth = require('oauth-1.0a');
const crypto = require('crypto');
const appConfig = require('../../config/app.json');
const http = require('../../config/http');
const errors = require('../../config/errors');
const firebase = require('firebase-admin');
/**
* Verifies if the request is valid by checking if the request has the right app secret.
@ -71,10 +71,37 @@ function createOAuthHeader(request, app) {
return oauth.toHeader(oauth.authorize(request, app.token));
}
/**
*
* @param {*} image as raw bytes
* @param {*} path to saving image in firebase
* @param {*} bucketName bucketName
*
* @returns {*} imageURL
*/
async function uploadImage(imageData, path, bucketName) {
try {
const bucket = firebase.storage().bucket(`gs://${bucketName}`);
const file = bucket.file(`${path}.${appConfig.imageFormat[imageData.metaData.contentType]}`);
const imageBuffer = Buffer.from(imageData.base64Data, 'base64');
await file.save(imageBuffer);
const fileMetaData = await file.getMetadata();
return fileMetaData[0].mediaLink;
} catch (error) {
throw error;
}
}
module.exports = {
isAppSecretValid,
isBodyValid,
getSessionIdFromAuthHeader,
isProfileNumberValid,
createOAuthHeader
createOAuthHeader,
uploadImage
};