Eric Whale

Build login/signup

MIT License
Copyright (c) 2022 HWANG SUN HYUK
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESSFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
const asyncHandler = require("express-async-handler");
// @desc Create chatroom
// @route POST /api/chats
// @access Private
const createChatroom = asyncHandler(async (req, res) => {
return;
});
// @desc Delete chatroom
// @route DELETE /api/chats
// @access Private
const delChatroom = asyncHandler(async (req, res) => {
return;
});
module.exports = {
createChatroom,
delChatroom,
};
const bcrypt = require("bcryptjs");
// handles "exception" inside of async express routes
const asyncHandler = require("express-async-handler");
const User = require("../models/userModel");
const { jwtGenerator } = require("../config/jwt");
// @desc Signup new user
// @route POST /api/users
// @access Public
const signupUser = asyncHandler(async (req, res) => {
const { username, email, password } = req.body;
if (!username || !email || !password) {
res.status(400);
throw new Error("Please fill in all fields");
}
// Check if user already exists
const userExists = await User.findOne({ email });
if (userExists) {
res.status(400);
throw new Error("User with the email already exists");
}
// Hash password (bcrypt)
const salt = await bcrypt.genSalt(10);
const hashedPassword = await bcrypt.hash(password, salt);
// Create/Build user
const user = await User.create({
username,
email,
password: hashedPassword,
});
// Send response
if (user) {
// 201: Resource successfully created
res.status(201).json({
_id: user.id,
username: user.username,
email: user.email,
token: jwtGenerator(user._id),
});
} else {
res.status(400);
throw new Error("Invalid user data");
}
});
// @desc Login user
// @route POST /api/users/login
// @access Public
const loginUser = asyncHandler(async (req, res) => {
const { email, password } = req.body;
// Check email & password
const userInDB = await User.findOne({ email });
const validPassword = await bcrypt.compare(password, userInDB.password);
if (userInDB && validPassword) {
res.status(200).json({
_id: userInDB.id,
username: userInDB.username,
email: userInDB.email,
token: jwtGenerator(userInDB._id),
});
} else {
res.status(400);
throw new Error("Invalid credentials");
}
});
// @desc Get all users
// @route GET /api/users/all
// @access Public
const getAllusers = asyncHandler(async (req, res) => {
const users = await User.find()
.select("-password")
.select("-updatedAt")
.select("-createdAt")
.select("-email");
res.status(200).json(users);
});
// @desc Get user
// @route GET /api/users/self
// @access Private
const getSelf = asyncHandler(async (req, res) => {
res.status(200).json(req.user);
});
module.exports = {
signupUser,
loginUser,
getAllusers,
getSelf,
};
......@@ -17,6 +17,7 @@
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"sass": "^1.51.0",
"socket.io-client": "^4.5.1",
"web-vitals": "^2.1.4"
}
},
......@@ -2994,6 +2995,11 @@
"@sinonjs/commons": "^1.7.0"
}
},
"node_modules/@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
},
"node_modules/@surma/rollup-plugin-off-main-thread": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
......@@ -6343,6 +6349,46 @@
"node": ">= 0.8"
}
},
"node_modules/engine.io-client": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz",
"integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.0.3",
"ws": "~8.2.3",
"xmlhttprequest-ssl": "~2.0.0"
}
},
"node_modules/engine.io-client/node_modules/ws": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/engine.io-parser": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/enhanced-resolve": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz",
......@@ -14348,6 +14394,32 @@
"node": ">=8"
}
},
"node_modules/socket.io-client": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz",
"integrity": "sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.2.1",
"socket.io-parser": "~4.2.0"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.0.tgz",
"integrity": "sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/sockjs": {
"version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
......@@ -16272,6 +16344,14 @@
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
},
"node_modules/xmlhttprequest-ssl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
......@@ -18356,6 +18436,11 @@
"@sinonjs/commons": "^1.7.0"
}
},
"@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
},
"@surma/rollup-plugin-off-main-thread": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
......@@ -20831,6 +20916,31 @@
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
"integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
},
"engine.io-client": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz",
"integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.0.3",
"ws": "~8.2.3",
"xmlhttprequest-ssl": "~2.0.0"
},
"dependencies": {
"ws": {
"version": "8.2.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
"integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
"requires": {}
}
}
},
"engine.io-parser": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
"integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg=="
},
"enhanced-resolve": {
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz",
......@@ -26485,6 +26595,26 @@
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
},
"socket.io-client": {
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz",
"integrity": "sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.2.1",
"socket.io-parser": "~4.2.0"
}
},
"socket.io-parser": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.0.tgz",
"integrity": "sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng==",
"requires": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
}
},
"sockjs": {
"version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
......@@ -27965,6 +28095,11 @@
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
},
"xmlhttprequest-ssl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
......
{
"name": "client",
"version": "0.1.0",
"proxy": "http://localhost:6000",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.16.4",
......@@ -13,6 +12,7 @@
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"sass": "^1.51.0",
"socket.io-client": "^4.5.1",
"web-vitals": "^2.1.4"
},
"scripts": {
......@@ -22,17 +22,10 @@
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
"extends": ["react-app", "react-app/jest"]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"production": [">0.2%", "not dead", "not op_mini all"],
"development": [
"last 1 chrome version",
"last 1 firefox version",
......
// Weather broadcasting page
import axios from "axios";
import { useState, useEffect } from "react";
// components
......@@ -8,36 +9,25 @@ import ChatroomBox from "./components/ChatroomBox";
function App() {
const [chats, setChats] = useState(null);
useEffect(() => {
axios.get("/api/chat").then((response) => {
setChats(response.data);
});
}, []);
useEffect(() => {}, []);
return (
<div>
<Topbar />
<h1>Chatroom page</h1>
<div>
<div>Weather Chatbot</div>
<div>Weather Chatbot</div>
<div>Weather Chatbot</div>
</div>
<div></div>
<br />
<div>
{Array.isArray(chats) ? (
chats.map((chat, i) => {
return <ChatroomBox key={i} chat={chat} />;
})
) : (
<h2>No chatting room!</h2>
)}
</div>
<Bottombar />
</div>
);
}
export default App;
// {Array.isArray(chats) ? (
// chats.map((chat, i) => {
// return <ChatroomBox key={i} chat={chat} />;
// })
// ) : (
// <h2>No chatting room!</h2>
// )}
......
......@@ -14,15 +14,17 @@ import "./styles/layout.scss";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<Routes>
<Route path="/" element={<App />} />
<Route path="/login" element={<Login />} />
<Route path="/signup" element={<Signup />} />
<Route path="/userroom" element={<Userroom />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</BrowserRouter>
<div className="container">
<BrowserRouter>
<Routes>
<Route exact path="/" element={<App />} />
<Route exact path="/login" element={<Login />} />
<Route exact path="/signup" element={<Signup />} />
<Route exact path="/userroom" element={<Userroom />} />
<Route exact path="/settings" element={<Settings />} />
</Routes>
</BrowserRouter>
</div>
);
// If you want to start measuring performance in your app, pass a function
......
import { Link } from "react-router-dom";
import { useState } from "react";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
// lib
import { handleLogin } from "../service/auth";
import authService from "../service/auth";
// styles
import "../styles/layout.scss";
function Login() {
const [email, setEmail] = useState("");
const [pwd, setPwd] = useState("");
const [loginSuccess, setLoginSuccess] = useState(0);
const navigate = useNavigate();
const [userinfo, setUserinfo] = useState({
email: "",
password: "",
});
const handleSubmit = (e) => {
useEffect(() => {
if (localStorage.key("user-token")) {
navigate("/", { replace: true });
}
}, [loginSuccess, setLoginSuccess, navigate]);
const onChange = (e) => {
setUserinfo((orgState) => ({
...orgState,
[e.target.id]: e.target.value,
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
handleLogin(email, pwd);
const answer = await authService.handleLogin(userinfo);
setLoginSuccess(answer);
};
return (
<div className="container">
<h1>Welcome back to Weather-Chatbot/Messanger!</h1>
<h2>Stay connected with weather/friends all the time</h2>
<h1>Welcome back!</h1>
<h2>Stay connected to weather*stories*friends</h2>
<button>Login with Google</button>
<button>Login with GitHub</button>
......@@ -24,20 +45,20 @@ function Login() {
<form className="authForm" onSubmit={(e) => handleSubmit(e)}>
<label htmlFor="email">
email:{" "}
<input
onChange={(e) => setEmail(e.target.value)}
value={email}
type="text"
placeholder="email"
onChange={(e) => onChange(e)}
value={userinfo.email}
type="email"
id="email"
/>
</label>
<label htmlFor="password">
password:{" "}
<input
onChange={(e) => setPwd(e.target.value)}
value={pwd}
type="text"
placeholder="password"
onChange={(e) => onChange(e)}
value={userinfo.password}
type="password"
id="password"
/>
</label>
......
import { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import authService from "../service/auth";
// styles
import "../styles/layout.scss";
function Signup() {
const handleSubmit = (e) => {
const navigate = useNavigate();
const [signupSuccess, setSignupSuccess] = useState(0);
const [userinfo, setUserInfo] = useState({
username: "",
country: "",
email: "",
password: "",
});
useEffect(() => {
if (localStorage.key("user-token")) {
navigate("/", { replace: true });
}
}, [signupSuccess, setSignupSuccess, navigate]);
const onChange = (e) => {
setUserInfo((orgState) => ({
...orgState,
[e.target.id]: e.target.value,
}));
};
const handleSubmit = async (e) => {
e.preventDefault();
console.log("signup form submit called");
const answer = await authService.handleSignup(userinfo);
setSignupSuccess(answer);
};
return (
<div className="container">
<h1>Welcome to Weather-Chatbot/Messanger!</h1>
<h2>Stay connected with weather/friends all the time</h2>
<h1>Welcome to WeatherAPP/twitter/Messanger!</h1>
<h2>Stay connected to weather*stories*friends</h2>
<button>Create account with Google</button>
<button>Create account with GitHub</button>
......@@ -18,14 +46,42 @@ function Signup() {
<form className="authForm" onSubmit={(e) => handleSubmit(e)}>
<label htmlFor="username">
username: <input type="text" id="username" />
<input
placeholder="username"
onChange={(e) => onChange(e)}
value={userinfo.username}
type="text"
id="username"
/>
</label>
<label htmlFor="country">
<input
placeholder="Please use Alpha-2 Country Code"
onChange={(e) => onChange(e)}
value={userinfo.country}
type="text"
id="country"
/>
</label>
<label htmlFor="email">
email: <input type="text" id="email" />
<input
placeholder="email"
onChange={(e) => onChange(e)}
value={userinfo.email}
type="email"
id="email"
/>
</label>
<label htmlFor="password">
password: <input type="text" id="password" />
<input
placeholder="password"
onChange={(e) => onChange(e)}
value={userinfo.password}
type="password"
id="password"
/>
</label>
<label htmlFor="submit">
<input type="submit" id="submit" />
</label>
......
......@@ -8,12 +8,6 @@ import UserBox from "../components/UserBox";
const Userroom = () => {
const [users, setUsers] = useState(null);
useEffect(() => {
axios.get("/api/users/all/").then((response) => {
setUsers(response.data);
});
}, []);
if (!users) return null;
return (
......
const axios = require("axios").default;
export const handleLogin = (email, password) => {
console.log(email, password);
axios
.post("http://localhost:8000/api/login", {
const handleSignup = async ({ username, country, email, password }) => {
try {
const response = await axios.post("http://localhost:8080/api/users", {
username,
country,
email,
password,
})
.then(function (response) {
console.log("login request sent");
console.log(response);
})
.catch(function (err) {
console.log(err);
});
if (response.data) {
console.log("signup request sent...");
localStorage.setItem("user-token", JSON.stringify(response.data));
return "success";
}
} catch (err) {
console.log(err);
}
};
const handleLogin = async ({ email, password }) => {
try {
const response = await axios.post("http://localhost:8080/api/users/login", {
email,
password,
});
if (response.data) {
console.log("signin request sent...");
localStorage.setItem("user-token", JSON.stringify(response.data));
return "success";
}
} catch (err) {
console.log(err);
}
};
const authService = {
handleSignup,
handleLogin,
};
export default authService;
......
......@@ -6,9 +6,15 @@
.container {
display: flex;
flex-direction: column;
margin-left: 0.5rem;
margin-right: 0.5rem;
}
.authForm {
display: flex;
flex-direction: column;
input {
width: 100%;
}
}
......
const mongoose = require("mongoose");
const colors = require("colors");
const connectDB = async () => {
try {
const conn = await mongoose.connect(process.env.MONGO_URI);
console.log(`MongoDB Connected: ${conn.connection.host}`.cyan.underline);
} catch (error) {
console.log(
`Error occured while connecting to the mongoDB`.magenta.underline
);
console.log(error);
process.exit(1);
}
};
module.exports = connectDB;
const jwt = require("jsonwebtoken");
const jwtGenerator = (id) => {
// https://github.com/auth0/node-jsonwebtoken
const token = jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: "2 days",
});
return token;
};
module.exports = { jwtGenerator };
const jwt = require("jsonwebtoken");
const asyncHandler = require("express-async-handler");
const User = require("../models/userModel");
const authHandler = asyncHandler(async (req, res, next) => {
// Check if token exists
if (!req.headers.authorization) {
res.status(401);
throw new Error("Not authorized");
}
// Evaluate the token
const token = req.headers.authorization.split(" ")[1];
const decoded = jwt.verify(
token,
process.env.JWT_SECRET,
function (err, decoded) {
if (err) {
res.status(401);
throw new Error("Not authorized");
}
return decoded;
}
);
const user = await User.findById(decoded.id).select("-password");
req.user = user;
return next();
});
module.exports = { authHandler };
const errorHandler = (err, req, res, next) => {
const statusCode = res.statusCode ? res.statusCode : 500;
res.status(statusCode);
res.json({
message: err.message,
// stack from mongoDB TODO: Check it!
stack: process.env.NODE_ENV === "production" ? null : err.stack,
});
};
module.exports = {
errorHandler,
};
const mongoose = require("mongoose");
const chatroomSchema = mongoose.Schema(
{
roomName: {
type: String,
required: [true, "Please add chatroom name"],
},
participants: [
{
user: {
type: String,
required: [true, "Please add participants"],
},
},
],
messages: [],
},
{
timestamps: true,
}
);
module.exports = mongoose.model("Chatroom", chatroomSchema);
const mongoose = require("mongoose");
const userSchema = mongoose.Schema(
{
username: {
type: String,
required: [true, "Please add a username"],
},
email: {
type: String,
required: [true, "Please add a email"],
},
password: {
type: String,
required: [true, "Please add a password"],
},
},
{
timestamps: true,
}
);
module.exports = mongoose.model("User", userSchema);
This diff could not be displayed because it is too large.
{
"name": "weather_chatbot",
"version": "1.0.0",
"description": "web-app weather chatbot",
"main": "server.js",
"scripts": {
"start": "node server.js",
"server": "nodemon server.js",
"client": "npm start --prefix client",
"dev": "concurrently \"npm run client\" \"npm run server\""
},
"repository": {
"type": "git",
"url": "http://khuhub.khu.ac.kr/2019102244/weather_chatbot.git"
},
"author": "황선혁",
"license": "MIT",
"dependencies": {
"bcryptjs": "^2.4.3",
"colors": "^1.4.0",
"dotenv": "^16.0.1",
"express": "^4.18.1",
"express-async-handler": "^1.2.0",
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.3.4"
},
"devDependencies": {
"concurrently": "^7.2.1",
"nodemon": "^2.0.16"
}
}
const express = require("express");
const router = express.Router();
const { createChatroom, delChatroom } = require("../actions/chatroomActions");
const { authHandler } = require("../middleware/authMiddleware");
router.post("/", authHandler, createChatroom);
router.delete("/", authHandler, delChatroom);
// router.post("/message", authHandler, sendMessage);
module.exports = router;
const express = require("express");
const router = express.Router();
const {
signupUser,
loginUser,
getAllusers,
getSelf,
} = require("../actions/userActions");
const { authHandler } = require("../middleware/authMiddleware");
router.post("/", signupUser);
router.post("/login", loginUser);
router.get("/all", getAllusers);
router.get("/self", authHandler, getSelf);
module.exports = router;
const express = require("express");
const dotenv = require("dotenv").config();
const { errorHandler } = require("./middleware/errorMiddleware");
const connectDB = require("./config/db");
const port = process.env.PORT || 6000;
connectDB();
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/api/users", require("./routes/userRoutes"));
app.use("/api/chats", require("./routes/chatroomRoutes"));
app.use(errorHandler);
app.listen(port, () => {
console.log(`Server started on port ${port}`);
});
const asyncHandler = require("express-async-handler");
// @desc Create chatroom
// @route POST /api/chats
// @access Private
const createChatroom = asyncHandler(async (req, res) => {
return;
});
// @desc Delete chatroom
// @route DELETE /api/chats
// @access Private
const delChatroom = asyncHandler(async (req, res) => {
return;
});
module.exports = {
createChatroom,
delChatroom,
};
......@@ -8,10 +8,10 @@ const { jwtGenerator } = require("../config/jwt");
// @route POST /api/users
// @access Public
const signupUser = asyncHandler(async (req, res) => {
const { username, email, password } = req.body;
const { username, country, email, password } = req.body;
if (!username || !email || !password) {
res.status(400);
throw new Error("Please fill in all fields");
throw new Error("Please fill in required fields");
}
// Check if user already exists
......@@ -28,6 +28,7 @@ const signupUser = asyncHandler(async (req, res) => {
// Create/Build user
const user = await User.create({
username,
country,
email,
password: hashedPassword,
});
......@@ -38,6 +39,7 @@ const signupUser = asyncHandler(async (req, res) => {
res.status(201).json({
_id: user.id,
username: user.username,
country: user.country,
email: user.email,
token: jwtGenerator(user._id),
});
......@@ -58,9 +60,6 @@ const loginUser = asyncHandler(async (req, res) => {
const validPassword = await bcrypt.compare(password, userInDB.password);
if (userInDB && validPassword) {
res.status(200).json({
_id: userInDB.id,
username: userInDB.username,
email: userInDB.email,
token: jwtGenerator(userInDB._id),
});
} else {
......@@ -75,7 +74,6 @@ const loginUser = asyncHandler(async (req, res) => {
const getAllusers = asyncHandler(async (req, res) => {
const users = await User.find()
.select("-password")
.select("-updatedAt")
.select("-createdAt")
.select("-email");
......
......@@ -6,6 +6,10 @@ const userSchema = mongoose.Schema(
type: String,
required: [true, "Please add a username"],
},
country: {
type: String,
required: false,
},
email: {
type: String,
required: [true, "Please add a email"],
......
const express = require("express");
const router = express.Router();
const { createChatroom, delChatroom } = require("../actions/chatroomActions");
const { authHandler } = require("../middleware/authMiddleware");
// "/api/rooms/"
router.post("/", authHandler, createChatroom);
router.delete("/", authHandler, delChatroom);
// router.post("/message", authHandler, sendMessage);
module.exports = router;
......@@ -11,7 +11,7 @@ const { authHandler } = require("../middleware/authMiddleware");
// "/api/users/"
router.post("/", signupUser);
router.post("/login", loginUser);
router.get("/all", getAllusers);
router.get("/all", authHandler, getAllusers);
router.get("/self", authHandler, getSelf);
module.exports = router;
......
const express = require("express");
const dotenv = require("dotenv").config();
const { errorHandler } = require("./middleware/errorMiddleware");
const { createServer } = require("http");
const { Server } = require("socket.io");
const cors = require("cors");
const { errorHandler } = require("./middleware/errorMiddleware");
const connectDB = require("./config/db");
const port = process.env.PORT || 8080;
connectDB();
const app = express();
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use("/api/users", require("./routes/userRoutes"));
app.use("/api/rooms", require("./routes/chatroomRoutes"));
// chatbot
app.use(cors());
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: "http://localhost:3000/",
methods: ["GET", "POST"],
},
});
io.on("connection", (socket) => {
console.log(`User Connected: ${socket.id}`);
socket.on("join_room", (data) => {
socket.join(data);
});
socket.on("send_message", (data) => {
socket.to(data.room).emit("receive_message", data);
});
});
app.use(errorHandler);
......