initial commit
This commit is contained in:
35
app/Dockerfile
Normal file
35
app/Dockerfile
Normal 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
3
app/config/keys.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
mongoProdURI: 'mongodb://todo-database:27017/todoapp',
|
||||
};
|
||||
15
app/models/Todo.js
Normal file
15
app/models/Todo.js
Normal 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
1384
app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
app/package.json
Normal file
20
app/package.json
Normal 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
34
app/routes/front.js
Normal 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
29
app/server.js
Normal 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
70
app/views/todos.ejs
Normal 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>
|
||||
Reference in New Issue
Block a user