From 0a299746b6a6bfb7d624d440ad845c4bf1fe32d7 Mon Sep 17 00:00:00 2001 From: Claudi1991 Date: Thu, 31 Oct 2024 13:17:57 +0100 Subject: [PATCH] update test folder with xhr #183 --- staff/claudi-cano/unsocial/api/data/index.js | 9 +++ .../claudi-cano/unsocial/api/data/posts.json | 20 ++++++ .../claudi-cano/unsocial/api/data/storage.js | 31 ++++++++ .../unsocial/api/data/storage.test.js | 11 +++ .../claudi-cano/unsocial/api/data/users.json | 16 +++++ staff/claudi-cano/unsocial/api/data/uuid.js | 3 + staff/claudi-cano/unsocial/api/index.js | 71 +++++++++++++++++++ .../unsocial/api/logic/authenticateUser.js | 19 +++++ .../api/logic/authenticateUser.test.js | 7 ++ .../unsocial/api/logic/createPost.js | 29 ++++++++ .../unsocial/api/logic/createPost.test.js | 7 ++ .../unsocial/api/logic/getUserName.js | 14 ++++ .../unsocial/api/logic/getUserName.test.js | 7 ++ .../unsocial/api/logic/helpers/index.js | 5 ++ .../unsocial/api/logic/helpers/validate.js | 54 ++++++++++++++ staff/claudi-cano/unsocial/api/logic/index.js | 14 ++++ .../unsocial/api/logic/registerUser.js | 24 +++++++ .../unsocial/api/logic/registerUser.test.js | 7 ++ staff/claudi-cano/unsocial/api/package.json | 18 +++++ .../unsocial/api/test/authenticate-user.js | 9 +++ .../unsocial/api/test/authenticate-user.sh | 1 + .../unsocial/api/test/create-post.js | 10 +++ .../unsocial/api/test/create-post.sh | 1 + .../unsocial/api/test/get-user-name.js | 8 +++ .../unsocial/api/test/get-user-name.sh | 1 + .../unsocial/api/test/register-user.js | 9 +++ .../unsocial/api/test/register-user.sh | 1 + 27 files changed, 406 insertions(+) create mode 100644 staff/claudi-cano/unsocial/api/data/index.js create mode 100644 staff/claudi-cano/unsocial/api/data/posts.json create mode 100644 staff/claudi-cano/unsocial/api/data/storage.js create mode 100644 staff/claudi-cano/unsocial/api/data/storage.test.js create mode 100644 staff/claudi-cano/unsocial/api/data/users.json create mode 100644 staff/claudi-cano/unsocial/api/data/uuid.js create mode 100644 staff/claudi-cano/unsocial/api/index.js create mode 100644 staff/claudi-cano/unsocial/api/logic/authenticateUser.js create mode 100644 staff/claudi-cano/unsocial/api/logic/authenticateUser.test.js create mode 100644 staff/claudi-cano/unsocial/api/logic/createPost.js create mode 100644 staff/claudi-cano/unsocial/api/logic/createPost.test.js create mode 100644 staff/claudi-cano/unsocial/api/logic/getUserName.js create mode 100644 staff/claudi-cano/unsocial/api/logic/getUserName.test.js create mode 100644 staff/claudi-cano/unsocial/api/logic/helpers/index.js create mode 100644 staff/claudi-cano/unsocial/api/logic/helpers/validate.js create mode 100644 staff/claudi-cano/unsocial/api/logic/index.js create mode 100644 staff/claudi-cano/unsocial/api/logic/registerUser.js create mode 100644 staff/claudi-cano/unsocial/api/logic/registerUser.test.js create mode 100644 staff/claudi-cano/unsocial/api/package.json create mode 100644 staff/claudi-cano/unsocial/api/test/authenticate-user.js create mode 100644 staff/claudi-cano/unsocial/api/test/authenticate-user.sh create mode 100644 staff/claudi-cano/unsocial/api/test/create-post.js create mode 100644 staff/claudi-cano/unsocial/api/test/create-post.sh create mode 100644 staff/claudi-cano/unsocial/api/test/get-user-name.js create mode 100644 staff/claudi-cano/unsocial/api/test/get-user-name.sh create mode 100644 staff/claudi-cano/unsocial/api/test/register-user.js create mode 100644 staff/claudi-cano/unsocial/api/test/register-user.sh diff --git a/staff/claudi-cano/unsocial/api/data/index.js b/staff/claudi-cano/unsocial/api/data/index.js new file mode 100644 index 000000000..f2c266297 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/data/index.js @@ -0,0 +1,9 @@ +import storage from './users.js' + +import uuid from './uuid.js' + +export { + storage, + + uuid +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/data/posts.json b/staff/claudi-cano/unsocial/api/data/posts.json new file mode 100644 index 000000000..e08ffba58 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/data/posts.json @@ -0,0 +1,20 @@ +[ + { + "id": "m2vw4ucygv", + "image": "https://images.squarespace-cdn.com/content/v1/6137f1eafdd46630c1744367/118c6bda-87ce-422c-95eb-1c8085e160f4/DSC00486-2.jpg", + "text": "hola patagonia", + "author": "m2vvw4xzn6d", + "date": "2024-10-30T13:06:39.922Z", + "likes": [], + "comments": [] + }, + { + "id": "m2x2g9dhsdo", + "image": "https://media.giphy.com/media/QLiqUx7aHg10bl5FVj/giphy.gif?cid=790b7611k9bnssjixy10hu88u0buneurbrjffxxhlxderris&ep=v1_gifs_search&rid=giphy.gif&ct=g", + "text": "hallo weendy", + "author": "m2vvqdtgcba", + "date": "2024-10-31T08:51:16.469Z", + "likes": [], + "comments": [] + } +] \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/data/storage.js b/staff/claudi-cano/unsocial/api/data/storage.js new file mode 100644 index 000000000..603fe655c --- /dev/null +++ b/staff/claudi-cano/unsocial/api/data/storage.js @@ -0,0 +1,31 @@ +import fs from 'fs' + +export default { + get users() { + const json = fs.readFileSync('./data/users.json', 'utf-8') + + const users = JSON.parse(json) + + return users + }, + + set users(users) { + const json = JSON.stringify(users) + + fs.writeFileSync('./data/posts.json', json) + }, + + get posts() { + const json = fs.readFileSync('./data/posts.json', 'utf-8') + + const posts = JSON.parse(json) + + return posts + }, + + set posts(posts) { + const json = JSON.stringify(posts) + + fs.writeFileSync('./data/posts.json', json) + } +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/data/storage.test.js b/staff/claudi-cano/unsocial/api/data/storage.test.js new file mode 100644 index 000000000..4ddd67caa --- /dev/null +++ b/staff/claudi-cano/unsocial/api/data/storage.test.js @@ -0,0 +1,11 @@ +import uuid from './uuid.js' + +import storage from './storage.js' + +storage.users = [ + { id: uuid(), name: 'Pepito Grillo', email: 'pepito@grillo.com', username: 'pepitogrillo', password: '123123123' } +] + +storage.posts = [] + +console.log(storage.users) \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/data/users.json b/staff/claudi-cano/unsocial/api/data/users.json new file mode 100644 index 000000000..f8adb8a77 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/data/users.json @@ -0,0 +1,16 @@ +[ + { + "id": "m2vvqdtgcba", + "name": "Pepito Grillo", + "email": "pepito@grillo.com", + "username": "pepitogrillo", + "password": "123123123" + }, + { + "id": "m2vvw4xzn6d", + "name": "Coco Drilo", + "email": "coco@drilo.com", + "username": "cocodrilo", + "password": "123123123" + } +] \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/data/uuid.js b/staff/claudi-cano/unsocial/api/data/uuid.js new file mode 100644 index 000000000..dda113a0e --- /dev/null +++ b/staff/claudi-cano/unsocial/api/data/uuid.js @@ -0,0 +1,3 @@ +const uuid = () => (Date.now() + Math.random()).toString(36).replace('.', '') + +export default uuid \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/index.js b/staff/claudi-cano/unsocial/api/index.js new file mode 100644 index 000000000..52447a650 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/index.js @@ -0,0 +1,71 @@ +import express from 'express' +import logic from './logic/index.js' + +const server = express() + +const jsonBodyParser = express.json() + +server.use(express.static('public')) + +server.post('/authenticate', jsonBodyParser, (req, res) => { + const { username, password } = req.body + + try { + const userId = logic.authenticateUser(username, password) + + res.json(userId) + } catch (error) { + res.status(401).json({ error: error.constructor.name, message: error.message }) + + console.error(error) + } +}) + +server.post('/register', jsonBodyParser, (req, res) => { + const { name, email, username, password, passwordRepeat } = req.body + + try { + logic.registerUser(name, email, username, password, passwordRepeat) + + res.status(201).send() + } catch (error) { + res.status(400).json({ error: error.constructor.name, message: error.message }) + + console.error(error) + } +}) + +server.get('/users/:userId/name', (req, res) => { + const { userId } = req.params + + try { + const name = logic.getUserName(userId) + + res.json(name) + } catch (error) { + res.status(400).json({ error: error.constructor.name, message: error.message }) + + console.error(error) + } +}) + +server.post('/posts', jsonBodyParser, (req, res) => { + const userId = req.headers.authorization.slice(6) + + const { image, text } = req.body + + try { + logic.createPost(userId, image, text) + + res.status(201).send() + } catch (error) { + res.status(400).json({ error: error.constructor.name, message: error.message }) + + console.error(error) + } +}) + + +server.listen(8080, () => console.log('api is up')) + +// TODO use cookies for session management (RTFM cookies + express) \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/authenticateUser.js b/staff/claudi-cano/unsocial/api/logic/authenticateUser.js new file mode 100644 index 000000000..0b3ff6654 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/authenticateUser.js @@ -0,0 +1,19 @@ +import { storage } from '../data/index.js' +import validate from './helpers/validate.js' + +export default (username, password) => { + validate.username(username) + validate.password(password) + + if (password.length < 8) + throw new Error('invalid password') + + const { users } = storage + + const user = users.find(user => user.username === username && user.password === password) + + if (user === undefined) + throw new Error('wrong credentials') + + return user.id +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/authenticateUser.test.js b/staff/claudi-cano/unsocial/api/logic/authenticateUser.test.js new file mode 100644 index 000000000..4b44c2d34 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/authenticateUser.test.js @@ -0,0 +1,7 @@ +import authenticateUser from "./authenticateUser"; + +try { + console.log(authenticateUser('cocodrilo', '123123123')) +} catch (error) { + console.error(error) +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/createPost.js b/staff/claudi-cano/unsocial/api/logic/createPost.js new file mode 100644 index 000000000..b7dae9e31 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/createPost.js @@ -0,0 +1,29 @@ +import { validate } from './helpers/index.js' + +import { storage, uuid } from '../data/index.js' + +export default (userId, image, text) => { + validate.id(userId, 'userId') + validate.image(image) + validate.text(text) + + const { users, posts } = storage + + const found = users.some(({ id }) => id === userId) + + if (!found) throw new Error('user not found') + + const post = { + id: uuid(), + image: image, + text: text, + author: userId, + date: new Date, + likes: [], + comments: [] + } + + posts.push(post) + + storage.posts = posts +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/createPost.test.js b/staff/claudi-cano/unsocial/api/logic/createPost.test.js new file mode 100644 index 000000000..bfa52f3d8 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/createPost.test.js @@ -0,0 +1,7 @@ +import createPost from "./createPost"; + +try { + createPost('m2vvw4xzn6d', 'https://images.squarespace-cdn.com/content/v1/6137f1eafdd46630c1744367/118c6bda-87ce-422c-95eb-1c8085e160f4/DSC00486-2.jpg', 'hola patagonia') +} catch (error) { + console.error(error) +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/getUserName.js b/staff/claudi-cano/unsocial/api/logic/getUserName.js new file mode 100644 index 000000000..6226081ba --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/getUserName.js @@ -0,0 +1,14 @@ +import { storage } from '../data/index.js' +import validate from './helpers/validate.js' + +export default userId => { + validate.id(userId, 'userId') + + const { users } = storage + + const user = users.find(user => user.id === userId) + + if (!user) throw new Error('user not found') + + return user.name +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/getUserName.test.js b/staff/claudi-cano/unsocial/api/logic/getUserName.test.js new file mode 100644 index 000000000..349282ba3 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/getUserName.test.js @@ -0,0 +1,7 @@ +import getUserName from './getUserName.js' + +try { + console.log(getUserName('m2vvw4xzn6d')) +} catch (error) { + console.error(error) +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/helpers/index.js b/staff/claudi-cano/unsocial/api/logic/helpers/index.js new file mode 100644 index 000000000..33f690fe2 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/helpers/index.js @@ -0,0 +1,5 @@ +import validate from './validate.js' + +export { + validate +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/helpers/validate.js b/staff/claudi-cano/unsocial/api/logic/helpers/validate.js new file mode 100644 index 000000000..e0e931656 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/helpers/validate.js @@ -0,0 +1,54 @@ +const validateName = name => { + if (typeof name !== 'string') throw new Error('invalid name') + if (name.length < 2) + throw new Error('invalid name length') +} + +const validateEmail = email => { + if (typeof email !== 'string') throw new Error('invalid email') + if (!/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i.test(email)) + throw new Error('invalid e-mail') +} + +const validateUsername = username => { + if (typeof username !== 'string') throw new Error('invalid username') + if (username.length < 4 || username.length > 12) + throw new Error('invalid username length') +} + +const validatePassword = password => { + if (typeof password !== 'string') throw new Error('invalid password') + if (password.length < 8) + throw new Error('invalid password length') +} + +const validatePasswordsMatch = (password, passwordRepeat) => { + if (typeof passwordRepeat !== 'string') throw new Error('invalid password repeat') + if (password !== passwordRepeat) + throw new Error('passwords do not match') +} + +const validateImage = image => { + if (typeof image !== 'string') throw new Error('invalid image') +} + +const validateText = text => { + if (typeof text !== 'string') throw new Error('invalid text') +} + +const validateId = (id, explain = 'id') => { + if (typeof id !== 'string') throw new Error(`invalid ${explain}`) +} + +const validate = { + name: validateName, + email: validateEmail, + username: validateUsername, + password: validatePassword, + passwordsMatch: validatePasswordsMatch, + image: validateImage, + text: validateText, + id: validateId +} + +export default validate \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/index.js b/staff/claudi-cano/unsocial/api/logic/index.js new file mode 100644 index 000000000..7fcac320e --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/index.js @@ -0,0 +1,14 @@ +import authenticateUser from './authenticateUser.js' +import registerUser from './registerUser.js' +import getUserName from './getUserName.js' +import createPost from './createPost.js' + +const logic = { + authenticateUser, + registerUser, + getUserName, + + createPost +} + +export default logic \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/registerUser.js b/staff/claudi-cano/unsocial/api/logic/registerUser.js new file mode 100644 index 000000000..67aac41c5 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/registerUser.js @@ -0,0 +1,24 @@ +import { storage, uuid } from '../data/index.js' + +import validate from './helpers/validate.js' + +export default (name, email, username, password, passwordRepeat) => { + validate.name(name) + validate.email(email) + validate.username(username) + validate.password(password) + validate.passwordsMatch(password, passwordRepeat) + + const { users } = storage + + let user = users.find(user => user.username === username || user.email === email) + + if (user !== undefined) + throw new Error('user already exists') + + user = { id: uuid(), name: name, email: email, username: username, password: password } + + users.push(user) + + storage.users = users +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/logic/registerUser.test.js b/staff/claudi-cano/unsocial/api/logic/registerUser.test.js new file mode 100644 index 000000000..b2d50d0fe --- /dev/null +++ b/staff/claudi-cano/unsocial/api/logic/registerUser.test.js @@ -0,0 +1,7 @@ +import registerUser from './registerUser.js' + +try { + registerUser('Coco Drilo', 'coco@drilo.com', 'cocodrilo', '123123123', '123123123') +} catch (error) { + console.error(error) +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/package.json b/staff/claudi-cano/unsocial/api/package.json new file mode 100644 index 000000000..b40e80739 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/package.json @@ -0,0 +1,18 @@ +{ + "name": "api", + "version": "1.0.0", + "description": "", + "type": "module", + "main": "index.js", + "scripts": { + "start": "node .", + "inspect": "node --inspect-brk .", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "express": "^4.21.1" + } +} \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/test/authenticate-user.js b/staff/claudi-cano/unsocial/api/test/authenticate-user.js new file mode 100644 index 000000000..80d8c9477 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/test/authenticate-user.js @@ -0,0 +1,9 @@ +const xhr = new XMLHttpRequest + +xhr.addEventListener('load', () => { + console.log(xhr.status, xhr.response) +}) + +xhr.open('POST', 'http://localhost:8080/authenticate') +xhr.setRequestHeader('Content-Type', 'application/json') +xhr.send('{"username":"pepitogrillo","password":"123123123"}') \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/test/authenticate-user.sh b/staff/claudi-cano/unsocial/api/test/authenticate-user.sh new file mode 100644 index 000000000..3b6c86fbd --- /dev/null +++ b/staff/claudi-cano/unsocial/api/test/authenticate-user.sh @@ -0,0 +1 @@ + curl -H 'Content-Type: application/json' -d '{"username":"pepitogrillo","password":"123123123"}' http://localhost:8080/authenticate -v \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/test/create-post.js b/staff/claudi-cano/unsocial/api/test/create-post.js new file mode 100644 index 000000000..e4a2397e5 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/test/create-post.js @@ -0,0 +1,10 @@ +const xhr = new XMLHttpRequest + +xhr.addEventListener('load', () => { + console.log(xhr.status, xhr.response) +}) + +xhr.open('POST', 'http://localhost:8080/posts') +xhr.setRequestHeader('Authorization', 'Basic m2vvqdtgcba') +xhr.setRequestHeader('Content-Type', 'application/json') +xhr.send('{"image":"https://media.giphy.com/media/QLiqUx7aHg10bl5FVj/giphy.gif?cid=790b7611k9bnssjixy10hu88u0buneurbrjffxxhlxderris&ep=v1_gifs_search&rid=giphy.gif&ct=g","text":"hallo weendy"}') \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/test/create-post.sh b/staff/claudi-cano/unsocial/api/test/create-post.sh new file mode 100644 index 000000000..140583b00 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/test/create-post.sh @@ -0,0 +1 @@ + curl -H 'Authorization: Basic m2vvqdtgcba' -H 'Content-Type: application/json' -d '{"image":"https://media.giphy.com/media/QLiqUx7aHg10bl5FVj/giphy.gif?cid=790b7611k9bnssjixy10hu88u0buneurbrjffxxhlxderris&ep=v1_gifs_search&rid=giphy.gif&ct=g","text":"hallo weendy"}' http://localhost:8080/posts -v \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/test/get-user-name.js b/staff/claudi-cano/unsocial/api/test/get-user-name.js new file mode 100644 index 000000000..8110365b5 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/test/get-user-name.js @@ -0,0 +1,8 @@ +const xhr = new XMLHttpRequest + +xhr.addEventListener('load', () => { + console.log(xhr.status, xhr.response) +}) + +xhr.open('GET', 'http://localhost:8080/users/m2vvqdtgcba/name') +xhr.send() \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/test/get-user-name.sh b/staff/claudi-cano/unsocial/api/test/get-user-name.sh new file mode 100644 index 000000000..1f0f1e216 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/test/get-user-name.sh @@ -0,0 +1 @@ +curl http://localhost:8080/users/m2vvqdtgcba/name -v \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/test/register-user.js b/staff/claudi-cano/unsocial/api/test/register-user.js new file mode 100644 index 000000000..ed1cd8dd4 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/test/register-user.js @@ -0,0 +1,9 @@ +const xhr = new XMLHttpRequest + +xhr.addEventListener('load', () => { + console.log(xhr.status, xhr.response) +}) + +xhr.open('POST', 'http://localhost:8080/register') +xhr.setRequestHeader('Content-Type', 'application/json') +xhr.send('{"name":"Pin Otto","email":"pin@otto.com","username":"pinotto","password":"123123123","password-repeat":"123123123"}') \ No newline at end of file diff --git a/staff/claudi-cano/unsocial/api/test/register-user.sh b/staff/claudi-cano/unsocial/api/test/register-user.sh new file mode 100644 index 000000000..16867f646 --- /dev/null +++ b/staff/claudi-cano/unsocial/api/test/register-user.sh @@ -0,0 +1 @@ + curl -H 'Content-Type: application/json' -d '{"name":"Pepito Grillo","email":"pepito@grillo.com","username":"pepitogrillo","password":"123123123","password-repeat":"123123123"}' http://localhost:8080/register -v \ No newline at end of file