diff --git a/functions/handlers/post.js b/functions/handlers/post.js
index e3d0c01..1db0144 100644
--- a/functions/handlers/post.js
+++ b/functions/handlers/post.js
@@ -4,8 +4,9 @@ exports.putPost = (req, res) => {
const newPost = {
body: req.body.body,
- userHandle: req.body.userHandle,
+ userHandle: req.userData.handle,
userImage: req.body.userImage,
+ userID: req.userData.userId,
microBlogTitle: req.body.microBlogTitle,
createdAt: new Date().toISOString(),
likeCount: 0,
@@ -27,7 +28,7 @@ exports.putPost = (req, res) => {
};
exports.getallPostsforUser = (req, res) => {
- admin.firestore().collection('posts').where('userHandle', '==', 'new user' ).get()
+ admin.firestore().collection('posts').where('userHandle', '==', req.userData.handle ).get()
.then((data) => {
let posts = [];
data.forEach(function(doc) {
diff --git a/functions/handlers/topic.js b/functions/handlers/topic.js
new file mode 100644
index 0000000..4d3dc3d
--- /dev/null
+++ b/functions/handlers/topic.js
@@ -0,0 +1,52 @@
+/* eslint-disable promise/always-return */
+const { admin, db } = require("../util/admin");
+exports.putTopic = (req, res) => {
+
+ const newTopic = {
+ topic: req.body.topic
+ };
+
+ admin.firestore().collection('topics').add(newTopic)
+ .then((doc) => {
+ const resTopic = newTopic;
+ newTopic.topicId = doc.id;
+ return res.status(200).json(resTopic);
+ })
+ .catch((err) => {
+ console.error(err);
+ return res.status(500).json({ error: 'something is wrong'});
+ });
+};
+
+exports.getAllTopics = (req, res) => {
+ admin.firestore().collection('topics').get()
+ .then((data) => {
+ let topics = [];
+ data.forEach(function(doc) {
+ topics.push(doc.data());
+ });
+ return res.status(200).json(topics);
+ })
+ .catch((err) => {
+ console.error(err);
+ return res.status(500).json({error: 'Failed to fetch all topics.'})
+ })
+};
+
+exports.deleteTopic = (req, res) => {
+ const topic = db.doc(`/topics/${req.params.topicId}`);
+ topic.get().then((doc) => {
+ if (!doc.exists) {
+ return res.status(404).json({error: 'Topic not found'});
+ } else {
+ return topic.delete();
+ }
+ })
+ .then(() => {
+ res.json({ message: 'Topic successfully deleted!'});
+ })
+ .catch((err) => {
+ console.error(err);
+ return res.status(500).json({error: 'Failed to delete topic.'})
+ })
+}
\ No newline at end of file
diff --git a/functions/handlers/users.js b/functions/handlers/users.js
index 87733bc..f3ad079 100644
--- a/functions/handlers/users.js
+++ b/functions/handlers/users.js
@@ -75,7 +75,8 @@ exports.signup = (req, res) => {
email: newUser.email,
handle: newUser.handle,
createdAt: newUser.createdAt,
- userId
+ userId,
+ followedTopics: []
};
return db.doc(`/users/${newUser.handle}`).set(userCred);
})
@@ -168,7 +169,7 @@ exports.login = (req, res) => {
})
.catch((err) => {
console.error(err);
- if (err.code === "auth/wrong-password" || err.code === "auth/invalid-email") {
+ if (err.code === "auth/wrong-password" || err.code === "auth/invalid-email" || err.code === "auth/user-not-found") {
return res
.status(403)
.json({ general: "Invalid credentials. Please try again." });
@@ -231,7 +232,7 @@ exports.updateProfileInfo = (req, res) => {
// TODO: Add functionality for adding/updating profile images
// Data validation
- const { valid, errors, profileData } = validateUpdateProfileInfo(req.body);
+ const { valid, errors, profileData } = validateUpdateProfileInfo(req);
if (!valid) return res.status(400).json(errors);
// Update the database entry for this user
@@ -256,50 +257,11 @@ exports.updateProfileInfo = (req, res) => {
exports.getUserDetails = (req, res) => {
let userData = {};
- db.doc(`/users/${req.params.handle}`)
+ db.doc(`/users/${req.body.handle}`)
.get()
.then((doc) => {
if (doc.exists) {
- userData.user = doc.data();
- return db
- .collection("post")
- .where("userHandle", "==", req.params.handle)
- .orderBy("createdAt", "desc")
- .get();
- } else {
- return res.status(404).json({
- error: "User not found"
- });
- }
- })
- .then((data) => {
- userData.posts = [];
- data.forEach((doc) => {
- userData.posts.push({
- body: doc.data().body,
- createAt: doc.data().createAt,
- userHandle: doc.data().userHandle,
- userImage: doc.data().userImage,
- likeCount: doc.data().likeCount,
- commentCount: doc.data().commentCount,
- postId: doc.id
- });
- });
- return res.json(userData);
- })
- .catch((err) => {
- console.error(err);
- return res.status(500).json({ error: err.code });
- });
-};
-
-exports.getAuthenticatedUser = (req, res) => {
- let userData = {};
- db.doc(`/users/${req.user.handle}`)
- .get()
- .then((doc) => {
- if (doc.exists) {
- userData.credentials = doc.data();
+ userData = doc.data();
return res.status(200).json({userData});
} else {
return res.status(400).json({error: "User not found."})
@@ -309,3 +271,22 @@ exports.getAuthenticatedUser = (req, res) => {
return res.status(500).json({ error: err.code });
});
};
+
+exports.getAuthenticatedUser = (req, res) => {
+ let credentials = {};
+ db.doc(`/users/${req.user.handle}`)
+ .get()
+ .then((doc) => {
+ if (doc.exists) {
+ credentials = doc.data();
+ return res.status(200).json({credentials});
+ } else {
+ return res.status(400).json({error: "User not found."})
+ }})
+ .catch((err) => {
+ console.error(err);
+ return res.status(500).json({ error: err.code });
+ });
+};
+
+
diff --git a/functions/index.js b/functions/index.js
index 45d181a..33ce166 100644
--- a/functions/index.js
+++ b/functions/index.js
@@ -31,7 +31,7 @@ app.post("/login", login);
//Deletes user account
app.delete("/delete", fbAuth, deleteUser);
-app.get("/getUser/:handle", getUserDetails);
+app.get("/getUser", fbAuth, getUserDetails);
// Returns all profile data of the currently logged in user
app.get("/getProfileInfo", fbAuth, getProfileInfo);
@@ -44,11 +44,30 @@ app.get("/user", fbAuth, getAuthenticatedUser);
/*------------------------------------------------------------------*
* handlers/post.js *
*------------------------------------------------------------------*/
-const { getallPostsforUser, putPost } = require("./handlers/post");
+const { getallPostsforUser, putPost
+} = require("./handlers/post");
app.get("/getallPostsforUser", getallPostsforUser);
// Adds one post to the database
app.post("/putPost", fbAuth, putPost);
+/*------------------------------------------------------------------*
+ * handlers/topic.js *
+ *------------------------------------------------------------------*/
+const {
+ putTopic,
+ getAllTopics,
+ deleteTopic
+} = require("./handlers/topic");
+
+// add topic to database
+app.post("/putTopic", fbAuth, putTopic);
+
+// get all topics from database
+app.get("/getAllTopics", fbAuth, getAllTopics);
+
+// delete a specific topic
+app.delete("/deleteTopic/:topicId", fbAuth, deleteTopic);
+
exports.api = functions.https.onRequest(app);
diff --git a/functions/package-lock.json b/functions/package-lock.json
index 439a2e2..acfe9ce 100644
--- a/functions/package-lock.json
+++ b/functions/package-lock.json
@@ -535,6 +535,11 @@
"integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
"dev": true
},
+ "ansi-regex": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
+ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
+ },
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
@@ -1190,11 +1195,18 @@
"progress": "^2.0.0",
"regexpp": "^2.0.1",
"semver": "^5.5.1",
+ "strip-ansi": "^4.0.0",
"strip-json-comments": "^2.0.1",
"table": "^5.2.3",
"text-table": "^0.2.0"
},
"dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
@@ -1209,6 +1221,15 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"dev": true
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
}
}
},
@@ -2355,6 +2376,7 @@
"mute-stream": "0.0.7",
"run-async": "^2.2.0",
"rxjs": "^6.4.0",
+ "string-width": "^2.1.0",
"strip-ansi": "^5.1.0",
"through": "^2.3.6"
},
@@ -2403,6 +2425,12 @@
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
"optional": true
},
+ "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
+ },
"is-obj": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
@@ -3252,7 +3280,8 @@
"dev": true,
"requires": {
"ansi-styles": "^3.2.0",
- "astral-regex": "^1.0.0"
+ "astral-regex": "^1.0.0",
+ "is-fullwidth-code-point": "^2.0.0"
}
},
"snakeize": {
@@ -3292,12 +3321,47 @@
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
},
+ "string-width": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
+ "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
+ "dev": true,
+ "requires": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "dependencies": {
+ "ansi-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
+ "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
+ "dev": true
+ },
+ "strip-ansi": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
+ "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
+ "dev": true,
+ "requires": {
+ "ansi-regex": "^3.0.0"
+ }
+ }
+ }
+ },
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
"optional": true
},
+ "strip-ansi": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
+ "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
+ "requires": {
+ "ansi-regex": "^4.1.0"
+ }
+ },
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -3344,6 +3408,7 @@
"dev": true,
"requires": {
"emoji-regex": "^7.0.1",
+ "is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
diff --git a/functions/package.json b/functions/package.json
index 2e308b3..29b3e89 100644
--- a/functions/package.json
+++ b/functions/package.json
@@ -16,7 +16,8 @@
"axios": "^0.19.0",
"firebase": "^6.6.2",
"firebase-admin": "^8.6.0",
- "firebase-functions": "^3.1.0"
+ "firebase-functions": "^3.1.0",
+ "strip-ansi": "^5.2.0"
},
"devDependencies": {
"eslint": "^5.12.0",
diff --git a/functions/util/fbAuth.js b/functions/util/fbAuth.js
index 3b59d14..35253e7 100644
--- a/functions/util/fbAuth.js
+++ b/functions/util/fbAuth.js
@@ -32,6 +32,7 @@ module.exports = (req, res, next) => {
.then((data) => {
req.user.handle = data.docs[0].data().handle; // Save username
req.user.imageUrl = data.docs[0].data().imageUrl;
+ req.userData = data.docs[0].data(); // Stores all user data from the database
return next();
})
.catch((err) => {
diff --git a/functions/util/validator.js b/functions/util/validator.js
index c2b1240..8265d6b 100644
--- a/functions/util/validator.js
+++ b/functions/util/validator.js
@@ -9,23 +9,39 @@ const isEmpty = (str) => {
else return false;
};
-exports.validateUpdateProfileInfo = (data) => {
+exports.validateUpdateProfileInfo = (req) => {
+ const newData = req.body;
+ // const oldData = req.userData;
let errors = {};
- let profileData = {};
+ let profileData = req.userData;
// ?: Should users be able to change their handles and emails?
- // Only adds the key to the database if the values are not empty
- if (!isEmpty(data.firstName)) profileData.firstName = data.firstName.trim();
- if (!isEmpty(data.lastName)) profileData.lastName = data.lastName.trim();
- if (!isEmpty(data.bio)) profileData.bio = data.bio.trim();
+ // Deletes any unused keys so that they aren't stored in the database
+ if (newData.firstName) {
+ profileData.firstName = newData.firstName.toString().trim();
+ } else {
+ delete profileData.firstName;
+ }
- if (isEmpty(data.email)) {
+ if (newData.lastName) {
+ profileData.lastName = newData.lastName.toString().trim();
+ } else {
+ delete profileData.lastName;
+ }
+
+ if (newData.bio) {
+ profileData.bio = newData.bio.toString().trim();
+ } else {
+ delete profileData.bio;
+ }
+
+ if (isEmpty(newData.email)) {
errors.email = "Must not be empty.";
- } else if (!isEmail(data.email)) {
+ } else if (!isEmail(newData.email)) {
errors.email = "Must be a valid email.";
} else {
- profileData.email = data.email;
+ profileData.email = newData.email;
}
return {
diff --git a/package-lock.json b/package-lock.json
index c7bbe95..c65b0ba 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,15 @@
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
},
+ "axios": {
+ "version": "0.19.0",
+ "resolved": "https://registry.npmjs.org/axios/-/axios-0.19.0.tgz",
+ "integrity": "sha512-1uvKqKQta3KBxIz14F2v06AEHZ/dIoeKfbTRkK1E5oqjDnuEerLmYTgJB5AiQZHJcljpg1TuRzdjDR06qNk0DQ==",
+ "requires": {
+ "follow-redirects": "1.5.10",
+ "is-buffer": "^2.0.2"
+ }
+ },
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
@@ -164,6 +173,24 @@
"unpipe": "~1.0.0"
}
},
+ "follow-redirects": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
+ "integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
+ "requires": {
+ "debug": "=3.1.0"
+ },
+ "dependencies": {
+ "debug": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
+ "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ }
+ }
+ },
"forwarded": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
@@ -204,6 +231,16 @@
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
"integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
},
+ "is-buffer": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
+ "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A=="
+ },
+ "jwt-decode": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-2.2.0.tgz",
+ "integrity": "sha1-fYa9VmefWM5qhHBKZX3TkruoGnk="
+ },
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
diff --git a/twistter-e4649-firebase-adminsdk-pgjve-1e57494429.json b/twistter-e4649-firebase-adminsdk-pgjve-1e57494429.json
deleted file mode 100644
index d24aa3c..0000000
--- a/twistter-e4649-firebase-adminsdk-pgjve-1e57494429.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "type": "service_account",
- "project_id": "twistter-e4649",
- "private_key_id": "1e57494429e4fd7d17f6fc28524e14b8e5227596",
- "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCyRdMZwXrpf3HB\nsVrGZVoPt+S+ahkT4SCCEWV/Q4O4hVyW277Rs0p7k5ZkZfkhcVVBUqKGMgW/Esvz\npx0VIgpg3gg308kMRmC3MGzYbodjynVyDHatyAZhhUi9cg0N2K9+vSsW5eSmWROe\nfVvB8hvr6m5xGVdJFA7DV4/0vm2cfy+Q/FlFb6vFmQTZtPZzGFf5BKoNMe7pMxey\n4zspAIZgRmxWDbAqqzX0PYk/WbXFgH/wn2X25S+ArHhoay2Hms65/NbWCV6mpFUJ\nYqzrlCn/WcwXGAm7tjmu00yD+bARabImh8R7+PSBaHMQ+SGdri2snIXWsvB/xi9/\nSNFqzHynAgMBAAECggEAVty/zapg1bnTt0FPziBfIA6FpaPzoSSN3uJUFozSdwuA\nAD+E/A9EiO7yFew71egvVrtJVmK0OxQRDSDNglkKPoWg8na+XL1D7a5qMpC0ZlKl\nJBNfljBCr6yuMySJqMf+Rp4siyUr4kO/0/cXyOnLYglhk7j5tzFPOi4FhgZtSRU9\nYckk5wwcBObUFE0Rmqf0gPcI9WuFUkusIjz3rjuEju1/U6E/VV5gHmMuQy3f9LHB\nnsiLAobx9+TGgs12CvkjWYpW5raUCCn5z/EYNPZSt7rg9CSWqXW009HCfTqi6i7o\nNpZ7qpp5DVQdHNFJunSGvI+k44+i8OE7HEY4xXt+OQKBgQDZ/E1QwJQoHuzPkrGW\nAc0a+NQeG8NwaXwsezlvYXMTbL27SxKXC3dzPT1WgNUKpaKj3wLJPar4NgPPSPi3\nqgmcvMqgwm4B+HPbXc1oxBS7/jD3pWJVyPO9Re17Uc0RYV/DORQhWe1Yq7TyMHvl\nbD/KqIvOxswigVxK4JMIxp4s7wKBgQDRXJfb4BHdR7CGfuTVQ19gH5uLgrK9ezBk\nQOLK+u9yBpoKyYSnD3OH/i0wG5bm3rUegzvwHGKKhDfiLbajMIt04n2DuVUm57HQ\n+Jca29V8XMWfhTbu3kDl+OOFmLvPCwg8C9edNTJWUVYu3EbwsyzCQY5TDroWGQdF\n6cQIkAIbyQKBgQCUtWd1UHuCR16cWOHniQEIhnoGtEAHHx9EJShQkLV1qfhhnlxn\nSL5LkpqWubsc0VR74LbA3N4XCJpevdRXT5vRHoZJV3q+w2UeYQaxkxrmCQoU1/GW\nvklxdRQGzg5M7hXrU7Qk8HlXxYPiuSq8n7WBJqyB+uLmI0P4HO6RzRW5ZwKBgBkr\nf5pQkvU+dCuHP+2fvuyogCPCn8iF8ehroJh0mKrlvklDtu36vpH/7eDVwEubRL0Z\nW/BfCT3L7YgEpOtzn6B6xko60tDtlAQijtAM09qysJOgCV2oXLcJOBlMpm+azO+j\nINXmmlmkR680jlbLw7rK9NhpcdfMRIKUOxwobAh5AoGBAJMN6n7Hy8nJRJZ18iHY\n3hEkVbKrLLMMHFDQj5BZQCeAp1v0Fj30RYJWS4hTzR9ht0MtdmPub460lh9hhqCM\nl3UnCJoz00ApF3Z2FRN/l0KpCFD9Gw2Hjyc3u9sEUpqd8G3cg3IZE6eZ6CZWljFT\nHcuQ2cTFdB8bq8oLUxXeY3Yv\n-----END PRIVATE KEY-----\n",
- "client_email": "firebase-adminsdk-pgjve@twistter-e4649.iam.gserviceaccount.com",
- "client_id": "102241295911303209723",
- "auth_uri": "https://accounts.google.com/o/oauth2/auth",
- "token_uri": "https://oauth2.googleapis.com/token",
- "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
- "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-pgjve%40twistter-e4649.iam.gserviceaccount.com"
-}
diff --git a/twistter-e4649-firebase-adminsdk-pgjve-382fc005e1.json b/twistter-e4649-firebase-adminsdk-pgjve-382fc005e1.json
new file mode 100644
index 0000000..3d3ce5d
--- /dev/null
+++ b/twistter-e4649-firebase-adminsdk-pgjve-382fc005e1.json
@@ -0,0 +1,12 @@
+{
+ "type": "service_account",
+ "project_id": "twistter-e4649",
+ "private_key_id": "382fc005e17340a21dd39079feca75371330644d",
+ "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDL1bwTpEluR6dJ\nVfS/K1d76j2I3Wrn4qSbrTYm4/cAPBPlsBRO0bwrkhr+g0I6rwW/fFz8udjNAFB1\nfDfz769buR6go5us71I5LxMNviIhzFr59ZsEkcnUCgW8G7koicLEjWdstI4lJxZT\nRRolH+SFpPwsQAY399zjdBiCC8STbavVVhe+ChEDl/S2K72W7A7nWSMbLsyGsz2o\nQ9uIG3onwFNE7WRIeObWCxSBKlydMmTJ+p/CsTdFY4fUHb97QsMEmzRJox10kmyt\nP9l5wfJ2wUYvRXRJKq7Mwx1UnLduXP2oe/XvR5fzJLJ780HO6BNBf5IKcTHXHVBA\ne6ZtiL5dAgMBAAECggEAFvfN1NttjXL0KKak3hMA1+z8Y2WqXC1aUFMOMlz8Qhct\nmXNjy8CFAYEvGtVTgHqkR9Vi7PShYfLSc3U8diI155H5H4S6pUaPmfNHTwRzosyn\ncQRPJA6sEqvRGvHMxVfwjbvultMpiTTZpnxiMSNiLqT5PUs26CuSb5bErt1V7dP5\nn/lhY+4rzfXSrw38ZsO/gEvLZ/7iRA+JZgqE3Qs2cD5idxqqOcOLLiW741JpXTmd\n5ug/urJgSyvz+cNo3yHnajEtAxiSfkpU4sUHZ/WWqaRGWxpt3XWILtR9Q/4afPeM\n/T82YvddoW5pUwDpgvZxdVYjopuoxvnS298L0AGySQKBgQDqDD7Yh6SbOR3w4ZN9\nRO7q5KiJbyZmVdZ3lLZddsL/vto9JkUtnLDOMpYnb2TezGfN6ErzAkRQCSUsWK4m\nERbSK6oyUvevhlt/gHGP34uc/OCxGk2D7WCAS3s54ofDt2369tzIpGjsnkYM+h3b\nuZ5lFoWHG1YM3JtgcIIU6UygTwKBgQDe9ArV08wPDuXf4rcldmImQDB7xhGcg9xU\njAKEn5FZW1mvmBy3Sq1qpZj0baZz6eEDn6FBLwH1Ke5gdfrd8WnESUNnFnBBqpA1\nospIgUmKZ1sjyly9CHMQ11Kbzt7+kA9GYZrMbaMjS8M18qFEBZ7CoPLv5DLyabJW\nOkPzTwb/kwKBgQDR3fUkmEzj202bx8pHE97gxfTSd9aJAQN06uaz3GByjyKGnqB9\ni/mGjBnUdrCOj9+s5VT/ntK+qdSpdUODYuOBxiGxSnBK9kFpjTVHe35nYOHiLOHB\nIMPdhtGSUCzJNNvrpBzJ1ZM4SZwq2sSXWFRN9On7Amog0liJG5mpQqGxRQKBgHmP\nzFycF3XaZKH2xm8ppgg/FXBXJYEWMEr07+aJ7kEvWq4wHPAfSoCMe+JB6vDmg2Zr\nYgvdao7W5v83NKpQl5+LZrHNfTWAnxJviSWRQJyzD/Fqw7fZ5Is5K/SCDfn0aC+y\nxilSWhHDnFNM0Hr7KX3rLap43QJpePAk4qnF3AX7AoGBAOe5C1VMKoTapnxvo/FI\nBCvXw05SSEExfXVR0ryoqUxgu1asCkYyJSoWxOZQ+33npQ1/zV1mCXn/lNZcyveW\nZ5/cUw71grW8KBYFrW7LeQIzjZb7xPI3Z4EV0uYd2b69GkQk1buHj/gsswRhGEvx\nJM1DN1SCenbGcVLprM0vVelp\n-----END PRIVATE KEY-----\n",
+ "client_email": "firebase-adminsdk-pgjve@twistter-e4649.iam.gserviceaccount.com",
+ "client_id": "102241295911303209723",
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
+ "token_uri": "https://oauth2.googleapis.com/token",
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
+ "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-pgjve%40twistter-e4649.iam.gserviceaccount.com"
+}
diff --git a/twistter-frontend/package-lock.json b/twistter-frontend/package-lock.json
index 5b4b20d..c14d5b6 100644
--- a/twistter-frontend/package-lock.json
+++ b/twistter-frontend/package-lock.json
@@ -61,6 +61,14 @@
}
}
},
+ "@material-ui/icons": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.5.1.tgz",
+ "integrity": "sha512-YZ/BgJbXX4a0gOuKWb30mBaHaoXRqPanlePam83JQPZ/y4kl+3aW0Wv9tlR70hB5EGAkEJGW5m4ktJwMgxQAeA==",
+ "requires": {
+ "@babel/runtime": "^7.4.4"
+ }
+ },
"@material-ui/styles": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.5.0.tgz",
@@ -9717,6 +9725,11 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
},
+ "typeface-roboto": {
+ "version": "0.0.75",
+ "resolved": "https://registry.npmjs.org/typeface-roboto/-/typeface-roboto-0.0.75.tgz",
+ "integrity": "sha512-VrR/IiH00Z1tFP4vDGfwZ1esNqTiDMchBEXYY9kilT6wRGgFoCAlgkEUMHb1E3mB0FsfZhv756IF0+R+SFPfdg=="
+ },
"uglify-js": {
"version": "3.4.10",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
diff --git a/twistter-frontend/package.json b/twistter-frontend/package.json
index f03c528..f7dd12f 100644
--- a/twistter-frontend/package.json
+++ b/twistter-frontend/package.json
@@ -4,6 +4,7 @@
"private": true,
"dependencies": {
"@material-ui/core": "^4.4.3",
+ "@material-ui/icons": "^4.5.1",
"@material-ui/styles": "^4.5.0",
"@material-ui/system": "^4.5.0",
"axios": "^0.19.0",
@@ -18,7 +19,8 @@
"react-router-dom": "^5.1.0",
"react-scripts": "0.9.5",
"redux": "^4.0.4",
- "redux-thunk": "^2.3.0"
+ "redux-thunk": "^2.3.0",
+ "typeface-roboto": "0.0.75"
},
"devDependencies": {},
"scripts": {
diff --git a/twistter-frontend/src/App.js b/twistter-frontend/src/App.js
index b767156..2335b20 100644
--- a/twistter-frontend/src/App.js
+++ b/twistter-frontend/src/App.js
@@ -19,6 +19,8 @@ import { logoutUser, getUserData } from './redux/actions/userActions';
// Components
import AuthRoute from "./util/AuthRoute";
+// axios.defaults.baseURL = 'http://localhost:5006/twistter-e4649/us-central1/api';
+
// Pages
import home from './pages/Home';
import signup from './pages/Signup';
@@ -34,14 +36,20 @@ const theme = createMuiTheme(themeObject);
const token = localStorage.FBIdToken;
if (token) {
- const decodedToken = jwtDecode(token);
- if (decodedToken.exp * 1000 < Date.now()) {
- store.dispatch(logoutUser);
+
+ try {
+ const decodedToken = jwtDecode(token);
+ if (decodedToken.exp * 1000 < Date.now()) {
+ store.dispatch(logoutUser());
+ window.location.href = "/login";
+ } else {
+ store.dispatch({ type: SET_AUTHENTICATED });
+ axios.defaults.headers.common['Authorization'] = token;
+ store.dispatch(getUserData());
+ }
+ } catch (invalidTokenError) {
+ store.dispatch(logoutUser());
window.location.href = "/login";
- } else {
- store.dispatch({ type: SET_AUTHENTICATED });
- axios.defaults.headers.common['Authorization'] = token;
- store.dispatch(getUserData());
}
}
diff --git a/twistter-frontend/src/Writing_Microblogs.js b/twistter-frontend/src/Writing_Microblogs.js
index b1570d8..6ddb974 100644
--- a/twistter-frontend/src/Writing_Microblogs.js
+++ b/twistter-frontend/src/Writing_Microblogs.js
@@ -36,7 +36,6 @@ class Writing_Microblogs extends Component {
// alert('A title for the microblog was inputted: ' + this.state.title + '\nA microblog was posted: ' + this.state.value);
const postData = {
body: this.state.value,
- userHandle: "new user",
userImage: "bing-url",
microBlogTitle: this.state.title,
microBlogTopics: this.state.topics.split(', ')
@@ -46,7 +45,7 @@ class Writing_Microblogs extends Component {
}
axios
- .post('/putPost', postData, headers)
+ .post("/putPost", postData, headers)
.then((res) =>{
alert('Post was shared successfully!')
console.log(res.data);
diff --git a/twistter-frontend/src/components/layout/NavBar.js b/twistter-frontend/src/components/layout/NavBar.js
index 5f8d28d..ceab08f 100644
--- a/twistter-frontend/src/components/layout/NavBar.js
+++ b/twistter-frontend/src/components/layout/NavBar.js
@@ -1,7 +1,7 @@
/* eslint-disable */
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
-// import PropTypes from 'prop-types';
+import PropTypes from 'prop-types';
// Material UI stuff
import AppBar from '@material-ui/core/AppBar';
@@ -11,26 +11,26 @@ import withStyles from "@material-ui/core/styles/withStyles";
// Redux stuff
// import { logoutUser } from '../../redux/actions/userActions';
-// import { connect } from 'react-redux';
+import { connect } from 'react-redux';
-// const styles = {
-// form: {
-// textAlign: "center"
-// },
-// textField: {
-// marginBottom: 30
-// },
-// pageTitle: {
-// marginBottom: 40
-// },
-// button: {
-// positon: "relative",
-// marginBottom: 30
-// },
-// progress: {
-// position: "absolute"
-// }
-// };
+const styles = {
+ form: {
+ textAlign: "center"
+ },
+ textField: {
+ marginBottom: 30
+ },
+ pageTitle: {
+ marginBottom: 40
+ },
+ button: {
+ positon: "relative",
+ marginBottom: 30
+ },
+ progress: {
+ position: "absolute"
+ }
+ };
@@ -38,42 +38,44 @@ import withStyles from "@material-ui/core/styles/withStyles";
export class Navbar extends Component {
render() {
+ const authenticated = this.props.user.authenticated;
return (
+
loading profile...
+ + return profileMarkup; + } +} + +const mapStateToProps = state => ({ + user: state.user, + classes: PropTypes.object.isRequired +}); + +export default connect(mapStateToProps)(withStyles(styles)(Profile)); diff --git a/twistter-frontend/src/components/profile/StaticProfile.js b/twistter-frontend/src/components/profile/StaticProfile.js deleted file mode 100644 index e69de29..0000000 diff --git a/twistter-frontend/src/images/original.png b/twistter-frontend/src/images/original.png new file mode 100644 index 0000000..c28e365 Binary files /dev/null and b/twistter-frontend/src/images/original.png differ diff --git a/twistter-frontend/src/images/twistter-logo.png b/twistter-frontend/src/images/twistter-logo.png index c28e365..1baf97c 100644 Binary files a/twistter-frontend/src/images/twistter-logo.png and b/twistter-frontend/src/images/twistter-logo.png differ diff --git a/twistter-frontend/src/pages/editProfile.js b/twistter-frontend/src/pages/editProfile.js index 3c3c51b..ff6f3f7 100644 --- a/twistter-frontend/src/pages/editProfile.js +++ b/twistter-frontend/src/pages/editProfile.js @@ -88,6 +88,14 @@ export class edit extends Component { handle: this.state.handle, bio: this.state.bio }; + + // Removes all keys from newProfileData that are empty, undefined, or null + Object.keys(newProfileData).forEach(key => { + if (newProfileData[key] === "" || newProfileData[key] === undefined || newProfileData[key] === null) { + delete newProfileData[key]; + } + }) + axios .post("/updateProfileInfo", newProfileData) .then((res) => { diff --git a/twistter-frontend/src/pages/user.js b/twistter-frontend/src/pages/user.js index f1113a0..27a0c94 100644 --- a/twistter-frontend/src/pages/user.js +++ b/twistter-frontend/src/pages/user.js @@ -1,49 +1,124 @@ /* eslint-disable */ import React, { Component } from 'react'; +import PropTypes from 'prop-types'; import axios from 'axios'; //import '../App.css'; import { makeStyles, styled } from '@material-ui/core/styles'; import Grid from '@material-ui/core/Grid'; import Card from '@material-ui/core/Card'; -import CardMedia from '@material-ui/core/CardMedia'; -import CardContent from '@material-ui/core/CardContent'; import Chip from '@material-ui/core/Chip'; -import Paper from '@material-ui/core/Paper'; +import Typography from "@material-ui/core/Typography"; +import AddCircle from '@material-ui/icons/AddCircle'; +import TextField from '@material-ui/core/TextField'; +// component +import Userline from '../Userline'; +import noImage from '../images/no-img.png'; -const PostCard = styled(Card)({ - background: 'linear-gradient(45deg, #1da1f2 90%)', - border: 3, - borderRadius: 3, - height:325, - width: 345, - padding: '0 30px', +const MyChip = styled(Chip)({ + margin: 2, + color: 'primary' }); - -class user extends Component { - componentDidMount(){ - //TODO: get user details - //TODO: get posts +class user extends Component { + state = { + profile: null, + imageUrl: null, + topics: null, + newTopic: null + }; + + handleDelete = (topic) => { + alert(`Delete topic: ${topic}!`); + } + + handleAddCircle = () => { + axios.post('/putTopic', { + topic: this.state.newTopic + }) + .then(function () { + location.reload(); + }) + .catch(function (err) { + console.log(err); + }); } + handleChange(event) { + this.setState({ + newTopic: event.target.value + }) + } + + componentDidMount() { + axios + .get("/user") + .then(res => { + this.setState({ + profile: res.data.credentials.handle, + imageUrl: res.data.credentials.imageUrl + }); + }) + .catch(err => console.log(err)); + axios + .get("/getAllTopics") + .then(res => { + this.setState({ + topics: res.data + }) + }) + .catch(err => console.log(err)); + } render() { + const classes = this.props; + let profileMarkup = this.state.profile ? ( +
+
loading username...
); + + + let topicsMarkup = this.state.topics ? ( + this.state.topics.map(topic =>loading topics...
); + + let imageMarkup = this.state.imageUrl ? ( +Post