diff --git a/.firebaserc b/.firebaserc
index 0b3cf99..2e9e776 100644
--- a/.firebaserc
+++ b/.firebaserc
@@ -5,4 +5,4 @@
"Twistter1": "twistter-6a42d",
"SuperTiger69": "twistter-e4649"
}
-}
\ No newline at end of file
+}
diff --git a/firebase.json b/firebase.json
index ad362e4..0e2c6a7 100644
--- a/firebase.json
+++ b/firebase.json
@@ -1,25 +1,30 @@
{
- "database": {
- "rules": "database.rules.json"
- },
- "firestore": {
- "rules": "firestore.rules",
- "indexes": "firestore.indexes.json"
- },
- "functions": {
- "predeploy": [
- "npm --prefix \"$RESOURCE_DIR\" run lint"
- ]
- },
- "hosting": {
- "public": "public",
- "ignore": [
- "firebase.json",
- "**/.*",
- "**/node_modules/**"
- ]
- },
- "storage": {
- "rules": "storage.rules"
+ "database": {
+ "rules": "database.rules.json"
+ },
+ "firestore": {
+ "rules": "firestore.rules",
+ "indexes": "firestore.indexes.json"
+ },
+ "functions": {
+ "predeploy": [
+ "npm --prefix \"$RESOURCE_DIR\" run lint"
+ ]
+ },
+ "hosting": {
+ "public": "public",
+ "ignore": [
+ "firebase.json",
+ "**/.*",
+ "**/node_modules/**"
+ ],
+ "rewrites": [{
+ "source": "/feed",
+ "destination": "/feed.html"
+ }]
+ },
+ "storage": {
+ "rules": "storage.rules"
+ }
}
-}
+
\ No newline at end of file
diff --git a/functions/handlers/post.js b/functions/handlers/post.js
index e2d195b..d15ea33 100644
--- a/functions/handlers/post.js
+++ b/functions/handlers/post.js
@@ -1,20 +1,21 @@
+const admin = require('firebase-admin');
/* eslint-disable promise/always-return */
exports.putPost = (req, res) => {
- if (req.body.body.trim() === '') {
- return res.status(400).json({ body: 'Body must not be empty!'});
- }
+
const newPost = {
body: req.body.body,
- userHandle: req.user.handle,
- userImage: req.user.imageUrl,
+ userHandle: req.body.userHandle,
+ userImage: req.body.userImage,
+ microBlogTitle: req.body.microBlogTitle,
createdAt: new Date().toISOString(),
likeCount: 0,
- commentCount: 0
+ commentCount: 0,
+
};
- db.collection('post').add(newPost)
- .then((doc) => {
+ admin.firestore().collection('posts').add(newPost)
+ .then((doc) => {
const resPost = newPost;
resPost.postId = doc.id;
return res.status(200).json(resPost);
@@ -25,3 +26,20 @@ exports.putPost = (req, res) => {
});
};
+exports.getallPostsforUser = (req, res) => {
+
+ admin.firestore().collection('posts').where('userHandle', '==', 'user' ).get()
+ .then((data) => {
+ let posts = [];
+ data.forEach(function(doc) {
+ posts.push(doc.data());
+ });
+ return res.status(200).json(posts);
+ })
+ .catch((err) => {
+ console.error(err);
+ return res.status(500).json({error: 'Failed to fetch all posts written by specific user.'})
+ })
+ }
+
+
diff --git a/functions/handlers/users.js b/functions/handlers/users.js
index c165ae0..54dcf00 100644
--- a/functions/handlers/users.js
+++ b/functions/handlers/users.js
@@ -1,6 +1,138 @@
-const {db} = require('../util/admin');
+/* eslint-disable promise/catch-or-return */
+const {admin, db} = require('../util/admin');
+const config = require('../util/config');
+
const {validateUpdateProfileInfo} = require('../util/validator');
+const firebase = require('firebase');
+firebase.initializeApp(config);
+
+
+
+exports.signup = (req, res) => {
+ const newUser = {
+ email: req.body.email,
+ handle: req.body.handle,
+ password: req.body.password,
+ confirmPassword: req.body.confirmPassword,
+ createdAt: new Date().toISOString()
+ };
+
+ // console.log(newUser);
+
+ let errors = {};
+
+ const emailRegEx = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@(([[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+
+ //Email check
+ if(newUser.email.trim() === '') {
+ errors.email = 'Email must not be blank.';
+ }
+ else if(!newUser.email.match(emailRegEx)) {
+ errors.email = 'Email is invalid.';
+ }
+
+ //handle check
+ if(newUser.handle.trim() === '') {
+ errors.handle = 'Username must not be blank.';
+ }
+ else if(newUser.handle.length < 4 || newUser.handle.length > 30) {
+ errors.handle = 'Username must be between 4-30 characters long.';
+ }
+
+ //Password check
+ if(newUser.password.trim() === '') {
+ errors.password = 'Password must not be blank.';
+ }
+ else if(newUser.password.length < 8 || newUser.password.length > 20) {
+ errors.password = 'Password must be between 8-20 characters long.';
+ }
+
+ //Confirm password check
+ if(newUser.confirmPassword !== newUser.password) {
+ errors.confirmPassword = 'Passwords must match.';
+ }
+
+ //Overall check
+ if(Object.keys(errors).length > 0) {
+ return res.status(400).json(errors);
+ }
+
+ let idToken, userId;
+
+ db.doc(`/users/${newUser.handle}`).get()
+ .then(doc => {
+ if(doc.exists) {
+ return res.status(400).json({ handle: 'This username is already taken.' });
+ }
+ return firebase.auth().createUserWithEmailAndPassword(newUser.email, newUser.password);
+ })
+ .then(data => {
+ userId = data.user.uid;
+ return data.user.getIdToken();
+ })
+ .then(token => {
+ idToken = token;
+ const userCred = {
+ email: req.body.email,
+ handle: newUser.handle,
+ createdAt: newUser.createdAt,
+ userId
+ }
+ return db.doc(`/users/${newUser.handle}`).set(userCred);
+ })
+ .then(() => {
+ return res.status(201).json({ idToken });
+ })
+ .catch(err => {
+ console.error(err);
+ if(err.code === 'auth/email-already-in-use') {
+ return res.status(500).json({ email: 'This email is already taken.' });
+ }
+ return res.status(500).json({ error: err.code });
+ });
+};
+
+exports.login = (req, res) => {
+ const user = {
+ email: req.body.email,
+ password: req.body.password
+ }
+
+ //Auth validation
+ let errors = {};
+
+ //Email check
+ if(user.email.trim() === '') {
+ errors.email = 'Email must not be blank.';
+ }
+
+ //Password check
+ if(user.password.trim() === '') {
+ errors.password = 'Password must not be blank.';
+ }
+
+ //Overall check
+ if(Object.keys(errors).length > 0) {
+ return res.status(400).json(errors);
+ }
+
+ firebase.auth().signInWithEmailAndPassword(user.email, user.password)
+ .then(data => {
+ return data.user.getIdToken();
+ })
+ .then(token => {
+ return res.json({token});
+ })
+ .catch(err => {
+ console.error(err);
+ if(err.code === 'auth/wrong-password') {
+ return res.status(403).json({ general: 'Invalid credentials. Please try again.' });
+ }
+ return res.status(500).json({ error: err.code });
+ });
+ };
+
exports.getProfileInfo = (req, res) => {
// FIXME: Delete this after login is implemented
req.user = {};
diff --git a/functions/index.js b/functions/index.js
index e764338..04d3b4e 100644
--- a/functions/index.js
+++ b/functions/index.js
@@ -6,10 +6,24 @@ app.use(cors());
const fbAuth = require('./util/fbAuth');
+
+const {db} = require('./util/admin');
+
+// const firebase = require('firebase');
+// firebase.initializeApp(config);
+
+
+
+
+
/*------------------------------------------------------------------*
- * handlers/users.js *
- *------------------------------------------------------------------*/
-const {getUserDetails, getProfileInfo, updateProfileInfo} = require('./handlers/users');
+* handlers/users.js *
+*------------------------------------------------------------------*/
+const {getUserDetails, getProfileInfo, updateProfileInfo, signup, login} = require('./handlers/users');
+
+app.post('/signup', signup);
+
+app.post('/login', login);
app.get('/getUser/:handle', getUserDetails);
@@ -24,7 +38,9 @@ app.post('/updateProfileInfo', updateProfileInfo);
/*------------------------------------------------------------------*
* handlers/post.js *
*------------------------------------------------------------------*/
-const {putPost} = require('./handlers/post');
+const {putPost, getallPostsforUser} = require('./handlers/post');
+
+app.get('/getallPostsforUser', getallPostsforUser);
// Adds one post to the database
app.post('/putPost', fbAuth, putPost);
diff --git a/functions/package-lock.json b/functions/package-lock.json
index a119731..a20f589 100644
--- a/functions/package-lock.json
+++ b/functions/package-lock.json
@@ -70,9 +70,15 @@
"integrity": "sha512-foQHhvyB0RR+mb/+wmHXd/VOU+D8fruFEW1k79Q9wzyTPpovMBa1Mcns5fwEWBhUfi8bmoEtaGB8RSAHnTFzTg=="
},
"@firebase/database": {
+<<<<<<< HEAD
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.3.tgz",
+ "integrity": "sha512-LnXKRE1AmjlS+iRF7j8vx+Ni8x85CmLP5u5Pw5rDKhKLn2eTR1tJKD937mUeeGEtDHwR1rrrkLYOqRR2cSG3hQ==",
+=======
"version": "0.5.4",
"resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.4.tgz",
"integrity": "sha512-Hz1Bi3fzIcNNocE4EhvvwoEQGurG2BGssWD3/6a2bzty+K1e57SLea2Ied8QYNBUU1zt/4McHfa3Y71EQIyn/w==",
+>>>>>>> 7969d3b10bc35a9078834c5ee2ba8c8fd60d338f
"requires": {
"@firebase/database-types": "0.4.3",
"@firebase/logger": "0.1.25",
@@ -107,7 +113,11 @@
"@firebase/firestore": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.5.3.tgz",
+<<<<<<< HEAD
+ "integrity": "sha512-CPYLvkGZBKE47oQC9a0q13UMVRj3LvnSbB1nOerktE3CGRHKy44LxDumamN8Kj067hV/80mKK9FdbeUufwO/Rg==",
+=======
"integrity": "sha512-O/yAbXpitOA6g627cUl0/FHYlkTy1EiEKMKOlnlMOJF2fH+nLVZREXjsrCC7N2tIvTn7yYwfpZ4zpSNvrhwiTA==",
+>>>>>>> 7969d3b10bc35a9078834c5ee2ba8c8fd60d338f
"requires": {
"@firebase/firestore-types": "1.5.0",
"@firebase/logger": "0.1.25",
@@ -600,7 +610,7 @@
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
- "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
},
"ansi-styles": {
@@ -820,28 +830,28 @@
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"requires": {
"number-is-nan": "^1.0.0"
- }
- },
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "requires": {
- "code-point-at": "^1.0.0",
- "is-fullwidth-code-point": "^1.0.0",
- "strip-ansi": "^3.0.0"
- }
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "requires": {
- "ansi-regex": "^2.0.0"
- }
- }
}
},
+ "string-width": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+ "requires": {
+ "code-point-at": "^1.0.0",
+ "is-fullwidth-code-point": "^1.0.0",
+ "strip-ansi": "^3.0.0"
+ }
+ },
+ "strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+ "requires": {
+ "ansi-regex": "^2.0.0"
+ }
+ }
+ }
+},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
@@ -1180,9 +1190,15 @@
}
},
"end-of-stream": {
+<<<<<<< HEAD
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
+ "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
+=======
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.3.tgz",
"integrity": "sha512-cbNhPFS6MlYlWTGncSiDYbdqKhwWFy7kNeb1YSOG6K65i/wPTkLVCJQj0hXA4j0m5Da+hBWnqopEnu1FFelisQ==",
+>>>>>>> 7969d3b10bc35a9078834c5ee2ba8c8fd60d338f
"optional": true,
"requires": {
"once": "^1.4.0"
@@ -1694,7 +1710,8 @@
"functional-red-black-tree": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
- "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
+ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
+ "optional": true
},
"gaxios": {
"version": "2.0.1",
@@ -2242,9 +2259,15 @@
}
},
"gtoken": {
+<<<<<<< HEAD
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.0.0.tgz",
+ "integrity": "sha512-XaRCfHJxhj06LmnWNBzVTAr85NfAErq0W1oabkdqwbq3uL/QTB1kyvGog361Uu2FMG/8e3115sIy/97Rnd4GjQ==",
+=======
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.0.tgz",
"integrity": "sha512-wqyn2gf5buzEZN4QNmmiiW2i2JkEdZnL7Z/9p44RtZqgt4077m4khRgAYNuu8cBwHWCc6MsP6eDUn/KkF6jFIw==",
+>>>>>>> 7969d3b10bc35a9078834c5ee2ba8c8fd60d338f
"optional": true,
"requires": {
"gaxios": "^2.0.0",
@@ -2418,7 +2441,8 @@
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+ "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+ "optional": true
},
"inflight": {
"version": "1.0.6",
@@ -2433,7 +2457,8 @@
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "optional": true
},
"inquirer": {
"version": "6.5.2",
@@ -2503,8 +2528,10 @@
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
- "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
- "dev": true
+ "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+ "requires": {
+ "number-is-nan": "^1.0.0"
+ }
},
"is-obj": {
"version": "2.0.0",
@@ -2902,6 +2929,7 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+ "optional": true,
"requires": {
"wrappy": "1"
}
@@ -3346,7 +3374,8 @@
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
- "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+ "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+ "optional": true
},
"slice-ansi": {
"version": "2.1.0",
@@ -3399,9 +3428,9 @@
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
- "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
- "dev": true,
+ "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": {
+ "code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
}
@@ -3415,7 +3444,7 @@
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
- "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^3.0.0"
@@ -3726,7 +3755,8 @@
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+ "optional": true
},
"write": {
"version": "1.0.3",
diff --git a/functions/package.json b/functions/package.json
index c5049dd..2e308b3 100644
--- a/functions/package.json
+++ b/functions/package.json
@@ -10,7 +10,7 @@
"logs": "firebase functions:log"
},
"engines": {
- "node": "8"
+ "node": "10"
},
"dependencies": {
"axios": "^0.19.0",
diff --git a/functions/util/fbAuth.js b/functions/util/fbAuth.js
index 04d71ed..a9243cc 100644
--- a/functions/util/fbAuth.js
+++ b/functions/util/fbAuth.js
@@ -7,8 +7,8 @@ module.exports = (req, res, next) => {
let idToken;
// Checking that the token exists in the header of the request
- if (req.headers.authorization) {
- idToken = req.headers.authorization;
+ if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
+ idToken = req.headers.authorization.split('Bearer ')[1];
} else {
console.error('No token found');
return res.status(403).json({ error: 'Unauthorized'});
diff --git a/twistter-frontend/package.json b/twistter-frontend/package.json
index 0cb0dda..bc4672f 100644
--- a/twistter-frontend/package.json
+++ b/twistter-frontend/package.json
@@ -24,5 +24,17 @@
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
- "proxy": "https://us-central1-twistter-e4649.cloudfunctions.net/api"
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "proxy": "https://us-central1-twistter-e4649.cloudfunctions.net/api"
}
diff --git a/twistter-frontend/src/App.js b/twistter-frontend/src/App.js
index 7d104c5..f7157c9 100644
--- a/twistter-frontend/src/App.js
+++ b/twistter-frontend/src/App.js
@@ -5,6 +5,7 @@ import './App.css';
import { BrowserRouter as Router } from 'react-router-dom';
import Route from 'react-router-dom/Route';
+import NavBar, { Navbar } from './components/layout/NavBar';
// Pages
import home from './Home.js';
@@ -13,12 +14,15 @@ import login from './Login.js';
import user from './pages/user';
import writeMicroblog from './Writing_Microblogs.js';
import edit from './pages/edit.js';
+import userLine from './Userline.js';
class App extends Component {
render() {
return (
{microBlog.body}
)} +