From 5c64529e77f150f8b83930f17e792b2cb8e38a87 Mon Sep 17 00:00:00 2001
From: Jan Tuomi
Date: Thu, 29 Feb 2024 21:10:43 +0200
Subject: Add whole day mode, various improvements
---
app.py | 22 ++++++---
db.py | 24 ++++++++--
migrations/0003_whole_day_poll.sql | 1 +
static/styles.css | 17 ++++++-
templates/index.html.j2 | 21 +--------
templates/manage.html.j2 | 70 ++++++++++++++++------------
templates/poll_choice_datetime_range.html.j2 | 24 ++++++++++
templates/poll_info_table.html.j2 | 24 ++++++++++
templates/poll_vote_list.html.j2 | 21 +--------
templates/poll_vote_table.html.j2 | 20 +-------
10 files changed, 143 insertions(+), 101 deletions(-)
create mode 100644 migrations/0003_whole_day_poll.sql
create mode 100644 templates/poll_choice_datetime_range.html.j2
create mode 100644 templates/poll_info_table.html.j2
diff --git a/app.py b/app.py
index 3cf9e71..f9e3b03 100644
--- a/app.py
+++ b/app.py
@@ -37,7 +37,7 @@ def validation_error(message: str):
return render_template("error.html.j2", error=message), 400
@app.route("/")
-def hello_world():
+def index():
created_poll_codes = []
for k, _ in request.cookies.items():
if k.startswith("diddle_manage_code_"):
@@ -71,6 +71,7 @@ def create():
form["description"],
form["author_name"],
form["author_email"],
+ "is_whole_day" in form,
choices,
)
@@ -177,6 +178,7 @@ def update_poll_info(code):
form["description"],
form["author_name"],
form["author_email"],
+ "is_whole_day" in form,
)
return redirect(f"/manage/{code}")
@@ -188,16 +190,24 @@ def add_choice(code):
return validation_error("Start datetime is required")
if "end_datetime" not in form or len(form["end_datetime"]) == 0:
return validation_error("End datetime is required")
- if form["start_datetime"] >= form["end_datetime"]:
+ if form["start_datetime"] > form["end_datetime"]:
return validation_error("Start datetime must be before end datetime")
+ start_datetime = form["start_datetime"]
+ if len(start_datetime) == 10:
+ start_datetime += "T00:00"
+
+ end_datetime = form["end_datetime"]
+ if len(end_datetime) == 10:
+ end_datetime += "T23:59"
+
db.add_choice_to_poll(
code,
- form["start_datetime"],
- form["end_datetime"],
+ start_datetime,
+ end_datetime,
)
- return redirect(f"/manage/{code}")
+ return redirect(f"/manage/{code}?focus_next=1")
@app.post("/manage//delete_choice/")
def delete_choice(code, choice_id):
@@ -207,7 +217,7 @@ def delete_choice(code, choice_id):
db.delete_choice(choice_id)
- return redirect(f"/manage/{code}")
+ return redirect(f"/manage/{code}?focus_next=1")
@app.get("/manage/")
def manage(code):
diff --git a/db.py b/db.py
index f660d94..57b54e3 100644
--- a/db.py
+++ b/db.py
@@ -70,9 +70,19 @@ class Choice:
def end_datetime_notz(self):
return self.end_datetime.replace(tzinfo=None)
+ def start_date_notz(self):
+ return self.start_datetime.date()
+
+ def end_date_notz(self):
+ return self.end_datetime.date()
+
def ends_on_same_day(self):
return self.start_datetime.date() == self.end_datetime.date()
+ def ends_at_same_datetime(self):
+ return self.start_datetime.date() == self.end_datetime.date() \
+ and self.start_datetime.time() == self.end_datetime.time()
+
@dataclass
class Poll:
id: str
@@ -83,6 +93,7 @@ class Poll:
author_email: str | None
choices: list[Choice]
manage_code: str
+ is_whole_day: bool
def share_url(self):
return f"{BASE_URL}/poll/{self.id}"
@@ -99,6 +110,7 @@ def tuple_to_poll(poll_t: tuple) -> Poll:
author_name=poll_t[4],
author_email=poll_t[5],
manage_code=poll_t[6],
+ is_whole_day=poll_t[7],
choices=[]
)
@@ -159,13 +171,14 @@ def create_poll(title: str,
description: str,
author_name: str,
author_email: str,
+ is_whole_day: bool,
choices: list[Choice]):
with db.cursor() as (conn, cur):
try:
- cur.execute("INSERT INTO polls (title, description, author_name, author_email)"
- "VALUES (%s, %s, %s, %s) RETURNING *",
- (title, description, author_name, author_email))
+ cur.execute("INSERT INTO polls (title, description, author_name, author_email, whole_day)"
+ "VALUES (%s, %s, %s, %s, %s) RETURNING *",
+ (title, description, author_name, author_email, is_whole_day))
poll_t = cur.fetchone()
if poll_t is None:
@@ -228,12 +241,13 @@ def update_poll_info(
description,
author_name,
author_email,
+ is_whole_day,
) -> None:
with db.cursor() as (conn, cur):
try:
- cur.execute("UPDATE polls SET title = %s, description = %s, author_name = %s, author_email = %s "
+ cur.execute("UPDATE polls SET title = %s, description = %s, author_name = %s, author_email = %s, whole_day = %s "
"WHERE manage_code = %s",
- (title, description, author_name, author_email, code))
+ (title, description, author_name, author_email, is_whole_day, code))
conn.commit()
except Exception as e:
conn.rollback()
diff --git a/migrations/0003_whole_day_poll.sql b/migrations/0003_whole_day_poll.sql
new file mode 100644
index 0000000..e532d0c
--- /dev/null
+++ b/migrations/0003_whole_day_poll.sql
@@ -0,0 +1 @@
+ALTER TABLE polls ADD COLUMN IF NOT EXISTS whole_day BOOLEAN NOT NULL DEFAULT FALSE;
diff --git a/static/styles.css b/static/styles.css
index 229149c..0e538e8 100644
--- a/static/styles.css
+++ b/static/styles.css
@@ -43,13 +43,13 @@ input[type="submit"].yellow {
}
input[type="text"],
-input[type="datetime-local"] {
+input[type*="date"] {
font-size: 16px;
color: black;
}
input[type="text"]:disabled,
-input[type="datetime-local"]:disabled {
+input[type*="date"]:disabled {
color: #666;
}
@@ -73,6 +73,10 @@ table {
padding: 7px 5px;
}
+.vote-table th {
+ vertical-align: bottom;
+}
+
.vote-table th span {
display: block;
}
@@ -140,3 +144,12 @@ input[type="checkbox"] {
input[type="checkbox"]:disabled {
cursor: initial;
}
+
+td.checkbox-field {
+ text-align: left;
+}
+
+td.checkbox-field input[type="checkbox"] {
+ flex: initial;
+ margin-left: 0;
+}
diff --git a/templates/index.html.j2 b/templates/index.html.j2
index f84b428..db458da 100644
--- a/templates/index.html.j2
+++ b/templates/index.html.j2
@@ -3,26 +3,7 @@
{% block content %}
Create new diddle
@@ -55,11 +36,17 @@