initial commit

This commit is contained in:
Nuno Coração
2023-07-25 10:37:56 +01:00
parent e4a17a52bc
commit 0116c081ef
8 changed files with 1590 additions and 0 deletions

35
app/Dockerfile Normal file
View File

@@ -0,0 +1,35 @@
# syntax=docker/dockerfile:1
# Comments are provided throughout this file to help you get started.
# If you need more help, visit the Dockerfile reference guide at
# https://docs.docker.com/engine/reference/builder/
ARG NODE_VERSION=19.5.0
FROM node:${NODE_VERSION}-alpine
# Use production node environment by default.
ENV NODE_ENV production
WORKDIR /usr/src/app
# Download dependencies as a separate step to take advantage of Docker's caching.
# Leverage a cache mount to /root/.npm to speed up subsequent builds.
# Leverage a bind mounts to package.json and package-lock.json to avoid having to copy them into
# into this layer.
RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=package-lock.json,target=package-lock.json \
--mount=type=cache,target=/root/.npm \
npm ci --omit=dev
# Run the application as a non-root user.
USER node
# Copy the rest of the source files into the image.
COPY . .
# Expose the port that the application listens on.
EXPOSE 3001
# Run the application.
CMD npm run dev

3
app/config/keys.js Normal file
View File

@@ -0,0 +1,3 @@
module.exports = {
mongoProdURI: 'mongodb://todo-database:27017/todoapp',
};

15
app/models/Todo.js Normal file
View File

@@ -0,0 +1,15 @@
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const TodoSchema = new Schema({
task: {
type: String,
required: true
},
created_at: {
type: Date,
default: Date.now()
}
});
module.exports = Todo = mongoose.model('todos', TodoSchema);

1384
app/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

20
app/package.json Normal file
View File

@@ -0,0 +1,20 @@
{
"name": "multi-container-apps",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "node server.js",
"dev": "nodemon server.js -e js,ejs,mjs,cjs,json"
},
"author": "",
"license": "ISC",
"dependencies": {
"body-parser": "^1.20.2",
"ejs": "^3.1.9",
"express": "^4.18.2",
"moment": "^2.29.4",
"mongoose": "^7.1.0",
"nodemon": "^3.0.1"
}
}

34
app/routes/front.js Normal file
View File

@@ -0,0 +1,34 @@
const express = require('express');
const Todo = require('./../models/Todo');
const router = express.Router();
// Home page route
router.get('/', async (req, res) => {
const todos = await Todo.find()
res.render("todos", {
tasks: (Object.keys(todos).length > 0 ? todos : {})
});
});
// POST - Submit Task
router.post('/', (req, res) => {
const newTask = new Todo({
task: req.body.task
});
newTask.save()
.then(task => res.redirect('/'))
.catch(err => console.log(err));
});
// POST - Destroy todo item
router.post('/todo/destroy', async (req, res) => {
const taskKey = req.body._key;
const err = await Todo.findOneAndRemove({_id: taskKey})
res.redirect('/');
});
module.exports = router;

29
app/server.js Normal file
View File

@@ -0,0 +1,29 @@
const mongoose = require('mongoose');
const bodyParse = require('body-parser');
const app = require('express')();
const moment = require('moment');
// Fontend route
const FrontRouter = require('./routes/front');
// Set ejs template engine
app.set('view engine', 'ejs');
app.use(bodyParse.urlencoded({ extended: false }));
app.locals.moment = moment;
// Database connection
const db = require('./config/keys').mongoProdURI;
mongoose
.connect(db, { useNewUrlParser: true })
.then(() => console.log(`Mongodb Connected`))
.catch(error => console.log(error));
app.use(FrontRouter);
const PORT = process.env.PORT || 3001;
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});

70
app/views/todos.ejs Normal file
View File

@@ -0,0 +1,70 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Todo App</title>
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="//stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<div class="app">
<header>
<nav class="navbar navbar-dark bg-primary">
<span class="navbar-brand mb-0 h1">Todo App</span>
</nav>
</header>
<div class="container">
<div class="row">
<div class="col-md-8 m-auto pt-4">
<form method="POST" action="/" autocomplete="off">
<div class="row">
<div class="col-12 form-group">
<label for="todo">Enter your task</label>
<input type="text" name="task" class="form-control" />
</div>
</div>
</form>
<hr>
<div class="row">
<div class="col-12">
<% if(Object.keys(tasks).length> 0) { %>
<ul class="nav flex-column">
<% tasks.forEach(todo=> { %>
<li class="nav-item">
<div class="d-flex justify-content-between py-1">
<div class="d-flex flex-row">
<div>
<%= todo.task %>
<p class="text-muted"><small>
<%= moment(todo.created_at).fromNow() %>
</small></p>
</div>
</div>
<a href="javascript:;" onclick="this.children[0].submit()"
class="text-danger">
<form method="POST" action="/todo/destroy">
<input type="hidden" name="_key" value="<%= todo._id %>" />
</form>
<i class="fa fa-trash-o"></i>
</a>
</div>
</li>
<% }) %>
</ul>
<% } else { %>
<div class="text-center"><strong>Please add some task.</strong></div>
<% }%>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>