From 13c1bdb99f1a57e8b4f61a5c7ee4d6a00fdb6df7 Mon Sep 17 00:00:00 2001 From: Mohammed Niaz Khaleel Jameel Date: Wed, 20 May 2026 08:14:48 +0000 Subject: [PATCH] Upload files to "sk1" --- sk1/Dockerfile | 9 ++ sk1/app.py | 329 +++++++++++++++++++++++++++++++++++++++++++ sk1/init.sql | 27 ++++ sk1/requirements.txt | 3 + 4 files changed, 368 insertions(+) create mode 100644 sk1/Dockerfile create mode 100644 sk1/app.py create mode 100644 sk1/init.sql create mode 100644 sk1/requirements.txt diff --git a/sk1/Dockerfile b/sk1/Dockerfile new file mode 100644 index 0000000..5437e7e --- /dev/null +++ b/sk1/Dockerfile @@ -0,0 +1,9 @@ +FROM python:3.11-slim +WORKDIR /app +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt +COPY . . +RUN useradd -m appuser && chown -R appuser /app +USER appuser +EXPOSE 5000 +CMD ["gunicorn", "--workers", "2", "--bind", "0.0.0.0:5000", "--timeout", "60", "--access-logfile", "-", "app:app"] diff --git a/sk1/app.py b/sk1/app.py new file mode 100644 index 0000000..9b3d7f2 --- /dev/null +++ b/sk1/app.py @@ -0,0 +1,329 @@ +"""TaskFlow — Flask task management application.""" +import os +import psycopg2 +import psycopg2.extras +from flask import Flask, request, redirect, url_for, render_template_string, jsonify + +app = Flask(__name__) + +def get_db(): + return psycopg2.connect( + host=os.environ.get("POSTGRES_HOST"), + port=int(os.environ.get("POSTGRES_PORT", 5432)), + user=os.environ["POSTGRES_USER"], + password=os.environ["POSTGRES_PASSWORD"], + dbname=os.environ["POSTGRES_DB"], + sslmode="require" + ) + +@app.route("/health") +def health(): + try: + conn = get_db(); conn.close() + return jsonify({"status": "ok"}), 200 + except Exception as e: + return jsonify({"status": "error", "detail": str(e)}), 500 + +TEMPLATE = """ + + + + + TaskFlow + + + + +
+ +
+ To Do {{tasks['todo']|length}} + In Progress {{tasks['in_progress']|length}} + Done {{tasks['done']|length}} +
+
+ +
+ +
+
New Task
+
+
+
+ + +
+
+ + +
+ +
+
+
+ + +
+ {% for col,label,css,icon in [ + ('todo','To Do','col-todo','◯'), + ('in_progress','In Progress','col-progress','▶'), + ('done','Done','col-done','✓')] %} +
+
+
+ {{icon}} {{label}} +
+ {{tasks[col]|length}} +
+
+ {% if tasks[col] %} + {% for t in tasks[col] %} +
+
{{t.title}}
+ {% if t.description %}
{{t.description}}
{% endif %} + +
+ {% endfor %} + {% else %} +
+
+ Nothing here yet +
+ {% endif %} +
+
+ {% endfor %} +
+
+ +""" +NEXT_STATUS = {"todo": "in_progress", "in_progress": "done"} + +@app.route("/") +def index(): + conn = get_db() + cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) + cur.execute("SELECT * FROM tasks ORDER BY created_at") + rows = cur.fetchall() + cur.close(); conn.close() + tasks = {"todo": [], "in_progress": [], "done": []} + for row in rows: + tasks[row["status"]].append(row) + return render_template_string(TEMPLATE, tasks=tasks) + +@app.route("/create", methods=["POST"]) +def create(): + title = request.form.get("title", "").strip() + desc = request.form.get("description", "").strip() + if title: + conn = get_db(); cur = conn.cursor() + cur.execute( + "INSERT INTO tasks (title, description, status) VALUES (%s, %s, 'todo')", + (title, desc or None)) + conn.commit(); cur.close(); conn.close() + return redirect(url_for("index")) + +@app.route("/advance/", methods=["POST"]) +def advance(task_id): + conn = get_db(); cur = conn.cursor() + cur.execute("SELECT status FROM tasks WHERE id = %s", (task_id,)) + row = cur.fetchone() + if row and row[0] in NEXT_STATUS: + cur.execute("UPDATE tasks SET status = %s WHERE id = %s", + (NEXT_STATUS[row[0]], task_id)) + conn.commit() + cur.close(); conn.close() + return redirect(url_for("index")) + +@app.route("/delete/", methods=["POST"]) +def delete(task_id): + conn = get_db(); cur = conn.cursor() + cur.execute("DELETE FROM tasks WHERE id = %s", (task_id,)) + conn.commit(); cur.close(); conn.close() + return redirect(url_for("index")) + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000, debug=False) \ No newline at end of file diff --git a/sk1/init.sql b/sk1/init.sql new file mode 100644 index 0000000..2543620 --- /dev/null +++ b/sk1/init.sql @@ -0,0 +1,27 @@ +CREATE TABLE IF NOT EXISTS tasks ( + id SERIAL PRIMARY KEY, + title VARCHAR(200) NOT NULL, + description TEXT, + status VARCHAR(20) NOT NULL DEFAULT 'todo' + CHECK (status IN ('todo', 'in_progress', 'done')), + created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW() +); + +CREATE OR REPLACE FUNCTION update_updated_at() +RETURNS TRIGGER AS $$ +BEGIN NEW.updated_at = NOW(); RETURN NEW; END; +$$ LANGUAGE plpgsql; + +DROP TRIGGER IF EXISTS set_updated_at ON tasks; +CREATE TRIGGER set_updated_at + BEFORE UPDATE ON tasks + FOR EACH ROW EXECUTE FUNCTION update_updated_at(); + +INSERT INTO tasks (title, description, status) VALUES + ('Set up Azure resources', 'Create App Service and PostgreSQL Flexible Server', 'done'), + ('Build Docker image', 'Push image to Azure Container Registry', 'done'), + ('Configure App Service', 'Set environment variables and container settings', 'in_progress'), + ('Enable HTTPS', 'Built-in on azurewebsites.net — automatic', 'todo'), + ('Write README', 'Document deployment and cost analysis', 'todo') +ON CONFLICT DO NOTHING; diff --git a/sk1/requirements.txt b/sk1/requirements.txt new file mode 100644 index 0000000..14f28ad --- /dev/null +++ b/sk1/requirements.txt @@ -0,0 +1,3 @@ +flask==3.0.3 +gunicorn==21.2.0 +psycopg2-binary==2.9.9