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

- - - - - - - - - - - - - - - - - - - -
+ {% include "poll_info_table.html.j2" %}

You can add options after submitting.

diff --git a/templates/manage.html.j2 b/templates/manage.html.j2 index 55a14bd..4a5da8d 100644 --- a/templates/manage.html.j2 +++ b/templates/manage.html.j2 @@ -14,27 +14,8 @@

- - - - - - - - - - - - - - - - - - - -
-
+ {% include "poll_info_table.html.j2" %} +

@@ -55,11 +36,17 @@
- - @@ -71,10 +58,10 @@ - + - + @@ -94,7 +81,9 @@ diff --git a/templates/poll_choice_datetime_range.html.j2 b/templates/poll_choice_datetime_range.html.j2 new file mode 100644 index 0000000..ddfa970 --- /dev/null +++ b/templates/poll_choice_datetime_range.html.j2 @@ -0,0 +1,24 @@ + +{{ choice.start_datetime.strftime("%a %d.%m") }} + + + {% if now.year != choice.start_datetime.year %}.{{choice.start_datetime.year}}{% endif %} + + + {% if not poll.is_whole_day %}{{ choice.start_datetime.strftime("%H:%M") }}{% endif %} + +{% if (poll.is_whole_day and not choice.ends_on_same_day()) or (not poll.is_whole_day and not choice.ends_at_same_datetime()) %} + +{% endif %} + +{% if not choice.ends_on_same_day() %} + + {{ choice.end_datetime.strftime("%a %d.%m") }} + + + {% if now.year != choice.end_datetime.year %}.{{choice.end_datetime.year}}{% endif %} + +{% endif %} + + {% if not poll.is_whole_day %}{{ choice.end_datetime.strftime("%H:%M") }}{% endif %} + diff --git a/templates/poll_info_table.html.j2 b/templates/poll_info_table.html.j2 new file mode 100644 index 0000000..7955ca8 --- /dev/null +++ b/templates/poll_info_table.html.j2 @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/templates/poll_vote_list.html.j2 b/templates/poll_vote_list.html.j2 index c18b3e0..845356b 100644 --- a/templates/poll_vote_list.html.j2 +++ b/templates/poll_vote_list.html.j2 @@ -4,26 +4,7 @@