Eric Whale

Build login/signup

1 -MIT License
2 -
3 -Copyright (c) 2022 HWANG SUN HYUK
4 -
5 -Permission is hereby granted, free of charge, to any person obtaining a copy
6 -of this software and associated documentation files (the "Software"), to deal
7 -in the Software without restriction, including without limitation the rights
8 -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 -copies of the Software, and to permit persons to whom the Software is
10 -furnished to do so, subject to the following conditions:
11 -
12 -The above copyright notice and this permission notice shall be included in all
13 -copies or substantial portions of the Software.
14 -
15 -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 -FITNESSFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 -SOFTWARE.
1 -const asyncHandler = require("express-async-handler");
2 -
3 -// @desc Create chatroom
4 -// @route POST /api/chats
5 -// @access Private
6 -const createChatroom = asyncHandler(async (req, res) => {
7 - return;
8 -});
9 -
10 -// @desc Delete chatroom
11 -// @route DELETE /api/chats
12 -// @access Private
13 -const delChatroom = asyncHandler(async (req, res) => {
14 - return;
15 -});
16 -
17 -module.exports = {
18 - createChatroom,
19 - delChatroom,
20 -};
1 -const bcrypt = require("bcryptjs");
2 -// handles "exception" inside of async express routes
3 -const asyncHandler = require("express-async-handler");
4 -const User = require("../models/userModel");
5 -const { jwtGenerator } = require("../config/jwt");
6 -
7 -// @desc Signup new user
8 -// @route POST /api/users
9 -// @access Public
10 -const signupUser = asyncHandler(async (req, res) => {
11 - const { username, email, password } = req.body;
12 - if (!username || !email || !password) {
13 - res.status(400);
14 - throw new Error("Please fill in all fields");
15 - }
16 -
17 - // Check if user already exists
18 - const userExists = await User.findOne({ email });
19 - if (userExists) {
20 - res.status(400);
21 - throw new Error("User with the email already exists");
22 - }
23 -
24 - // Hash password (bcrypt)
25 - const salt = await bcrypt.genSalt(10);
26 - const hashedPassword = await bcrypt.hash(password, salt);
27 -
28 - // Create/Build user
29 - const user = await User.create({
30 - username,
31 - email,
32 - password: hashedPassword,
33 - });
34 -
35 - // Send response
36 - if (user) {
37 - // 201: Resource successfully created
38 - res.status(201).json({
39 - _id: user.id,
40 - username: user.username,
41 - email: user.email,
42 - token: jwtGenerator(user._id),
43 - });
44 - } else {
45 - res.status(400);
46 - throw new Error("Invalid user data");
47 - }
48 -});
49 -
50 -// @desc Login user
51 -// @route POST /api/users/login
52 -// @access Public
53 -const loginUser = asyncHandler(async (req, res) => {
54 - const { email, password } = req.body;
55 -
56 - // Check email & password
57 - const userInDB = await User.findOne({ email });
58 - const validPassword = await bcrypt.compare(password, userInDB.password);
59 - if (userInDB && validPassword) {
60 - res.status(200).json({
61 - _id: userInDB.id,
62 - username: userInDB.username,
63 - email: userInDB.email,
64 - token: jwtGenerator(userInDB._id),
65 - });
66 - } else {
67 - res.status(400);
68 - throw new Error("Invalid credentials");
69 - }
70 -});
71 -
72 -// @desc Get all users
73 -// @route GET /api/users/all
74 -// @access Public
75 -const getAllusers = asyncHandler(async (req, res) => {
76 - const users = await User.find()
77 - .select("-password")
78 - .select("-updatedAt")
79 - .select("-createdAt")
80 - .select("-email");
81 -
82 - res.status(200).json(users);
83 -});
84 -
85 -// @desc Get user
86 -// @route GET /api/users/self
87 -// @access Private
88 -const getSelf = asyncHandler(async (req, res) => {
89 - res.status(200).json(req.user);
90 -});
91 -
92 -module.exports = {
93 - signupUser,
94 - loginUser,
95 - getAllusers,
96 - getSelf,
97 -};
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
17 "react-router-dom": "^6.3.0", 17 "react-router-dom": "^6.3.0",
18 "react-scripts": "5.0.1", 18 "react-scripts": "5.0.1",
19 "sass": "^1.51.0", 19 "sass": "^1.51.0",
20 + "socket.io-client": "^4.5.1",
20 "web-vitals": "^2.1.4" 21 "web-vitals": "^2.1.4"
21 } 22 }
22 }, 23 },
...@@ -2994,6 +2995,11 @@ ...@@ -2994,6 +2995,11 @@
2994 "@sinonjs/commons": "^1.7.0" 2995 "@sinonjs/commons": "^1.7.0"
2995 } 2996 }
2996 }, 2997 },
2998 + "node_modules/@socket.io/component-emitter": {
2999 + "version": "3.1.0",
3000 + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
3001 + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
3002 + },
2997 "node_modules/@surma/rollup-plugin-off-main-thread": { 3003 "node_modules/@surma/rollup-plugin-off-main-thread": {
2998 "version": "2.2.3", 3004 "version": "2.2.3",
2999 "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", 3005 "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
...@@ -6343,6 +6349,46 @@ ...@@ -6343,6 +6349,46 @@
6343 "node": ">= 0.8" 6349 "node": ">= 0.8"
6344 } 6350 }
6345 }, 6351 },
6352 + "node_modules/engine.io-client": {
6353 + "version": "6.2.2",
6354 + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz",
6355 + "integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==",
6356 + "dependencies": {
6357 + "@socket.io/component-emitter": "~3.1.0",
6358 + "debug": "~4.3.1",
6359 + "engine.io-parser": "~5.0.3",
6360 + "ws": "~8.2.3",
6361 + "xmlhttprequest-ssl": "~2.0.0"
6362 + }
6363 + },
6364 + "node_modules/engine.io-client/node_modules/ws": {
6365 + "version": "8.2.3",
6366 + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
6367 + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
6368 + "engines": {
6369 + "node": ">=10.0.0"
6370 + },
6371 + "peerDependencies": {
6372 + "bufferutil": "^4.0.1",
6373 + "utf-8-validate": "^5.0.2"
6374 + },
6375 + "peerDependenciesMeta": {
6376 + "bufferutil": {
6377 + "optional": true
6378 + },
6379 + "utf-8-validate": {
6380 + "optional": true
6381 + }
6382 + }
6383 + },
6384 + "node_modules/engine.io-parser": {
6385 + "version": "5.0.4",
6386 + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
6387 + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==",
6388 + "engines": {
6389 + "node": ">=10.0.0"
6390 + }
6391 + },
6346 "node_modules/enhanced-resolve": { 6392 "node_modules/enhanced-resolve": {
6347 "version": "5.9.3", 6393 "version": "5.9.3",
6348 "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", 6394 "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz",
...@@ -14348,6 +14394,32 @@ ...@@ -14348,6 +14394,32 @@
14348 "node": ">=8" 14394 "node": ">=8"
14349 } 14395 }
14350 }, 14396 },
14397 + "node_modules/socket.io-client": {
14398 + "version": "4.5.1",
14399 + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz",
14400 + "integrity": "sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==",
14401 + "dependencies": {
14402 + "@socket.io/component-emitter": "~3.1.0",
14403 + "debug": "~4.3.2",
14404 + "engine.io-client": "~6.2.1",
14405 + "socket.io-parser": "~4.2.0"
14406 + },
14407 + "engines": {
14408 + "node": ">=10.0.0"
14409 + }
14410 + },
14411 + "node_modules/socket.io-parser": {
14412 + "version": "4.2.0",
14413 + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.0.tgz",
14414 + "integrity": "sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng==",
14415 + "dependencies": {
14416 + "@socket.io/component-emitter": "~3.1.0",
14417 + "debug": "~4.3.1"
14418 + },
14419 + "engines": {
14420 + "node": ">=10.0.0"
14421 + }
14422 + },
14351 "node_modules/sockjs": { 14423 "node_modules/sockjs": {
14352 "version": "0.3.24", 14424 "version": "0.3.24",
14353 "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", 14425 "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
...@@ -16272,6 +16344,14 @@ ...@@ -16272,6 +16344,14 @@
16272 "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", 16344 "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
16273 "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" 16345 "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
16274 }, 16346 },
16347 + "node_modules/xmlhttprequest-ssl": {
16348 + "version": "2.0.0",
16349 + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
16350 + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
16351 + "engines": {
16352 + "node": ">=0.4.0"
16353 + }
16354 + },
16275 "node_modules/xtend": { 16355 "node_modules/xtend": {
16276 "version": "4.0.2", 16356 "version": "4.0.2",
16277 "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 16357 "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
...@@ -18356,6 +18436,11 @@ ...@@ -18356,6 +18436,11 @@
18356 "@sinonjs/commons": "^1.7.0" 18436 "@sinonjs/commons": "^1.7.0"
18357 } 18437 }
18358 }, 18438 },
18439 + "@socket.io/component-emitter": {
18440 + "version": "3.1.0",
18441 + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
18442 + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
18443 + },
18359 "@surma/rollup-plugin-off-main-thread": { 18444 "@surma/rollup-plugin-off-main-thread": {
18360 "version": "2.2.3", 18445 "version": "2.2.3",
18361 "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", 18446 "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
...@@ -20831,6 +20916,31 @@ ...@@ -20831,6 +20916,31 @@
20831 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 20916 "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
20832 "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 20917 "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
20833 }, 20918 },
20919 + "engine.io-client": {
20920 + "version": "6.2.2",
20921 + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz",
20922 + "integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==",
20923 + "requires": {
20924 + "@socket.io/component-emitter": "~3.1.0",
20925 + "debug": "~4.3.1",
20926 + "engine.io-parser": "~5.0.3",
20927 + "ws": "~8.2.3",
20928 + "xmlhttprequest-ssl": "~2.0.0"
20929 + },
20930 + "dependencies": {
20931 + "ws": {
20932 + "version": "8.2.3",
20933 + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz",
20934 + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==",
20935 + "requires": {}
20936 + }
20937 + }
20938 + },
20939 + "engine.io-parser": {
20940 + "version": "5.0.4",
20941 + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz",
20942 + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg=="
20943 + },
20834 "enhanced-resolve": { 20944 "enhanced-resolve": {
20835 "version": "5.9.3", 20945 "version": "5.9.3",
20836 "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", 20946 "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz",
...@@ -26485,6 +26595,26 @@ ...@@ -26485,6 +26595,26 @@
26485 "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", 26595 "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
26486 "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" 26596 "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
26487 }, 26597 },
26598 + "socket.io-client": {
26599 + "version": "4.5.1",
26600 + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz",
26601 + "integrity": "sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==",
26602 + "requires": {
26603 + "@socket.io/component-emitter": "~3.1.0",
26604 + "debug": "~4.3.2",
26605 + "engine.io-client": "~6.2.1",
26606 + "socket.io-parser": "~4.2.0"
26607 + }
26608 + },
26609 + "socket.io-parser": {
26610 + "version": "4.2.0",
26611 + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.0.tgz",
26612 + "integrity": "sha512-tLfmEwcEwnlQTxFB7jibL/q2+q8dlVQzj4JdRLJ/W/G1+Fu9VSxCx1Lo+n1HvXxKnM//dUuD0xgiA7tQf57Vng==",
26613 + "requires": {
26614 + "@socket.io/component-emitter": "~3.1.0",
26615 + "debug": "~4.3.1"
26616 + }
26617 + },
26488 "sockjs": { 26618 "sockjs": {
26489 "version": "0.3.24", 26619 "version": "0.3.24",
26490 "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", 26620 "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
...@@ -27965,6 +28095,11 @@ ...@@ -27965,6 +28095,11 @@
27965 "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", 28095 "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
27966 "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" 28096 "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
27967 }, 28097 },
28098 + "xmlhttprequest-ssl": {
28099 + "version": "2.0.0",
28100 + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
28101 + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A=="
28102 + },
27968 "xtend": { 28103 "xtend": {
27969 "version": "4.0.2", 28104 "version": "4.0.2",
27970 "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 28105 "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
......
1 { 1 {
2 "name": "client", 2 "name": "client",
3 "version": "0.1.0", 3 "version": "0.1.0",
4 - "proxy": "http://localhost:6000",
5 "private": true, 4 "private": true,
6 "dependencies": { 5 "dependencies": {
7 "@testing-library/jest-dom": "^5.16.4", 6 "@testing-library/jest-dom": "^5.16.4",
...@@ -13,6 +12,7 @@ ...@@ -13,6 +12,7 @@
13 "react-router-dom": "^6.3.0", 12 "react-router-dom": "^6.3.0",
14 "react-scripts": "5.0.1", 13 "react-scripts": "5.0.1",
15 "sass": "^1.51.0", 14 "sass": "^1.51.0",
15 + "socket.io-client": "^4.5.1",
16 "web-vitals": "^2.1.4" 16 "web-vitals": "^2.1.4"
17 }, 17 },
18 "scripts": { 18 "scripts": {
...@@ -22,17 +22,10 @@ ...@@ -22,17 +22,10 @@
22 "eject": "react-scripts eject" 22 "eject": "react-scripts eject"
23 }, 23 },
24 "eslintConfig": { 24 "eslintConfig": {
25 - "extends": [ 25 + "extends": ["react-app", "react-app/jest"]
26 - "react-app",
27 - "react-app/jest"
28 - ]
29 }, 26 },
30 "browserslist": { 27 "browserslist": {
31 - "production": [ 28 + "production": [">0.2%", "not dead", "not op_mini all"],
32 - ">0.2%",
33 - "not dead",
34 - "not op_mini all"
35 - ],
36 "development": [ 29 "development": [
37 "last 1 chrome version", 30 "last 1 chrome version",
38 "last 1 firefox version", 31 "last 1 firefox version",
......
1 +// Weather broadcasting page
1 import axios from "axios"; 2 import axios from "axios";
2 import { useState, useEffect } from "react"; 3 import { useState, useEffect } from "react";
3 // components 4 // components
...@@ -8,36 +9,25 @@ import ChatroomBox from "./components/ChatroomBox"; ...@@ -8,36 +9,25 @@ import ChatroomBox from "./components/ChatroomBox";
8 function App() { 9 function App() {
9 const [chats, setChats] = useState(null); 10 const [chats, setChats] = useState(null);
10 11
11 - useEffect(() => { 12 + useEffect(() => {}, []);
12 - axios.get("/api/chat").then((response) => {
13 - setChats(response.data);
14 - });
15 - }, []);
16 13
17 return ( 14 return (
18 <div> 15 <div>
19 <Topbar /> 16 <Topbar />
20 <h1>Chatroom page</h1> 17 <h1>Chatroom page</h1>
21 - <div> 18 + <div></div>
22 - <div>Weather Chatbot</div>
23 - <div>Weather Chatbot</div>
24 - <div>Weather Chatbot</div>
25 - </div>
26 19
27 - <br />
28 -
29 - <div>
30 - {Array.isArray(chats) ? (
31 - chats.map((chat, i) => {
32 - return <ChatroomBox key={i} chat={chat} />;
33 - })
34 - ) : (
35 - <h2>No chatting room!</h2>
36 - )}
37 - </div>
38 <Bottombar /> 20 <Bottombar />
39 </div> 21 </div>
40 ); 22 );
41 } 23 }
42 24
43 export default App; 25 export default App;
26 +
27 +// {Array.isArray(chats) ? (
28 +// chats.map((chat, i) => {
29 +// return <ChatroomBox key={i} chat={chat} />;
30 +// })
31 +// ) : (
32 +// <h2>No chatting room!</h2>
33 +// )}
......
...@@ -14,15 +14,17 @@ import "./styles/layout.scss"; ...@@ -14,15 +14,17 @@ import "./styles/layout.scss";
14 const root = ReactDOM.createRoot(document.getElementById("root")); 14 const root = ReactDOM.createRoot(document.getElementById("root"));
15 15
16 root.render( 16 root.render(
17 - <BrowserRouter> 17 + <div className="container">
18 - <Routes> 18 + <BrowserRouter>
19 - <Route path="/" element={<App />} /> 19 + <Routes>
20 - <Route path="/login" element={<Login />} /> 20 + <Route exact path="/" element={<App />} />
21 - <Route path="/signup" element={<Signup />} /> 21 + <Route exact path="/login" element={<Login />} />
22 - <Route path="/userroom" element={<Userroom />} /> 22 + <Route exact path="/signup" element={<Signup />} />
23 - <Route path="/settings" element={<Settings />} /> 23 + <Route exact path="/userroom" element={<Userroom />} />
24 - </Routes> 24 + <Route exact path="/settings" element={<Settings />} />
25 - </BrowserRouter> 25 + </Routes>
26 + </BrowserRouter>
27 + </div>
26 ); 28 );
27 29
28 // If you want to start measuring performance in your app, pass a function 30 // If you want to start measuring performance in your app, pass a function
......
1 import { Link } from "react-router-dom"; 1 import { Link } from "react-router-dom";
2 -import { useState } from "react"; 2 +import { useEffect, useState } from "react";
3 +import { useNavigate } from "react-router-dom";
3 // lib 4 // lib
4 -import { handleLogin } from "../service/auth"; 5 +import authService from "../service/auth";
6 +// styles
7 +import "../styles/layout.scss";
5 8
6 function Login() { 9 function Login() {
7 - const [email, setEmail] = useState(""); 10 + const [loginSuccess, setLoginSuccess] = useState(0);
8 - const [pwd, setPwd] = useState(""); 11 + const navigate = useNavigate();
12 + const [userinfo, setUserinfo] = useState({
13 + email: "",
14 + password: "",
15 + });
9 16
10 - const handleSubmit = (e) => { 17 + useEffect(() => {
18 + if (localStorage.key("user-token")) {
19 + navigate("/", { replace: true });
20 + }
21 + }, [loginSuccess, setLoginSuccess, navigate]);
22 +
23 + const onChange = (e) => {
24 + setUserinfo((orgState) => ({
25 + ...orgState,
26 + [e.target.id]: e.target.value,
27 + }));
28 + };
29 +
30 + const handleSubmit = async (e) => {
11 e.preventDefault(); 31 e.preventDefault();
12 - handleLogin(email, pwd); 32 + const answer = await authService.handleLogin(userinfo);
33 + setLoginSuccess(answer);
13 }; 34 };
14 35
15 return ( 36 return (
16 <div className="container"> 37 <div className="container">
17 - <h1>Welcome back to Weather-Chatbot/Messanger!</h1> 38 + <h1>Welcome back!</h1>
18 - <h2>Stay connected with weather/friends all the time</h2> 39 + <h2>Stay connected to weather*stories*friends</h2>
19 40
20 <button>Login with Google</button> 41 <button>Login with Google</button>
21 <button>Login with GitHub</button> 42 <button>Login with GitHub</button>
...@@ -24,20 +45,20 @@ function Login() { ...@@ -24,20 +45,20 @@ function Login() {
24 45
25 <form className="authForm" onSubmit={(e) => handleSubmit(e)}> 46 <form className="authForm" onSubmit={(e) => handleSubmit(e)}>
26 <label htmlFor="email"> 47 <label htmlFor="email">
27 - email:{" "}
28 <input 48 <input
29 - onChange={(e) => setEmail(e.target.value)} 49 + placeholder="email"
30 - value={email} 50 + onChange={(e) => onChange(e)}
31 - type="text" 51 + value={userinfo.email}
52 + type="email"
32 id="email" 53 id="email"
33 /> 54 />
34 </label> 55 </label>
35 <label htmlFor="password"> 56 <label htmlFor="password">
36 - password:{" "}
37 <input 57 <input
38 - onChange={(e) => setPwd(e.target.value)} 58 + placeholder="password"
39 - value={pwd} 59 + onChange={(e) => onChange(e)}
40 - type="text" 60 + value={userinfo.password}
61 + type="password"
41 id="password" 62 id="password"
42 /> 63 />
43 </label> 64 </label>
......
1 +import { useState, useEffect } from "react";
1 import { Link } from "react-router-dom"; 2 import { Link } from "react-router-dom";
3 +import { useNavigate } from "react-router-dom";
4 +import authService from "../service/auth";
5 +// styles
6 +import "../styles/layout.scss";
2 7
3 function Signup() { 8 function Signup() {
4 - const handleSubmit = (e) => { 9 + const navigate = useNavigate();
10 + const [signupSuccess, setSignupSuccess] = useState(0);
11 + const [userinfo, setUserInfo] = useState({
12 + username: "",
13 + country: "",
14 + email: "",
15 + password: "",
16 + });
17 +
18 + useEffect(() => {
19 + if (localStorage.key("user-token")) {
20 + navigate("/", { replace: true });
21 + }
22 + }, [signupSuccess, setSignupSuccess, navigate]);
23 +
24 + const onChange = (e) => {
25 + setUserInfo((orgState) => ({
26 + ...orgState,
27 + [e.target.id]: e.target.value,
28 + }));
29 + };
30 +
31 + const handleSubmit = async (e) => {
5 e.preventDefault(); 32 e.preventDefault();
6 - console.log("signup form submit called"); 33 + const answer = await authService.handleSignup(userinfo);
34 + setSignupSuccess(answer);
7 }; 35 };
8 36
9 return ( 37 return (
10 <div className="container"> 38 <div className="container">
11 - <h1>Welcome to Weather-Chatbot/Messanger!</h1> 39 + <h1>Welcome to WeatherAPP/twitter/Messanger!</h1>
12 - <h2>Stay connected with weather/friends all the time</h2> 40 + <h2>Stay connected to weather*stories*friends</h2>
13 41
14 <button>Create account with Google</button> 42 <button>Create account with Google</button>
15 <button>Create account with GitHub</button> 43 <button>Create account with GitHub</button>
...@@ -18,14 +46,42 @@ function Signup() { ...@@ -18,14 +46,42 @@ function Signup() {
18 46
19 <form className="authForm" onSubmit={(e) => handleSubmit(e)}> 47 <form className="authForm" onSubmit={(e) => handleSubmit(e)}>
20 <label htmlFor="username"> 48 <label htmlFor="username">
21 - username: <input type="text" id="username" /> 49 + <input
50 + placeholder="username"
51 + onChange={(e) => onChange(e)}
52 + value={userinfo.username}
53 + type="text"
54 + id="username"
55 + />
56 + </label>
57 + <label htmlFor="country">
58 + <input
59 + placeholder="Please use Alpha-2 Country Code"
60 + onChange={(e) => onChange(e)}
61 + value={userinfo.country}
62 + type="text"
63 + id="country"
64 + />
22 </label> 65 </label>
23 <label htmlFor="email"> 66 <label htmlFor="email">
24 - email: <input type="text" id="email" /> 67 + <input
68 + placeholder="email"
69 + onChange={(e) => onChange(e)}
70 + value={userinfo.email}
71 + type="email"
72 + id="email"
73 + />
25 </label> 74 </label>
26 <label htmlFor="password"> 75 <label htmlFor="password">
27 - password: <input type="text" id="password" /> 76 + <input
77 + placeholder="password"
78 + onChange={(e) => onChange(e)}
79 + value={userinfo.password}
80 + type="password"
81 + id="password"
82 + />
28 </label> 83 </label>
84 +
29 <label htmlFor="submit"> 85 <label htmlFor="submit">
30 <input type="submit" id="submit" /> 86 <input type="submit" id="submit" />
31 </label> 87 </label>
......
...@@ -8,12 +8,6 @@ import UserBox from "../components/UserBox"; ...@@ -8,12 +8,6 @@ import UserBox from "../components/UserBox";
8 const Userroom = () => { 8 const Userroom = () => {
9 const [users, setUsers] = useState(null); 9 const [users, setUsers] = useState(null);
10 10
11 - useEffect(() => {
12 - axios.get("/api/users/all/").then((response) => {
13 - setUsers(response.data);
14 - });
15 - }, []);
16 -
17 if (!users) return null; 11 if (!users) return null;
18 12
19 return ( 13 return (
......
1 const axios = require("axios").default; 1 const axios = require("axios").default;
2 2
3 -export const handleLogin = (email, password) => { 3 +const handleSignup = async ({ username, country, email, password }) => {
4 - console.log(email, password); 4 + try {
5 - axios 5 + const response = await axios.post("http://localhost:8080/api/users", {
6 - .post("http://localhost:8000/api/login", { 6 + username,
7 + country,
7 email, 8 email,
8 password, 9 password,
9 - })
10 - .then(function (response) {
11 - console.log("login request sent");
12 - console.log(response);
13 - })
14 - .catch(function (err) {
15 - console.log(err);
16 }); 10 });
11 + if (response.data) {
12 + console.log("signup request sent...");
13 + localStorage.setItem("user-token", JSON.stringify(response.data));
14 + return "success";
15 + }
16 + } catch (err) {
17 + console.log(err);
18 + }
17 }; 19 };
20 +
21 +const handleLogin = async ({ email, password }) => {
22 + try {
23 + const response = await axios.post("http://localhost:8080/api/users/login", {
24 + email,
25 + password,
26 + });
27 + if (response.data) {
28 + console.log("signin request sent...");
29 + localStorage.setItem("user-token", JSON.stringify(response.data));
30 + return "success";
31 + }
32 + } catch (err) {
33 + console.log(err);
34 + }
35 +};
36 +
37 +const authService = {
38 + handleSignup,
39 + handleLogin,
40 +};
41 +
42 +export default authService;
......
...@@ -6,9 +6,15 @@ ...@@ -6,9 +6,15 @@
6 .container { 6 .container {
7 display: flex; 7 display: flex;
8 flex-direction: column; 8 flex-direction: column;
9 + margin-left: 0.5rem;
10 + margin-right: 0.5rem;
9 } 11 }
10 12
11 .authForm { 13 .authForm {
12 display: flex; 14 display: flex;
13 flex-direction: column; 15 flex-direction: column;
16 +
17 + input {
18 + width: 100%;
19 + }
14 } 20 }
......
1 -const mongoose = require("mongoose");
2 -const colors = require("colors");
3 -
4 -const connectDB = async () => {
5 - try {
6 - const conn = await mongoose.connect(process.env.MONGO_URI);
7 - console.log(`MongoDB Connected: ${conn.connection.host}`.cyan.underline);
8 - } catch (error) {
9 - console.log(
10 - `Error occured while connecting to the mongoDB`.magenta.underline
11 - );
12 - console.log(error);
13 - process.exit(1);
14 - }
15 -};
16 -
17 -module.exports = connectDB;
1 -const jwt = require("jsonwebtoken");
2 -
3 -const jwtGenerator = (id) => {
4 - // https://github.com/auth0/node-jsonwebtoken
5 - const token = jwt.sign({ id }, process.env.JWT_SECRET, {
6 - expiresIn: "2 days",
7 - });
8 - return token;
9 -};
10 -
11 -module.exports = { jwtGenerator };
1 -const jwt = require("jsonwebtoken");
2 -const asyncHandler = require("express-async-handler");
3 -const User = require("../models/userModel");
4 -
5 -const authHandler = asyncHandler(async (req, res, next) => {
6 - // Check if token exists
7 - if (!req.headers.authorization) {
8 - res.status(401);
9 - throw new Error("Not authorized");
10 - }
11 -
12 - // Evaluate the token
13 - const token = req.headers.authorization.split(" ")[1];
14 - const decoded = jwt.verify(
15 - token,
16 - process.env.JWT_SECRET,
17 - function (err, decoded) {
18 - if (err) {
19 - res.status(401);
20 - throw new Error("Not authorized");
21 - }
22 - return decoded;
23 - }
24 - );
25 -
26 - const user = await User.findById(decoded.id).select("-password");
27 - req.user = user;
28 - return next();
29 -});
30 -
31 -module.exports = { authHandler };
1 -const errorHandler = (err, req, res, next) => {
2 - const statusCode = res.statusCode ? res.statusCode : 500;
3 -
4 - res.status(statusCode);
5 - res.json({
6 - message: err.message,
7 - // stack from mongoDB TODO: Check it!
8 - stack: process.env.NODE_ENV === "production" ? null : err.stack,
9 - });
10 -};
11 -
12 -module.exports = {
13 - errorHandler,
14 -};
1 -const mongoose = require("mongoose");
2 -
3 -const chatroomSchema = mongoose.Schema(
4 - {
5 - roomName: {
6 - type: String,
7 - required: [true, "Please add chatroom name"],
8 - },
9 - participants: [
10 - {
11 - user: {
12 - type: String,
13 - required: [true, "Please add participants"],
14 - },
15 - },
16 - ],
17 - messages: [],
18 - },
19 - {
20 - timestamps: true,
21 - }
22 -);
23 -
24 -module.exports = mongoose.model("Chatroom", chatroomSchema);
1 -const mongoose = require("mongoose");
2 -
3 -const userSchema = mongoose.Schema(
4 - {
5 - username: {
6 - type: String,
7 - required: [true, "Please add a username"],
8 - },
9 - email: {
10 - type: String,
11 - required: [true, "Please add a email"],
12 - },
13 - password: {
14 - type: String,
15 - required: [true, "Please add a password"],
16 - },
17 - },
18 - {
19 - timestamps: true,
20 - }
21 -);
22 -
23 -module.exports = mongoose.model("User", userSchema);
This diff could not be displayed because it is too large.
1 -{
2 - "name": "weather_chatbot",
3 - "version": "1.0.0",
4 - "description": "web-app weather chatbot",
5 - "main": "server.js",
6 - "scripts": {
7 - "start": "node server.js",
8 - "server": "nodemon server.js",
9 - "client": "npm start --prefix client",
10 - "dev": "concurrently \"npm run client\" \"npm run server\""
11 - },
12 - "repository": {
13 - "type": "git",
14 - "url": "http://khuhub.khu.ac.kr/2019102244/weather_chatbot.git"
15 - },
16 - "author": "황선혁",
17 - "license": "MIT",
18 - "dependencies": {
19 - "bcryptjs": "^2.4.3",
20 - "colors": "^1.4.0",
21 - "dotenv": "^16.0.1",
22 - "express": "^4.18.1",
23 - "express-async-handler": "^1.2.0",
24 - "jsonwebtoken": "^8.5.1",
25 - "mongoose": "^6.3.4"
26 - },
27 - "devDependencies": {
28 - "concurrently": "^7.2.1",
29 - "nodemon": "^2.0.16"
30 - }
31 -}
1 -const express = require("express");
2 -const router = express.Router();
3 -const { createChatroom, delChatroom } = require("../actions/chatroomActions");
4 -const { authHandler } = require("../middleware/authMiddleware");
5 -
6 -router.post("/", authHandler, createChatroom);
7 -router.delete("/", authHandler, delChatroom);
8 -// router.post("/message", authHandler, sendMessage);
9 -
10 -module.exports = router;
1 -const express = require("express");
2 -const router = express.Router();
3 -const {
4 - signupUser,
5 - loginUser,
6 - getAllusers,
7 - getSelf,
8 -} = require("../actions/userActions");
9 -const { authHandler } = require("../middleware/authMiddleware");
10 -
11 -router.post("/", signupUser);
12 -router.post("/login", loginUser);
13 -router.get("/all", getAllusers);
14 -router.get("/self", authHandler, getSelf);
15 -
16 -module.exports = router;
1 -const express = require("express");
2 -const dotenv = require("dotenv").config();
3 -const { errorHandler } = require("./middleware/errorMiddleware");
4 -const connectDB = require("./config/db");
5 -const port = process.env.PORT || 6000;
6 -
7 -connectDB();
8 -const app = express();
9 -
10 -app.use(express.json());
11 -app.use(express.urlencoded({ extended: false }));
12 -
13 -app.use("/api/users", require("./routes/userRoutes"));
14 -app.use("/api/chats", require("./routes/chatroomRoutes"));
15 -
16 -app.use(errorHandler);
17 -
18 -app.listen(port, () => {
19 - console.log(`Server started on port ${port}`);
20 -});
1 -const asyncHandler = require("express-async-handler");
2 -
3 -// @desc Create chatroom
4 -// @route POST /api/chats
5 -// @access Private
6 -const createChatroom = asyncHandler(async (req, res) => {
7 - return;
8 -});
9 -
10 -// @desc Delete chatroom
11 -// @route DELETE /api/chats
12 -// @access Private
13 -const delChatroom = asyncHandler(async (req, res) => {
14 - return;
15 -});
16 -
17 -module.exports = {
18 - createChatroom,
19 - delChatroom,
20 -};
...@@ -8,10 +8,10 @@ const { jwtGenerator } = require("../config/jwt"); ...@@ -8,10 +8,10 @@ const { jwtGenerator } = require("../config/jwt");
8 // @route POST /api/users 8 // @route POST /api/users
9 // @access Public 9 // @access Public
10 const signupUser = asyncHandler(async (req, res) => { 10 const signupUser = asyncHandler(async (req, res) => {
11 - const { username, email, password } = req.body; 11 + const { username, country, email, password } = req.body;
12 if (!username || !email || !password) { 12 if (!username || !email || !password) {
13 res.status(400); 13 res.status(400);
14 - throw new Error("Please fill in all fields"); 14 + throw new Error("Please fill in required fields");
15 } 15 }
16 16
17 // Check if user already exists 17 // Check if user already exists
...@@ -28,6 +28,7 @@ const signupUser = asyncHandler(async (req, res) => { ...@@ -28,6 +28,7 @@ const signupUser = asyncHandler(async (req, res) => {
28 // Create/Build user 28 // Create/Build user
29 const user = await User.create({ 29 const user = await User.create({
30 username, 30 username,
31 + country,
31 email, 32 email,
32 password: hashedPassword, 33 password: hashedPassword,
33 }); 34 });
...@@ -38,6 +39,7 @@ const signupUser = asyncHandler(async (req, res) => { ...@@ -38,6 +39,7 @@ const signupUser = asyncHandler(async (req, res) => {
38 res.status(201).json({ 39 res.status(201).json({
39 _id: user.id, 40 _id: user.id,
40 username: user.username, 41 username: user.username,
42 + country: user.country,
41 email: user.email, 43 email: user.email,
42 token: jwtGenerator(user._id), 44 token: jwtGenerator(user._id),
43 }); 45 });
...@@ -58,9 +60,6 @@ const loginUser = asyncHandler(async (req, res) => { ...@@ -58,9 +60,6 @@ const loginUser = asyncHandler(async (req, res) => {
58 const validPassword = await bcrypt.compare(password, userInDB.password); 60 const validPassword = await bcrypt.compare(password, userInDB.password);
59 if (userInDB && validPassword) { 61 if (userInDB && validPassword) {
60 res.status(200).json({ 62 res.status(200).json({
61 - _id: userInDB.id,
62 - username: userInDB.username,
63 - email: userInDB.email,
64 token: jwtGenerator(userInDB._id), 63 token: jwtGenerator(userInDB._id),
65 }); 64 });
66 } else { 65 } else {
...@@ -75,7 +74,6 @@ const loginUser = asyncHandler(async (req, res) => { ...@@ -75,7 +74,6 @@ const loginUser = asyncHandler(async (req, res) => {
75 const getAllusers = asyncHandler(async (req, res) => { 74 const getAllusers = asyncHandler(async (req, res) => {
76 const users = await User.find() 75 const users = await User.find()
77 .select("-password") 76 .select("-password")
78 - .select("-updatedAt")
79 .select("-createdAt") 77 .select("-createdAt")
80 .select("-email"); 78 .select("-email");
81 79
......
...@@ -6,6 +6,10 @@ const userSchema = mongoose.Schema( ...@@ -6,6 +6,10 @@ const userSchema = mongoose.Schema(
6 type: String, 6 type: String,
7 required: [true, "Please add a username"], 7 required: [true, "Please add a username"],
8 }, 8 },
9 + country: {
10 + type: String,
11 + required: false,
12 + },
9 email: { 13 email: {
10 type: String, 14 type: String,
11 required: [true, "Please add a email"], 15 required: [true, "Please add a email"],
......
1 -const express = require("express");
2 -const router = express.Router();
3 -const { createChatroom, delChatroom } = require("../actions/chatroomActions");
4 -const { authHandler } = require("../middleware/authMiddleware");
5 -
6 -// "/api/rooms/"
7 -router.post("/", authHandler, createChatroom);
8 -router.delete("/", authHandler, delChatroom);
9 -// router.post("/message", authHandler, sendMessage);
10 -
11 -module.exports = router;
...@@ -11,7 +11,7 @@ const { authHandler } = require("../middleware/authMiddleware"); ...@@ -11,7 +11,7 @@ const { authHandler } = require("../middleware/authMiddleware");
11 // "/api/users/" 11 // "/api/users/"
12 router.post("/", signupUser); 12 router.post("/", signupUser);
13 router.post("/login", loginUser); 13 router.post("/login", loginUser);
14 -router.get("/all", getAllusers); 14 +router.get("/all", authHandler, getAllusers);
15 router.get("/self", authHandler, getSelf); 15 router.get("/self", authHandler, getSelf);
16 16
17 module.exports = router; 17 module.exports = router;
......
1 const express = require("express"); 1 const express = require("express");
2 const dotenv = require("dotenv").config(); 2 const dotenv = require("dotenv").config();
3 -const { errorHandler } = require("./middleware/errorMiddleware");
4 -const { createServer } = require("http");
5 -const { Server } = require("socket.io");
6 const cors = require("cors"); 3 const cors = require("cors");
4 +const { errorHandler } = require("./middleware/errorMiddleware");
7 const connectDB = require("./config/db"); 5 const connectDB = require("./config/db");
8 const port = process.env.PORT || 8080; 6 const port = process.env.PORT || 8080;
9 7
10 connectDB(); 8 connectDB();
11 const app = express(); 9 const app = express();
12 10
11 +app.use(cors());
13 app.use(express.json()); 12 app.use(express.json());
14 app.use(express.urlencoded({ extended: false })); 13 app.use(express.urlencoded({ extended: false }));
15 14
16 app.use("/api/users", require("./routes/userRoutes")); 15 app.use("/api/users", require("./routes/userRoutes"));
17 -app.use("/api/rooms", require("./routes/chatroomRoutes"));
18 -
19 -// chatbot
20 -app.use(cors());
21 -const httpServer = createServer(app);
22 -const io = new Server(httpServer, {
23 - cors: {
24 - origin: "http://localhost:3000/",
25 - methods: ["GET", "POST"],
26 - },
27 -});
28 -
29 -io.on("connection", (socket) => {
30 - console.log(`User Connected: ${socket.id}`);
31 -
32 - socket.on("join_room", (data) => {
33 - socket.join(data);
34 - });
35 -
36 - socket.on("send_message", (data) => {
37 - socket.to(data.room).emit("receive_message", data);
38 - });
39 -});
40 16
41 app.use(errorHandler); 17 app.use(errorHandler);
42 18
......