z1 docker app
This commit is contained in:
commit
9fb1ac67af
42
README.md
Normal file
42
README.md
Normal file
@ -0,0 +1,42 @@
|
||||
# TODO Docker aplikacia
|
||||
|
||||
## Podmienky
|
||||
- Linux
|
||||
- Docker
|
||||
- Docker Compose
|
||||
|
||||
## Opis aplikacie
|
||||
Jednoducha TODO aplikacia, kde moze pouzivatel:
|
||||
- pridavat ulohy
|
||||
- upravovat ich
|
||||
- mazat ich
|
||||
- nastavovat datum a cas
|
||||
|
||||
## Sluzby
|
||||
- frontend: nginx (port 8080)
|
||||
- backend: Node.js (port 3000)
|
||||
- databaza: MongoDB
|
||||
|
||||
## Siet a volume
|
||||
- siet: app_network
|
||||
- volume: mongo_data (uchovanie dat)
|
||||
|
||||
## Spustenie
|
||||
|
||||
- Priprava:
|
||||
./prepare-app.sh
|
||||
|
||||
|
||||
- Spustenie:
|
||||
.start-app.sh
|
||||
|
||||
|
||||
- Aplikacia:
|
||||
http://localhost:8080
|
||||
|
||||
- Zastavenie:
|
||||
./stop-app.sh
|
||||
|
||||
|
||||
- Odstranenie:
|
||||
./remove-app.sh
|
||||
9
backend/Dockerfile
Normal file
9
backend/Dockerfile
Normal file
@ -0,0 +1,9 @@
|
||||
FROM node:18
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY server.js .
|
||||
|
||||
RUN npm init -y && npm install express mongoose cors
|
||||
|
||||
CMD ["node", "server.js"]
|
||||
50
backend/server.js
Normal file
50
backend/server.js
Normal file
@ -0,0 +1,50 @@
|
||||
const express = require('express');
|
||||
const mongoose = require('mongoose');
|
||||
const cors = require('cors');
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
app.use(cors());
|
||||
|
||||
mongoose.connect('mongodb://db:27017/todo');
|
||||
|
||||
const Task = mongoose.model('Task', {
|
||||
text: String,
|
||||
due: String
|
||||
});
|
||||
|
||||
// GET
|
||||
app.get('/tasks', async (req, res) => {
|
||||
const tasks = await Task.find();
|
||||
res.json(tasks);
|
||||
});
|
||||
|
||||
// POST
|
||||
app.post('/tasks', async (req, res) => {
|
||||
const task = new Task({
|
||||
text: req.body.text,
|
||||
due: req.body.due
|
||||
});
|
||||
await task.save();
|
||||
res.send("ok");
|
||||
});
|
||||
|
||||
// DELETE
|
||||
app.delete('/tasks/:id', async (req, res) => {
|
||||
await Task.findByIdAndDelete(req.params.id);
|
||||
res.send("deleted");
|
||||
});
|
||||
|
||||
// UPDATE
|
||||
app.put('/tasks/:id', async (req, res) => {
|
||||
await Task.findByIdAndUpdate(req.params.id, {
|
||||
text: req.body.text,
|
||||
due: req.body.due
|
||||
});
|
||||
res.send("updated");
|
||||
});
|
||||
|
||||
app.listen(3000, () => {
|
||||
console.log("Backend bezi na porte 3000");
|
||||
});
|
||||
36
docker-compose.yaml
Normal file
36
docker-compose.yaml
Normal file
@ -0,0 +1,36 @@
|
||||
services:
|
||||
frontend:
|
||||
image: nginx:latest
|
||||
restart: always
|
||||
ports:
|
||||
- "8080:80"
|
||||
volumes:
|
||||
- ./frontend:/usr/share/nginx/html
|
||||
depends_on:
|
||||
- backend
|
||||
networks:
|
||||
- app_network
|
||||
|
||||
backend:
|
||||
build: ./backend
|
||||
restart: always
|
||||
ports:
|
||||
- "3000:3000"
|
||||
depends_on:
|
||||
- db
|
||||
networks:
|
||||
- app_network
|
||||
|
||||
db:
|
||||
image: mongo:latest
|
||||
restart: always
|
||||
volumes:
|
||||
- mongo_data:/data/db
|
||||
networks:
|
||||
- app_network
|
||||
|
||||
volumes:
|
||||
mongo_data:
|
||||
|
||||
networks:
|
||||
app_network:
|
||||
86
frontend/index.html
Normal file
86
frontend/index.html
Normal file
@ -0,0 +1,86 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>TODO App</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>TODO List</h1>
|
||||
|
||||
<input id="task" placeholder="napis ulohu">
|
||||
<input id="due" type="datetime-local">
|
||||
<button onclick="addTask()">Pridaj</button>
|
||||
|
||||
<div id="list"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function loadTasks() {
|
||||
const res = await fetch('http://localhost:3000/tasks');
|
||||
const data = await res.json();
|
||||
|
||||
const list = document.getElementById('list');
|
||||
list.innerHTML = "";
|
||||
|
||||
data.forEach(t => {
|
||||
const li = document.createElement('div');
|
||||
li.className = "task";
|
||||
|
||||
li.innerHTML = `
|
||||
<span>
|
||||
${t.text} |
|
||||
${t.due ? t.due.split('T')[0] : ""} |
|
||||
${t.due ? t.due.split('T')[1] : ""}
|
||||
</span>
|
||||
<div class="buttons">
|
||||
<button class="delete" onclick="deleteTask('${t._id}')">X</button>
|
||||
<button class="edit" onclick="editTask('${t._id}', '${t.text}', '${t.due}')">Edit</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
list.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
async function addTask() {
|
||||
const text = document.getElementById('task').value;
|
||||
const due = document.getElementById('due').value;
|
||||
|
||||
await fetch('http://localhost:3000/tasks', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({text, due})
|
||||
});
|
||||
|
||||
document.getElementById('task').value = "";
|
||||
document.getElementById('due').value = "";
|
||||
|
||||
loadTasks();
|
||||
}
|
||||
|
||||
async function deleteTask(id) {
|
||||
await fetch(`http://localhost:3000/tasks/${id}`, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
loadTasks();
|
||||
}
|
||||
|
||||
async function editTask(id, oldText, oldDue) {
|
||||
const text = prompt("novy text:", oldText);
|
||||
const due = prompt("novy datum:", oldDue);
|
||||
|
||||
await fetch(`http://localhost:3000/tasks/${id}`, {
|
||||
method: 'PUT',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({text, due})
|
||||
});
|
||||
|
||||
loadTasks();
|
||||
}
|
||||
|
||||
loadTasks();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
65
frontend/style.css
Normal file
65
frontend/style.css
Normal file
@ -0,0 +1,65 @@
|
||||
body {
|
||||
font-family: Arial;
|
||||
background: #f4f6f8;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 10px;
|
||||
width: 400px;
|
||||
margin: 50px auto; /* vycentrovanie */
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
h1 {
|
||||
text-align: center; /* nadpis na stred */
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 8px;
|
||||
margin: 5px 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 8px;
|
||||
margin-top: 5px;
|
||||
cursor: pointer;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#list {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.task {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background: #eee;
|
||||
padding: 8px;
|
||||
margin-top: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.task span {
|
||||
text-align: left; /* zarovnanie dolava */
|
||||
}
|
||||
|
||||
.buttons button {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.delete {
|
||||
background: red;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.edit {
|
||||
background: orange;
|
||||
color: white;
|
||||
}
|
||||
7
prepare-app.sh
Executable file
7
prepare-app.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
echo "Preparing app..."
|
||||
|
||||
docker network create app_network || true
|
||||
docker volume create mongo_data || true
|
||||
|
||||
docker compose build
|
||||
9
remove-app.sh
Executable file
9
remove-app.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
echo "Removing app..."
|
||||
|
||||
docker compose down -v
|
||||
|
||||
docker volume rm mongo_data || true
|
||||
docker network rm app_network || true
|
||||
|
||||
echo "Removed app."
|
||||
6
start-app.sh
Executable file
6
start-app.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
echo "Running app..."
|
||||
|
||||
docker compose up -d
|
||||
|
||||
echo "App bezi na: http://localhost:8080"
|
||||
4
stop-app.sh
Executable file
4
stop-app.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
echo "Stopping app..."
|
||||
|
||||
docker compose down
|
||||
Loading…
Reference in New Issue
Block a user