Skip to content

Commit

Permalink
add logics: deleteUser, deleteFile, registerAdmin with handlers | add…
Browse files Browse the repository at this point in the history
… html and spec testing b00tc4mp#361
  • Loading branch information
Abel Prieto committed Mar 10, 2024
1 parent 33f89ee commit 6f577be
Show file tree
Hide file tree
Showing 29 changed files with 521 additions and 53 deletions.
23 changes: 19 additions & 4 deletions staff/abel-prieto/PROYECT/API/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,32 @@
- Response (error) : 500|404|406 "Content-Type": application/json { error, message }

`Change Email`
- Request: PATCH /users/email
- Request: PATCH /users/email Authorization: Bearer ${session.token}
- Response: 200
- Response (error) : 500|404|406|409 "Content-Type": application/json { error, message }

`Change Password`
- Request: PATCH /users/password
- Request: PATCH /users/password Authorization: Bearer ${session.token}
- Response: 200
- Response (error) : 500|404|406|409 "Content-Type": application/json { error, message }

`Upload Files`
- Request: POST /upload Authorization: Bearer ${session.token}
- Request: POST /upload "Contet-Type": multipart/form-data Authorization: Bearer ${session.token}
- Response: 201
- Response (error) : 500|404|406|409 "Content-Type": multipart/form-data { error, message }

`Retrieve Files`
- Request: GET /download Authorization: Bearer ${session.token}
- Response: 200 "Content-Type": application/json { filename, filetype }
- Respose (error): 500 "Content-Type": application/json { error, message }

`Download Files`
- Request: GET /download/:fileId Authorization: Bearer ${session.token}
- Response: 201
- Response (error) : 500|404|406|409 "Content-Type": multipart/form-data { error, message }

`Delete Files`
- Request: GET /download/delete/:fileId Authorization: Bearer ${session.token}
- Response: 201
- Response (error) : 500|404|406|409 "Content-Type": multipart/form-data { error, message }

Expand All @@ -52,6 +67,6 @@
- Response (error) : 500|409|406|401 "Content-Type": application/json { error, message }

`Delete User`
- Request: DELETE /users Authorization: Bearer ${session.token}
- Request: DELETE /users/:userId Authorization: Bearer ${session.token}
- Response: 200
- Response (error): 500|404|406|401 "Content-Type": application/json { error, message }
38 changes: 38 additions & 0 deletions staff/abel-prieto/PROYECT/API/handlers/deleteFileHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import jwt from 'jsonwebtoken'
import deleteFile from "../logic/deleteFile.js"
import { errors } from 'com'
const { NotFoundError, ContentError, AuthorizationError, TokenError } = errors
const { JsonWebTokenError } = jwt

export default async (req, res) => {
const token = req.headers.authorization.substring(7)
const { sub: userId } = jwt.verify(token, process.env.JWT_SECRET)

const { fileId } = req.params
try {
await deleteFile(userId, fileId)
res.status(201).send()

} catch (error) {
let status = 500

if (error instanceof AuthorizationError) {
status = 401
}

if (error instanceof NotFoundError) {
status = 404
}

if (error instanceof TypeError || error instanceof ContentError) {
status = 406
}

if (error instanceof JsonWebTokenError) {
status = 401
error = new TokenError(error.message)
}

res.status(status).json({ error: error.constructor.name, message: error.message })
}
}
42 changes: 42 additions & 0 deletions staff/abel-prieto/PROYECT/API/handlers/downloadFileHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import jwt from 'jsonwebtoken'
import fs from 'fs'
import path from 'path'
import downloadFile from '../logic/downloadFile.js'
import { errors } from 'com'

const { JsonWebTokenError } = jwt
const { NotFoundError, ContentError, TokenError, AuthorizationError } = errors

export default async (req, res) => {
const token = req.headers.authorization.substring(7)
const { sub: userId } = jwt.verify(token, process.env.JWT_SECRET)

const { fileId } = req.params

try {
const file = await downloadFile(userId, fileId)

res.download(file)
} catch (error) {
let status = 500

if (error instanceof NotFoundError) {
status = 404
}

if (error instanceof ContentError || error instanceof TypeError) {
status = 406
}

if (error instanceof AuthorizationError) {
status = 401
}

if (error instanceof JsonWebTokenError) {
status = 401
error = new TokenError(error.message)
}

res.status(status).json({ error: error.constructor.name, message: error.message })
}
}
8 changes: 6 additions & 2 deletions staff/abel-prieto/PROYECT/API/handlers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import retrieveGuestHandler from './retrieveGuestHandler.js'
import changeUserEmailHandler from './changeUserEmailHandler.js'
import changeUserPasswordHandler from './changeUserPasswordHandler.js'

import retrieveFilesHandler from './retrieveFilesHandler.js'
import uploadFileHandler from './uploadFileHandler.js'
import uploadFileBBHandler from './uploadFileBBHandler.js'
import downloadFileHandler from './downloadFileHandler.js'
import deleteFileHandler from './deleteFileHandler.js'

