From 15f976398a6ac6447be40493ed58998d624c6c41 Mon Sep 17 00:00:00 2001 From: Clayton Wilson Date: Sun, 29 Sep 2019 01:35:06 -0400 Subject: [PATCH] Code refactoring --- functions/handlers/users.js | 46 +++++++++++++ functions/index.js | 130 +++--------------------------------- functions/util/FBAuth.js | 35 ++++++++++ functions/util/admin.js | 7 ++ functions/util/config.js | 9 +++ functions/util/validator.js | 17 +++++ 6 files changed, 123 insertions(+), 121 deletions(-) create mode 100644 functions/handlers/users.js create mode 100644 functions/util/FBAuth.js create mode 100644 functions/util/admin.js create mode 100644 functions/util/config.js create mode 100644 functions/util/validator.js diff --git a/functions/handlers/users.js b/functions/handlers/users.js new file mode 100644 index 0000000..39e1e83 --- /dev/null +++ b/functions/handlers/users.js @@ -0,0 +1,46 @@ +const {db} = require('../util/admin'); +const {validateUpdateProfileInfo} = require('../util/validator'); + +exports.getProfileInfo = (req, res) => { + // FIXME: Delete this after login is implemented + req.user = {}; + req.user.handle = 'itsjimmy'; + + db.collection('users').doc(req.user.handle).get() + .then((data) => { + return res.status(200).json(data.data()); + }); +}; + +exports.updateProfileInfo = (req, res) => { + // FIXME: Delete this after login is implemented + req.user = {}; + req.user.handle = 'itsjimmy'; + + // TODO: Add functionality for adding/updating profile images + + // ?: Should users be able to change their handles? + const profileData = { + firstName: req.body.firstName.trim(), // Can be empty + lastName: req.body.lastName.trim(), // Can be empty + email: req.body.email.trim(), // Cannot be empty + bio: req.body.bio.trim(), // Can be empty + }; + + // Data validation + const {valid, errors} = validateUpdateProfileInfo(profileData); + if (!valid) return res.status(400).json(errors); + + // Update the database entry for this user + db.collection('users').doc(req.user.handle).set(profileData, {merge: true}) + .then(() => { + console.log(`${req.user.handle}'s profile info has been updated.`) + return res.status(201).json({general: `${req.user.handle}'s profile info has been updated.`}); + }) + .catch((err) => { + console.error(err); + return res.status(500).json({ + error: 'Error updating profile data' + }); + }) +}; \ No newline at end of file diff --git a/functions/index.js b/functions/index.js index da1d19f..aba5607 100644 --- a/functions/index.js +++ b/functions/index.js @@ -1,134 +1,22 @@ /* eslint-disable promise/always-return */ const functions = require('firebase-functions'); -const admin = require('firebase-admin'); const app = require('express')(); -admin.initializeApp(); -const db = admin.firestore(); -const firebaseConfig = { - apiKey: "AIzaSyCvsWetg4qFdsPGfJ3LCw_QaaYzoan7Q34", - authDomain: "twistter-e4649.firebaseapp.com", - databaseURL: "https://twistter-e4649.firebaseio.com", - projectId: "twistter-e4649", - storageBucket: "twistter-e4649.appspot.com", - messagingSenderId: "20131817365", - appId: "1:20131817365:web:633c95fb08b16d4526b89c" -}; +const FBAuth = require('./util/FBAuth'); -const firebase = require('firebase'); -firebase.initializeApp(firebaseConfig); +/*------------------------------------------------------------------* + * users.js * + *------------------------------------------------------------------*/ -const isEmpty = (str) => { - if (str.trim() === '') return true; - else return false; -} - -// Acts as a middleman between the client and any function that you use it with -// The function will only execute if the user is logged in, or rather, they have -// a valid token -const FBAuth = (req, resp, next) => { - let idToken; - - // Checking that the token exists in the header of the request - if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) { - idToken = req.headers.authorization.split('Bearer ')[1]; - } else { - console.error('No token found'); - return resp.status(403).json({ error: 'Unauthorized' }); - } - - // Checking that the token is valid in firebase - admin.auth().verifyIdToken(idToken) - .then(decodedToken => { - req.user = decodedToken; - console.log(decodedToken); - return db.collection('users') - .where('userId', '==', req.user.uid) - .limit(1) - .get(); - }) - .then(data => { - req.user.handle = data.docs[0].data().handle; // Save username - return next(); - }) - .catch(err => { - console.error('Error verifying token', err); - return res.status(403).json(err); - }) -} - -app.get('/getUsers', (req, res) => { - db.collection('users').get().then(data => { - let users = []; - data.forEach(doc => { - users.push(doc.data()); - }); return res.json(users); - }).catch((err) => console.error(err)); -}); - -app.post('/postUser', (req, res) => { - const newUser = { - body: req.body.body - }; - db.collection('users').add(newUser).then((doc) => { - res.json({ - message: 'Successfully added!' - }); - }).catch((err) => { - res.status(500).json({ - error: 'Error in posting user!' - }); - console.error(err); - }); -}); +const {getProfileInfo, updateProfileInfo} = require('./handlers/users'); // Returns all profile data of the currently logged in user -app.get('/getProfileInfo', (req, res) => { - // FIXME: Delete this after login is implemented - req.user = {}; - req.user.handle = 'itsjimmy'; - - db.collection('users').doc(req.user.handle).get() - .then((data) => { - return res.status(200).json(data.data()); - }); -}); +// TODO: Add FBAuth +app.get('/getProfileInfo', getProfileInfo); // Updates the currently logged in user's profile information -app.post('/updateProfileInfo', (req, res) => { - // FIXME: Delete this after login is implemented - req.user = {}; - req.user.handle = 'itsjimmy'; +// TODO: Add FBAuth +app.post('/updateProfileInfo', updateProfileInfo); - // TODO: Add functionality for adding/updating profile images - - // ?: Should users be able to change their handles? - const profileData = { - firstName: req.body.firstName.trim(), // Can be empty - lastName: req.body.lastName.trim(), // Can be empty - email: req.body.email.trim(), // Cannot be empty - bio: req.body.bio.trim(), // Can be empty - }; - - // Data validation - let errors = {} - - if (isEmpty(profileData.email)) { - errors.email = "Must not be empty."; - } - - // Update the database entry for this user - db.collection('users').doc(req.user.handle).set(profileData, {merge: true}) - .then(() => { - console.log(`${req.user.handle}'s profile info has been updated.`) - return res.status(200).json({general: `${req.user.handle}'s profile info has been updated.`}); - }) - .catch((err) => { - console.error(err); - return res.status(500).json({ - error: 'Error updating profile data' - }); - }) -}); exports.api = functions.https.onRequest(app); \ No newline at end of file diff --git a/functions/util/FBAuth.js b/functions/util/FBAuth.js new file mode 100644 index 0000000..e9ebf97 --- /dev/null +++ b/functions/util/FBAuth.js @@ -0,0 +1,35 @@ +const {admin, db} = require('./admin'); + +// Acts as a middleman between the client and any function that you use it with +// The function will only execute if the user is logged in, or rather, they have +// a valid token +module.exports = (req, resp, next) => { + let idToken; + + // Checking that the token exists in the header of the request + if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) { + idToken = req.headers.authorization.split('Bearer ')[1]; + } else { + console.error('No token found'); + return resp.status(403).json({ error: 'Unauthorized' }); + } + + // Checking that the token is valid in firebase + admin.auth().verifyIdToken(idToken) + .then(decodedToken => { + req.user = decodedToken; + console.log(decodedToken); + return db.collection('users') + .where('userId', '==', req.user.uid) + .limit(1) + .get(); + }) + .then(data => { + req.user.handle = data.docs[0].data().handle; // Save username + return next(); + }) + .catch(err => { + console.error('Error verifying token', err); + return res.status(403).json(err); + }) +}; \ No newline at end of file diff --git a/functions/util/admin.js b/functions/util/admin.js new file mode 100644 index 0000000..7710d59 --- /dev/null +++ b/functions/util/admin.js @@ -0,0 +1,7 @@ +const admin = require('firebase-admin'); + +admin.initializeApp(); + +const db = admin.firestore(); + +module.exports = {admin, db}; \ No newline at end of file diff --git a/functions/util/config.js b/functions/util/config.js new file mode 100644 index 0000000..903fed5 --- /dev/null +++ b/functions/util/config.js @@ -0,0 +1,9 @@ +module.exports = { + apiKey: "AIzaSyCvsWetg4qFdsPGfJ3LCw_QaaYzoan7Q34", + authDomain: "twistter-e4649.firebaseapp.com", + databaseURL: "https://twistter-e4649.firebaseio.com", + projectId: "twistter-e4649", + storageBucket: "twistter-e4649.appspot.com", + messagingSenderId: "20131817365", + appId: "1:20131817365:web:633c95fb08b16d4526b89c" +}; \ No newline at end of file diff --git a/functions/util/validator.js b/functions/util/validator.js new file mode 100644 index 0000000..b7c18d8 --- /dev/null +++ b/functions/util/validator.js @@ -0,0 +1,17 @@ +const isEmpty = (str) => { + if (str.trim() === '') return true; + else return false; +}; + +exports.validateUpdateProfileInfo = (profileData) => { + let errors = {} + + if (isEmpty(profileData.email)) { + errors.email = "Must not be empty."; + } + + return { + errors, + valid: Object.keys(errors).length === 0 ? true : false + } +}; \ No newline at end of file