diff --git a/functions/handlers/post.js b/functions/handlers/post.js index a57cfe1..af1b854 100644 --- a/functions/handlers/post.js +++ b/functions/handlers/post.js @@ -1,6 +1,8 @@ /* eslint-disable prefer-arrow-callback */ /* eslint-disable promise/always-return */ const admin = require('firebase-admin'); +const { db } = require('../util/admin'); + exports.putPost = (req, res) => { const newPost = { @@ -12,7 +14,8 @@ exports.putPost = (req, res) => { createdAt: new Date().toISOString(), likeCount: 0, commentCount: 0, - microBlogTopics: req.body.microBlogTopics + microBlogTopics: req.body.microBlogTopics, + quoteBody: null }; admin.firestore().collection('posts').add(newPost) @@ -30,6 +33,7 @@ exports.putPost = (req, res) => { exports.getallPostsforUser = (req, res) => { var post_query = admin.firestore().collection("posts").where("userHandle", "==", req.user.handle); + post_query.get() .then(function(myPosts) { let posts = []; @@ -39,11 +43,11 @@ exports.getallPostsforUser = (req, res) => { return res.status(200).json(posts); }) .then(function() { - res.status(200).send("Successfully retrieved all user's posts from database."); - return; + return res.status(200).json("Successfully retrieved all user's posts from database."); + }) .catch(function(err) { - res.status(500).send("Failed to retrieve user's posts from database.", err); + return res.status(500).json("Failed to retrieve user's posts from database.", err); }); }; @@ -58,14 +62,236 @@ exports.getallPosts = (req, res) => { return res.status(200).json(posts); }) .then(function() { - res.status(200).send("Successfully retrieved every post from database."); - return; + return res.status(200).json("Successfully retrieved every post from database."); }) .catch(function(err) { - res.status(500).send("Failed to retrieve posts from database.", err); + return res.status(500).json("Failed to retrieve posts from database.", err); }); }; +exports.quoteWithPost = (req, res) => { + + let quoteData; + const quoteDoc = admin.firestore().collection('quote'). + where('userHandle', '==', req.user.handle). + where('postId', '==', req.params.postId).limit(1); + + const postDoc = db.doc(`/posts/${req.params.postId}`); + + postDoc.get() + .then((doc) => { + if(doc.exists) { + quoteData = doc.data(); + return quoteDoc.get(); + } + else + { + return res.status(404).json({error: 'Post not found'}); + } + }) + .then((data) => { + if(data.empty) { + return admin.firestore().collection('quote').add({ + quoteId : req.params.postId, + userHandle : req.user.handle, + quoteBody : req.body.quoteBody + }) + .then(() => { + const post = { + body: quoteData.body, + userHandle : req.user.handle, + quoteBody: req.body.quoteBody, + createdAt : new Date().toISOString(), + userImage: req.body.userImage, + likeCount: 0, + commentCount: 0, + userID: req.user.uid, + microBlogTitle: quoteData.microBlogTitle, + microBlogTopics: quoteData.microBlogTopics, + quoteId: req.params.postId + } + return admin.firestore().collection('posts').add(post) + .then((doc) => { + doc.update({postId: doc.id}) + const resPost = post; + resPost.postId = doc.id; + return res.status(200).json(resPost); + }) + }) + } + else { + return res.status(400).json({ error: 'Post has already been quoted.' }); + } + }) + .catch((err) => { + return res.status(500).json({error: err}); + + }) + +} + +exports.quoteWithoutPost = (req, res) => { + let quoteData; + const quoteDoc = admin.firestore().collection('quote'). + where('userHandle', '==', req.user.handle). + where('postId', '==', req.params.postId).limit(1); + + const postDoc = db.doc(`/posts/${req.params.postId}`); + + postDoc.get() + .then((doc) => { + if(doc.exists) { + quoteData = doc.data(); + return quoteDoc.get(); + } + else + { + return res.status(404).json({error: 'Post not found'}); + } + }) + .then((data) => { + if(data.empty) { + return admin.firestore().collection('quote').add({ + quoteId : req.params.postId, + userHandle : req.user.handle, + quoteBody: null + }) + .then(() => { + const post = { + userHandle : req.user.handle, + body: quoteData.body, + quoteBody: null, + createdAt : new Date().toISOString(), + likeCount: 0, + commentCount: 0, + userID: req.user.uid, + userImage: req.body.userImage, + microBlogTitle: quoteData.microBlogTitle, + microBlogTopics: quoteData.microBlogTopics, + quoteId: req.params.postId + } + return admin.firestore().collection('posts').add(post) + .then((doc) => { + doc.update({postId: doc.id}) + const resPost = post; + resPost.postId = doc.id; + return res.status(200).json(resPost); + }) + + + + }) + } + else { + return res.status(400).json({ error: 'Post has already been quoted.' }); + } + }) + .catch((err) => { + return res.status(500).json({error: 'Something is wrong'}); + + }) + +} + +exports.checkforLikePost = (req, res) => { + const likedPostDoc = admin.firestore().collection('likes').where('userHandle', '==', req.user.handle) + .where('postId', '==', req.params.postId).limit(1); + let result; + + likedPostDoc.get() + .then((data) => { + if (data.empty) { + result = false; + return res.status(200).json(result); + } + else + { + result = true; + return res.status(200).json(result); + } + }) +} + +exports.likePost = (req, res) => { + let postData; + const likeDoc = admin.firestore().collection('likes').where('userHandle', '==', req.user.handle) + .where('postId', '==', req.params.postId).limit(1); + + const postDoc = db.doc(`/posts/${req.params.postId}`); + + postDoc.get() + .then((doc) => { + if(doc.exists) { + postData = doc.data(); + return likeDoc.get(); + } + else + { + return res.status(404).json({error: 'Post not found'}); + } + }) + .then((data) => { + if (data.empty) { + return admin.firestore().collection('likes').add({ + postId : req.params.postId, + userHandle: req.user.handle + + }) + .then(() => { + postData.likeCount++; + return postDoc.update({likeCount : postData.likeCount}) + }) + .then(() => { + return res.status(200).json(postData); + }) + } + }) + .catch((err) => { + return res.status(500).json({error: 'Something is wrong'}); + }) + +} + + +exports.unlikePost = (req, res) => { + + let postData; + const likeDoc = admin.firestore().collection('likes').where('userHandle', '==', req.user.handle) + .where('postId', '==', req.params.postId).limit(1); + + const postDoc = db.doc(`/posts/${req.params.postId}`); + + postDoc.get() + .then((doc) => { + if(doc.exists) { + postData = doc.data(); + return likeDoc.get(); + } + else + { + return res.status(404).json({error: 'Post not found'}); + } + }) + .then((data) => { + return db + .doc(`/likes/${data.docs[0].id}`) + .delete() + .then(() => { + postData.likeCount--; + return postDoc.update({ likeCount: postData.likeCount }); + }) + .then(() => { + res.status(200).json(postData); + }); + + }) + .catch((err) => { + console.error(err); + return res.status(500).json({error: 'Something is wrong'}); + }) + +} + exports.getFilteredPosts = (req, res) => { admin.firestore().collection('posts').where('userHandle', '==', 'new user').where('microBlogTopics', '==') }; diff --git a/functions/handlers/users.js b/functions/handlers/users.js index 283b97b..3430fff 100644 --- a/functions/handlers/users.js +++ b/functions/handlers/users.js @@ -331,6 +331,24 @@ exports.getUserDetails = (req, res) => { }); }; +exports.getAllHandles = (req, res) => { + var user_query = admin.firestore().collection("users"); + user_query.get() + .then((allUsers) => { + let users = []; + allUsers.forEach((user) => { + users.push(user.data().handle); + }); + return res.status(200).json(users); + }) + .catch((err) => { + return res.status(500).json({ + message:"Failed to retrieve posts from database.", + error: err + }); + }); +}; + exports.getAuthenticatedUser = (req, res) => { let credentials = {}; db.doc(`/users/${req.user.handle}`) @@ -449,7 +467,7 @@ exports.addSubscription = (req, res) => { .catch(err => { return res.status(500).json({ err }); }); - return res.status(500).json({ error: "shouldn't execute" }); + return res.status(200).json({ message: "ok" }); }); }; @@ -489,6 +507,6 @@ exports.removeSub = (req, res) => { .catch(err => { return res.status(500).json({ err }); }); - return res.status(500).json({ error: "shouldn't execute" }); + return res.status(200).json({ message: "ok" }); }); }; diff --git a/functions/index.js b/functions/index.js index 4626e47..eab8aa9 100644 --- a/functions/index.js +++ b/functions/index.js @@ -11,6 +11,7 @@ app.use(cors()); *------------------------------------------------------------------*/ const { getAuthenticatedUser, + getAllHandles, getUserDetails, getProfileInfo, login, @@ -39,6 +40,10 @@ app.delete("/delete", fbAuth, deleteUser); app.post("/getUserDetails", fbAuth, getUserDetails); +// Returns a list of all usernames +// Used for searching +app.get("/getAllHandles", fbAuth, getAllHandles); + // Returns all profile data of the currently logged in user app.get("/getProfileInfo", fbAuth, getProfileInfo); @@ -70,7 +75,7 @@ app.post("/removeSub", fbAuth, removeSub); /*------------------------------------------------------------------* * handlers/post.js * *------------------------------------------------------------------*/ -const { getallPostsforUser, getallPosts, putPost } = require("./handlers/post"); +const { getallPostsforUser, getallPosts, putPost, likePost, unlikePost, quoteWithPost, quoteWithoutPost, checkforLikePost} = require("./handlers/post"); app.get("/getallPostsforUser", fbAuth, getallPostsforUser); @@ -79,6 +84,15 @@ app.get("/getallPosts", getallPosts); // Adds one post to the database app.post("/putPost", fbAuth, putPost); +app.get("/like/:postId", fbAuth, likePost); +app.get("/unlike/:postId", fbAuth, unlikePost); +app.get("/checkforLikePost/:postId", fbAuth, checkforLikePost); + +app.post("/quoteWithPost/:postId", fbAuth, quoteWithPost); +app.post("/quoteWithoutPost/:postId", fbAuth, quoteWithoutPost); + + + /*------------------------------------------------------------------* * handlers/topic.js * *------------------------------------------------------------------*/ diff --git a/twistter-frontend/package.json b/twistter-frontend/package.json index f7dd12f..52e50f3 100644 --- a/twistter-frontend/package.json +++ b/twistter-frontend/package.json @@ -10,11 +10,13 @@ "axios": "^0.19.0", "clsx": "^1.0.4", "create-react-app": "^3.1.2", + "fuse.js": "^3.4.6", "install": "^0.13.0", "jwt-decode": "^2.2.0", "node-pre-gyp": "^0.13.0", "react": "^16.9.0", "react-dom": "^16.9.0", + "react-modal": "^3.11.1", "react-redux": "^7.1.1", "react-router-dom": "^5.1.0", "react-scripts": "0.9.5", @@ -41,5 +43,5 @@ "last 1 safari version" ] }, - "proxy": "https://us-central1-twistter-e4649.cloudfunctions.net/api" + "proxy": "http://localhost:5001/twistter-e4649/us-central1/api" } diff --git a/twistter-frontend/src/Writing_Microblogs.js b/twistter-frontend/src/Writing_Microblogs.js index 9cac7b7..2283e61 100644 --- a/twistter-frontend/src/Writing_Microblogs.js +++ b/twistter-frontend/src/Writing_Microblogs.js @@ -3,6 +3,27 @@ import { BrowserRouter as Router } from "react-router-dom"; import Route from "react-router-dom/Route"; import axios from "axios"; +// Material-UI +import TextField from '@material-ui/core/TextField'; +import Typography from '@material-ui/core/Typography'; +import Button from '@material-ui/core/Button'; +import withStyles from "@material-ui/styles/withStyles"; + +const styles = { + container: { + position: "fixed" + }, + form: { + width: "300px", + height: "50px", + marginTop: "180px", + marginLeft: "50px" + }, + textField: { + marginBottom: 15 + } +} + class Writing_Microblogs extends Component { constructor(props) { super(props); @@ -27,7 +48,7 @@ class Writing_Microblogs extends Component { this.setState({ topics: event.target.value }); } - handleSubmit(event) { + handleSubmit = (event) => { // alert('A title for the microblog was inputted: ' + this.state.title + '\nA microblog was posted: ' + this.state.value); const postData = { body: this.state.value, @@ -40,20 +61,34 @@ class Writing_Microblogs extends Component { }; axios - .post("/putPost", postData, headers) + .post("/putPost", postData, headers) // TODO: add topics .then(res => { - alert("Post was shared successfully!"); + // alert("Post was shared successfully!"); console.log(res.data); }) .catch(err => { alert("An error occured."); console.error(err); }); + console.log(postData.microBlogTopics); + postData.microBlogTopics.forEach(topic => { + axios + .post("/putTopic", { + following: topic + }) + .then(res => { + console.log(res.data); + }) + .catch(err => { + console.error(err); + }); + }); event.preventDefault(); this.setState({ value: "", title: "", characterCount: 250, topics: "" }); } handleChangeforPost(event) { + this.setState({ value: event.target.value }); } @@ -64,65 +99,68 @@ class Writing_Microblogs extends Component { } render() { + const { classes } = this.props; return ( -
-
-
-