From 4ea8c9f2b3ad20afa6dbba91f5a07dd2f8193d29 Mon Sep 17 00:00:00 2001 From: Lukian Date: Mon, 24 Mar 2025 14:41:48 +0100 Subject: [PATCH] add: added homepage --- back/api/auth.js | 46 +++++++++++++++++++++++++++++++++ back/api/channels.js | 26 +++++++++++-------- back/api/connect.js | 24 ------------------ back/api/users.js | 11 +------- back/libs/mysql.js | 4 +-- front/src/main.tsx | 6 ++++- front/src/pages/Channel.tsx | 27 +++++--------------- front/src/pages/Home.tsx | 49 ++++++++++++++++++++++++++++++++++++ front/src/pages/Login.tsx | 45 +++++++++++++++++++++++++++++++++ front/src/pages/Register.tsx | 47 ++++++++++++++++++++++++++++++++++ front/src/types.tsx | 22 ++++++++++++++++ 11 files changed, 239 insertions(+), 68 deletions(-) create mode 100644 back/api/auth.js delete mode 100644 back/api/connect.js create mode 100644 front/src/pages/Login.tsx create mode 100644 front/src/pages/Register.tsx create mode 100644 front/src/types.tsx diff --git a/back/api/auth.js b/back/api/auth.js new file mode 100644 index 0000000..c1a2640 --- /dev/null +++ b/back/api/auth.js @@ -0,0 +1,46 @@ +const express = require('express'); +const sha256 = require("sha256"); +const jwt = require('jsonwebtoken'); +const { getConnection, getUserByUsername, addUser, getUser } = require('../libs/mysql'); + +const router = express.Router(); + +router.post('/login', async (req, res) => { + const { username, password } = req.body; + const connection = await getConnection(); + const users = await getUserByUsername(connection, username); + connection.end(); + if (users[0]) { + if (users[0].password === sha256(password)) { + const token = jwt.sign({ id: users[0].id }, process.env.JWT_SECRET, { + expiresIn: 1000 * 60 * 60 * 24 * 7, + }); + return res.send({ token: token }); + } + } + res.status(401).send({ error: 'Invalid username or password' }); +}); + +router.post('/register', async (req, res) => { + const { username, password } = req.body; + const connection = await getConnection(); + const hash = sha256(password); + await addUser(connection, username, hash); + connection.end(); + res.send({ message: 'User added' }); +}); + +router.post('/me', async (req, res) => { + const { token } = req.body; + const decoded = jwt.verify(token, process.env.JWT_SECRET); + const connection = await getConnection(); + const users = await getUser(connection, decoded.id); + connection.end(); + if (users[0]) { + res.send({ id: users[0].id, username: users[0].username }); + } else { + res.status(401).send({ error: 'Invalid token' }); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/back/api/channels.js b/back/api/channels.js index 3e28996..01f24d0 100644 --- a/back/api/channels.js +++ b/back/api/channels.js @@ -11,10 +11,10 @@ router.get('/', async (req, res) => { res.send(channels); }); -router.get('/:id', async (req, res) => { - const id = req.params.id; +router.get('/:name', async (req, res) => { + const name = req.params.name; const connection = await getConnection(); - const channel = await getChannel(connection, id); + const channel = await getChannel(connection, name); connection.end(); if (channel[0]) { res.send(channel[0]); @@ -23,22 +23,22 @@ router.get('/:id', async (req, res) => { } }); -router.get('/:id/messages', async (req, res) => { - const id = req.params.id; +router.get('/:name/messages', async (req, res) => { + const name = req.params.name; const connection = await getConnection(); - const channel = await getChannel(connection, id); + const channel = await getChannel(connection, name); if (!channel[0]) { connection.end(); return res.send('No channel found'); } - const messages = await getMessages(connection, id); + const messages = await getMessages(connection, channel[0].id); connection.end(); res.send(messages); }); -router.post('/:id/messages/send', async (req, res) => { +router.post('/:name/messages/send', async (req, res) => { const { token, message } = req.body; - const id = req.params.id; + const name = req.params.name; const connection = await getConnection(); const decoded = jwt.verify(token, process.env.JWT_SECRET); @@ -48,7 +48,13 @@ router.post('/:id/messages/send', async (req, res) => { return res.status(401).send({ error: 'Invalid token' }); } - await addMessage(connection, id, user[0].id, message.replace("\"", "'")); + const channel = await getChannel(connection, name); + if (!channel[0]) { + connection.end(); + return res.send('No channel found'); + } + + await addMessage(connection, channel[0].id, user[0].id, message.replace("\"", "'")); connection.end(); res.send({ message: 'Message sent' }); }); diff --git a/back/api/connect.js b/back/api/connect.js deleted file mode 100644 index f5c0023..0000000 --- a/back/api/connect.js +++ /dev/null @@ -1,24 +0,0 @@ -const express = require('express'); -const sha256 = require("sha256"); -const jwt = require('jsonwebtoken'); -const { getConnection, getUserByUsername } = require('../libs/mysql'); - -const router = express.Router(); - -router.post('/', async (req, res) => { - const { username, password } = req.body; - const connection = await getConnection(); - const users = await getUserByUsername(connection, username); - connection.end(); - if (users[0]) { - if (users[0].password === sha256(password)) { - const token = jwt.sign({ id: users[0].id }, process.env.JWT_SECRET, { - expiresIn: 1000 * 60 * 60 * 24 * 7, - }); - res.send({ token: token }); - } - } - res.status(401).send({ error: 'Invalid username or password' }); -}); - -module.exports = router; \ No newline at end of file diff --git a/back/api/users.js b/back/api/users.js index 4e6b7cc..9b7b065 100644 --- a/back/api/users.js +++ b/back/api/users.js @@ -10,19 +10,10 @@ router.get('/:id', async (req, res) => { const users = await getUser(connection, id); connection.end(); if (users[0]) { - res.send(users[0]); + res.send({id: users[0].id, username: users[0].username}); } else { res.send('No user found'); } }); -router.post('/add', async (req, res) => { - const { username, password } = req.body; - const connection = await getConnection(); - const hash = sha256(password); - await addUser(connection, username, hash); - connection.end(); - res.send({ message: 'User added' }); -}); - module.exports = router; \ No newline at end of file diff --git a/back/libs/mysql.js b/back/libs/mysql.js index c0e717a..d3d7edd 100644 --- a/back/libs/mysql.js +++ b/back/libs/mysql.js @@ -65,10 +65,10 @@ function getChannels(connection) { }); } -function getChannel(connection, id) { +function getChannel(connection, name) { return new Promise((resolve, reject) => { connection.query( - `SELECT * FROM channels WHERE id = ${id}`, + `SELECT * FROM channels WHERE name = "${name}"`, (error, result) => { if (error) { reject(new Error(error)); diff --git a/front/src/main.tsx b/front/src/main.tsx index bb634ea..db1c8ea 100644 --- a/front/src/main.tsx +++ b/front/src/main.tsx @@ -4,12 +4,16 @@ import './index.css' import Home from './pages/Home' import Channel from './pages/Channel' +import Login from './pages/Login' +import Register from './pages/Register' createRoot(document.getElementById('root')!).render( } /> - } /> + } /> + } /> + } /> ) diff --git a/front/src/pages/Channel.tsx b/front/src/pages/Channel.tsx index ab97e9b..3017c14 100644 --- a/front/src/pages/Channel.tsx +++ b/front/src/pages/Channel.tsx @@ -1,37 +1,22 @@ import { useParams } from "react-router-dom"; import { useEffect, useState } from "react"; +import { Channel_type, Messages } from "../types"; import axios from "axios"; -type Channel ={ - id: number, - name: string - description: string -} - -type Message = { - id: number, - user_id: number, - username: string, - content: string, - date: number -} - -type Messages = Message[] - export default function Channel() { - const { id } = useParams(); - const [channel, setChannel] = useState(); + const { name } = useParams(); + const [channel, setChannel] = useState(); const [messages, setMessages] = useState(); useEffect(() => { - axios.get(`/api/channels/${id}`).then((res) => { + axios.get(`/api/channels/${name}`).then((res) => { setChannel(res.data); }); - axios.get(`/api/channels/${id}/messages`).then((res) => { + axios.get(`/api/channels/${name}/messages`).then((res) => { setMessages(res.data); }); - }, [id]); + }, [name]); if (!channel || !messages) { return
Loading...
; diff --git a/front/src/pages/Home.tsx b/front/src/pages/Home.tsx index fb10956..9f1fd91 100644 --- a/front/src/pages/Home.tsx +++ b/front/src/pages/Home.tsx @@ -1,7 +1,56 @@ +import { useState, useEffect } from "react" +import { Link } from "react-router-dom" +import { Channels, User } from "../types" +import axios from "axios" + export default function Home() { + const [user, setUser] = useState(); + const [channels, setChannels] = useState(); + + useEffect(() => { + const token = localStorage.getItem("token") + if (token) { + axios.post("/api/auth/me", { + token: token + }).then((res) => { + setUser(res.data) + }).catch((err) => { + console.error(err) + }) + } + + axios.get("/api/channels").then((res) => { + setChannels(res.data) + }).catch((err) => { + console.error(err) + }) + }, []) + return (

Home

+ {user ? ( +
+

Welcome {user.username}

+ +
+ ) : ( +
+ Login + Register +
+ )} +

Channels

+
    + {channels?.map((channel) => ( +
  • + {channel.name} +
  • + ))} +
) } \ No newline at end of file diff --git a/front/src/pages/Login.tsx b/front/src/pages/Login.tsx new file mode 100644 index 0000000..4379897 --- /dev/null +++ b/front/src/pages/Login.tsx @@ -0,0 +1,45 @@ +import axios from "axios"; +import { useState } from "react"; +import { useNavigate, Link } from "react-router-dom"; + +export default function Login() { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const navigate = useNavigate(); + + function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + axios + .post("/api/auth/login", { username, password }) + .then((res) => { + localStorage.setItem("token", res.data.token); + navigate("/"); + }) + .catch((err) => { + alert(err.response.data.message); + }); + } + + return ( +
+ Home +

Login

+
+ setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
+ Register +
+ ); +} \ No newline at end of file diff --git a/front/src/pages/Register.tsx b/front/src/pages/Register.tsx new file mode 100644 index 0000000..31f7a9a --- /dev/null +++ b/front/src/pages/Register.tsx @@ -0,0 +1,47 @@ +import axios from "axios"; +import { useState } from "react"; +import { useNavigate, Link } from "react-router-dom"; + +export default function Register () { + const [username, setUsername] = useState(""); + const [password, setPassword] = useState(""); + const navigate = useNavigate(); + + function handleSubmit(e: React.FormEvent) { + e.preventDefault(); + axios.post("/api/auth/register", { username, password }); + axios + .post("/api/auth/login", { username, password }) + .then((res) => { + localStorage.setItem("token", res.data.token); + navigate("/"); + }) + .catch((err) => { + alert(err.response.data.message); + } + ); + } + + return ( +
+ Home +

Register

+
+ setUsername(e.target.value)} + /> + setPassword(e.target.value)} + /> + +
+ Login +
+ ); +} \ No newline at end of file diff --git a/front/src/types.tsx b/front/src/types.tsx new file mode 100644 index 0000000..02a2d8c --- /dev/null +++ b/front/src/types.tsx @@ -0,0 +1,22 @@ +export type Channel_type ={ + id: number, + name: string + description: string +} + +export type Channels = Channel_type[] + +export type Message = { + id: number, + user_id: number, + username: string, + content: string, + date: number +} + +export type Messages = Message[] + +export type User = { + id: number, + username: string +}