Skip to content

Commit

Permalink
WIP loginUser b00tc4mp#99
Browse files Browse the repository at this point in the history
  • Loading branch information
TatiGV committed Aug 12, 2024
1 parent cfbf584 commit 564a150
Show file tree
Hide file tree
Showing 19 changed files with 271 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import jwt from 'jsonwebtoken'

import { logic } from '../../cor/index.js'
import { errors } from '../../com/index.js'

const { SessionError } = errors

export default (req, res, next) => {
const { username, password } = req.body

try {
logic.authenticateUser(username, password)
.then(userId =>
jwt.sign({ sub: userId }, process.env.JWT_SECRET, (error, token) => {
if (error) {
next(new SessionError(error.message))

return
}

res.json(token)
})
)
.catch(error => next(error))
} catch (error) {
next(error)
}
}
5 changes: 4 additions & 1 deletion staff/tatiana-garcia/project/api/handlers/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import registerUserHandler from './registerUserHandler.js'
import authenticateUserHandler from './authenticateUserHandler.js'


export {
registerUserHandler
registerUserHandler,
authenticateUserHandler
}
5 changes: 4 additions & 1 deletion staff/tatiana-garcia/project/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import express from 'express'

import { mongoose } from '../cor/index.js'

import { cors, jsonBodyParser, errorHandler } from './middlewares/index.js'
import { cors, jsonBodyParser, jwtVerifier, errorHandler } from './middlewares/index.js'

import {
registerUserHandler,
authenticateUserHandler

} from './handlers/index.js'

mongoose.connect(process.env.MONGODB_URI)
Expand All @@ -18,6 +20,7 @@ mongoose.connect(process.env.MONGODB_URI)
api.use(cors)

api.post('/users', jsonBodyParser, registerUserHandler)
api.post('/users/auth', jsonBodyParser, authenticateUserHandler)

api.use(errorHandler)

Expand Down
9 changes: 8 additions & 1 deletion staff/tatiana-garcia/project/api/middlewares/errorHandler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { errors } from '../../com/index.js'

const { ValidationError, DuplicityError } = errors
const { ValidationError, DuplicityError, CredentialsError, NotFoundError, SessionError } = errors

export default (error, req, res, next) => {
let status = 500
Expand All @@ -9,5 +9,12 @@ export default (error, req, res, next) => {
status = 400
else if (error instanceof DuplicityError)
status = 409
else if (error instanceof CredentialsError)
status = 401
else if (error instanceof NotFoundError)
status = 404
else if (error instanceof SessionError)
status = 498

res.status(status).json({ error: error.constructor.name, message: error.message })
}
2 changes: 2 additions & 0 deletions staff/tatiana-garcia/project/api/middlewares/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import cors from './cors.js'
import jsonBodyParser from './jsonBodyParser.js'
import jwtVerifier from './jwtVerifier.js'
import errorHandler from './errorHandler.js'

export {
cors,
jsonBodyParser,
jwtVerifier,
errorHandler
}
25 changes: 25 additions & 0 deletions staff/tatiana-garcia/project/api/middlewares/jwtVerifier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import jwt from 'jsonwebtoken'

import { errors } from '../../com/index.js'

const { SessionError } = errors

export default (req, res, next) => {
const { authorization } = req.headers

const token = authorization.slice(7)

jwt.verify(token, process.env.JWT_SECRET, (error, payload) => {
if (error) {
res.status(498).json({ error: SessionError.name, message: error.message })

return
}

const { sub: userId } = payload

req.userId = userId

next()
})
}
6 changes: 5 additions & 1 deletion staff/tatiana-garcia/project/app/logic/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import registerUser from './registerUser'
import loginUser from './loginUser'
import isUserLoggedIn from './isUserLoggedIn'

const logic = {
registerUser
registerUser,
loginUser,
isUserLoggedIn
}

export default logic
1 change: 1 addition & 0 deletions staff/tatiana-garcia/project/app/logic/isUserLoggedIn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => !!sessionStorage.token
32 changes: 32 additions & 0 deletions staff/tatiana-garcia/project/app/logic/loginUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { validate, errors } from '../../com/index.js'

const { SystemError } = errors

export default (username, password) => {
validate.username(username)
validate.password(password)

return fetch(`${import.meta.env.VITE_API_URL}/users/auth`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
})
.catch(error => { throw new SystemError(error.message) })
.then(response => {
const { status } = response

if (status === 200)
return response.json()
.then(token => sessionStorage.token = token)
return response.json()
.then(body => {
const { error, message } = body

const constructor = errors[error]

throw new constructor(message)
})
})
}
24 changes: 14 additions & 10 deletions staff/tatiana-garcia/project/app/view/App.jsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import { Routes, Route, useNavigate } from 'react-router-dom'
import { Routes, Route, useNavigate, Navigate } from 'react-router-dom'

import Register from './register'
import Login from './login/index.jsx'

