diff --git a/functions/handlers/post.js b/functions/handlers/post.js index c14c61c..1db0144 100644 --- a/functions/handlers/post.js +++ b/functions/handlers/post.js @@ -4,9 +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, + userID: req.userData.userId, microBlogTitle: req.body.microBlogTitle, createdAt: new Date().toISOString(), likeCount: 0, @@ -28,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 index bac0322..4d3dc3d 100644 --- a/functions/handlers/topic.js +++ b/functions/handlers/topic.js @@ -1,5 +1,5 @@ /* eslint-disable promise/always-return */ -const admin = require('firebase-admin'); +const { admin, db } = require("../util/admin"); exports.putTopic = (req, res) => { const newTopic = { @@ -9,6 +9,7 @@ exports.putTopic = (req, res) => { admin.firestore().collection('topics').add(newTopic) .then((doc) => { const resTopic = newTopic; + newTopic.topicId = doc.id; return res.status(200).json(resTopic); }) .catch((err) => { @@ -17,8 +18,6 @@ exports.putTopic = (req, res) => { }); }; - - exports.getAllTopics = (req, res) => { admin.firestore().collection('topics').get() .then((data) => { @@ -30,6 +29,24 @@ exports.getAllTopics = (req, res) => { }) .catch((err) => { console.error(err); - return res.status(500).json({error: 'Failed to fetch all posts written by specific user.'}) + return res.status(500).json({error: 'Failed to fetch all topics.'}) }) -}; \ No newline at end of file +}; + +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 71c8783..d8429db 100644 --- a/functions/handlers/users.js +++ b/functions/handlers/users.js @@ -80,7 +80,8 @@ exports.signup = (req, res) => { handle: newUser.handle, createdAt: newUser.createdAt, imageUrl: `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${noImg}?alt=media`, - userId + userId, + followedTopics: [] }; handle2Email.set(userCred.handle, userCred.email); return db.doc(`/users/${newUser.handle}`).set(userCred); diff --git a/functions/index.js b/functions/index.js index 47dda28..155363c 100644 --- a/functions/index.js +++ b/functions/index.js @@ -61,7 +61,10 @@ app.post("/putPost", fbAuth, putPost); /*------------------------------------------------------------------* * handlers/topic.js * *------------------------------------------------------------------*/ -const { putTopic, getAllTopics +const { + putTopic, + getAllTopics, + deleteTopic } = require("./handlers/topic"); // add topic to database @@ -70,4 +73,7 @@ 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 492ff05..04a805c 100644 --- a/functions/package.json +++ b/functions/package.json @@ -17,7 +17,8 @@ "busboy": "^0.3.1", "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/twistter-frontend/src/App.js b/twistter-frontend/src/App.js index bec4ac6..2335b20 100644 --- a/twistter-frontend/src/App.js +++ b/twistter-frontend/src/App.js @@ -36,6 +36,7 @@ const theme = createMuiTheme(themeObject); const token = localStorage.FBIdToken; if (token) { + try { const decodedToken = jwtDecode(token); if (decodedToken.exp * 1000 < Date.now()) { 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/pages/user.js b/twistter-frontend/src/pages/user.js index 435c92c..27a0c94 100644 --- a/twistter-frontend/src/pages/user.js +++ b/twistter-frontend/src/pages/user.js @@ -6,66 +6,63 @@ import axios from 'axios'; 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 Profile from '../components/profile/Profile'; 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' }); - -const styles = (theme) => ({ - ...theme -}); - -const handleDelete = () => { - alert("Delete this topic!"); -} - -const handleAddCircle = () => { - alert("Add topic"); -} - class user extends Component { state = { profile: null, - topics: 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 => { - console.log(res.data.credentials.handle); this.setState({ - profile: res.data.credentials.handle + profile: res.data.credentials.handle, + imageUrl: res.data.credentials.imageUrl }); }) .catch(err => console.log(err)); axios .get("/getAllTopics") .then(res => { - console.log(res.data[1]); this.setState({ topics: res.data }) @@ -83,22 +80,40 @@ class user extends Component { let topicsMarkup = this.state.topics ? ( this.state.topics.map(topic => ) + key={{topic}.topic.topicId} + onDelete={ (topic) => this.handleDelete(topic)}/>) ) : (

loading topics...

); + let imageMarkup = this.state.imageUrl ? ( + + ) : (); + return (

Post

- + {imageMarkup} {profileMarkup} {topicsMarkup} - } + this.handleChange(event)} + /> +
@@ -106,12 +121,4 @@ class user extends Component { } } -Userline.PropTypes = { - handle: PropTypes.object.isRequired -}; - -const mapStateToProps = (state) => ({ - user: state.user -}); - export default user;