diff --git a/README.md b/README.md index e69de29..4f2740c 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,8 @@ +# node-docker-example + +This app showcases a website built with NodeJS. The site has a set of +articles, each article has a separate page, all data about the article +is stored in the PostgreSQL database. Docker is used to deploy the +application. + +## How to deploy diff --git a/controllers/ArticleController.js b/controllers/ArticleController.js index 1a78a3e..914a4dc 100644 --- a/controllers/ArticleController.js +++ b/controllers/ArticleController.js @@ -40,8 +40,7 @@ class ArticleController { /** * Validate url `id` param */ - const id = req.params.id; - if (!/^\d+$/.test(id)) { + if (!req.params || !/^\d+$/.test(req.params.id)) { res.render( './views/404.hbs', { title: '404 | Article not found.' }, @@ -50,7 +49,7 @@ class ArticleController { return; } - const article = await ArticleModel.getById(id); + const article = await ArticleModel.getById(req.params.id); /** * Not found @@ -94,6 +93,29 @@ class ArticleController { res.serverError(error); } } + + /** + * Delete article by `id` + * + * @param {http.ClientRequest} req + * @param {Response} res + */ + static async delete(req, res) { + try { + /** + * Validate url `id` param + */ + if (!req.params || !/^\d+$/.test(req.params.id)) { + res.render('./views/403.hbs', { title: '403 | Bad request.' }, 403); + return; + } + + await ArticleModel.delete(req.params.id); + res.redirect(`/`); + } catch (error) { + res.serverError(error); + } + } } export default ArticleController; diff --git a/models/ArticleModel.js b/models/ArticleModel.js index fd82dca..370e940 100644 --- a/models/ArticleModel.js +++ b/models/ArticleModel.js @@ -14,6 +14,7 @@ import db from '#app/db'; class ArticleModel { /** * Get list of articles + * * @returns {Promise>} List of articles */ static async getAll() { @@ -73,6 +74,19 @@ class ArticleModel { throw error; } } + + /** + * Delete article by `id` + * + * @param {string} id + */ + static async delete(id) { + try { + await db.client.query(`DELETE FROM "articles" WHERE id = $1`, [id]); + } catch (error) { + throw error; + } + } } export default ArticleModel; diff --git a/preloads/routes.js b/preloads/routes.js index 8c36a61..7f3e605 100644 --- a/preloads/routes.js +++ b/preloads/routes.js @@ -17,4 +17,5 @@ import WaitMiddleware from '#middlewares/WaitMiddleware'; router.get('/', ArticleController.index).middleware([WaitMiddleware.handle]); router.get('/articles/:id', ArticleController.show); router.post('/articles', ArticleController.create); +router.post('/articles/:id', ArticleController.delete); router.get('/editor/create', EditorController.create); diff --git a/public/css/style.css b/public/css/style.css index bb981f0..e151d65 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -55,6 +55,16 @@ textarea { display: block; } +.app article .article-heading { + display: flex; + align-items: center; + justify-content: space-between; +} + +.app article .article-heading button { + padding: 5px; +} + .app .app-footer { text-align: center; } diff --git a/router.js b/router.js index d5fd0d6..0ca5956 100644 --- a/router.js +++ b/router.js @@ -179,6 +179,16 @@ class Router { post(url, handler) { return this.define('POST', url, handler); } + + /** + * DELETE Method route + * + * @param {*} url + * @param {*} handler + */ + delete(url, handler) { + return this.define('DELETE', url, handler); + } } export default new Router(); diff --git a/views/403.hbs b/views/403.hbs new file mode 100644 index 0000000..92e5ece --- /dev/null +++ b/views/403.hbs @@ -0,0 +1,7 @@ + + {{> head }} + +

{{ title }}

+ < return to home + + \ No newline at end of file diff --git a/views/index.hbs b/views/index.hbs index c31650e..b0bee26 100644 --- a/views/index.hbs +++ b/views/index.hbs @@ -23,13 +23,22 @@ {{/unless}} {{#each articles}}
-

- - {{ this.title }} - -

-

{{ this.description }}

- +
+

+ + {{ this.title }} + +

+
+ +
+
+
+

{{ this.description }}

+
+
+ +

{{/each}}