mirror of
https://github.com/sergeyyarkov/node-docker-example.git
synced 2026-10-11 18:29:34 +03:00
feat: deleting article
This commit is contained in:
parent
9c84c17308
commit
3266939fdc
@ -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
|
||||||
@ -40,8 +40,7 @@ class ArticleController {
|
|||||||
/**
|
/**
|
||||||
* Validate url `id` param
|
* Validate url `id` param
|
||||||
*/
|
*/
|
||||||
const id = req.params.id;
|
if (!req.params || !/^\d+$/.test(req.params.id)) {
|
||||||
if (!/^\d+$/.test(id)) {
|
|
||||||
res.render(
|
res.render(
|
||||||
'./views/404.hbs',
|
'./views/404.hbs',
|
||||||
{ title: '404 | Article not found.' },
|
{ title: '404 | Article not found.' },
|
||||||
@ -50,7 +49,7 @@ class ArticleController {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const article = await ArticleModel.getById(id);
|
const article = await ArticleModel.getById(req.params.id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Not found
|
* Not found
|
||||||
@ -94,6 +93,29 @@ class ArticleController {
|
|||||||
res.serverError(error);
|
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;
|
export default ArticleController;
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import db from '#app/db';
|
|||||||
class ArticleModel {
|
class ArticleModel {
|
||||||
/**
|
/**
|
||||||
* Get list of articles
|
* Get list of articles
|
||||||
|
*
|
||||||
* @returns {Promise<Array<Article>>} List of articles
|
* @returns {Promise<Array<Article>>} List of articles
|
||||||
*/
|
*/
|
||||||
static async getAll() {
|
static async getAll() {
|
||||||
@ -73,6 +74,19 @@ class ArticleModel {
|
|||||||
throw error;
|
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;
|
export default ArticleModel;
|
||||||
|
|||||||
@ -17,4 +17,5 @@ import WaitMiddleware from '#middlewares/WaitMiddleware';
|
|||||||
router.get('/', ArticleController.index).middleware([WaitMiddleware.handle]);
|
router.get('/', ArticleController.index).middleware([WaitMiddleware.handle]);
|
||||||
router.get('/articles/:id', ArticleController.show);
|
router.get('/articles/:id', ArticleController.show);
|
||||||
router.post('/articles', ArticleController.create);
|
router.post('/articles', ArticleController.create);
|
||||||
|
router.post('/articles/:id', ArticleController.delete);
|
||||||
router.get('/editor/create', EditorController.create);
|
router.get('/editor/create', EditorController.create);
|
||||||
|
|||||||
@ -55,6 +55,16 @@ textarea {
|
|||||||
display: block;
|
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 {
|
.app .app-footer {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|||||||
10
router.js
10
router.js
@ -179,6 +179,16 @@ class Router {
|
|||||||
post(url, handler) {
|
post(url, handler) {
|
||||||
return this.define('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();
|
export default new Router();
|
||||||
|
|||||||
7
views/403.hbs
Normal file
7
views/403.hbs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<html lang='en'>
|
||||||
|
{{> head }}
|
||||||
|
<body>
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
<a href="/">< return to home</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -23,13 +23,22 @@
|
|||||||
{{/unless}}
|
{{/unless}}
|
||||||
{{#each articles}}
|
{{#each articles}}
|
||||||
<article>
|
<article>
|
||||||
|
<div class="article-heading">
|
||||||
<h2>
|
<h2>
|
||||||
<a href='articles/{{this.id}}'>
|
<a href='articles/{{ this.id }}'>
|
||||||
{{ this.title }}
|
{{ this.title }}
|
||||||
</a>
|
</a>
|
||||||
</h2>
|
</h2>
|
||||||
|
<form method='post' action='/articles/{{ this.id }}'>
|
||||||
|
<button type="submit">✕</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="article-description">
|
||||||
<p>{{ this.description }}</p>
|
<p>{{ this.description }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="article-time">
|
||||||
<time>{{ this.created_at }}</time>
|
<time>{{ this.created_at }}</time>
|
||||||
|
</div>
|
||||||
</article>
|
</article>
|
||||||
<hr />
|
<hr />
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user