export {
authenticateUserHandler,
Expand All @@ -16,6 +18,8 @@ export {
changeUserEmailHandler,
changeUserPasswordHandler,

retrieveFilesHandler,
uploadFileHandler,
uploadFileBBHandler
downloadFileHandler,
deleteFileHandler
}
34 changes: 34 additions & 0 deletions staff/abel-prieto/PROYECT/API/handlers/retrieveFilesHandler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import jwt from 'jsonwebtoken'
import retrieveFiles from '../logic/retrieveFiles.js'
import { errors } from 'com'

const { JsonWebTokenError } = jwt
const { NotFoundError, ContentError, TokenError } = errors

export default async (req, res) => {
const token = req.headers.authorization.substring(7)
const { sub: userId } = jwt.verify(token, process.env.JWT_SECRET)

try {
const files = await retrieveFiles(userId)
res.json(files)

} catch (error) {
let status = 500

if (error instanceof NotFoundError) {
status = 404
}

if (error instanceof ContentError || error instanceof TypeError) {
status = 406
}

if (error instanceof JsonWebTokenError) {
status = 401
error = new TokenError(error.message)
}

res.status(status).json({ error: error.constructor.name, message: error.message })
}
}
14 changes: 13 additions & 1 deletion staff/abel-prieto/PROYECT/API/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import {
changeUserEmailHandler,
changeUserPasswordHandler,
uploadFileHandler,
uploadFileBBHandler
downloadFileHandler,
deleteFileHandler,
retrieveFilesHandler
} from './handlers/index.js'

dotenv.config()
Expand All @@ -21,6 +23,7 @@ mongoose.connect(process.env.URL_MONGODB_HIINIT_API)
const server = express()
const jsonBodyParser = express.json()

// DISK STORAGE
const upload = multer({ dest: 'uploads/' })

server.use(cors())
Expand Down Expand Up @@ -50,6 +53,15 @@ mongoose.connect(process.env.URL_MONGODB_HIINIT_API)
server.post('/upload', upload.single('file'), uploadFileHandler)
// server.post('/upload', uploadFileBBHandler)

// RETRIEVE FILES
server.get('/download', retrieveFilesHandler)

// DOWNLOAD FILE
server.get('/download/:fileId', downloadFileHandler)

// DELETE FILE
server.delete('/download/delete/:fileId', deleteFileHandler)

server.listen(process.env.PORT, () => console.log(`server online! Listen on: ${process.env.PORT}`))
})
.catch(error => console.error(error))
39 changes: 39 additions & 0 deletions staff/abel-prieto/PROYECT/API/logic/deleteFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import fs from 'fs/promises'
import path from 'path'
import { User, File } from '../data/models.js'
import { validate, errors } from 'com'
const { SystemError, NotFoundError, AuthorizationError } = errors

export default async function deleteFile(userId, fileId) {
validate.id(userId, 'ID User')
validate.id(fileId, 'ID File')

try {
const user = await User.findById(userId).lean()
if (!user) {
throw new NotFoundError('User not found')
}

const file = await File.findById(fileId).lean()
if (!file) {
throw new NotFoundError('File not found')
}

if (file.owner[0] === user.id || user.role[0] === 'admin') {
const filePath = `./uploads/${file._id.toString()}`

await fs.unlink(filePath)
await File.findByIdAndDelete(fileId)

} else {
throw new AuthorizationError('Authorization denied. Try again')
}

} catch (error) {
if (error instanceof NotFoundError || error instanceof AuthorizationError) {
throw error
}

throw new SystemError(error.message)
}
}
41 changes: 41 additions & 0 deletions staff/abel-prieto/PROYECT/API/logic/downloadFile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import fs from 'fs'
import path from 'path'
import { User, File } from '../data/models.js'
import { validate, errors } from 'com'
const { SystemError, NotFoundError, AuthorizationError } = errors

export default async function downloadFile(userId, fileId) {
validate.id(userId, 'ID User')
validate.id(fileId, 'ID File')

try {
const user = await User.findById(userId)

if (!user) {
throw new NotFoundError('User not found')
}

const file = await File.findById(fileId)

if (!file) {
throw new NotFoundError('File not found')
}

if (file.owner === user.id || user.role[0] === 'admin') {
const originalName = file.originalName
const filePath = `./uploads/${file._id.toString()}`

// Devolvemos la info de la ruta y el nombre original
return { filePath, originalName }
} else {
throw new AuthorizationError('Authorization denied. Try again')
}

} catch (error) {
if (error instanceof NotFoundError || error instanceof AuthorizationError) {
throw error
}

throw new SystemError(error.message)
}
}
44 changes: 17 additions & 27 deletions staff/abel-prieto/PROYECT/API/logic/registerUser.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,32 @@
import { User, Group } from '../data/models.js';
import bcrypt from 'bcrypt';
import { errors } from 'com';
import { validate } from 'com';
import { User, Group } from '../data/models.js'
import bcrypt from 'bcrypt'
import { errors } from 'com'
import { validate } from 'com'

const { SystemError, DuplicityError } = errors;
const { SystemError, DuplicityError } = errors

async function registerUser(username, email, password) {
try {
// Validación de datos
validate.text(username, 'Username');
validate.email(email, 'Email');
validate.password(password, 'Password');
validate.text(username, 'Username')
validate.email(email, 'Email')
validate.password(password, 'Password')

// Hash de la contraseña
const hash = await bcrypt.hash(password, 5);
const hash = await bcrypt.hash(password, 5)
const user = await User.create({ username, email, password: hash, group: 'localhost', role: 'user' })

// Crear el usuario
const user = await User.create({ username, email, password: hash, group: 'localhost', role: 'user' });
const group = await Group.findOne({ name: 'localhost' })
group.members.push(user._id)
await group.save()

// Buscar o crear el grupo 'localhost'
let group = await Group.findOne({ name: 'localhost' });

// Agregar el ID del usuario al array de miembros
group.members.push(user._id);

// Guardar el grupo
await group.save();

// Devolver el usuario creado o cualquier otro valor necesario
return user;
return user

} catch (error) {
if (error.code === 11000) {
throw new DuplicityError('Account already exists. Try again');
throw new DuplicityError('Account already exist. Try again')
}

throw new SystemError(error.message);
throw new SystemError(error.message)
}
}

export default registerUser;
export default registerUser
Loading

0 comments on commit 6f577be

Please sign in to comment.