export default function App() {
import logic from '../logic/index.js'

export default function App() {
const navigate = useNavigate()

const handleRegisterClick = () => {
navigate('/register')
}
const handleLogin = () => { navigate('/') }

const handleRegisterClick = () => { navigate('/register') }

const handleRegister = () => { navigate('/login') }

const handleRegister = () => {
console.debug('App -> handleRegister')
const handleLoginClick = () => { navigate('/login') }

navigate('/login')
}
const handleLogout = () => { navigate('/login') }

return <Routes>
<Route path="/register" element={<Register onRegister={handleRegister} onRegisterClick={handleRegisterClick} />} />
<Route path="/login" element={logic.isUserLoggedIn() ? <Navigate to="/" /> : <Login onLogin={handleLogin} onRegisterClick={handleRegisterClick} />} />
<Route path="/register" element={logic.isUserLoggedIn() ? <Navigate to="/" /> : <Register onRegister={handleRegister} onLoginClick={handleLoginClick} />} />
<Route path="/*" element={logic.isUserLoggedIn() ? <Home onLogout={handleLogout} /> : <Navigate to="/login" />} />
</Routes>
}
16 changes: 16 additions & 0 deletions staff/tatiana-garcia/project/app/view/common/Alert.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Container from '../library/Container'
import Button from '../library/Button'

export default function Alert({ message, onAccept }) {
return <>
<Container classname="fixed flex w-screen h-screen bg-black opacity-50">
</Container>

<Container className="fixed w-screen top-0 h-screen flex items-center justify-center">
<Container className="p-4 border bg-white dark:bg-black dark:text-white flex-col">
<p>{message}</p>
<Button onClick={onAccept}>Accept</Button>
</Container>
</Container >
</>
}
3 changes: 3 additions & 0 deletions staff/tatiana-garcia/project/app/view/library/Link.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Link({ children, ...nextProps }) {
return <a href="#" {...nextProps}>{children}</a>
}
71 changes: 71 additions & 0 deletions staff/tatiana-garcia/project/app/view/login/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import logic from '../../logic/index.js'

import Container from '../library/Container.jsx'

import useContext from '../context.js'

import { errors } from '../../../com/index.js'

const { NotFoundError, CredentialsError } = errors

export default function Login({ onlogin, onRegisterClick }) {
const { alert } = useContext()

const handleLoginSubmit = event => {
event.preventDefault()

const form = event.target

const usernameInput = form['username-input']
const passwordInput = form['password-input']

const username = usernameInput.value
const password = passwordInput.value

try {
logic.loginUser(username, password)
.then(() => onlogin())
.catch(error => {
console.error(error)

let message = error.message

if (error instanceof NotFoundError || error instanceof CredentialsError)
message = 'incorrect username and/or password'

alert(message)
})
} catch (error) {
console.error(error)

alert(error.message)
}
}

const handleRegisterClick = event => {
event.preventDefault()

onRegisterClick()
}

return <main>
<header>Login</header>

<form onSubmit={handleLoginSubmit}>
<Container>
<label htmlFor='username-input'>Nombre de usuario</label>
<input type='text' id='username-input' name='username' placeholder='nombre de usuario' />
</Container>

<Container>
<label htmlFor='password-input'>Contraseña</label>
<input type='password' id='password-input' name='password' placeholder='contraseña' />
</Container>

<button type='submit'>Login</button>
</form>

<link onClick={handleRegisterClick}>Registro</link>

</main>
}
10 changes: 9 additions & 1 deletion staff/tatiana-garcia/project/app/view/register/index.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { useState } from 'react'
import logic from '../../logic'
import Container from '../library/Container'
import Link from '../library/Link'

export default function Register({ onRegister }) {
export default function Register({ onRegister, onLoginClick }) {
const [role, setRole] = useState('user')
const [selectedPets, setSelectedPets] = useState([])

Expand Down Expand Up @@ -65,6 +66,12 @@ export default function Register({ onRegister }) {
}
}

const handleLoginClick = event => {
event.preventDefault()

onLoginClick()
}

return <main>
<header>Registro</header>

Expand Down Expand Up @@ -241,5 +248,6 @@ export default function Register({ onRegister }) {
<button type="submit">{'Register'}</button>
</form>

<Link onClick={handleLoginClick}>Login</Link>
</main>
}
28 changes: 28 additions & 0 deletions staff/tatiana-garcia/project/cor/logic/authenticateUser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import bcrypt from 'bcryptjs'

import { User } from '../data/models.js'

import { validate, errors } from '../../com/index.js'

const { NotFoundError, CredentialsError, SystemError } = errors

export default (username, password) => {
validate.username(username)
validate.password(password)

return User.findOne({ username }).lean()
.catch(error => { throw new SystemError(error.message) })
.then(user => {
if (!user)
throw new NotFoundError('user not found')

return bcrypt.compare(password, user.password)
.catch(error => { throw new SystemError(error.message) })
.then(match => {
if (!match)
throw new CredentialsError('wrong password')

return user._id.toString()
})
})
}
10 changes: 10 additions & 0 deletions staff/tatiana-garcia/project/cor/logic/authenticateUser.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'dotenv/config'
import authenticateUser from './authenticateUser.js'

import mongoose from 'mongoose'

mongoose.connect(process.env.MONGODB_URI)
.then(() => authenticateUser('tatig', '123123123'))
.then(() => console.log('user authenticated'))
.catch(error => console.error(error))
.finally(() => mongoose.disconnect())
4 changes: 3 additions & 1 deletion staff/tatiana-garcia/project/cor/logic/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import registerUser from './registerUser.js'
import authenticateUser from './authenticateUser.js'

const logic = {
registerUser
registerUser,
authenticateUser
}

export default logic
Loading

0 comments on commit 564a150

Please sign in to comment.