diff --git a/staff/adrian-martin/socialcode/api/README.md b/staff/adrian-martin/socialcode/api/README.md index bebcf5c54..7e8235e84 100644 --- a/staff/adrian-martin/socialcode/api/README.md +++ b/staff/adrian-martin/socialcode/api/README.md @@ -69,6 +69,27 @@ xhr.send(json) ``` - list posts +```js +const xhr = new XMLHttpRequest + +xhr.onload = () => { + if (xhr.status === 200) { + const posts = JSON.parse(xhr.response) + + console.log('posts retrived', posts) + + return + } + + const { error, message } = JSON.parse(xhr.response) + + console.error(error, message) +} + +xhr.open('GET', 'http://localhost:8080/posts') + +xhr.send() +``` ```sh 🐖 curl http://localhost:8080/posts -v ``` @@ -76,5 +97,5 @@ xhr.send(json) - create post ```sh -🐖 curl -X POST http://localhost:8080/posts -H "Content-Type: application/json" -d '{"author":"pepitogrillo","title":"blah","image":"https://m.media-amazon.com/images/I/41xsPjrM-pL._AC_UF350,350_QL50_.jpg","description":"blah blah"}' -v +🐖 $ curl -X POST http://localhost:8080/posts -H "Authorization: Basic AdrianGon" -H "Content-Type: application/json" -d '{"title":"Buenos Dias","image":"https://imgs.search.brave.com/J8imP8bduv7lIhsfCsnGwaeKNgdHqp2g5dCpK8aVkYA/rs:fit:860:0:0/g:ce/aHR0cHM6Ly90My5m/dGNkbi5uZXQvanBn/LzAxLzAzLzM2LzA0/LzM2MF9GXzEwMzM2/MDQyNV9IekJxZEkx/d1dOTjBWU3Z2ZXkw/R3RRTlRvaDJLenhy/Ny5qcGc","description":"blah blah"}' -v ``` \ No newline at end of file diff --git a/staff/adrian-martin/socialcode/api/data/posts.json b/staff/adrian-martin/socialcode/api/data/posts.json index f4e3774c7..f147bc38e 100644 --- a/staff/adrian-martin/socialcode/api/data/posts.json +++ b/staff/adrian-martin/socialcode/api/data/posts.json @@ -1 +1 @@ -[{"author":"jameshook","title":"smile 2","image":"https://m.media-amazon.com/images/I/41xsPjrM-pL._AC_UF350,350_QL50_.jpg","description":"hi 2","date":"2024-05-27T14:44:14.236Z","id":"8448820043690848-1716821054237"},{"author":"jameshook","title":"smile 2","image":"https://m.media-amazon.com/images/I/41xsPjrM-pL._AC_UF350,350_QL50_.jpg","description":"hi 2","date":"2024-05-27T14:44:21.737Z","id":"05670034285101688-1716821061738"},{"author":"jameshook","title":"smile 2","image":"https://m.media-amazon.com/images/I/41xsPjrM-pL._AC_UF350,350_QL50_.jpg","description":"hi 2","date":"2024-05-27T14:44:23.250Z","id":"549161270915079-1716821063251"}] \ No newline at end of file +[{"author":"jameshook","title":"smile1","image":"https://m.media-amazon.com/images/I/41xsPjrM-pL._AC_UF350,350_QL50_.jpg","description":"hi 2","date":"2024-05-27T14:44:14.236Z","id":"8448820043690848-1716821054237"},{"author":"jameshook","title":"smile2","image":"https://m.media-amazon.com/images/I/41xsPjrM-pL._AC_UF350,350_QL50_.jpg","description":"hi 2","date":"2024-05-27T14:44:21.737Z","id":"05670034285101688-1716821061738"},{"author":"jameshook","title":"smile3","image":"https://m.media-amazon.com/images/I/41xsPjrM-pL._AC_UF350,350_QL50_.jpg","description":"hi 2","date":"2024-05-27T14:44:23.250Z","id":"549161270915079-1716821063251"},{"id":"7049627815708344-1716989932607","author":"AdrianGon","title":"smil3","image":"https://imgs.search.brave.com/rY4vd7ChrTffot87xezWVyJZcsjp10UPNHx2EQMRCfs/rs:fit:860:0:0/g:ce/aHR0cHM6Ly9pLnBp/bmltZy5jb20vb3Jp/Z2luYWxzLzFiL2Qx/L2I2LzFiZDFiNjE1/ZTZkYTcwZGQ3MWRj/ODRmZDJmNDdjODBk/LmpwZw","description":"hi 2","date":"2024-05-29T13:38:52.607Z"},{"id":"11703272214754645-1716989975016","author":"AdrianGon","title":"smil3","image":"https://imgs.search.brave.com/rY4vd7ChrTffot87xezWVyJZcsjp10UPNHx2EQMRCfs/rs:fit:860:0:0/g:ce/aHR0cHM6Ly9pLnBp/bmltZy5jb20vb3Jp/Z2luYWxzLzFiL2Qx/L2I2LzFiZDFiNjE1/ZTZkYTcwZGQ3MWRj/ODRmZDJmNDdjODBk/LmpwZw","description":"hi 2","date":"2024-05-29T13:39:35.015Z"},{"id":"7956804321626201-1716989998965","author":"AdrianGon","title":"smile4","image":"https://imgs.search.brave.com/rY4vd7ChrTffot87xezWVyJZcsjp10UPNHx2EQMRCfs/rs:fit:860:0:0/g:ce/aHR0cHM6Ly9pLnBp/bmltZy5jb20vb3Jp/Z2luYWxzLzFiL2Qx/L2I2LzFiZDFiNjE1/ZTZkYTcwZGQ3MWRj/ODRmZDJmNDdjODBk/LmpwZw","description":"hi 2","date":"2024-05-29T13:39:58.965Z"},{"author":"AdrianGon","title":"Buenos Dias","image":"https://imgs.search.brave.com/J8imP8bduv7lIhsfCsnGwaeKNgdHqp2g5dCpK8aVkYA/rs:fit:860:0:0/g:ce/aHR0cHM6Ly90My5m/dGNkbi5uZXQvanBn/LzAxLzAzLzM2LzA0/LzM2MF9GXzEwMzM2/MDQyNV9IekJxZEkx/d1dOTjBWU3Z2ZXkw/R3RRTlRvaDJLenhy/Ny5qcGc","description":"blah blah","date":"2024-05-29T13:55:28.417Z","id":"7707579376266043-1716990928418"},{"author":"AdrianGon","title":"Buenos Dias","image":"https://imgs.search.brave.com/J8imP8bduv7lIhsfCsnGwaeKNgdHqp2g5dCpK8aVkYA/rs:fit:860:0:0/g:ce/aHR0cHM6Ly90My5m/dGNkbi5uZXQvanBn/LzAxLzAzLzM2LzA0/LzM2MF9GXzEwMzM2/MDQyNV9IekJxZEkx/d1dOTjBWU3Z2ZXkw/R3RRTlRvaDJLenhy/Ny5qcGc","description":"blah blah","date":"2024-05-29T14:01:59.825Z","id":"7741423721689134-1716991319825"},{"author":"AdrianGon","title":"Adrian","image":"https://imgs.search.brave.com/2TUrjrEEig4i0QI4ygiyBBQipd90pfaTC6MV2CYvsjg/rs:fit:500:0:0/g:ce/aHR0cHM6Ly93d3cu/aGFpa3Utb3Mub3Jn/L2RvY3MvdXNlcmd1/aWRlL2VzL2ltYWdl/cy9hcHBzLWltYWdl/cy9kZWJ1Z2dlci5w/bmc","description":"debugger","date":"2024-05-29T14:16:48.728Z","id":"9617450442045541-1716992208729"}] \ No newline at end of file diff --git a/staff/adrian-martin/socialcode/api/index.js b/staff/adrian-martin/socialcode/api/index.js index 9cce5c3e2..9b2375d8d 100644 --- a/staff/adrian-martin/socialcode/api/index.js +++ b/staff/adrian-martin/socialcode/api/index.js @@ -76,7 +76,7 @@ api.get('/posts', (req, res) => { return } - res.status(201).send(posts) + res.json(posts) }) } catch (error) { res.status(500).json({ error: error.constructor.name, message: error.message }) @@ -85,36 +85,24 @@ api.get('/posts', (req, res) => { api.post('/posts', jsonBodyParser, (req, res) => { - const post = req.body + const username = req.headers.authorization.slice(6) - // TODO use logic here - - fs.readFile('./data/posts.json', 'utf8', (error, json) => { - if (error) { - res.status(500).json({ error: error.constructor.name, message: error.message }) - - return - } - - const posts = JSON.parse(json) - - post.id = `${Math.random().toString().slice(2)}-${Date.now()}` - post.date = new Date().toISOString() - - posts.push(post) - - const newJson = JSON.stringify(posts) + const { title, image, description } = req.body + - fs.writeFile('./data/posts.json', newJson, error => { + try { + logic.createPost(username, title, image, description, error => { if (error) { - res.status(500).json({ error: error.constructor.name, message: error.message }) - + res.status(500).json({error: error.constructor.name, message: error.message}) + return } - + res.status(201).send() }) - }) + } catch (error) { + console.error(error) + } }) api.listen(8080, () => console.log('api is up')) diff --git a/staff/adrian-martin/socialcode/api/logic/index.js b/staff/adrian-martin/socialcode/api/logic/index.js index 596d7fcbb..a21d873b6 100644 --- a/staff/adrian-martin/socialcode/api/logic/index.js +++ b/staff/adrian-martin/socialcode/api/logic/index.js @@ -128,25 +128,49 @@ logic.getAllPosts = callback => { return } - callback(null, posts) + callback(null, posts.reverse()) }) } -logic.createPost = (username, image, description) => { +logic.createPost = (username, title, image, description, callback) => { + if (!USERNAME_REGEX.test(username)) + throw new ContentError('username is not valid') if (typeof title !== 'string' || !title.length || title.length > 50) throw new ContentError('title is not valid') if (typeof image !== 'string' || !image.startsWith('http')) throw new ContentError('image is not valid') if (typeof description !== 'string' || !description.length || description.length > 200) throw new ContentError('description is not valid') - const post = { - id: Date.now(), - author: username, - title, - image, - description, - date: new Date().toISOString() - } + data.findUser(user => user.username === username, (error, user) => { + if (error) { + callback(error) + + return + } + + if (!user) { + callback(new MatchError('user not found')) + + return + } + + const post = { + author: username, + title, + image, + description, + date: new Date().toISOString() + } + + data.insertPost(post, error => { + if (error) { + callback(error) + + return + } + + callback(null) + }) + }) - data.insertPost(post) } diff --git a/staff/adrian-martin/socialcode/api/logic/index.test.js b/staff/adrian-martin/socialcode/api/logic/index.test.js index dfbfd849b..3dd5e03d1 100644 --- a/staff/adrian-martin/socialcode/api/logic/index.test.js +++ b/staff/adrian-martin/socialcode/api/logic/index.test.js @@ -14,29 +14,33 @@ import logic from './index.js' // console.error(error) // } -try { - logic.authenticateUser('AdrianGon', '321321321', error => { - if (error) { - console.error(error) +// try { +// logic.authenticateUser('AdrianGon', '321321321', error => { +// if (error) { +// console.error(error) - return - } +// return +// } - console.log('user authenticated') - }) -} catch (error) { - console.error(error) -} +// console.log('user authenticated') +// }) +// } catch (error) { +// console.error(error) +// } -// logic.getAllPosts( (error, posts) => { -// if(error) { -// console.error(error) +// try { +// logic.getAllPosts((error, posts) => { +// if (error) { +// console.error(error) -// return -// } +// return +// } -// console.log(posts) -// }) +// console.log('posts retrived', posts) +// }) +// } catch (error) { +// console.error(error) +// } // logic.getUsername('Pepito', error => { // if(error){ @@ -46,4 +50,18 @@ try { // } // console.log(users) -// }) \ No newline at end of file +// }) + +try { + logic.createPost('AdrianGon', 'smile4', 'https://imgs.search.brave.com/rY4vd7ChrTffot87xezWVyJZcsjp10UPNHx2EQMRCfs/rs:fit:860:0:0/g:ce/aHR0cHM6Ly9pLnBp/bmltZy5jb20vb3Jp/Z2luYWxzLzFiL2Qx/L2I2LzFiZDFiNjE1/ZTZkYTcwZGQ3MWRj/ODRmZDJmNDdjODBk/LmpwZw', 'hi 2', error => { + if (error) { + console.error(error) + + return + } + + console.log('posts created') + }) +} catch (error) { + console.error(error) +} \ No newline at end of file diff --git a/staff/adrian-martin/socialcode/api/public/app/home/components/CreatePostForm.js b/staff/adrian-martin/socialcode/api/public/app/home/components/CreatePostForm.js index 291e51790..c7df88c48 100644 --- a/staff/adrian-martin/socialcode/api/public/app/home/components/CreatePostForm.js +++ b/staff/adrian-martin/socialcode/api/public/app/home/components/CreatePostForm.js @@ -16,10 +16,10 @@ class CreatePostForm extends FormWithFeedback { const cancelButton = new Button('Cancel') cancelButton.setType('button') - + cancelButton.onClick(event => { event.preventDefault() - + this.clear() this.onCancelClickListener() @@ -35,51 +35,63 @@ class CreatePostForm extends FormWithFeedback { this.onSubmit(event => { event.preventDefault() - + const title = this.getTitle() const image = this.getImage() const description = this.getDescription() - try{ - logic.createPost(title, image, description) + try { + logic.createPost(title, image, description, error => { + if (error) { + console.error(error.message) + + if (error instanceof ContentError) + this.setFeedback(error.message + '. please, repeat it') - this.clear() + else + this.setFeedback('sorry, there was an error, please try again later') - this.onPostCreatedListener() - }catch (error){ - if (error instanceof ContentError) + return + } + this.clear() + + this.onPostCreatedListener() + }) + + } catch (error) { + if (error instanceof ContentError) this.setFeedback(error.message + '. please, repeat it') else this.setFeedback('sorry, there was an error, please try again later') - } + } }) - - } - getTitle() { - const titleField = this.children[0] + } - return titleField.getValue() - } + getTitle() { + const titleField = this.children[0] - getImage() { - const imageField = this.children[1] + return titleField.getValue() + } + + getImage() { + const imageField = this.children[1] + + return imageField.getValue() + } - return imageField.getValue() - } + getDescription() { + const descriptionField = this.children[2] - getDescription() { - const descriptionField = this.children[2] - - return descriptionField.getValue() - } + return descriptionField.getValue() + } - onCancelClick(listener) { - this.onCancelClickListener = listener - } + onCancelClick(listener) { + this.onCancelClickListener = listener + } - onPostCreated(listener) { - this.onPostCreatedListener = listener - } + onPostCreated(listener) { + this.onPostCreatedListener = listener } +} diff --git a/staff/adrian-martin/socialcode/api/public/app/home/components/PostList.js b/staff/adrian-martin/socialcode/api/public/app/home/components/PostList.js index 0e50e6fc4..84a9a6d1d 100644 --- a/staff/adrian-martin/socialcode/api/public/app/home/components/PostList.js +++ b/staff/adrian-martin/socialcode/api/public/app/home/components/PostList.js @@ -10,14 +10,33 @@ class PostList extends Component { load() { this.removeAll() - const posts = logic.getAllPosts() + try { + logic.getAllPosts((error, posts) => { + if (error) { + console.error(error) - posts.forEach(post => { - const post2 = new Post(post) + //TODO show feedback to the user - post2.onPostDeleted(() => this.load()) + alert(error.message) + + return + } + + posts.forEach(post => { + const post2 = new Post(post) + + post2.onPostDeleted(() => this.load()) + + this.add(post2) + }); + }) + } catch (error) { + console.error(error) + + //TODO show feedback to the user + + alert(error.message) + } - this.add(post2) - }); } } \ No newline at end of file diff --git a/staff/adrian-martin/socialcode/api/public/app/home/index.js b/staff/adrian-martin/socialcode/api/public/app/home/index.js index 64803002f..5f160939b 100644 --- a/staff/adrian-martin/socialcode/api/public/app/home/index.js +++ b/staff/adrian-martin/socialcode/api/public/app/home/index.js @@ -68,8 +68,8 @@ addPostButton.setText('+') addPostButton.onClick(() => main.add(createPostForm)) header.add(appTitle) -header.add(logoutButton) header.add(usernameTitle) +header.add(logoutButton) footer.add(addPostButton) diff --git a/staff/adrian-martin/socialcode/api/public/app/logic.js b/staff/adrian-martin/socialcode/api/public/app/logic.js index 390e12869..24a7ee8d8 100644 --- a/staff/adrian-martin/socialcode/api/public/app/logic.js +++ b/staff/adrian-martin/socialcode/api/public/app/logic.js @@ -124,26 +124,65 @@ logic.getUsername = (username, callback) => { }) } -logic.getAllPosts = () => { - const posts = data.findPosts(() => { return true }) +logic.getAllPosts = callback => { + const xhr = new XMLHttpRequest + + xhr.onload = () => { + if (xhr.status === 200) { + const posts = JSON.parse(xhr.response) + + callback(null, posts) + + return + } + + const { error, message } = JSON.parse(xhr.response) - return posts.reverse() + const constructor = errors[error] + + callback(new constructor(message)) + } + + xhr.open('GET', 'http://localhost:8080/posts') + + xhr.send() } -logic.createPost = (title, image, description) => { +logic.createPost = (title, image, description, callback) => { if (typeof title !== 'string' || !title.length || title.length > 30) throw new ContentError('title is not valid') if (typeof image !== 'string' || !image.startsWith('http')) throw new ContentError('image is not valid') if (typeof description !== 'string' || !description.length || description.length > 200) throw new ContentError('description is not valid') - const post = { - author: sessionStorage.username, + const xhr = new XMLHttpRequest + + xhr.onload = () => { + if (xhr.status === 201) { + callback(null) + + return + } + + const { error, message } = JSON.parse(xhr.response) + + const constructor = errors[error] + + callback(new constructor(message)) + } + + xhr.open('POST', 'http://localhost:8080/posts') + + xhr.setRequestHeader('Authorization', `Basic ${sessionStorage.username}`) + + const body = { title, image, description, - date: new Date().toISOString() } - data.insertPost(post) + const json = JSON.stringify(body) + + xhr.setRequestHeader('Content-Type', 'application/json') + xhr.send(json) } logic.getLoggedInUsername = () => sessionStorage.username