mirror of
https://github.com/ClaytonWWilson/CS307-Team24.git
synced 2026-03-10 21:25:04 +00:00
Compare commits
77 Commits
write_micr
...
remotes/or
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf0c4c78ee | ||
|
|
51fb554133 | ||
|
|
b1f5ddaa49 | ||
| 8f949f14be | |||
|
|
e110bdd47a | ||
|
|
b7f0eba7a9 | ||
| 878bb28a71 | |||
| 88310714b2 | |||
| c218081759 | |||
|
|
16973fb340 | ||
|
|
9d4f175a49 | ||
|
|
f627b91543 | ||
|
|
ec6e41d16f | ||
|
|
2e157b9088 | ||
|
|
89e8942624 | ||
|
|
b9909c1616 | ||
|
|
fadb0f0399 | ||
|
|
931929061f | ||
|
|
8eb0872d16 | ||
| 07e9271132 | |||
| 724adc9b0b | |||
| b711521b4b | |||
| 967e66313b | |||
| 76caf4de12 | |||
| eb945fa0cf | |||
| c5bec46b52 | |||
| cc98fa7884 | |||
|
|
101d9918e5 | ||
| 5116a705bc | |||
|
|
311e8b3716 | ||
|
|
754c2f2d75 | ||
|
|
13b57eedc6 | ||
|
|
60d1d76839 | ||
|
|
e273b1474b | ||
|
|
022f440cb9 | ||
| 721aeeb350 | |||
|
|
4517bc6756 | ||
|
|
201f5d8949 | ||
| 696b00e304 | |||
|
|
b1cfcda948 | ||
|
|
7969d3b10b | ||
|
|
d298843268 | ||
|
|
55dc62e57e | ||
| d255a301a3 | |||
| 0f127521ca | |||
| 90442fe3cd | |||
| 2dc89b99b6 | |||
| 5176f0250c | |||
| 929216c05e | |||
| dc498a3a1d | |||
| f4ef1ee8e1 | |||
| ce8ee36354 | |||
| 13fcd9b3ab | |||
|
|
7f2d6a3a1e | ||
| d05f87c7a7 | |||
|
|
b1faacd312 | ||
| 15f976398a | |||
| 262e59df65 | |||
|
|
cbf9b94248 | ||
|
|
6cb3441ad7 | ||
|
|
015f1c1e9f | ||
|
|
2d00090988 | ||
|
|
cc1ce1bfc9 | ||
|
|
1306c1654a | ||
|
|
5caea0871e | ||
| 5642b685bc | |||
|
|
8a5b115666 | ||
|
|
e961379e3f | ||
|
|
d703843277 | ||
|
|
70037a5342 | ||
|
|
8fa03700b1 | ||
|
|
a930353d79 | ||
|
|
e2883a04c5 | ||
|
|
6f94623d0c | ||
|
|
bcdd452aa8 | ||
|
|
4fbacaf822 | ||
|
|
709af8007d |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -63,3 +63,6 @@ node_modules/
|
|||||||
|
|
||||||
# dotenv environment variables file
|
# dotenv environment variables file
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
# The keyfile for google services authentication
|
||||||
|
twistter-e4649-firebase-adminsdk-pgjve-1e57494429.json
|
||||||
@@ -1,29 +1,30 @@
|
|||||||
{
|
{
|
||||||
"database": {
|
"database": {
|
||||||
"rules": "database.rules.json"
|
"rules": "database.rules.json"
|
||||||
},
|
},
|
||||||
"firestore": {
|
"firestore": {
|
||||||
"rules": "firestore.rules",
|
"rules": "firestore.rules",
|
||||||
"indexes": "firestore.indexes.json"
|
"indexes": "firestore.indexes.json"
|
||||||
},
|
},
|
||||||
"functions": {
|
"functions": {
|
||||||
"predeploy": [
|
"predeploy": [
|
||||||
"npm --prefix \"$RESOURCE_DIR\" run lint"
|
"npm --prefix \"$RESOURCE_DIR\" run lint"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"hosting": {
|
"hosting": {
|
||||||
"public": "public",
|
"public": "public",
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"firebase.json",
|
"firebase.json",
|
||||||
"**/.*",
|
"**/.*",
|
||||||
"**/node_modules/**"
|
"**/node_modules/**"
|
||||||
],
|
],
|
||||||
"rewrites": [{
|
"rewrites": [{
|
||||||
"source": "/feed",
|
"source": "/feed",
|
||||||
"destination": "/feed.html"
|
"destination": "/feed.html"
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
"storage": {
|
"storage": {
|
||||||
"rules": "storage.rules"
|
"rules": "storage.rules"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
60
functions/handlers/post.js
Normal file
60
functions/handlers/post.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/* eslint-disable promise/always-return */
|
||||||
|
const admin = require('firebase-admin');
|
||||||
|
exports.putPost = (req, res) => {
|
||||||
|
|
||||||
|
const newPost = {
|
||||||
|
body: req.body.body,
|
||||||
|
userHandle: req.body.userHandle,
|
||||||
|
userImage: req.body.userImage,
|
||||||
|
microBlogTitle: req.body.microBlogTitle,
|
||||||
|
createdAt: new Date().toISOString(),
|
||||||
|
likeCount: 0,
|
||||||
|
commentCount: 0,
|
||||||
|
microBlogTopics: req.body.microBlogTopics
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
admin.firestore().collection('posts').add(newPost)
|
||||||
|
.then((doc) => {
|
||||||
|
const resPost = newPost;
|
||||||
|
resPost.postId = doc.id;
|
||||||
|
return res.status(200).json(resPost);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
return res.status(500).json({ error: 'something is wrong'});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getallPostsforUser = (req, res) => {
|
||||||
|
|
||||||
|
admin.firestore().collection('posts').where('userHandle', '==', 'new 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.'})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.getallPostsrelatedtoTopics = (req, res) => {
|
||||||
|
admin.firestore().collection('posts').where('microBlogTopics', '==', 'Joker').get()
|
||||||
|
.then((data) => {
|
||||||
|
let posts = [];
|
||||||
|
data.forEach(function(doc) {
|
||||||
|
posts.push(doc.data());
|
||||||
|
});
|
||||||
|
return res.status(200).json(posts);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.err(err);
|
||||||
|
return res.status(500).json({error: 'Failed to fetch all posts with a specific Topic.'})
|
||||||
|
}
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
216
functions/handlers/users.js
Normal file
216
functions/handlers/users.js
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
/* 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()
|
||||||
|
};
|
||||||
|
|
||||||
|
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.";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking if any errors have been raised
|
||||||
|
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 });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns all data in the database for the user who is currently signed in
|
||||||
|
exports.getProfileInfo = (req, res) => {
|
||||||
|
db.collection("users")
|
||||||
|
.doc(req.user.handle)
|
||||||
|
.get()
|
||||||
|
.then((data) => {
|
||||||
|
return res.status(200).json(data.data());
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
return res.status(500).json(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Updates the data in the database of the user who is currently logged in
|
||||||
|
exports.updateProfileInfo = (req, res) => {
|
||||||
|
// TODO: Add functionality for adding/updating profile images
|
||||||
|
|
||||||
|
// Data validation
|
||||||
|
const { valid, errors, profileData } = validateUpdateProfileInfo(req.body);
|
||||||
|
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"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.getUserDetails = (req, res) => {
|
||||||
|
let userData = {};
|
||||||
|
db.doc(`/users/${req.params.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 });
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,43 +1,47 @@
|
|||||||
/* eslint-disable promise/always-return */
|
/* eslint-disable promise/always-return */
|
||||||
const functions = require('firebase-functions');
|
const app = require("express")();
|
||||||
const admin = require('firebase-admin');
|
const cors = require("cors");
|
||||||
const app = require('express')();
|
const { db } = require("./util/admin");
|
||||||
admin.initializeApp();
|
const fbAuth = require("./util/fbAuth");
|
||||||
|
const functions = require("firebase-functions");
|
||||||
|
app.use(cors());
|
||||||
|
|
||||||
const firebaseConfig = {
|
/*------------------------------------------------------------------*
|
||||||
apiKey: "AIzaSyCvsWetg4qFdsPGfJ3LCw_QaaYzoan7Q34",
|
* handlers/users.js *
|
||||||
authDomain: "twistter-e4649.firebaseapp.com",
|
*------------------------------------------------------------------*/
|
||||||
databaseURL: "https://twistter-e4649.firebaseio.com",
|
const {
|
||||||
projectId: "twistter-e4649",
|
getUserDetails,
|
||||||
storageBucket: "twistter-e4649.appspot.com",
|
getProfileInfo,
|
||||||
messagingSenderId: "20131817365",
|
login,
|
||||||
appId: "1:20131817365:web:633c95fb08b16d4526b89c"
|
signup,
|
||||||
};
|
updateProfileInfo
|
||||||
const firebase = require('firebase');
|
} = require("./handlers/users");
|
||||||
firebase.initializeApp(firebaseConfig);
|
|
||||||
|
|
||||||
app.get('/getUsers', (req, res) => {
|
// Adds a user to the database and registers them in firebase with
|
||||||
admin.firestore().collection('users').get().then(data => {
|
// an email and password pair
|
||||||
let users = [];
|
// Returns a token for the new user
|
||||||
data.forEach(doc => {
|
app.post("/signup", signup);
|
||||||
users.push(doc.data());
|
|
||||||
}); return res.json(users);
|
// Returns a token for the user that matches the provided username
|
||||||
}).catch((err) => console.error(err));
|
// and password
|
||||||
});
|
app.post("/login", login);
|
||||||
|
|
||||||
|
app.get("/getUser/:handle", getUserDetails);
|
||||||
|
|
||||||
|
// Returns all profile data of the currently logged in user
|
||||||
|
app.get("/getProfileInfo", fbAuth, getProfileInfo);
|
||||||
|
|
||||||
|
// Updates the currently logged in user's profile information
|
||||||
|
app.post("/updateProfileInfo", fbAuth, updateProfileInfo);
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------*
|
||||||
|
* handlers/post.js *
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
const { getallPostsforUser, putPost } = require("./handlers/post");
|
||||||
|
|
||||||
|
app.get("/getallPostsforUser", getallPostsforUser);
|
||||||
|
|
||||||
|
// Adds one post to the database
|
||||||
|
app.post("/putPost", fbAuth, putPost);
|
||||||
|
|
||||||
app.post('/postUser', (req, res) => {
|
|
||||||
const newUser = {
|
|
||||||
body: req.body.body
|
|
||||||
};
|
|
||||||
admin.firestore().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);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
exports.api = functions.https.onRequest(app);
|
exports.api = functions.https.onRequest(app);
|
||||||
393
functions/package-lock.json
generated
393
functions/package-lock.json
generated
@@ -24,16 +24,31 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/app": {
|
"@firebase/app": {
|
||||||
"version": "0.4.16",
|
"version": "0.4.17",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.4.16.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.4.17.tgz",
|
||||||
"integrity": "sha512-4aa6ixQlV6xQxj4HbwFKrfYZnnKk8AtB/vEEuIaBCGQYBvV287OVNCozXd4CC4Q4I4Vtkzrc+kggahYFl8nDWQ==",
|
"integrity": "sha512-YkCe10/KHnfJ5Lx79SCQ4ZJRlpnwe8Yns6Ntf7kltXq1hCQCUrKEU3zaOTPY90SBx36hYm47IaqkKwT/kBOK3A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/app-types": "0.4.3",
|
"@firebase/app-types": "0.4.3",
|
||||||
"@firebase/logger": "0.1.24",
|
"@firebase/logger": "0.1.25",
|
||||||
"@firebase/util": "0.2.27",
|
"@firebase/util": "0.2.28",
|
||||||
"dom-storage": "2.1.0",
|
"dom-storage": "2.1.0",
|
||||||
"tslib": "1.10.0",
|
"tslib": "1.10.0",
|
||||||
"xmlhttprequest": "1.8.0"
|
"xmlhttprequest": "1.8.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@firebase/logger": {
|
||||||
|
"version": "0.1.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.25.tgz",
|
||||||
|
"integrity": "sha512-/lRhuepVcCCnQ2jcO5Hr08SYdmZDTQU9fdPdzg+qXJ9k/QnIrD2RbswXQcL6mmae3uPpX7fFXQAoScJ9pzp50w=="
|
||||||
|
},
|
||||||
|
"@firebase/util": {
|
||||||
|
"version": "0.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||||
|
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "1.10.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/app-types": {
|
"@firebase/app-types": {
|
||||||
@@ -55,15 +70,30 @@
|
|||||||
"integrity": "sha512-foQHhvyB0RR+mb/+wmHXd/VOU+D8fruFEW1k79Q9wzyTPpovMBa1Mcns5fwEWBhUfi8bmoEtaGB8RSAHnTFzTg=="
|
"integrity": "sha512-foQHhvyB0RR+mb/+wmHXd/VOU+D8fruFEW1k79Q9wzyTPpovMBa1Mcns5fwEWBhUfi8bmoEtaGB8RSAHnTFzTg=="
|
||||||
},
|
},
|
||||||
"@firebase/database": {
|
"@firebase/database": {
|
||||||
"version": "0.5.2",
|
"version": "0.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.4.tgz",
|
||||||
"integrity": "sha512-LnXKRE1AmjlS+iRF7j8vx+Ni8x85CmLP5u5Pw5rDKhKLn2eTR1tJKD937mUeeGEtDHwR1rrrkLYOqRR2cSG3hQ==",
|
"integrity": "sha512-Hz1Bi3fzIcNNocE4EhvvwoEQGurG2BGssWD3/6a2bzty+K1e57SLea2Ied8QYNBUU1zt/4McHfa3Y71EQIyn/w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/database-types": "0.4.3",
|
"@firebase/database-types": "0.4.3",
|
||||||
"@firebase/logger": "0.1.24",
|
"@firebase/logger": "0.1.25",
|
||||||
"@firebase/util": "0.2.27",
|
"@firebase/util": "0.2.28",
|
||||||
"faye-websocket": "0.11.3",
|
"faye-websocket": "0.11.3",
|
||||||
"tslib": "1.10.0"
|
"tslib": "1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@firebase/logger": {
|
||||||
|
"version": "0.1.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.25.tgz",
|
||||||
|
"integrity": "sha512-/lRhuepVcCCnQ2jcO5Hr08SYdmZDTQU9fdPdzg+qXJ9k/QnIrD2RbswXQcL6mmae3uPpX7fFXQAoScJ9pzp50w=="
|
||||||
|
},
|
||||||
|
"@firebase/util": {
|
||||||
|
"version": "0.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||||
|
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "1.10.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/database-types": {
|
"@firebase/database-types": {
|
||||||
@@ -75,17 +105,32 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/firestore": {
|
"@firebase/firestore": {
|
||||||
"version": "1.5.2",
|
"version": "1.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-1.5.3.tgz",
|
||||||
"integrity": "sha512-CPYLvkGZBKE47oQC9a0q13UMVRj3LvnSbB1nOerktE3CGRHKy44LxDumamN8Kj067hV/80mKK9FdbeUufwO/Rg==",
|
"integrity": "sha512-O/yAbXpitOA6g627cUl0/FHYlkTy1EiEKMKOlnlMOJF2fH+nLVZREXjsrCC7N2tIvTn7yYwfpZ4zpSNvrhwiTA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/firestore-types": "1.5.0",
|
"@firebase/firestore-types": "1.5.0",
|
||||||
"@firebase/logger": "0.1.24",
|
"@firebase/logger": "0.1.25",
|
||||||
"@firebase/util": "0.2.27",
|
"@firebase/util": "0.2.28",
|
||||||
"@firebase/webchannel-wrapper": "0.2.26",
|
"@firebase/webchannel-wrapper": "0.2.26",
|
||||||
"@grpc/proto-loader": "^0.5.0",
|
"@grpc/proto-loader": "^0.5.0",
|
||||||
"grpc": "1.23.3",
|
"grpc": "1.23.3",
|
||||||
"tslib": "1.10.0"
|
"tslib": "1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@firebase/logger": {
|
||||||
|
"version": "0.1.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.25.tgz",
|
||||||
|
"integrity": "sha512-/lRhuepVcCCnQ2jcO5Hr08SYdmZDTQU9fdPdzg+qXJ9k/QnIrD2RbswXQcL6mmae3uPpX7fFXQAoScJ9pzp50w=="
|
||||||
|
},
|
||||||
|
"@firebase/util": {
|
||||||
|
"version": "0.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||||
|
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "1.10.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/firestore-types": {
|
"@firebase/firestore-types": {
|
||||||
@@ -94,9 +139,9 @@
|
|||||||
"integrity": "sha512-VhRHNbEbak+R2iK8e1ir2Lec7eaHMZpGTRy6LMtzATYthlkwNHF9tO8JU8l6d1/kYkI4+DWzX++i3HhTziHEWA=="
|
"integrity": "sha512-VhRHNbEbak+R2iK8e1ir2Lec7eaHMZpGTRy6LMtzATYthlkwNHF9tO8JU8l6d1/kYkI4+DWzX++i3HhTziHEWA=="
|
||||||
},
|
},
|
||||||
"@firebase/functions": {
|
"@firebase/functions": {
|
||||||
"version": "0.4.17",
|
"version": "0.4.18",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.17.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/functions/-/functions-0.4.18.tgz",
|
||||||
"integrity": "sha512-heWMXrR3hgvQNe1JEZMUeY7a0QFLMVwVS+lzLq/lzk06bj22X9bJy7Yct+/P9P1ftnsCGLrhk3jAEuL78seoqg==",
|
"integrity": "sha512-N/ijwpxJy26kOErYIi5QS8pQgMZEuEMF/zDaNmgqcoN3J8P52NhBnVQZnIl+U4W96nQfNiURhSwXEERHFyvSZQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/functions-types": "0.3.8",
|
"@firebase/functions-types": "0.3.8",
|
||||||
"@firebase/messaging-types": "0.3.2",
|
"@firebase/messaging-types": "0.3.2",
|
||||||
@@ -110,14 +155,24 @@
|
|||||||
"integrity": "sha512-9hajHxA4UWVCGFmoL8PBYHpamE3JTNjObieMmnvZw3cMRTP2EwipMpzZi+GPbMlA/9swF9yHCY/XFAEkwbvdgQ=="
|
"integrity": "sha512-9hajHxA4UWVCGFmoL8PBYHpamE3JTNjObieMmnvZw3cMRTP2EwipMpzZi+GPbMlA/9swF9yHCY/XFAEkwbvdgQ=="
|
||||||
},
|
},
|
||||||
"@firebase/installations": {
|
"@firebase/installations": {
|
||||||
"version": "0.2.6",
|
"version": "0.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/installations/-/installations-0.2.7.tgz",
|
||||||
"integrity": "sha512-hkuKmBtnsmqIfWxt9KyaN+cP574pfTcB81IG5tnmVcgP1xQ4hyQ9LRP0M7jDTGWMw272TInBzUuaM05xw9GMnA==",
|
"integrity": "sha512-67tzowHVwRBtEuB1HLMD+fCdoRyinOQlMKBes7UwrtZIVd0CPDUqAKxNqup5EypWZb7O2tqFtRzK7POajfSNMA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/installations-types": "0.1.2",
|
"@firebase/installations-types": "0.1.2",
|
||||||
"@firebase/util": "0.2.27",
|
"@firebase/util": "0.2.28",
|
||||||
"idb": "3.0.2",
|
"idb": "3.0.2",
|
||||||
"tslib": "1.10.0"
|
"tslib": "1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@firebase/util": {
|
||||||
|
"version": "0.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||||
|
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "1.10.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/installations-types": {
|
"@firebase/installations-types": {
|
||||||
@@ -125,19 +180,24 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/installations-types/-/installations-types-0.1.2.tgz",
|
||||||
"integrity": "sha512-fQaWIW8hyX1XUN7+FCSPjvM1agFjGidVuF4Sxi7aFwfyh5t+4fD2VpM4wCQbWmodnx4fZLvsuQd9mkxxU+lGYQ=="
|
"integrity": "sha512-fQaWIW8hyX1XUN7+FCSPjvM1agFjGidVuF4Sxi7aFwfyh5t+4fD2VpM4wCQbWmodnx4fZLvsuQd9mkxxU+lGYQ=="
|
||||||
},
|
},
|
||||||
"@firebase/logger": {
|
|
||||||
"version": "0.1.24",
|
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.24.tgz",
|
|
||||||
"integrity": "sha512-wPwhWCepEjWiTIqeC9U+7Hcw4XwezKPdXmyXbYSPiWNDcVekNgMPkntwSK+/2ufJO/1nMwAL2n6fL12oQG/PpQ=="
|
|
||||||
},
|
|
||||||
"@firebase/messaging": {
|
"@firebase/messaging": {
|
||||||
"version": "0.4.10",
|
"version": "0.4.11",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.4.10.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/messaging/-/messaging-0.4.11.tgz",
|
||||||
"integrity": "sha512-WqtSqlulV2ix4MZ3r1HwGAEj0DiEWtpNCSPh5wOXZsj8Kd01Q2QPTLUtUWmwXSV9WCQWnowfE2x8wjq5388ixw==",
|
"integrity": "sha512-KYt479yio6ThkV7Pb9LRB1KPIBio+OR4RozwyoLC1ZSVQdTIrd/sVEuDSzYY88Wh/6Kg6ejdu2z6mfWG9l1ZaQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/messaging-types": "0.3.2",
|
"@firebase/messaging-types": "0.3.2",
|
||||||
"@firebase/util": "0.2.27",
|
"@firebase/util": "0.2.28",
|
||||||
"tslib": "1.10.0"
|
"tslib": "1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@firebase/util": {
|
||||||
|
"version": "0.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||||
|
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "1.10.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/messaging-types": {
|
"@firebase/messaging-types": {
|
||||||
@@ -146,15 +206,30 @@
|
|||||||
"integrity": "sha512-2qa2qNKqpalmtwaUV3+wQqfCm5myP/dViIBv+pXF8HinemIfO1IPQtr9pCNfsSYyus78qEhtfldnPWXxUH5v0w=="
|
"integrity": "sha512-2qa2qNKqpalmtwaUV3+wQqfCm5myP/dViIBv+pXF8HinemIfO1IPQtr9pCNfsSYyus78qEhtfldnPWXxUH5v0w=="
|
||||||
},
|
},
|
||||||
"@firebase/performance": {
|
"@firebase/performance": {
|
||||||
"version": "0.2.18",
|
"version": "0.2.19",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.2.18.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/performance/-/performance-0.2.19.tgz",
|
||||||
"integrity": "sha512-PcN+nTPaMGqODfwAXgwbaCvcxXH+YzvK6UpZzm0Bl9wmW28/oJipnUxF3cYbVGCiaLAaByIPVSIF22XhTOjUtA==",
|
"integrity": "sha512-dINWwR/XcSiSnFNNX7QWfec8bymiXk1Zp6mPyPN+R9ONMrpDbygQUy06oT/6r/xx9nHG4Za6KMUJag3sWNKqnQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/installations": "0.2.6",
|
"@firebase/installations": "0.2.7",
|
||||||
"@firebase/logger": "0.1.24",
|
"@firebase/logger": "0.1.25",
|
||||||
"@firebase/performance-types": "0.0.3",
|
"@firebase/performance-types": "0.0.3",
|
||||||
"@firebase/util": "0.2.27",
|
"@firebase/util": "0.2.28",
|
||||||
"tslib": "1.10.0"
|
"tslib": "1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@firebase/logger": {
|
||||||
|
"version": "0.1.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.25.tgz",
|
||||||
|
"integrity": "sha512-/lRhuepVcCCnQ2jcO5Hr08SYdmZDTQU9fdPdzg+qXJ9k/QnIrD2RbswXQcL6mmae3uPpX7fFXQAoScJ9pzp50w=="
|
||||||
|
},
|
||||||
|
"@firebase/util": {
|
||||||
|
"version": "0.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||||
|
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "1.10.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/performance-types": {
|
"@firebase/performance-types": {
|
||||||
@@ -163,9 +238,9 @@
|
|||||||
"integrity": "sha512-RuC63nYJPJU65AsrNMc3fTRcRgHiyNcQLh9ufeKUT1mEsFgpxr167gMb+tpzNU4jsbvM6+c6nQAFdHpqcGkRlQ=="
|
"integrity": "sha512-RuC63nYJPJU65AsrNMc3fTRcRgHiyNcQLh9ufeKUT1mEsFgpxr167gMb+tpzNU4jsbvM6+c6nQAFdHpqcGkRlQ=="
|
||||||
},
|
},
|
||||||
"@firebase/polyfill": {
|
"@firebase/polyfill": {
|
||||||
"version": "0.3.21",
|
"version": "0.3.22",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/polyfill/-/polyfill-0.3.21.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/polyfill/-/polyfill-0.3.22.tgz",
|
||||||
"integrity": "sha512-2mqS3FQHMhCGyfMGRsaZEypHSBD8hVmp9ZBnZSkn8hq5sSOLiNTFSC0FsvNu5z99GNsPQJFTui8bxcZl5cHQbw==",
|
"integrity": "sha512-PYbEqDHJhJJoF2Q5IB/oP0Tz6O2vSUPtODy9kUQibi+T0bK1gkTaySPwz8GAgHfIpFNENj1kK+7Xpf87R8bYbw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-js": "3.2.1",
|
"core-js": "3.2.1",
|
||||||
"promise-polyfill": "8.1.3",
|
"promise-polyfill": "8.1.3",
|
||||||
@@ -180,13 +255,23 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/storage": {
|
"@firebase/storage": {
|
||||||
"version": "0.3.11",
|
"version": "0.3.12",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.3.11.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.3.12.tgz",
|
||||||
"integrity": "sha512-Q2ffXE+X62gFy5mZkg7qhzAC7+kqaNZWpgS+297h/hWr/cFBDyC8eBPmnI509eKi2okixmOMbWnNluZkNYNSfw==",
|
"integrity": "sha512-8hXt3qPZlVH+yPF4W9Dc15/gBiTPGUJUgYs3dH9WnO41QWl1o4aNlZpZK/pdnpCIO1GmN0+PxJW9TCNb0H0Hqw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/storage-types": "0.3.3",
|
"@firebase/storage-types": "0.3.3",
|
||||||
"@firebase/util": "0.2.27",
|
"@firebase/util": "0.2.28",
|
||||||
"tslib": "1.10.0"
|
"tslib": "1.10.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@firebase/util": {
|
||||||
|
"version": "0.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||||
|
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "1.10.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@firebase/storage-types": {
|
"@firebase/storage-types": {
|
||||||
@@ -194,23 +279,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.3.3.tgz",
|
||||||
"integrity": "sha512-fUp4kpbxwDiWs/aIBJqBvXgFHZvgoND2JA0gJYSEsXtWtVwfgzY/710plErgZDeQKopX5eOR1sHskZkQUy0U6w=="
|
"integrity": "sha512-fUp4kpbxwDiWs/aIBJqBvXgFHZvgoND2JA0gJYSEsXtWtVwfgzY/710plErgZDeQKopX5eOR1sHskZkQUy0U6w=="
|
||||||
},
|
},
|
||||||
"@firebase/util": {
|
|
||||||
"version": "0.2.27",
|
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.27.tgz",
|
|
||||||
"integrity": "sha512-kFlbWNX1OuLfHrDXZ5QLmNNiLtMyxzbBgMo1DY1tXMjKK1AMYsHnyjInA8esvO0SCDp5XN3Pt9EDlhY4sRiLsw==",
|
|
||||||
"requires": {
|
|
||||||
"tslib": "1.10.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"@firebase/webchannel-wrapper": {
|
"@firebase/webchannel-wrapper": {
|
||||||
"version": "0.2.26",
|
"version": "0.2.26",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.26.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.2.26.tgz",
|
||||||
"integrity": "sha512-VlTurkvs4v7EVFWESBZGOPghFEokQhU5au5CP9WqA8B2/PcQRDsaaQlQCA6VATuEnW+vtSiSBvTiOc4004f8xg=="
|
"integrity": "sha512-VlTurkvs4v7EVFWESBZGOPghFEokQhU5au5CP9WqA8B2/PcQRDsaaQlQCA6VATuEnW+vtSiSBvTiOc4004f8xg=="
|
||||||
},
|
},
|
||||||
"@google-cloud/common": {
|
"@google-cloud/common": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-2.2.2.tgz",
|
||||||
"integrity": "sha512-ArSNbbuMOWVhrSasxECEYRcjMzkPgTfXJHQE5gccyDaoBv0oKqG9S2lse2KAgHpRADRna7wKiX9PWOpeB19VvA==",
|
"integrity": "sha512-AgMdDgLeYlEG17tXtMCowE7mplm907pcugtfJYYAp06HNe9RDnunUIY5KMnn9yikYl7NXNofARC+hwG77Zsa4g==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@google-cloud/projectify": "^1.0.0",
|
"@google-cloud/projectify": "^1.0.0",
|
||||||
@@ -260,9 +337,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"@google-cloud/storage": {
|
"@google-cloud/storage": {
|
||||||
"version": "3.2.1",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@google-cloud/storage/-/storage-3.3.0.tgz",
|
||||||
"integrity": "sha512-129EwPGej6bXzY1u5nja2aeMDew6DIHaJn7ZV6nteQ74LQQSNv2jKrqTlyhndBsAwpuwQAxeghPTCoFT/H8Frg==",
|
"integrity": "sha512-9jmHJ0ncQTcrZRwq5MRjXEwuCFkIjHenYwVbycV6bbZ4O84Hcgg4Yp33sKcJug5rvZeVgrpCzPbYXqO3B0LzJw==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@google-cloud/common": "^2.1.1",
|
"@google-cloud/common": "^2.1.1",
|
||||||
@@ -271,27 +348,50 @@
|
|||||||
"arrify": "^2.0.0",
|
"arrify": "^2.0.0",
|
||||||
"compressible": "^2.0.12",
|
"compressible": "^2.0.12",
|
||||||
"concat-stream": "^2.0.0",
|
"concat-stream": "^2.0.0",
|
||||||
"date-and-time": "^0.9.0",
|
"date-and-time": "^0.10.0",
|
||||||
"duplexify": "^3.5.0",
|
"duplexify": "^3.5.0",
|
||||||
"extend": "^3.0.2",
|
"extend": "^3.0.2",
|
||||||
"gaxios": "^2.0.1",
|
"gaxios": "^2.0.1",
|
||||||
"gcs-resumable-upload": "^2.0.0",
|
"gcs-resumable-upload": "^2.2.4",
|
||||||
"hash-stream-validation": "^0.2.1",
|
"hash-stream-validation": "^0.2.1",
|
||||||
"mime": "^2.2.0",
|
"mime": "^2.2.0",
|
||||||
"mime-types": "^2.0.8",
|
"mime-types": "^2.0.8",
|
||||||
"onetime": "^5.1.0",
|
"onetime": "^5.1.0",
|
||||||
"p-limit": "^2.2.0",
|
"p-limit": "^2.2.0",
|
||||||
"pumpify": "^2.0.0",
|
"pumpify": "^2.0.0",
|
||||||
|
"readable-stream": "^3.4.0",
|
||||||
"snakeize": "^0.1.0",
|
"snakeize": "^0.1.0",
|
||||||
"stream-events": "^1.0.1",
|
"stream-events": "^1.0.1",
|
||||||
"through2": "^3.0.0",
|
"through2": "^3.0.0",
|
||||||
"xdg-basedir": "^4.0.0"
|
"xdg-basedir": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "3.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
|
||||||
|
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"inherits": "^2.0.3",
|
||||||
|
"string_decoder": "^1.1.1",
|
||||||
|
"util-deprecate": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
|
||||||
|
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
|
||||||
|
"optional": true,
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@grpc/grpc-js": {
|
"@grpc/grpc-js": {
|
||||||
"version": "0.5.3",
|
"version": "0.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-0.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-0.5.4.tgz",
|
||||||
"integrity": "sha512-doDzxjdN0IJihQJvjDkZun9bZp/TW2EKO5E4fNvw8634kU1eNqPnFtAmiEiIYptqJ9StC+zRo1mwrazhqI0k5A==",
|
"integrity": "sha512-aY4fTCz7jq7oKFmfAeZVqGzMCR5I9NLdY9E2fJ70QtGXwlJnTaN6cnbRmCk23/aKPx9UHqOtk2lyjpN6LbAaxw==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"semver": "^6.2.0"
|
"semver": "^6.2.0"
|
||||||
@@ -497,12 +597,6 @@
|
|||||||
"integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
|
"integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ansi-regex": {
|
|
||||||
"version": "3.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
|
||||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
@@ -547,6 +641,15 @@
|
|||||||
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
|
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
@@ -899,9 +1002,9 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"date-and-time": {
|
"date-and-time": {
|
||||||
"version": "0.9.0",
|
"version": "0.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.10.0.tgz",
|
||||||
"integrity": "sha512-4JybB6PbR+EebpFx/KyR5Ybl+TcdXMLIJkyYsCx3P4M4CWGMuDyFF19yh6TyasMAIF5lrsgIxiSHBXh2FFc7Fg==",
|
"integrity": "sha512-IbIzxtvK80JZOVsWF6+NOjunTaoFVYxkAQoyzmflJyuRCJAJebehy48mPiCAedcGp4P7/UO3QYRWa0fe6INftg==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
@@ -1071,9 +1174,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"end-of-stream": {
|
"end-of-stream": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.3.tgz",
|
||||||
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
|
"integrity": "sha512-cbNhPFS6MlYlWTGncSiDYbdqKhwWFy7kNeb1YSOG6K65i/wPTkLVCJQj0hXA4j0m5Da+hBWnqopEnu1FFelisQ==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"once": "^1.4.0"
|
"once": "^1.4.0"
|
||||||
@@ -1149,7 +1252,6 @@
|
|||||||
"progress": "^2.0.0",
|
"progress": "^2.0.0",
|
||||||
"regexpp": "^2.0.1",
|
"regexpp": "^2.0.1",
|
||||||
"semver": "^5.5.1",
|
"semver": "^5.5.1",
|
||||||
"strip-ansi": "^4.0.0",
|
|
||||||
"strip-json-comments": "^2.0.1",
|
"strip-json-comments": "^2.0.1",
|
||||||
"table": "^5.2.3",
|
"table": "^5.2.3",
|
||||||
"text-table": "^0.2.0"
|
"text-table": "^0.2.0"
|
||||||
@@ -1415,42 +1517,55 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firebase": {
|
"firebase": {
|
||||||
"version": "6.6.1",
|
"version": "6.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/firebase/-/firebase-6.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/firebase/-/firebase-6.6.2.tgz",
|
||||||
"integrity": "sha512-iXbHPIBRt04xYSjWffnARqZbc3vUc0RTnOHsMtAqaT7pqDWicaghEwj2WbCJ0+JLAiKnLNK7fTjW73zfKQSSoQ==",
|
"integrity": "sha512-uL9uNbutC0T8GAxrGgOCC35Ven3QKJqzJozNoVIpBuiWrB9ifm9aKOxn44h6o5ouviax3LVvoiG2jLkLkdQq4A==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/app": "0.4.16",
|
"@firebase/app": "0.4.17",
|
||||||
"@firebase/app-types": "0.4.3",
|
"@firebase/app-types": "0.4.3",
|
||||||
"@firebase/auth": "0.12.0",
|
"@firebase/auth": "0.12.0",
|
||||||
"@firebase/database": "0.5.3",
|
"@firebase/database": "0.5.4",
|
||||||
"@firebase/firestore": "1.5.2",
|
"@firebase/firestore": "1.5.3",
|
||||||
"@firebase/functions": "0.4.17",
|
"@firebase/functions": "0.4.18",
|
||||||
"@firebase/installations": "0.2.6",
|
"@firebase/installations": "0.2.7",
|
||||||
"@firebase/messaging": "0.4.10",
|
"@firebase/messaging": "0.4.11",
|
||||||
"@firebase/performance": "0.2.18",
|
"@firebase/performance": "0.2.19",
|
||||||
"@firebase/polyfill": "0.3.21",
|
"@firebase/polyfill": "0.3.22",
|
||||||
"@firebase/storage": "0.3.11",
|
"@firebase/storage": "0.3.12",
|
||||||
"@firebase/util": "0.2.27"
|
"@firebase/util": "0.2.28"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@firebase/database": {
|
"@firebase/database": {
|
||||||
"version": "0.5.3",
|
"version": "0.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.3.tgz",
|
"resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.5.4.tgz",
|
||||||
"integrity": "sha512-TFjQ/M0T4jO24jAMU5cZAHNk3ndNfeNtGKe5PL4o/YrGYJHg3XaE2LKzU/vFrXUFLnLxqbETzXjFa4hTA6cDUg==",
|
"integrity": "sha512-Hz1Bi3fzIcNNocE4EhvvwoEQGurG2BGssWD3/6a2bzty+K1e57SLea2Ied8QYNBUU1zt/4McHfa3Y71EQIyn/w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/database-types": "0.4.3",
|
"@firebase/database-types": "0.4.3",
|
||||||
"@firebase/logger": "0.1.24",
|
"@firebase/logger": "0.1.25",
|
||||||
"@firebase/util": "0.2.27",
|
"@firebase/util": "0.2.28",
|
||||||
"faye-websocket": "0.11.3",
|
"faye-websocket": "0.11.3",
|
||||||
"tslib": "1.10.0"
|
"tslib": "1.10.0"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"@firebase/logger": {
|
||||||
|
"version": "0.1.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/logger/-/logger-0.1.25.tgz",
|
||||||
|
"integrity": "sha512-/lRhuepVcCCnQ2jcO5Hr08SYdmZDTQU9fdPdzg+qXJ9k/QnIrD2RbswXQcL6mmae3uPpX7fFXQAoScJ9pzp50w=="
|
||||||
|
},
|
||||||
|
"@firebase/util": {
|
||||||
|
"version": "0.2.28",
|
||||||
|
"resolved": "https://registry.npmjs.org/@firebase/util/-/util-0.2.28.tgz",
|
||||||
|
"integrity": "sha512-ZQMAWtXj8y5kvB6izs0aTM/jG+WO8HpqhXA/EwD6LckJ+1P5LnAhaLZt1zR4HpuCE+jeP5I32Id5RJ/aifFs6A==",
|
||||||
|
"requires": {
|
||||||
|
"tslib": "1.10.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"firebase-admin": {
|
"firebase-admin": {
|
||||||
"version": "8.5.0",
|
"version": "8.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-8.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/firebase-admin/-/firebase-admin-8.6.0.tgz",
|
||||||
"integrity": "sha512-rvgCj5Z1iFOT6K6uW37VRl4PKNpAcBFu/FIQ4Nl5bFnqbHSxf+QxzsqdsUtIxdqZU1yh2DTs2t+s5qORx/T9+g==",
|
"integrity": "sha512-+JqOinU5bYUkg434LqEBXrHMrIBhL/+HwWEgbZpS1sBKHQRJK7LlcBrayqxvQKwJzgh5xs/JTInTmkozXk7h1w==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@firebase/database": "^0.5.1",
|
"@firebase/database": "^0.5.1",
|
||||||
"@google-cloud/firestore": "^2.0.0",
|
"@google-cloud/firestore": "^2.0.0",
|
||||||
@@ -1524,6 +1639,29 @@
|
|||||||
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
|
"integrity": "sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ms": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"forwarded": {
|
"forwarded": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
|
||||||
@@ -1564,9 +1702,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"gcp-metadata": {
|
"gcp-metadata": {
|
||||||
"version": "2.0.2",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-3.0.0.tgz",
|
||||||
"integrity": "sha512-dxPXBvjyfz5qFEBXzEwNmuZXwsGYfuASGYeg3CKZDaQRXdiWti9J3/Ezmtyon1OrCNpDO2YekyoSjEqMtsrcXw==",
|
"integrity": "sha512-WP5/TZWri9TrD41jNr8ukY9dKYLL+8jwQVwbtUbmprjWuyybdnJNkbXbwqD2sdbXIVXD1WCqzfj7QftSLB6K8Q==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"gaxios": "^2.0.1",
|
"gaxios": "^2.0.1",
|
||||||
@@ -1608,25 +1746,25 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"google-auth-library": {
|
"google-auth-library": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-5.2.2.tgz",
|
||||||
"integrity": "sha512-p9vO6UcRIK/zD3PxoMijaUfFYu6tvzaQwvag1K/82O42NBeAnmllyQUgqaBhcAh9FzFAVlN4bQIaO8+prpE7Vg==",
|
"integrity": "sha512-0vzniXbjD5SE9aenAMqhjVR99wvqLpyd5Fw6zC3WxJ15GIMGx96tq+Cu1WRviqsnQqhrmnad6T69kv6qkj/w2Q==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"arrify": "^2.0.0",
|
"arrify": "^2.0.0",
|
||||||
"base64-js": "^1.3.0",
|
"base64-js": "^1.3.0",
|
||||||
"fast-text-encoding": "^1.0.0",
|
"fast-text-encoding": "^1.0.0",
|
||||||
"gaxios": "^2.0.0",
|
"gaxios": "^2.0.0",
|
||||||
"gcp-metadata": "^2.0.0",
|
"gcp-metadata": "^3.0.0",
|
||||||
"gtoken": "^4.0.0",
|
"gtoken": "^4.0.0",
|
||||||
"jws": "^3.1.5",
|
"jws": "^3.1.5",
|
||||||
"lru-cache": "^5.0.0"
|
"lru-cache": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"google-gax": {
|
"google-gax": {
|
||||||
"version": "1.5.2",
|
"version": "1.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/google-gax/-/google-gax-1.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/google-gax/-/google-gax-1.6.1.tgz",
|
||||||
"integrity": "sha512-NceyDzlw4mQz6qH3bDIuRtfDAZKehM96QpnPPJ3Hur7FA/gPzpzboUYwhfP6q5obSP4LuSSDhI/76Fu51/ljtg==",
|
"integrity": "sha512-5/6uaUA9qAqRKVe2sjvMgsnU/HbfQisQTM5EZ5DfNGOYVBoTsPBdOhR2ZqEWPyqHe7YkdzVHev3FH9W3YWcORw==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@grpc/grpc-js": "^0.5.2",
|
"@grpc/grpc-js": "^0.5.2",
|
||||||
@@ -2097,9 +2235,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"gtoken": {
|
"gtoken": {
|
||||||
"version": "4.0.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-4.1.0.tgz",
|
||||||
"integrity": "sha512-XaRCfHJxhj06LmnWNBzVTAr85NfAErq0W1oabkdqwbq3uL/QTB1kyvGog361Uu2FMG/8e3115sIy/97Rnd4GjQ==",
|
"integrity": "sha512-wqyn2gf5buzEZN4QNmmiiW2i2JkEdZnL7Z/9p44RtZqgt4077m4khRgAYNuu8cBwHWCc6MsP6eDUn/KkF6jFIw==",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"gaxios": "^2.0.0",
|
"gaxios": "^2.0.0",
|
||||||
@@ -2306,7 +2444,6 @@
|
|||||||
"mute-stream": "0.0.7",
|
"mute-stream": "0.0.7",
|
||||||
"run-async": "^2.2.0",
|
"run-async": "^2.2.0",
|
||||||
"rxjs": "^6.4.0",
|
"rxjs": "^6.4.0",
|
||||||
"string-width": "^2.1.0",
|
|
||||||
"strip-ansi": "^5.1.0",
|
"strip-ansi": "^5.1.0",
|
||||||
"through": "^2.3.6"
|
"through": "^2.3.6"
|
||||||
},
|
},
|
||||||
@@ -2344,18 +2481,17 @@
|
|||||||
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
|
"integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"is-buffer": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw=="
|
||||||
|
},
|
||||||
"is-date-object": {
|
"is-date-object": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz",
|
||||||
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
|
"integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=",
|
||||||
"optional": true
|
"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": {
|
"is-obj": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
|
||||||
@@ -3205,8 +3341,7 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-styles": "^3.2.0",
|
"ansi-styles": "^3.2.0",
|
||||||
"astral-regex": "^1.0.0",
|
"astral-regex": "^1.0.0"
|
||||||
"is-fullwidth-code-point": "^2.0.0"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"snakeize": {
|
"snakeize": {
|
||||||
@@ -3246,31 +3381,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
|
||||||
"integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
|
"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"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string_decoder": {
|
"string_decoder": {
|
||||||
"version": "0.10.31",
|
"version": "0.10.31",
|
||||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
|
||||||
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
|
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
|
||||||
"optional": true
|
"optional": 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"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"strip-json-comments": {
|
"strip-json-comments": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||||
@@ -3317,7 +3433,6 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"emoji-regex": "^7.0.1",
|
"emoji-regex": "^7.0.1",
|
||||||
"is-fullwidth-code-point": "^2.0.0",
|
|
||||||
"strip-ansi": "^5.1.0"
|
"strip-ansi": "^5.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,11 +10,12 @@
|
|||||||
"logs": "firebase functions:log"
|
"logs": "firebase functions:log"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "8"
|
"node": "10"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"firebase": "^6.6.1",
|
"axios": "^0.19.0",
|
||||||
"firebase-admin": "^8.0.0",
|
"firebase": "^6.6.2",
|
||||||
|
"firebase-admin": "^8.6.0",
|
||||||
"firebase-functions": "^3.1.0"
|
"firebase-functions": "^3.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
6
functions/util/admin.js
Normal file
6
functions/util/admin.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
const admin = require('firebase-admin');
|
||||||
|
admin.initializeApp();
|
||||||
|
|
||||||
|
const db = admin.firestore();
|
||||||
|
|
||||||
|
module.exports = { admin, db };
|
||||||
9
functions/util/config.js
Normal file
9
functions/util/config.js
Normal file
@@ -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"
|
||||||
|
};
|
||||||
34
functions/util/fbAuth.js
Normal file
34
functions/util/fbAuth.js
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
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, res, 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 res.status(403).json({ error: 'Unauthorized'});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Checking that the token is valid in firebase
|
||||||
|
admin.auth().verifyIdToken(idToken)
|
||||||
|
.then((decodedToken) => {
|
||||||
|
req.user = 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
|
||||||
|
req.user.imageUrl = data.docs[0].data().imageUrl;
|
||||||
|
return next();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('Error while verifying token ', err);
|
||||||
|
return res.status(403).json(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
36
functions/util/validator.js
Normal file
36
functions/util/validator.js
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
const isEmail = (str) => {
|
||||||
|
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,}))$/;
|
||||||
|
if (str.match(emailRegEx)) return true;
|
||||||
|
else return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const isEmpty = (str) => {
|
||||||
|
if (str.trim() === "") return true;
|
||||||
|
else return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.validateUpdateProfileInfo = (data) => {
|
||||||
|
let errors = {};
|
||||||
|
let profileData = {};
|
||||||
|
|
||||||
|
// ?: 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();
|
||||||
|
|
||||||
|
if (isEmpty(data.email)) {
|
||||||
|
errors.email = "Must not be empty.";
|
||||||
|
} else if (!isEmail(data.email)) {
|
||||||
|
errors.email = "Must be a valid email.";
|
||||||
|
} else {
|
||||||
|
profileData.email = data.email;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
errors,
|
||||||
|
valid: Object.keys(errors).length === 0 ? true : false,
|
||||||
|
profileData
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
<title>Welcome to Firebase Hosting</title>
|
|
||||||
|
|
||||||
<!-- update the version number as needed -->
|
|
||||||
<script defer src="/__/firebase/6.6.0/firebase-app.js"></script>
|
|
||||||
<!-- include only the Firebase features as you need -->
|
|
||||||
<script defer src="/__/firebase/6.6.0/firebase-auth.js"></script>
|
|
||||||
<script defer src="/__/firebase/6.6.0/firebase-database.js"></script>
|
|
||||||
<script defer src="/__/firebase/6.6.0/firebase-messaging.js"></script>
|
|
||||||
<script defer src="/__/firebase/6.6.0/firebase-storage.js"></script>
|
|
||||||
<!-- initialize the SDK after all desired features are loaded -->
|
|
||||||
<script defer src="/__/firebase/init.js"></script>
|
|
||||||
|
|
||||||
<style media="screen">
|
|
||||||
body { background: #ECEFF1; color: rgba(0,0,0,0.87); font-family: Roboto, Helvetica, Arial, sans-serif; margin: 0; padding: 0; }
|
|
||||||
#message { background: white; max-width: 360px; margin: 100px auto 16px; padding: 32px 24px; border-radius: 3px; }
|
|
||||||
#message h2 { color: #ffa100; font-weight: bold; font-size: 16px; margin: 0 0 8px; }
|
|
||||||
#message h1 { font-size: 22px; font-weight: 300; color: rgba(0,0,0,0.6); margin: 0 0 16px;}
|
|
||||||
#message p { line-height: 140%; margin: 16px 0 24px; font-size: 14px; }
|
|
||||||
#message a { display: block; text-align: center; background: #039be5; text-transform: uppercase; text-decoration: none; color: white; padding: 16px; border-radius: 4px; }
|
|
||||||
#message, #message a { box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); }
|
|
||||||
#load { color: rgba(0,0,0,0.4); text-align: center; font-size: 13px; }
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
body, #message { margin-top: 0; background: white; box-shadow: none; }
|
|
||||||
body { border-top: 16px solid #ffa100; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="message">
|
|
||||||
<h2>This is a test message!</h2>
|
|
||||||
<h2>Welcome</h2>
|
|
||||||
|
|
||||||
|
|
||||||
<h1>Firebase Hosting Setup Complete</h1>
|
|
||||||
<p>You're seeing this because you've successfully setup Firebase Hosting. Now it's time to go build something extraordinary!</p>
|
|
||||||
<a target="_blank" href="https://firebase.google.com/docs/hosting/">Open Hosting Documentation</a>
|
|
||||||
<div id="like_button_container"></div>
|
|
||||||
</div>
|
|
||||||
<p id="load">Firebase SDK Loading…</p>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
|
|
||||||
// // The Firebase SDK is initialized and available here!
|
|
||||||
//
|
|
||||||
// firebase.auth().onAuthStateChanged(user => { });
|
|
||||||
// firebase.database().ref('/path/to/ref').on('value', snapshot => { });
|
|
||||||
// firebase.messaging().requestPermission().then(() => { });
|
|
||||||
// firebase.storage().ref('/path/to/ref').getDownloadURL().then(() => { });
|
|
||||||
//
|
|
||||||
// // 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
|
|
||||||
|
|
||||||
try {
|
|
||||||
let app = firebase.app();
|
|
||||||
let features = ['auth', 'database', 'messaging', 'storage'].filter(feature => typeof app[feature] === 'function');
|
|
||||||
document.getElementById('load').innerHTML = `Firebase SDK loaded with ${features.join(', ')}`;
|
|
||||||
} catch (e) {
|
|
||||||
console.error(e);
|
|
||||||
document.getElementById('load').innerHTML = 'Error loading the Firebase SDK, check the console.';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Load React. -->
|
|
||||||
<!-- Note: when deploying, replace "development.js" with "production.min.js". -->
|
|
||||||
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
|
|
||||||
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
|
|
||||||
|
|
||||||
<!-- Load our React component. -->
|
|
||||||
<script src="like_button.js"></script>
|
|
||||||
<script src="loader.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const e = React.createElement;
|
|
||||||
|
|
||||||
class LikeButton extends React.Component {
|
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
liked: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
if (this.state.liked) {
|
|
||||||
return 'You liked this.';
|
|
||||||
}
|
|
||||||
|
|
||||||
return e(
|
|
||||||
'button', {
|
|
||||||
onClick: () => this.setState({
|
|
||||||
liked: true
|
|
||||||
})
|
|
||||||
},
|
|
||||||
'Like'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const domContainer = document.querySelector('#like_button_container');
|
|
||||||
ReactDOM.render(e(LikeButton), domContainer);
|
|
||||||
5654
twistter-frontend/package-lock.json
generated
5654
twistter-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,10 +3,19 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@material-ui/core": "^4.4.3",
|
||||||
|
"axios": "^0.19.0",
|
||||||
|
"clsx": "^1.0.4",
|
||||||
|
"create-react-app": "^3.1.2",
|
||||||
|
"install": "^0.13.0",
|
||||||
|
"node-pre-gyp": "^0.13.0",
|
||||||
"react": "^16.9.0",
|
"react": "^16.9.0",
|
||||||
"react-dom": "^16.9.0",
|
"react-dom": "^16.9.0",
|
||||||
"react-router-dom": "^5.0.1",
|
"react-redux": "^7.1.1",
|
||||||
"react-scripts": "0.9.5"
|
"react-router-dom": "^5.1.0",
|
||||||
|
"react-scripts": "0.9.5",
|
||||||
|
"redux": "^4.0.4",
|
||||||
|
"redux-thunk": "^2.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {},
|
"devDependencies": {},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -14,5 +23,18 @@
|
|||||||
"build": "react-scripts build",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test --env=jsdom",
|
"test": "react-scripts test --env=jsdom",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
}
|
},
|
||||||
|
"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"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,13 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Twistter</title>
|
<title>Twistter</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
0
twistter-frontend/redux/actions/dataActions.js
Normal file
0
twistter-frontend/redux/actions/dataActions.js
Normal file
0
twistter-frontend/redux/actions/userActions.js
Normal file
0
twistter-frontend/redux/actions/userActions.js
Normal file
0
twistter-frontend/redux/reducers/dataReducer.js
Normal file
0
twistter-frontend/redux/reducers/dataReducer.js
Normal file
0
twistter-frontend/redux/reducers/uiReducer.js
Normal file
0
twistter-frontend/redux/reducers/uiReducer.js
Normal file
0
twistter-frontend/redux/reducers/userReducer.js
Normal file
0
twistter-frontend/redux/reducers/userReducer.js
Normal file
18
twistter-frontend/redux/store.js
Normal file
18
twistter-frontend/redux/store.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { createStore, combineReducers, applyMiddleware, compose } from 'redux';
|
||||||
|
import thunk from 'redux-thunk';
|
||||||
|
|
||||||
|
import userReducer from './reducers/userReducer';
|
||||||
|
import dataReducer from './reducers/dataReducer';
|
||||||
|
import uiReducer from './reducers/uiReducer';
|
||||||
|
|
||||||
|
const initialState = {};
|
||||||
|
|
||||||
|
const middleware = {thunk};
|
||||||
|
|
||||||
|
const reducers = combineReducers({
|
||||||
|
user: userReducer,
|
||||||
|
data: dataReducer,
|
||||||
|
UI: uiReducer
|
||||||
|
});
|
||||||
|
|
||||||
|
//const store = createStore(reducers, )
|
||||||
0
twistter-frontend/redux/types.js
Normal file
0
twistter-frontend/redux/types.js
Normal file
@@ -41,3 +41,9 @@
|
|||||||
border: 0px;
|
border: 0px;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
margin: 80px auto 0 auto;
|
||||||
|
max-width: 1200px;
|
||||||
|
color: #1da1f2;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,172 +1,38 @@
|
|||||||
|
/* eslint-disable */
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import logo from './twistter-logo.png';
|
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
|
||||||
import Route from 'react-router-dom/Route';
|
|
||||||
import './App.css';
|
import './App.css';
|
||||||
|
|
||||||
var validEmail = true;
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
var validUsername = false;
|
import Route from 'react-router-dom/Route';
|
||||||
var validPassword = false;
|
import Navbar from './components/layout/NavBar';
|
||||||
var passwordsMatch = false;
|
|
||||||
|
|
||||||
const emailBlur = () => {
|
import home from './pages/Home';
|
||||||
//var email = document.getElementById("email");
|
import register from './pages/Register';
|
||||||
|
import login from './pages/Login';
|
||||||
|
import user from './pages/user';
|
||||||
|
|
||||||
/*if() {
|
import writeMicroblog from './Writing_Microblogs.js';
|
||||||
validEmail = true;
|
import edit from './pages/edit.js';
|
||||||
}
|
import userLine from './Userline.js';
|
||||||
else {
|
|
||||||
validEmail = false;
|
|
||||||
alert("Email is invalid.");
|
|
||||||
}*/
|
|
||||||
|
|
||||||
if(validEmail && validUsername && validPassword && passwordsMatch) {
|
|
||||||
document.getElementById("submit").disabled = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
document.getElementById("submit").disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const usernameBlur = () => {
|
|
||||||
var username = document.getElementById("username");
|
|
||||||
|
|
||||||
if(username.value.length >= 3 && username.value.length <= 50) {
|
|
||||||
validUsername = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
validUsername = false;
|
|
||||||
alert("Username must be between 3 and 50 characters long.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(validEmail && validUsername && validPassword && passwordsMatch) {
|
|
||||||
document.getElementById("submit").disabled = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
document.getElementById("submit").disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const passwordBlur = () => {
|
|
||||||
var password = document.getElementById("password");
|
|
||||||
|
|
||||||
if(password.value.length >= 8 && password.value.length <= 20) {
|
|
||||||
validPassword = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
validPassword = false;
|
|
||||||
alert("Password must be between 8 and 20 characters long.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(validEmail && validUsername && validPassword && passwordsMatch) {
|
|
||||||
document.getElementById("submit").disabled = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
document.getElementById("submit").disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const confirmPasswordBlur = () => {
|
|
||||||
var password = document.getElementById("password");
|
|
||||||
var confirmPassword = document.getElementById("confirmPassword");
|
|
||||||
|
|
||||||
if(password.value === confirmPassword.value) {
|
|
||||||
passwordsMatch = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
passwordsMatch = false;
|
|
||||||
alert("Passwords must match.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(validEmail && validUsername && validPassword && passwordsMatch) {
|
|
||||||
document.getElementById("submit").disabled = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
document.getElementById("submit").disabled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<div className="app">
|
<div className='container' >
|
||||||
|
<Navbar />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<Route path="/" exact render={
|
|
||||||
() => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<img src={logo} className="app-logo" alt="logo" />
|
|
||||||
<br/><br/>
|
|
||||||
<b>Welcome to Twistter!</b>
|
|
||||||
<br/><br/>
|
|
||||||
<b>See the most interesting topics people are following right now.</b>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br/><br/><br/><br/>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<b>Join today or sign in if you already have an account.</b>
|
|
||||||
<br/><br/>
|
|
||||||
<button class="authButtons register"><a href="/register">Sign up</a></button>
|
|
||||||
<br/><br/>
|
|
||||||
<button class="authButtons login"><a href="/login">Sign in</a></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}/>
|
|
||||||
|
|
||||||
<Route path="/register" exact render={
|
|
||||||
() => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<img src={logo} className="app-logo" alt="logo" />
|
|
||||||
<br/><br/>
|
|
||||||
<b>Create your account</b>
|
|
||||||
<br/><br/>
|
|
||||||
<input class="authInput" id="email" placeholder="Email" onBlur={() => emailBlur()}></input>
|
|
||||||
<br/><br/>
|
|
||||||
<input class="authInput" id="username" placeholder="Username" onBlur={() => usernameBlur()}></input>
|
|
||||||
<br/><br/>
|
|
||||||
<input class="authInput" id="password" placeholder="Password" onBlur={() => passwordBlur()}></input>
|
|
||||||
<br/><br/>
|
|
||||||
<input class="authInput" id="confirmPassword" placeholder="Confirm Password" onBlur={() => confirmPasswordBlur()}></input>
|
|
||||||
<br/><br/>
|
|
||||||
<button class="authButtons register" id="submit" onclick="" disabled>Sign up</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}/>
|
|
||||||
|
|
||||||
<Route path="/login" exact render={
|
|
||||||
() => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<img src={logo} className="app-logo" alt="logo" />
|
|
||||||
<br/><br/>
|
|
||||||
<b>Log in to Twistter</b>
|
|
||||||
<br/><br/>
|
|
||||||
<input class="authInput" placeholder="Username or email"></input>
|
|
||||||
<br/><br/>
|
|
||||||
<input class="authInput" placeholder="Password"></input>
|
|
||||||
<br/><br/>
|
|
||||||
<button class="authButtons register" onclick="">Sign in</button>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}/>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="app">
|
||||||
|
<Route exact path="/" component={home}/>
|
||||||
|
<Route exact path="/register" component={register}/>
|
||||||
|
<Route exact path="/login" component={login}/>
|
||||||
|
<Route exact path="/user" component={user}/>
|
||||||
|
<Route exact path="/home" component={writeMicroblog}/>
|
||||||
|
<Route exact path="/edit" component={edit}/>
|
||||||
|
<Route exact path="/userline" component={userLine}/>
|
||||||
|
</div>
|
||||||
|
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
22
twistter-frontend/src/Logout.js
Normal file
22
twistter-frontend/src/Logout.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
import React, { Component} from 'react';
|
||||||
|
import './App.css';
|
||||||
|
import logo from './images/twistter-logo.png';
|
||||||
|
import TextField from '@material-ui/core/TextField';
|
||||||
|
|
||||||
|
class Logout extends Component {
|
||||||
|
render() {
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<img src={logo} className="app-logo" alt="logo" />
|
||||||
|
<br/><br/>
|
||||||
|
<b>Logout of your Twistter Account</b>
|
||||||
|
<br/><br/>
|
||||||
|
<br/><br/>
|
||||||
|
<button className="authButtons register" type="submit">Sign Out</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Logout;
|
||||||
64
twistter-frontend/src/Userline.js
Normal file
64
twistter-frontend/src/Userline.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import React, { Component } from "react";
|
||||||
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
|
import Route from 'react-router-dom/Route';
|
||||||
|
import axios from 'axios';
|
||||||
|
import Box from '@material-ui/core/Box'
|
||||||
|
import {borders} from '@material-ui/system';
|
||||||
|
import { sizing } from '@material-ui/system';
|
||||||
|
// var moment = require('moment');
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Userline extends Component {
|
||||||
|
|
||||||
|
constructor(props)
|
||||||
|
{
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
microBlogs : [],
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
|
||||||
|
axios.get('http://localhost:5001/twistter-e4649/us-central1/api/getallPostsforUser')
|
||||||
|
.then(res => {
|
||||||
|
const post = res.data;
|
||||||
|
this.setState({microBlogs : post})
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const sortedPosts = (this.state.microBlogs).sort((a,b) =>
|
||||||
|
-a.createdAt.localeCompare(b.createdAt)
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{fontsize: "13px", textAlign: "left", marginLeft: "14px"}}>
|
||||||
|
<p>Userline</p>
|
||||||
|
</div>
|
||||||
|
<Box border={1} width="25%" flex="1" height="auto" m={2} fontSize="13px" textAlign= "left" padding="5px" flexWrap= "wrap" flexDirection= "row" >
|
||||||
|
<div style={{flexWrap: "wrap", flex: "1", flexDirection: "row", wordBreak: "break-word"}}>
|
||||||
|
<p>
|
||||||
|
{sortedPosts.map((microBlog) => <p>Microblog Title: {microBlog.microBlogTitle}
|
||||||
|
<br></br>When post was created: {microBlog.createdAt.substring(0,10) +
|
||||||
|
" " + microBlog.createdAt.substring(11,19)}
|
||||||
|
<br></br>Number of comments: {microBlog.commentCount}
|
||||||
|
<br></br>Number of likes: {microBlog.likeCount}
|
||||||
|
<br></br>Body of post: {microBlog.body}
|
||||||
|
<br></br>Tagged topics: {microBlog.microBlogTopics.join("," + " ")}
|
||||||
|
</p>)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Box>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
export default Userline;
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
import Route from 'react-router-dom/Route';
|
import Route from 'react-router-dom/Route';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
|
||||||
class Writing_Microblogs extends Component {
|
class Writing_Microblogs extends Component {
|
||||||
@@ -10,7 +11,8 @@ class Writing_Microblogs extends Component {
|
|||||||
this.state = {
|
this.state = {
|
||||||
value: '',
|
value: '',
|
||||||
title: '',
|
title: '',
|
||||||
characterCount: 10
|
topics: '',
|
||||||
|
characterCount: 250
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -18,15 +20,37 @@ class Writing_Microblogs extends Component {
|
|||||||
this.handleChange = this.handleChange.bind(this);
|
this.handleChange = this.handleChange.bind(this);
|
||||||
this.handleSubmit = this.handleSubmit.bind(this);
|
this.handleSubmit = this.handleSubmit.bind(this);
|
||||||
this.handleChangeforPost = this.handleChangeforPost.bind(this);
|
this.handleChangeforPost = this.handleChangeforPost.bind(this);
|
||||||
|
this.handleChangeforTopics = this.handleChangeforTopics.bind(this);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChange(event) {
|
handleChange(event) {
|
||||||
this.setState( {title: event.target.value });
|
this.setState( {title: event.target.value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleChangeforTopics(event) {
|
||||||
|
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);
|
// alert('A title for the microblog was inputted: ' + this.state.title + '\nA microblog was posted: ' + this.state.value);
|
||||||
|
|
||||||
|
const response = axios.post(
|
||||||
|
'http://localhost:5001/twistter-e4649/us-central1/api/putPost',
|
||||||
|
{ body: this.state.value,
|
||||||
|
userHandle: "new user",
|
||||||
|
userImage: "bing-url",
|
||||||
|
microBlogTitle: this.state.title,
|
||||||
|
microBlogTopics: this.state.topics.split(', ')
|
||||||
|
|
||||||
|
},
|
||||||
|
{ headers: { 'Content-Type': 'application/json'} }
|
||||||
|
|
||||||
|
)
|
||||||
|
console.log(response.data);
|
||||||
|
alert('Post was shared successfully!');
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
this.setState({value: '', title: '',characterCount: 250, topics: ''})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleChangeforPost(event) {
|
handleChangeforPost(event) {
|
||||||
@@ -35,23 +59,29 @@ class Writing_Microblogs extends Component {
|
|||||||
|
|
||||||
handleChangeforCharacterCount(event) {
|
handleChangeforCharacterCount(event) {
|
||||||
const charCount = event.target.value.length
|
const charCount = event.target.value.length
|
||||||
const charRemaining = 10 - charCount
|
const charRemaining = 250 - charCount
|
||||||
this.setState({characterCount: charRemaining })
|
this.setState({characterCount: charRemaining })
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ width: "200px", height: "50px", marginTop: "180px", marginLeft: "30px" }}>
|
<div style={{ width: "200px", height: "50px", marginTop: "180px", marginLeft: "50px" }}>
|
||||||
<form>
|
<form>
|
||||||
<input type="text" placeholder="Enter Microblog Title" value={this.state.title} onChange={this.handleChange} />
|
<textarea placeholder="Enter Microblog Title" value={this.state.title} required onChange={this.handleChange} cols={30} rows={1} />
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div style={{ width: "200px", height: "50px", marginLeft: "50px"}} >
|
||||||
|
<form>
|
||||||
|
<textarea placeholder="Enter topics seperated by a comma" value={this.state.topics} required onChange={this.handleChangeforTopics} cols={40} rows={1} />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ width: "200px", marginLeft: "50px"}}>
|
<div style={{ width: "200px", marginLeft: "50px"}}>
|
||||||
<form onSubmit={this.handleSubmit}>
|
<form onSubmit={this.handleSubmit}>
|
||||||
<textarea value={this.state.value} maxLength="10" placeholder= "Write Microblog here..."
|
<textarea value={this.state.value} required maxLength="250" placeholder= "Write Microblog here..."
|
||||||
onChange = { (e) => { this.handleChangeforPost(e); this.handleChangeforCharacterCount(e) } } cols={40} rows={20} />
|
onChange = { (e) => { this.handleChangeforPost(e); this.handleChangeforCharacterCount(e) } } cols={40} rows={20} />
|
||||||
<div style={{ fontSize: "14px", marginRight: "-100px"}} >
|
<div style={{ fontSize: "14px", marginRight: "-100px"}} >
|
||||||
<p2>Characters Left: {this.state.characterCount}</p2>
|
<p2>Characters Left: {this.state.characterCount}</p2>
|
||||||
|
|||||||
31
twistter-frontend/src/components/layout/NavBar.js
Normal file
31
twistter-frontend/src/components/layout/NavBar.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import AppBar from '@material-ui/core/AppBar';
|
||||||
|
import ToolBar from '@material-ui/core/Toolbar';
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
|
||||||
|
export class Navbar extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<AppBar>
|
||||||
|
<ToolBar>
|
||||||
|
<Button component={ Link } to='/'>
|
||||||
|
Home
|
||||||
|
</Button>
|
||||||
|
<Button component={ Link } to='/login'>
|
||||||
|
Login
|
||||||
|
</Button>
|
||||||
|
<Button component={ Link } to='/register'>
|
||||||
|
Register
|
||||||
|
</Button>
|
||||||
|
<Button component={ Link } to='/logout'>
|
||||||
|
Logout
|
||||||
|
</Button>
|
||||||
|
</ToolBar>
|
||||||
|
</AppBar>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Navbar;
|
||||||
21
twistter-frontend/src/components/post/SinglePost.js
Normal file
21
twistter-frontend/src/components/post/SinglePost.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import React, { Component, Fragment } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import withStyles from '@material-ui/core/styles/withStyles';
|
||||||
|
|
||||||
|
// MUI Stuff
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import TextField from '@material-ui/core/TextField';
|
||||||
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
|
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||||
|
import AddIcon from '@material-ui/icons/Add';
|
||||||
|
import CloseIcon from '@material-ui/icons/Close';
|
||||||
|
|
||||||
|
class SinglePost extends Component{
|
||||||
|
state = {
|
||||||
|
open: false,
|
||||||
|
body: '',
|
||||||
|
errors: {}
|
||||||
|
}
|
||||||
|
};
|
||||||
54
twistter-frontend/src/components/topic/ChipsArray.js
Normal file
54
twistter-frontend/src/components/topic/ChipsArray.js
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { makeStyles } from '@material-ui/core/styles';
|
||||||
|
import Chip from '@material-ui/core/Chip';
|
||||||
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: fix the style
|
||||||
|
const styles = makeStyles(theme => ({
|
||||||
|
root: {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
padding: theme.spacing(0.5),
|
||||||
|
},
|
||||||
|
chip: {
|
||||||
|
margin: theme.spacing(0.5),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
export default function ChipsArray() {
|
||||||
|
const classes = useStyles();
|
||||||
|
const [chipData, setChipData] = React.useState([
|
||||||
|
{ key: 0, label: 'Angular' },
|
||||||
|
{ key: 1, label: 'jQuery' },
|
||||||
|
{ key: 2, label: 'Polymer' },
|
||||||
|
{ key: 3, label: 'React' },
|
||||||
|
{ key: 4, label: 'Vue.js' },
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleDelete = chipToDelete => () => {
|
||||||
|
if (chipToDelete.label === 'React') {
|
||||||
|
alert('Why would you want to delete React?! :)');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setChipData(chips => chips.filter(chip => chip.key !== chipToDelete.key));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Paper className={classes.root}>
|
||||||
|
{chipData.map(data => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Chip
|
||||||
|
key={data.key}
|
||||||
|
label={data.label}
|
||||||
|
onDelete={handleDelete(data)}
|
||||||
|
className={classes.chip}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
}
|
||||||
BIN
twistter-frontend/src/images/no-img.png
Normal file
BIN
twistter-frontend/src/images/no-img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
@@ -1,5 +0,0 @@
|
|||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
font-family: sans-serif;
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
import './index.css';
|
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<App />,
|
<App />,
|
||||||
|
|||||||
37
twistter-frontend/src/pages/Home.js
Normal file
37
twistter-frontend/src/pages/Home.js
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import '../App.css';
|
||||||
|
|
||||||
|
import logo from '../images/twistter-logo.png';
|
||||||
|
|
||||||
|
|
||||||
|
class Home extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<img src={logo} className="app-logo" alt="logo" />
|
||||||
|
<br/><br/>
|
||||||
|
<b>Welcome to Twistter!</b>
|
||||||
|
<br/><br/>
|
||||||
|
<b>See the most interesting topics people are following right now.</b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br/><br/><br/><br/>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<b>Join today or sign in if you already have an account.</b>
|
||||||
|
<br/><br/>
|
||||||
|
<form action="./register">
|
||||||
|
<button className="authButtons register">Sign up</button>
|
||||||
|
</form>
|
||||||
|
<br/>
|
||||||
|
<form action="./login">
|
||||||
|
<button className="authButtons login">Sign in</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Home;
|
||||||
26
twistter-frontend/src/pages/Login.js
Normal file
26
twistter-frontend/src/pages/Login.js
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import '../App.css';
|
||||||
|
|
||||||
|
import logo from '../images/twistter-logo.png';
|
||||||
|
import TextField from '@material-ui/core/TextField';
|
||||||
|
|
||||||
|
class Login extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<img src={logo} className="app-logo" alt="logo" />
|
||||||
|
<br/><br/>
|
||||||
|
<b>Log in to Twistter</b>
|
||||||
|
<br/><br/>
|
||||||
|
<TextField className="authInput" id="email" name="email" label="Email" />
|
||||||
|
<br/><br/>
|
||||||
|
<TextField className="authInput" id="password" name="password" label="Password" />
|
||||||
|
<br/><br/>
|
||||||
|
<button className="authButtons register" type="submit">Sign in</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Login;
|
||||||
29
twistter-frontend/src/pages/Register.js
Normal file
29
twistter-frontend/src/pages/Register.js
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import '../App.css';
|
||||||
|
|
||||||
|
import logo from '../images/twistter-logo.png';
|
||||||
|
import TextField from '@material-ui/core/TextField';
|
||||||
|
|
||||||
|
class Register extends Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<img src={logo} className="app-logo" alt="logo" />
|
||||||
|
<br/><br/>
|
||||||
|
<b>Create your account</b>
|
||||||
|
<br/><br/>
|
||||||
|
<TextField className="authInput" id="email" name="email" label="Email" />
|
||||||
|
<br/><br/>
|
||||||
|
<TextField className="authInput" id="username" name="username" label="Username" />
|
||||||
|
<br/><br/>
|
||||||
|
<TextField className="authInput" id="password" name="password" label="Password" />
|
||||||
|
<br/><br/>
|
||||||
|
<TextField className="authInput" id="confirmPassword" name="confirmPassword" label="Confirm Password" />
|
||||||
|
<br/><br/>
|
||||||
|
<button class="authButtons register" id="submit">Sign up</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Register;
|
||||||
224
twistter-frontend/src/pages/edit.js
Normal file
224
twistter-frontend/src/pages/edit.js
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
import React, { Component } from "react";
|
||||||
|
import axios from "axios";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
// TODO: Add a read-only '@' in the left side of the handle input
|
||||||
|
// TODO: Add a cancel button, that takes the user back to their profile page
|
||||||
|
|
||||||
|
// Material-UI stuff
|
||||||
|
import Button from "@material-ui/core/Button";
|
||||||
|
import CircularProgress from "@material-ui/core/CircularProgress";
|
||||||
|
import Grid from "@material-ui/core/Grid";
|
||||||
|
import TextField from "@material-ui/core/TextField";
|
||||||
|
import Typography from "@material-ui/core/Typography";
|
||||||
|
import withStyles from "@material-ui/core/styles/withStyles";
|
||||||
|
|
||||||
|
const styles = {
|
||||||
|
form: {
|
||||||
|
textAlign: "center"
|
||||||
|
},
|
||||||
|
textField: {
|
||||||
|
marginBottom: 30
|
||||||
|
},
|
||||||
|
pageTitle: {
|
||||||
|
// marginTop: 20,
|
||||||
|
marginBottom: 40
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
positon: "relative",
|
||||||
|
marginBottom: 30
|
||||||
|
},
|
||||||
|
progress: {
|
||||||
|
position: "absolute"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export class edit extends Component {
|
||||||
|
// Runs as soon as the page loads.
|
||||||
|
// Sets the default values of all the textboxes to the data
|
||||||
|
// that is stored in the database for the user.
|
||||||
|
componentDidMount() {
|
||||||
|
axios
|
||||||
|
.get("/getProfileInfo")
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({
|
||||||
|
firstName: res.data.firstName,
|
||||||
|
lastName: res.data.lastName,
|
||||||
|
email: res.data.email,
|
||||||
|
handle: res.data.handle,
|
||||||
|
bio: res.data.bio
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor for the state
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.state = {
|
||||||
|
firstName: "",
|
||||||
|
lastName: "",
|
||||||
|
email: "",
|
||||||
|
handle: "",
|
||||||
|
bio: "",
|
||||||
|
loading: false,
|
||||||
|
errors: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs whenever the submit button is clicked.
|
||||||
|
// Updates the database entry of the signed in user with the
|
||||||
|
// data stored in the state.
|
||||||
|
handleSubmit = (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
this.setState({
|
||||||
|
loading: true
|
||||||
|
});
|
||||||
|
const newProfileData = {
|
||||||
|
firstName: this.state.firstName,
|
||||||
|
lastName: this.state.lastName,
|
||||||
|
email: this.state.email,
|
||||||
|
handle: this.state.handle,
|
||||||
|
bio: this.state.bio
|
||||||
|
};
|
||||||
|
axios
|
||||||
|
.post("/updateProfileInfo", newProfileData)
|
||||||
|
.then((res) => {
|
||||||
|
this.setState({
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
// this.props.history.push('/');
|
||||||
|
// TODO: Need to redirect user to their profile page
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
this.setState({
|
||||||
|
errors: err.response.data,
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Updates the state whenever one of the textboxes changes.
|
||||||
|
// The key is the name of the textbox and the value is the
|
||||||
|
// value in the text box.
|
||||||
|
handleChange = (event) => {
|
||||||
|
this.setState({
|
||||||
|
[event.target.name]: event.target.value,
|
||||||
|
errors: {
|
||||||
|
[event.target.name]: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { classes } = this.props;
|
||||||
|
const { errors, loading } = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Grid container className={classes.form}>
|
||||||
|
<Grid item sm />
|
||||||
|
<Grid item sm>
|
||||||
|
<Typography variant="h2" className={classes.pageTitle}>
|
||||||
|
Edit Profile
|
||||||
|
</Typography>
|
||||||
|
<form noValidate onSubmit={this.handleSubmit}>
|
||||||
|
<Grid container className={classes.form} spacing={4}>
|
||||||
|
<Grid item sm>
|
||||||
|
<TextField
|
||||||
|
id="firstName"
|
||||||
|
name="firstName"
|
||||||
|
label="First Name"
|
||||||
|
className={classes.textField}
|
||||||
|
value={this.state.firstName}
|
||||||
|
helperText={errors.firstName}
|
||||||
|
error={errors.firstName ? true : false}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={this.handleChange}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid item sm>
|
||||||
|
<TextField
|
||||||
|
id="lastName"
|
||||||
|
name="lastName"
|
||||||
|
label="Last Name"
|
||||||
|
className={classes.textField}
|
||||||
|
value={this.state.lastName}
|
||||||
|
helperText={errors.lastname}
|
||||||
|
error={errors.lastName ? true : false}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={this.handleChange}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<TextField
|
||||||
|
id="email"
|
||||||
|
name="email"
|
||||||
|
label="Email*"
|
||||||
|
className={classes.textField}
|
||||||
|
value={this.state.email}
|
||||||
|
disabled
|
||||||
|
helperText="(disabled)"
|
||||||
|
// INFO: These will be uncommented if changing emails is allowed
|
||||||
|
// helperText={errors.email}
|
||||||
|
// error={errors.email ? true : false}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={this.handleChange}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="handle"
|
||||||
|
name="handle"
|
||||||
|
label="Handle*"
|
||||||
|
className={classes.textField}
|
||||||
|
value={this.state.handle}
|
||||||
|
disabled
|
||||||
|
helperText="(disabled)"
|
||||||
|
// INFO: These will be uncommented if changing usernames is allowed
|
||||||
|
// helperText={errors.handle}
|
||||||
|
// error={errors.handle ? true : false}
|
||||||
|
variant="outlined"
|
||||||
|
onChange={this.handleChange}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
id="bio"
|
||||||
|
name="bio"
|
||||||
|
label="Bio"
|
||||||
|
className={classes.textField}
|
||||||
|
value={this.state.bio}
|
||||||
|
helperText={errors.bio}
|
||||||
|
error={errors.bio ? true : false}
|
||||||
|
multiline
|
||||||
|
rows="8"
|
||||||
|
variant="outlined"
|
||||||
|
onChange={this.handleChange}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
variant="contained"
|
||||||
|
color="primary"
|
||||||
|
className={classes.button}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
{loading && (
|
||||||
|
<CircularProgress size={30} className={classes.progress} />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</form>
|
||||||
|
</Grid>
|
||||||
|
<Grid item sm />
|
||||||
|
</Grid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
edit.propTypes = {
|
||||||
|
classes: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withStyles(styles)(edit);
|
||||||
40
twistter-frontend/src/pages/user.js
Normal file
40
twistter-frontend/src/pages/user.js
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import StaticProfile from '../components/profile/StaticProfile';
|
||||||
|
import Grid from '@material-ui/core/Grid';
|
||||||
|
|
||||||
|
import PostSkeleton from '../util/PostSkeleton';
|
||||||
|
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
|
|
||||||
|
class user extends Component {
|
||||||
|
render() {
|
||||||
|
const postMarkup = PostSkeleton;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<b>User page</b>
|
||||||
|
// <Grid container spacing={16}>
|
||||||
|
// <Grid item sm={8} xs={12}>
|
||||||
|
// <b>postMarkup</b>
|
||||||
|
// {postMarkup}
|
||||||
|
// </Grid>
|
||||||
|
// {/* <Grid item sm={4} xs={12}>
|
||||||
|
// <StaticProfile profile={this.state.profile} />
|
||||||
|
// </Grid> */}
|
||||||
|
// </Grid>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user.propTypes = {
|
||||||
|
// getUserData: PropTypes.func.isRequired,
|
||||||
|
//data: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({
|
||||||
|
data: state.data
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(user);
|
||||||
77
twistter-frontend/src/util/PostSkeleton.js
Normal file
77
twistter-frontend/src/util/PostSkeleton.js
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/* eslint-disable */
|
||||||
|
import React, { Fragment } from 'react';
|
||||||
|
import NoImg from '../images/no-img.png';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
// MUI
|
||||||
|
import Card from '@material-ui/core/Card';
|
||||||
|
import CardMedia from '@material-ui/core/CardMedia';
|
||||||
|
import CardContent from '@material-ui/core/CardContent';
|
||||||
|
|
||||||
|
import withStyles from '@material-ui/core/styles/withStyles';
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
...theme,
|
||||||
|
card: {
|
||||||
|
display: 'flex',
|
||||||
|
marginBottom: 20
|
||||||
|
},
|
||||||
|
cardContent: {
|
||||||
|
width: '100%',
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: 25
|
||||||
|
},
|
||||||
|
cover: {
|
||||||
|
minWidth: 200,
|
||||||
|
objectFit: 'cover'
|
||||||
|
},
|
||||||
|
handle: {
|
||||||
|
width: 60,
|
||||||
|
height: 18,
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
marginBottom: 7
|
||||||
|
},
|
||||||
|
date: {
|
||||||
|
height: 14,
|
||||||
|
width: 100,
|
||||||
|
backgroundColor: 'rgba(0,0,0, 0.3)',
|
||||||
|
marginBottom: 10
|
||||||
|
},
|
||||||
|
fullLine: {
|
||||||
|
height: 15,
|
||||||
|
width: '90%',
|
||||||
|
backgroundColor: 'rgba(0,0,0, 0.6)',
|
||||||
|
marginBottom: 10
|
||||||
|
},
|
||||||
|
halfLine: {
|
||||||
|
height: 15,
|
||||||
|
width: '50%',
|
||||||
|
backgroundColor: 'rgba(0,0,0, 0.6)',
|
||||||
|
marginBottom: 10
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const PostSkeleton = (props) => {
|
||||||
|
const { classes } = props;
|
||||||
|
|
||||||
|
const content = Array.from({ length: 5 }).map((item, index) => (
|
||||||
|
<Card className={classes.card} key={index}>
|
||||||
|
<CardMedia className={classes.cover} image={NoImg} />
|
||||||
|
<CardContent className={classes.cardContent}>
|
||||||
|
<div className={classes.handle} />
|
||||||
|
<div className={classes.date} />
|
||||||
|
<div className={classes.fullLine} />
|
||||||
|
<div className={classes.fullLine} />
|
||||||
|
<div className={classes.halfLine} />
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
));
|
||||||
|
|
||||||
|
return <Fragment>{content}</Fragment>;
|
||||||
|
};
|
||||||
|
|
||||||
|
PostSkeleton.propTypes = {
|
||||||
|
classes: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withStyles(styles)(PostSkeleton);
|
||||||
|
|
||||||
64
twistter-frontend/src/util/ProfileSkeleton.js
Normal file
64
twistter-frontend/src/util/ProfileSkeleton.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import withStyles from '@material-ui/core/styles/withStyles';
|
||||||
|
import NoImg from '../images/no-img.png';
|
||||||
|
// MUI
|
||||||
|
import Paper from '@material-ui/core/Paper';
|
||||||
|
// Icons
|
||||||
|
import LocationOn from '@material-ui/icons/LocationOn';
|
||||||
|
import LinkIcon from '@material-ui/icons/Link';
|
||||||
|
import CalendarToday from '@material-ui/icons/CalendarToday';
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
...theme,
|
||||||
|
handle: {
|
||||||
|
height: 20,
|
||||||
|
backgroundColor: theme.palette.primary.main,
|
||||||
|
width: 60,
|
||||||
|
margin: '0 auto 7px auto'
|
||||||
|
},
|
||||||
|
fullLine: {
|
||||||
|
height: 15,
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.6)',
|
||||||
|
width: '100%',
|
||||||
|
marginBottom: 10
|
||||||
|
},
|
||||||
|
halfLine: {
|
||||||
|
height: 15,
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.6)',
|
||||||
|
width: '50%',
|
||||||
|
marginBottom: 10
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ProfileSkeleton = (props) => {
|
||||||
|
const { classes } = props;
|
||||||
|
return (
|
||||||
|
<Paper className={classes.paper}>
|
||||||
|
<div className={classes.profile}>
|
||||||
|
<div className="image-wrapper">
|
||||||
|
<img src={NoImg} alt="profile" className="profile-image" />
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<div className="profile-details">
|
||||||
|
<div className={classes.handle} />
|
||||||
|
<hr />
|
||||||
|
<div className={classes.fullLine} />
|
||||||
|
<div className={classes.fullLine} />
|
||||||
|
<hr />
|
||||||
|
<LocationOn color="primary" /> <span>Location</span>
|
||||||
|
<hr />
|
||||||
|
<LinkIcon color="primary" /> https://website.com
|
||||||
|
<hr />
|
||||||
|
<CalendarToday color="primary" /> Joined date
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Paper>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ProfileSkeleton.propTypes = {
|
||||||
|
classes: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
export default withStyles(styles)(ProfileSkeleton);
|
||||||
Reference in New Issue
Block a user