diff --git a/client/src/App.jsx b/client/src/App.jsx
index 21c5571b..042e44ef 100644
--- a/client/src/App.jsx
+++ b/client/src/App.jsx
@@ -2,7 +2,6 @@
import "./theme.scss";
// Global Style (includes normalize.css)
import "./assets/styles/global/global.scss";
-
// Import Routes
import Routes from "./routes";
diff --git a/client/src/assets/styles/components/logIn.css b/client/src/assets/styles/components/logIn.css
new file mode 100644
index 00000000..133f3432
--- /dev/null
+++ b/client/src/assets/styles/components/logIn.css
@@ -0,0 +1,64 @@
+.hero {
+ display: flex;
+ width: 22.5rem;
+ height: 40rem;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ margin: auto;
+ padding: 1.75rem 0.25rem;
+ gap: 1.1875rem;
+}
+
+.card {
+ background-color: #1f2a37;
+ border-radius: 1.875rem;
+ display: flex;
+ width: 16.9375rem;
+ padding: 1.0625rem 0rem;
+ margin-top: 3rem;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 0.875rem;
+}
+.card .input-field {
+ display: flex;
+ width: 14.16319rem;
+ padding: 0.125rem 0.75rem;
+ justify-content: flex-end;
+ align-items: center;
+ align-content: center;
+ gap: 0rem 9.25rem;
+ flex-wrap: wrap;
+}
+.card .input-field input {
+ background: #374151;
+ margin-block: 0.3rem;
+ border: 1px solid #4b5563;
+ border-radius: 0.25rem;
+ width: 12.66319rem;
+ height: 1.75rem;
+ flex-shrink: 0;
+}
+
+.no-account {
+ color: #0694A2;
+ font-family: "Noto Kufi Arabic";
+ margin-bottom: 1rem;
+}
+
+button {
+ color: #e2efee;
+ font-family: "Noto Kufi Arabic";
+ background: #046C4E;
+ border: 0px solid;
+ border-radius: 0.3125rem;
+ display: flex;
+ width: 7.25rem;
+ height: 1.875rem;
+ padding: 0.8125rem 0.625rem;
+ justify-content: center;
+ align-items: center;
+ gap: 1.25rem;
+}/*# sourceMappingURL=logIn.css.map */
\ No newline at end of file
diff --git a/client/src/assets/styles/components/logIn.scss b/client/src/assets/styles/components/logIn.scss
new file mode 100644
index 00000000..7b4053b1
--- /dev/null
+++ b/client/src/assets/styles/components/logIn.scss
@@ -0,0 +1,74 @@
+$Teal-900: #014451;
+$Teal-500: #0694A2;
+$grey-800: #1f2a37;
+$grey-700: #374151;
+$grey-600: #4b5563;
+$green-700: #046C4E;
+$Primary-900: #0e0218;
+$text-color: #e2efee;
+$font: 'Noto Kufi Arabic';
+
+.hero {
+ display: flex;
+ width: 22.5rem;
+ height: 40rem;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ margin: auto;
+ padding: 1.75rem 0.25rem;
+ gap: 1.1875rem;
+}
+
+.card {
+ background-color: $grey-800;
+ border-radius: 1.875rem;
+ display: flex;
+ width: 16.9375rem;
+ padding: 1.0625rem 0rem;
+ margin-top: 3rem;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 0.875rem;
+ .input-field {
+ display: flex;
+ width: 14.16319rem;
+ padding: 0.125rem 0.75rem;
+ justify-content: flex-end;
+ align-items: center;
+ align-content: center;
+ gap: 0rem 9.25rem;
+ flex-wrap: wrap;
+ input {
+ background: $grey-700;
+ margin-block: 0.3rem;
+ border: 1px solid $grey-600;
+ border-radius: 0.25rem;
+ width: 12.66319rem;
+ height: 1.75rem;
+ flex-shrink: 0;
+ }
+ }
+}
+
+.no-account {
+ color: $Teal-500;
+ font-family: $font;
+ margin-bottom: 1rem;
+}
+
+button {
+ color: $text-color;
+ font-family: $font;
+ background: $green-700;
+ border: 0px solid;
+ border-radius: 0.3125rem;
+ display: flex;
+ width: 7.25rem;
+ height: 1.875rem;
+ padding: 0.8125rem 0.625rem;
+ justify-content: center;
+ align-items: center;
+ gap: 1.25rem;
+}
diff --git a/client/src/assets/styles/components/signUp.css b/client/src/assets/styles/components/signUp.css
new file mode 100644
index 00000000..e40032e3
--- /dev/null
+++ b/client/src/assets/styles/components/signUp.css
@@ -0,0 +1,87 @@
+.hero {
+ display: flex;
+ width: 22.5rem;
+ height: 93.375rem;
+ flex-direction: column;
+ align-items: center;
+ margin: auto;
+ padding: 1.75rem 0.25rem;
+ gap: 1.1875rem;
+}
+
+.container {
+ background: #014451;
+ border-radius: 1.25rem;
+ display: flex;
+ width: 19rem;
+ padding: 1.5rem 0.4375rem;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 1.0625rem;
+}
+
+.card {
+ background-color: #1f2a37;
+ border-radius: 1.875rem;
+ display: flex;
+ width: 16.9375rem;
+ padding: 1.0625rem 0rem;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 0.875rem;
+}
+.card .input-field {
+ display: flex;
+ width: 14.16319rem;
+ padding: 0.125rem 0.75rem;
+ justify-content: flex-end;
+ align-items: center;
+ align-content: center;
+ gap: 0rem 9.25rem;
+ flex-wrap: wrap;
+}
+.card .input-field input {
+ background: #374151;
+ margin-block: 0.3rem;
+ border: 1px solid #4b5563;
+ border-radius: 0.25rem;
+ width: 12.66319rem;
+ height: 1.75rem;
+ flex-shrink: 0;
+}
+.card .radio-field {
+ display: flex;
+ width: 14.16319rem;
+ padding: 0.5625rem 0.75rem;
+ flex-direction: column;
+ justify-content: flex-end;
+ align-items: flex-end;
+ flex-wrap: wrap;
+ gap: 0.0625rem;
+}
+.card .radio-field .radio-buttons {
+ display: flex;
+ padding: 0.3125rem 0.5rem;
+ margin: auto;
+ gap: 3.1875rem;
+}
+.card .radio-field .radio-buttons small input {
+ margin: 0.5rem;
+}
+
+button {
+ color: #e2efee;
+ font-family: "Noto Kufi Arabic";
+ background: #0e0218;
+ border: 0px solid;
+ border-radius: 0.3125rem;
+ display: flex;
+ width: 12.5rem;
+ height: 3.125rem;
+ padding: 0.8125rem 0.6875rem 0.8125rem 0.625rem;
+ justify-content: center;
+ align-items: center;
+ gap: 2.5rem;
+}/*# sourceMappingURL=signUp.css.map */
\ No newline at end of file
diff --git a/client/src/assets/styles/components/signUp.scss b/client/src/assets/styles/components/signUp.scss
new file mode 100644
index 00000000..9705ee79
--- /dev/null
+++ b/client/src/assets/styles/components/signUp.scss
@@ -0,0 +1,97 @@
+$Teal-900: #014451;
+$grey-800: #1f2a37;
+$grey-700: #374151;
+$grey-600: #4b5563;
+$Primary-900: #0e0218;
+$text-color: #e2efee;
+$font: 'Noto Kufi Arabic';
+
+.hero {
+ display: flex;
+ width: 22.5rem;
+ height: 93.375rem;
+ flex-direction: column;
+ align-items: center;
+ margin: auto;
+ padding: 1.75rem 0.25rem;
+ gap: 1.1875rem;
+}
+
+.container {
+ background: $Teal-900;
+ border-radius: 1.25rem;
+ display: flex;
+ width: 19rem;
+ padding: 1.5rem 0.4375rem;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 1.0625rem;
+}
+
+.card {
+ background-color: $grey-800;
+ border-radius: 1.875rem;
+ display: flex;
+ width: 16.9375rem;
+ padding: 1.0625rem 0rem;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ gap: 0.875rem;
+ .input-field {
+ display: flex;
+ width: 14.16319rem;
+ padding: 0.125rem 0.75rem;
+ justify-content: flex-end;
+ align-items: center;
+ align-content: center;
+ gap: 0rem 9.25rem;
+ flex-wrap: wrap;
+ input {
+ background: $grey-700;
+ margin-block: 0.3rem;
+ border: 1px solid $grey-600;
+ border-radius: 0.25rem;
+ width: 12.66319rem;
+ height: 1.75rem;
+ flex-shrink: 0;
+ }
+ }
+
+ .radio-field {
+ display: flex;
+ width: 14.16319rem;
+ padding: 0.5625rem 0.75rem;
+ flex-direction: column;
+ justify-content: flex-end;
+ align-items: flex-end;
+ flex-wrap: wrap;
+ gap: 0.0625rem;
+ .radio-buttons {
+ display: flex;
+ padding: 0.3125rem 0.5rem;
+ margin: auto;
+ gap: 3.1875rem;
+ small input {
+ margin: 0.5rem;
+ }
+ }
+ }
+}
+
+
+button {
+ color: $text-color;
+ font-family: $font;
+ background: $Primary-900;
+ border: 0px solid;
+ border-radius: 0.3125rem;
+ display: flex;
+ width: 12.5rem;
+ height: 3.125rem;
+ padding: 0.8125rem 0.6875rem 0.8125rem 0.625rem;
+ justify-content: center;
+ align-items: center;
+ gap: 2.5rem;
+}
diff --git a/client/src/components/module_OR_PAGE/DELETEME.txt b/client/src/components/module_OR_PAGE/DELETEME.txt
deleted file mode 100644
index e69de29b..00000000
diff --git a/client/src/components/module_OR_PAGE/logIn.jsx b/client/src/components/module_OR_PAGE/logIn.jsx
new file mode 100644
index 00000000..65533d91
--- /dev/null
+++ b/client/src/components/module_OR_PAGE/logIn.jsx
@@ -0,0 +1,21 @@
+import '../../assets/styles/components/logIn.css'
+
+export default function LogIn() {
+ return (
+
+ )
+}
diff --git a/client/src/components/module_OR_PAGE/signUp.jsx b/client/src/components/module_OR_PAGE/signUp.jsx
new file mode 100644
index 00000000..8316d4fb
--- /dev/null
+++ b/client/src/components/module_OR_PAGE/signUp.jsx
@@ -0,0 +1,62 @@
+import '../../assets/styles/components/signUp.css'
+
+export default function SignUp() {
+ return (
+
+ )
+}
diff --git a/client/src/redux/DELETEME.txt b/client/src/redux/DELETEME.txt
deleted file mode 100644
index e69de29b..00000000
diff --git a/client/src/services/DELETEME.txt b/client/src/services/DELETEME.txt
deleted file mode 100644
index e69de29b..00000000
diff --git a/client/src/theme.css b/client/src/theme.css
new file mode 100644
index 00000000..e8dd6711
--- /dev/null
+++ b/client/src/theme.css
@@ -0,0 +1,52 @@
+* {
+ margin: 0;
+ padding: 0;
+}
+
+:root {
+ text-align: center;
+ background-color: #111928;
+ color: #E2EFEE;
+ font-family: "Noto Kufi Arabic";
+}
+
+h1 {
+ font-size: 2.98625rem;
+ font-weight: 800;
+ line-height: 139.429%; /* 4.16369rem */
+}
+
+h2 {
+ font-size: 2.48813rem;
+ font-weight: 700;
+}
+
+h3 {
+ font-size: 2.07375rem;
+ font-weight: 700;
+}
+
+h4 {
+ font-size: 1.72813rem;
+ font-weight: 600;
+}
+
+h5 {
+ font-size: 1.44rem;
+ font-weight: 600;
+}
+
+h6 {
+ font-size: 1.2rem;
+ font-weight: 500;
+}
+
+p, label {
+ font-size: 1rem;
+ font-weight: 500;
+}
+
+small {
+ font-size: 0.83313rem;
+ font-weight: 400;
+}/*# sourceMappingURL=theme.css.map */
\ No newline at end of file
diff --git a/client/src/theme.scss b/client/src/theme.scss
index 493db32c..f3bda648 100644
--- a/client/src/theme.scss
+++ b/client/src/theme.scss
@@ -5,6 +5,11 @@
// Import the fonts
@import url("https://fonts.googleapis.com/css2?family=Noto+Kufi+Arabic:wght@100;200;300;400;500;600;700;800;900&display=swap");
+* {
+ margin: 0;
+ padding: 0;
+}
+
:root {
//----------------------------//
// Colors
diff --git a/server/.env.example b/server/.env.example
index e69de29b..59dfe3ad 100644
--- a/server/.env.example
+++ b/server/.env.example
@@ -0,0 +1,22 @@
+# DB Config Variables
+DB_HOST=
+DB_PORT=
+DB_USER=
+DB_PASS=
+DB_DATABASE=
+
+# Token Config Variables
+JWT_SECRET=
+JWT_EXPIRES_IN=
+
+########## Example ##########
+# DB_HOST=localhost
+# DB_PORT=5432
+# DB_USER=postgres
+# DB_PASS=********
+# DB_DATABASE=scoutsManagementSystem
+
+# To get a random string for JWT_SECRET
+# Run This in terminal => node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
+
+# JWT_EXPIRES_IN='48h'
\ No newline at end of file
diff --git a/server/app.js b/server/app.js
index 6db794e2..622cdf5b 100644
--- a/server/app.js
+++ b/server/app.js
@@ -1,21 +1,25 @@
-const {Client} = require('pg')
+const express = require('express')
+const cors = require('cors')
+const db = require('./database/db')
+const app = express()
+const PORT = process.env.PORT || 3000
+const authRouter = require('./routes/auth.route')
-const client = new Client({
- host: "localhost",
- user: "postgres",
- port: 5432,
- password: "admin123",
- database: "scoutsmanagementsystem"
-})
+db.connect()
+ .then(() => {
+ console.log('Database is connected')
+ })
+ .catch((err) => {
+ if (err) return console.error(err)
+ })
-client.connect();
+app.use(cors())
+app.use(express.json())
-client.query('SELECT * FROM public."Activity"', (err, res) => {
- if (!err) {
- console.log(res.rows);
- }
- else
- {
- console.log(err.message)
- }
+// Routes
+app.use("/auth", authRouter);
+
+app.listen(PORT, (err) => {
+ if (err) return console.error(err)
+ console.log(`Server started listening at port ${PORT}`)
})
\ No newline at end of file
diff --git a/server/controllers/auth.controller.js b/server/controllers/auth.controller.js
new file mode 100644
index 00000000..27840b52
--- /dev/null
+++ b/server/controllers/auth.controller.js
@@ -0,0 +1,125 @@
+const bcrypt = require('bcryptjs')
+const jwt = require('jsonwebtoken')
+const db = require('../database/db')
+const { jsonToArray, arrayToJson } = require('../utils/convert')
+
+const authController = {
+ signup: async (req, res) => {
+ try {
+ // get email and password from request body
+ const email = req.body['email']
+ const password = req.body['password']
+
+ // Check if email already exists
+ const captain = await db.query(
+ `SELECT "email", "password"
+ FROM "Captain"
+ WHERE "email" = $1;`,
+ [email]
+ )
+ if (captain.rows.length) {
+ return res.status(400).json({ error: 'Email is taken!!' })
+ }
+
+ // Hash the password
+ const hashedPassword = await bcrypt.hash(password, 10)
+
+ // Create a new Captain
+ req.body = { ...req.body, password: hashedPassword }
+ const params = jsonToArray(req.body)
+ const result = await db.query(
+ `INSERT INTO "Captain"("firstName", "middleName", "lastName", "email", "password", "phoneNumber", "gender", "type")
+ VALUES($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *;`,
+ params.concat(['regular'])
+ )
+ const newCaptain = result.rows[0]
+
+ // Generate a JWT token containing the captain's id
+ // Bearer token is the token that we will send to the client
+ const token = jwt.sign(
+ { id: newCaptain.captainId }, // Payload
+ process.env.JWT_SECRET,
+ {
+ expiresIn: process.env.JWT_EXPIRES_IN,
+ }
+ )
+
+ // Send the response
+ res.status(201).json({
+ message: 'Captain created successfully',
+ newCaptain,
+ token,
+ })
+ } catch (error) {
+ console.log(error)
+ res.status(500).json({
+ error: 'An error occurred while creating a new captain!!',
+ })
+ }
+ },
+
+ login: async (req, res) => {
+ try {
+ // Deconstruct the request body
+ const { email, password } = req.body
+
+ // Check if email already exists
+ const result = await db.query(
+ `SELECT "email", "password"
+ FROM "Captain"
+ WHERE "email" = $1;`,
+ [email]
+ )
+ if (!result.rows.length) {
+ return res.status(400).json({
+ error: 'Invalid email',
+ })
+ }
+
+ // Get Captain's data
+ const captain = result.rows[0]
+
+ // Check if the password is correct
+ const isCorrect = await bcrypt.compare(password, captain.password)
+ if (!isCorrect) {
+ return res.status(400).json({
+ error: 'Invalid password',
+ })
+ }
+
+ // Generate a JWT token containing the captain's id
+ // Bearer token is the token that we will send to the client
+ const token = jwt.sign(
+ { id: captain.captainId }, // Payload
+ process.env.JWT_SECRET,
+ {
+ expiresIn: process.env.JWT_EXPIRES_IN,
+ }
+ )
+
+ // Send the response
+ res.status(200).json({
+ message: 'Logged in successfully',
+ token,
+ })
+ } catch (error) {
+ console.log(error)
+ res.status(500).json({
+ error: 'An error occurred while logging you in',
+ })
+ }
+ },
+
+ // This controller is responsible for fetching data of the logged-in captain
+ me: (req, res) => {
+ try {
+ res.status(200).json({ user: req.captain })
+ } catch (error) {
+ console.log(error)
+ res.status(500).json({
+ error: 'An error occurred while fetching data.',
+ })
+ }
+ },
+}
+module.exports = authController
diff --git a/server/controllers/example.controller.js b/server/controllers/example.controller.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/server/database/createDatabase.psql b/server/database/createDatabase.psql
index 9fa189cf..dcc0f22d 100644
--- a/server/database/createDatabase.psql
+++ b/server/database/createDatabase.psql
@@ -245,8 +245,8 @@ CREATE TABLE public."Captain" (
"middleName" character varying(255) NOT NULL,
"lastName" character varying(255) NOT NULL,
"phoneNumber" character varying(255) NOT NULL,
- email character varying(255) NOT NULL,
- passward character varying(255) NOT NULL,
+ "email" character varying(255) NOT NULL,
+ "password" character varying(255) NOT NULL,
"rSectorBaseName" character varying(255),
"rSectorSuffixName" character varying(255),
gender public."Gender" NOT NULL,
@@ -1150,4 +1150,4 @@ ALTER TABLE ONLY public."Week"
--
-- PostgreSQL database dump complete
---
+--
\ No newline at end of file
diff --git a/server/database/db.js b/server/database/db.js
new file mode 100644
index 00000000..bacd5a53
--- /dev/null
+++ b/server/database/db.js
@@ -0,0 +1,13 @@
+const pg = require('pg')
+const dotenv = require('dotenv')
+
+dotenv.config()
+const db = new pg.Pool({
+ host: process.env.DB_HOST,
+ port: process.env.DB_PORT,
+ user: process.env.DB_USER,
+ password: process.env.DB_PASS,
+ database: process.env.DB_DATABASE,
+})
+
+module.exports = db
\ No newline at end of file
diff --git a/server/middlewares/auth.middleware.js b/server/middlewares/auth.middleware.js
new file mode 100644
index 00000000..ac5cbb34
--- /dev/null
+++ b/server/middlewares/auth.middleware.js
@@ -0,0 +1,47 @@
+const jwt = require('jsonwebtoken')
+const db = require('../database/db')
+
+const authMiddleware = async (req, res, next) => {
+ // Get authorization header and check if it exists
+ const auth = req.headers.authorization
+ if (!auth) {
+ return res.status(401).json({ error: 'No token provided' })
+ }
+
+ // Check if the authorization header is "Bearer "
+ if (!auth.startsWith('Bearer') || auth.split(' ').length !== 2) {
+ return res.status(401).json({ error: 'Invalid token, not Bearer' })
+ }
+
+ // Get token from the authorization header
+ const token = auth.split(' ')[1]
+
+ try {
+ // Verify token and get captain's id
+ const id = jwt.verify(token, process.env.JWT_SECRET).id
+
+ // Get captain's data
+ const result = await db.query(
+ `SELECT *
+ FROM "Captain"
+ WHERE "captainId" = $1;`,
+ [id]
+ )
+ if (!result.rows.length) {
+ return res.status(404).json({ error: 'Captain not found' })
+ }
+
+ // Attach captain to the request object
+ req.captain = result.rows[0]
+
+ next()
+ } catch (err) {
+ console.log(err)
+ if (err.name === 'TokenExpiredError') {
+ return res.status(401).json({ error: 'Provided token has expired' })
+ }
+ res.status(401).json({ error: 'Invalid token' })
+ }
+}
+
+module.exports = authMiddleware
diff --git a/server/middlewares/example.middleware.js b/server/middlewares/example.middleware.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/server/models/example.model.js b/server/models/example.model.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/server/package-lock.json b/server/package-lock.json
index 11ca95fd..a6128cfd 100644
--- a/server/package-lock.json
+++ b/server/package-lock.json
@@ -9,9 +9,11 @@
"version": "1.0.0",
"license": "ISC",
"dependencies": {
+ "bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
+ "jsonwebtoken": "^9.0.2",
"pg": "^8.11.3"
},
"devDependencies": {
@@ -60,6 +62,11 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
+ "node_modules/bcryptjs": {
+ "version": "2.4.3",
+ "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
+ "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ=="
+ },
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@@ -114,6 +121,11 @@
"node": ">=8"
}
},
+ "node_modules/buffer-equal-constant-time": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
+ "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
+ },
"node_modules/buffer-writer": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz",
@@ -269,6 +281,14 @@
"url": "https://github.com/motdotla/dotenv?sponsor=1"
}
},
+ "node_modules/ecdsa-sig-formatter": {
+ "version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
+ "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ }
+ },
"node_modules/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@@ -580,11 +600,90 @@
"node": ">=0.12.0"
}
},
+ "node_modules/jsonwebtoken": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
+ "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
+ "dependencies": {
+ "jws": "^3.2.2",
+ "lodash.includes": "^4.3.0",
+ "lodash.isboolean": "^3.0.3",
+ "lodash.isinteger": "^4.0.4",
+ "lodash.isnumber": "^3.0.3",
+ "lodash.isplainobject": "^4.0.6",
+ "lodash.isstring": "^4.0.1",
+ "lodash.once": "^4.0.0",
+ "ms": "^2.1.1",
+ "semver": "^7.5.4"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/jsonwebtoken/node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ },
+ "node_modules/jwa": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
+ "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
+ "dependencies": {
+ "buffer-equal-constant-time": "1.0.1",
+ "ecdsa-sig-formatter": "1.0.11",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/jws": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
+ "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
+ "dependencies": {
+ "jwa": "^1.4.1",
+ "safe-buffer": "^5.0.1"
+ }
+ },
+ "node_modules/lodash.includes": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
+ "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w=="
+ },
+ "node_modules/lodash.isboolean": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+ "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg=="
+ },
+ "node_modules/lodash.isinteger": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
+ "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA=="
+ },
+ "node_modules/lodash.isnumber": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
+ "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw=="
+ },
+ "node_modules/lodash.isplainobject": {
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA=="
+ },
+ "node_modules/lodash.isstring": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
+ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw=="
+ },
+ "node_modules/lodash.once": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
+ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
+ },
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
@@ -1012,7 +1111,6 @@
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
- "dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
@@ -1222,8 +1320,7 @@
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
+ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
}
diff --git a/server/package.json b/server/package.json
index 5c476c07..9cac5295 100644
--- a/server/package.json
+++ b/server/package.json
@@ -10,9 +10,11 @@
"author": "",
"license": "ISC",
"dependencies": {
+ "bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"express": "^4.18.2",
+ "jsonwebtoken": "^9.0.2",
"pg": "^8.11.3"
},
"devDependencies": {
diff --git a/server/routes/auth.route.js b/server/routes/auth.route.js
new file mode 100644
index 00000000..880e7482
--- /dev/null
+++ b/server/routes/auth.route.js
@@ -0,0 +1,9 @@
+const authRouter = require("express").Router();
+const authController = require("../controllers/auth.controller");
+const authMiddleware = require("../middlewares/auth.middleware");
+
+authRouter.post("/signUp", authController.signup);
+authRouter.post("/logIn", authController.login);
+authRouter.get("/me", authMiddleware, authController.me);
+
+module.exports = authRouter;
\ No newline at end of file
diff --git a/server/routes/example.route.js b/server/routes/example.route.js
deleted file mode 100644
index e69de29b..00000000
diff --git a/server/utils/convert.js b/server/utils/convert.js
new file mode 100644
index 00000000..69ac8ce7
--- /dev/null
+++ b/server/utils/convert.js
@@ -0,0 +1,20 @@
+const jsonToArray = (json) => {
+ const arr = []
+ for (const key in json) {
+ arr.push(json[key])
+ }
+ return arr
+}
+
+const arrayToJson = (arr) => {
+ const json = {}
+ for (const key in arr) {
+ json[key] = arr[key]
+ }
+ return json
+}
+
+module.exports = {
+ jsonToArray,
+ arrayToJson,
+}
diff --git a/server/utils/fileExample.js b/server/utils/fileExample.js
deleted file mode 100644
index e69de29b..00000000