18
.woodpecker/publish.yml
Normal file
18
.woodpecker/publish.yml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
when:
|
||||||
|
branch: main
|
||||||
|
event: push
|
||||||
|
|
||||||
|
steps:
|
||||||
|
publish:
|
||||||
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
|
settings:
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
auto_tag: true
|
||||||
|
tag: latest
|
||||||
|
repo: akulovsergei/test-app
|
||||||
|
username: akulovsergei
|
||||||
|
password:
|
||||||
|
from_secret: docker_token
|
||||||
|
|
||||||
8
Dockerfile
Normal file
8
Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
FROM python:3.9-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
CMD ["python", "run.py"]
|
||||||
18
app/__init__.py
Normal file
18
app/__init__.py
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
from flask import Flask
|
||||||
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
|
|
||||||
|
db = SQLAlchemy()
|
||||||
|
|
||||||
|
def create_app():
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///todo.db"
|
||||||
|
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
|
||||||
|
|
||||||
|
db.init_app(app)
|
||||||
|
|
||||||
|
# Импорт и регистрация маршрутов
|
||||||
|
with app.app_context():
|
||||||
|
from . import routes
|
||||||
|
db.create_all()
|
||||||
|
|
||||||
|
return app
|
||||||
BIN
app/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
app/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/models.cpython-39.pyc
Normal file
BIN
app/__pycache__/models.cpython-39.pyc
Normal file
Binary file not shown.
BIN
app/__pycache__/routes.cpython-39.pyc
Normal file
BIN
app/__pycache__/routes.cpython-39.pyc
Normal file
Binary file not shown.
6
app/models.py
Normal file
6
app/models.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from . import db
|
||||||
|
|
||||||
|
class Task(db.Model):
|
||||||
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
title = db.Column(db.String(120), nullable=False)
|
||||||
|
completed = db.Column(db.Boolean, default=False)
|
||||||
34
app/routes.py
Normal file
34
app/routes.py
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
from flask import Flask, render_template, request, redirect, url_for
|
||||||
|
from . import db
|
||||||
|
from .models import Task
|
||||||
|
from flask import current_app as app
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/")
|
||||||
|
def index():
|
||||||
|
tasks = Task.query.all()
|
||||||
|
return render_template("index.html", tasks=tasks)
|
||||||
|
|
||||||
|
@app.route("/add", methods=["POST"])
|
||||||
|
def add_task():
|
||||||
|
title = request.form.get("title")
|
||||||
|
if title:
|
||||||
|
new_task = Task(title=title)
|
||||||
|
db.session.add(new_task)
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
@app.route("/delete/<int:task_id>")
|
||||||
|
def delete_task(task_id):
|
||||||
|
task = Task.query.get_or_404(task_id)
|
||||||
|
db.session.delete(task)
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
|
@app.route("/complete/<int:task_id>")
|
||||||
|
def complete_task(task_id):
|
||||||
|
task = Task.query.get_or_404(task_id)
|
||||||
|
task.completed = not task.completed
|
||||||
|
db.session.commit()
|
||||||
|
return redirect(url_for("index"))
|
||||||
|
|
||||||
21
app/static/style.css
Normal file
21
app/static/style.css
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style-type: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
14
app/templates/base.html
Normal file
14
app/templates/base.html
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>To-Do List</title>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
21
app/templates/index.html
Normal file
21
app/templates/index.html
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h1>To-Do List for DEVOPS</h1>
|
||||||
|
<form action="/add" method="POST">
|
||||||
|
<input type="text" name="title" placeholder="Add a new task" required>
|
||||||
|
<button type="submit">Add</button>
|
||||||
|
</form>
|
||||||
|
<ul>
|
||||||
|
{% for task in tasks %}
|
||||||
|
<li>
|
||||||
|
<span style="text-decoration: {% if task.completed %}line-through{% else %}none{% endif %};">
|
||||||
|
{{ task.title }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<a href="/complete/{{ task.id }}">[{{ 'Undo' if task.completed else 'Complete' }}]</a>
|
||||||
|
<a href="/delete/{{ task.id }}">[Delete]</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endblock %}
|
||||||
10
docker-compose.yml
Normal file
10
docker-compose.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "5000:5000"
|
||||||
|
volumes:
|
||||||
|
- .:/app
|
||||||
|
environment:
|
||||||
|
- FLASK_ENV=development
|
||||||
BIN
instance/todo.db
Normal file
BIN
instance/todo.db
Normal file
Binary file not shown.
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
flask
|
||||||
|
flask_sqlalchemy
|
||||||
Reference in New Issue
Block a user