From 7c1e4b60dab07fb796ab28d9befb627874957ecf Mon Sep 17 00:00:00 2001 From: Stefan Hackenberg Date: Sat, 4 Jan 2025 13:04:58 +0100 Subject: [PATCH] Re-enable oneswipe --- .github/workflows/lint.yml | 36 +-- .github/workflows/test_backends.yml | 96 ++++---- .github/workflows/test_dockerdb.yml | 56 ++--- coffeebuddy/extensions/coffeemaker.py | 5 +- coffeebuddy/ui/__init__.py | 6 +- coffeebuddy/ui/base/templates/selectuser.html | 4 +- coffeebuddy/ui/base/templates/welcome.html | 2 +- coffeebuddy/ui/coffee/__init__.py | 35 ++- coffeebuddy/ui/coffee/templates/oneswipe.html | 78 +++---- coffeebuddy/ui/user/__init__.py | 8 +- coffeebuddy/ui/user/templates/edituser.html | 211 ++++++++++-------- tests/conftest.py | 2 +- tests/test_ui.py | 4 +- 13 files changed, 289 insertions(+), 254 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 06b0a13..86dab81 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -5,22 +5,22 @@ on: [push] jobs: build: runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.8", "3.10", "3.11"] steps: - - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install --user pdm - pdm sync -G dev - - name: Format - run: | - pdm run ruff format --check . - - name: Lint - run: | - pdm run ruff check . + - uses: actions/checkout@v3 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.13" + - name: Install dependencies + run: | + pip install --user pdm + pdm sync -G dev + - name: Format + run: | + pdm run ruff format --check . + - name: Lint + run: | + pdm run ruff check . + - name: Djlint + run: | + pdm run djlint coffeebuddy diff --git a/.github/workflows/test_backends.yml b/.github/workflows/test_backends.yml index b25c797..988a894 100644 --- a/.github/workflows/test_backends.yml +++ b/.github/workflows/test_backends.yml @@ -7,51 +7,51 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Set up Python 3.8 - uses: actions/setup-python@v1 - with: - python-version: 3.8 - - name: Install dependencies - run: | - sudo apt-get install libpcsclite-dev - pip install --user pdm - pdm sync --prod - - name: Test backend sqlite - run: | - sed -i 's/^CARD.*/CARD = ""/' config.py - sed -i 's/^FACERECOGNITION.*/FACERECOGNITION = False/' config.py - sed -i 's/^PIR.*/PIR = False/' config.py - sed -i 's/^ILLUMINATION.*/ILLUMINATION = False/' config.py - sed -i 's/^DB_BACKEND.*/DB_BACKEND = "sqlite"/' config.py - pdm run ./bin/run.py & - pid=$! - sleep 1 - ps | grep -c $pid || wait $pid - kill -SIGTERM $pid - - name: Test backend postgresql - run: | - sed -i 's/^CARD.*/CARD = ""/' config.py - sed -i 's/^FACERECOGNITION.*/FACERECOGNITION = False/' config.py - sed -i 's/^PIR.*/PIR = False/' config.py - sed -i 's/^ILLUMINATION.*/ILLUMINATION = False/' config.py - sed -i 's/^DB_BACKEND.*/DB_BACKEND = "postgres"/' config.py - pdm run ./bin/run.py & - pid=$! - sleep 1 - ps | grep -c $pid || wait $pid - kill -SIGTERM $pid - - name: Test backend testing - run: | - sed -i 's/^CARD.*/CARD = ""/' config.py - sed -i 's/^FACERECOGNITION.*/FACERECOGNITION = False/' config.py - sed -i 's/^PIR.*/PIR = False/' config.py - sed -i 's/^ILLUMINATION.*/ILLUMINATION = False/' config.py - sed -i 's/^DB_BACKEND.*/DB_BACKEND = "sqlite"/' config.py - export FLASK_ENV=prefilled - export FLASK_DEBUG=true - pdm run ./bin/run.py & - pid=$! - sleep 1 - ps | grep -c $pid || wait $pid - kill -SIGTERM $pid + - uses: actions/checkout@v2 + - name: Set up Python 3.13 + uses: actions/setup-python@v5 + with: + python-version: 3.13 + - name: Install dependencies + run: | + sudo apt-get install libpcsclite-dev + pip install --user pdm + pdm sync --prod + - name: Test backend sqlite + run: | + sed -i 's/^CARD.*/CARD = ""/' config.py + sed -i 's/^FACERECOGNITION.*/FACERECOGNITION = False/' config.py + sed -i 's/^PIR.*/PIR = False/' config.py + sed -i 's/^ILLUMINATION.*/ILLUMINATION = False/' config.py + sed -i 's/^DB_BACKEND.*/DB_BACKEND = "sqlite"/' config.py + pdm run ./bin/run.py & + pid=$! + sleep 1 + ps | grep -c $pid || wait $pid + kill -SIGTERM $pid + - name: Test backend postgresql + run: | + sed -i 's/^CARD.*/CARD = ""/' config.py + sed -i 's/^FACERECOGNITION.*/FACERECOGNITION = False/' config.py + sed -i 's/^PIR.*/PIR = False/' config.py + sed -i 's/^ILLUMINATION.*/ILLUMINATION = False/' config.py + sed -i 's/^DB_BACKEND.*/DB_BACKEND = "postgres"/' config.py + pdm run ./bin/run.py & + pid=$! + sleep 1 + ps | grep -c $pid || wait $pid + kill -SIGTERM $pid + - name: Test backend testing + run: | + sed -i 's/^CARD.*/CARD = ""/' config.py + sed -i 's/^FACERECOGNITION.*/FACERECOGNITION = False/' config.py + sed -i 's/^PIR.*/PIR = False/' config.py + sed -i 's/^ILLUMINATION.*/ILLUMINATION = False/' config.py + sed -i 's/^DB_BACKEND.*/DB_BACKEND = "sqlite"/' config.py + export FLASK_ENV=prefilled + export FLASK_DEBUG=true + pdm run ./bin/run.py & + pid=$! + sleep 1 + ps | grep -c $pid || wait $pid + kill -SIGTERM $pid diff --git a/.github/workflows/test_dockerdb.yml b/.github/workflows/test_dockerdb.yml index 3e99e0b..f5ca3fc 100644 --- a/.github/workflows/test_dockerdb.yml +++ b/.github/workflows/test_dockerdb.yml @@ -7,31 +7,31 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Patch docker-compose.yml - run: sed -i 's,.*/mnt/ssd/postgresql.*,#\\0,' database/docker-compose.yml - - name: Setup certificates - run: | - cd database - echo -e "1\nn" | ./gen_certs.sh - echo -e "2\ncoffeebuddydb" | ./gen_certs.sh - echo -e "3\ncoffeebuddy01\nn" | ./gen_certs.sh - - name: Create container - run: | - cd database - docker compose up - - name: Start container again - run: | - cd database - docker compose up -d - sleep 5 - PGSSLMODE=require \ - PGSSLROOTCERT=certs/ca/root.crt \ - PGSSLCERT=certs/client_coffeebuddy01/postgresql.crt \ - PGSSLKEY=certs/client_coffeebuddy01/postgresql.key \ - psql -U coffeebuddy01 -h localhost -d coffeebuddy -lqt - - name: Stop containers - if: always() - run: | - cd database - docker compose down + - uses: actions/checkout@v2 + - name: Patch docker-compose.yml + run: sed -i 's,.*/mnt/ssd/postgresql.*,#\\0,' database/docker-compose.yml + - name: Setup certificates + run: | + cd database + echo -e "1\nn" | ./gen_certs.sh + echo -e "2\ncoffeebuddydb" | ./gen_certs.sh + echo -e "3\ncoffeebuddy01\nn" | ./gen_certs.sh + - name: Create container + run: | + cd database + docker compose up + - name: Start container again + run: | + cd database + docker compose up -d + sleep 5 + PGSSLMODE=require \ + PGSSLROOTCERT=certs/ca/root.crt \ + PGSSLCERT=certs/client_coffeebuddy01/postgresql.crt \ + PGSSLKEY=certs/client_coffeebuddy01/postgresql.key \ + psql -U coffeebuddy01 -h localhost -d coffeebuddy -lqt + - name: Stop containers + if: always() + run: | + cd database + docker compose down diff --git a/coffeebuddy/extensions/coffeemaker.py b/coffeebuddy/extensions/coffeemaker.py index e95f74e..ebcd6fe 100644 --- a/coffeebuddy/extensions/coffeemaker.py +++ b/coffeebuddy/extensions/coffeemaker.py @@ -40,6 +40,7 @@ def brew(self, data): def init(): logging.getLogger(__name__).info("Init") app = flask.current_app + config = app.config.get("COFFEEMAKER", None) or {} - if (brew_time := app.config.get("COFFEEMAKER_MOCK_BREW_TIME", False)) is not False: - CoffeeMakerMock(brew_time=brew_time) + if "mock" in config: + CoffeeMakerMock(brew_time=config["mock"]) diff --git a/coffeebuddy/ui/__init__.py b/coffeebuddy/ui/__init__.py index cef229a..1055aab 100644 --- a/coffeebuddy/ui/__init__.py +++ b/coffeebuddy/ui/__init__.py @@ -40,7 +40,11 @@ def url(site: str, **kwargs): for key, value in kwargs.items(): if isinstance(value, bytes): kwargs[key] = value.hex() - return site + "?" + "&".join(f"{key}={value}" for key, value in kwargs.items()) + return ( + site + + "?" + + "&".join(f"{key}={value}" if value else key for key, value in kwargs.items()) + ) @flask.current_app.context_processor diff --git a/coffeebuddy/ui/base/templates/selectuser.html b/coffeebuddy/ui/base/templates/selectuser.html index ffff30d..5bf95b5 100644 --- a/coffeebuddy/ui/base/templates/selectuser.html +++ b/coffeebuddy/ui/base/templates/selectuser.html @@ -43,7 +43,7 @@

Most frequent users

{% for user in top_manual_users %}
+ onclick="window.location.href = '../coffee.html?tag={{ user.tag.hex() }}&manually&can-oneswipe'"> {{- user.name }} {{ user.prename -}}
{% endfor %} @@ -58,7 +58,7 @@

All users

{% for user in userlist %}
+ onclick="window.location.href = '../coffee.html?tag={{ user.tag.hex() }}&manually&can-oneswipe'"> {{- user.name }} {{ user.prename -}}
{% endfor %} diff --git a/coffeebuddy/ui/base/templates/welcome.html b/coffeebuddy/ui/base/templates/welcome.html index ef3b35b..7dafdd5 100644 --- a/coffeebuddy/ui/base/templates/welcome.html +++ b/coffeebuddy/ui/base/templates/welcome.html @@ -5,7 +5,7 @@ $(() => { var socket = io.connect(window.location.host); socket.on('card_connected', (msg) => { - window.location.href = `../coffee.html?tag=${msg['tag']}`; + window.location.href = `../coffee.html?tag=${msg['tag']}&can-oneswipe`; }); }); diff --git a/coffeebuddy/ui/coffee/__init__.py b/coffeebuddy/ui/coffee/__init__.py index 73236be..abdcf35 100644 --- a/coffeebuddy/ui/coffee/__init__.py +++ b/coffeebuddy/ui/coffee/__init__.py @@ -47,15 +47,22 @@ def post(): if request.method == "POST": return post() + has_coffeemaker = flask.current_app.config.get("COFFEEMAKER", None) is not None + + if ( + not has_coffeemaker + and "can-oneswipe" in flask.request.args + and user.option_oneswipe + ): + return flask.redirect(url("oneswipe.html", **flask.request.args)) + variants_favorites, variants = CoffeeVariant.all_for_user(user) return flask.render_template( "coffee.html", user=user, variants_favorites=variants_favorites, variants=variants, - coffeemaker=flask.current_app.config.get("COFFEEMAKER", False) - or flask.current_app.config.get("COFFEEMAKER_MOCK_BREW_TIME", False) - is not False, + coffeemaker=has_coffeemaker, price=flask.current_app.config["PRICE"], ) @@ -160,12 +167,28 @@ def post(): ) -@blueprint.route("/oneswipe.html", methods=["POST"]) +@blueprint.route("/oneswipe.html", methods=["GET", "POST"]) @require_tag def oneswipe(user: User): db = flask.current_app.db + selected_manually = "manually" in flask.request.args + if "coffee" in flask.request.form: - db.session.add(Drink(user=user, price=flask.current_app.config["PRICE"])) + db.session.add( + Drink( + user=user, + price=flask.current_app.config["PRICE"], + selected_manually=selected_manually, + ) + ) db.session.commit() - return "" + elif "undo" in flask.request.form: + return flask.redirect( + url( + "coffee.html", + tag=user.tag, + **{"manually" if selected_manually else None: None}, + ) + ) + return flask.render_template("oneswipe.html", user=user) diff --git a/coffeebuddy/ui/coffee/templates/oneswipe.html b/coffeebuddy/ui/coffee/templates/oneswipe.html index dea53fe..2126745 100644 --- a/coffeebuddy/ui/coffee/templates/oneswipe.html +++ b/coffeebuddy/ui/coffee/templates/oneswipe.html @@ -1,26 +1,33 @@ - - +{% extends "_base.html" %} - - - - - - - +{% block header %} + - - +{% block main_nav_items %} +{% endblock main_nav_items %} - -
-

{{ user.prename }} {{ user.name }}

- {{ hexstr(user.tag) }} -
Your bill: -
{{ "%.2f €" | format(user.unpayed) }}
-
-
- - -
+{% block main_content %} +
- @@ -69,6 +55,4 @@

{{ user.prename }} {{ user.name }}

- - - +{% endblock main_content %} diff --git a/coffeebuddy/ui/user/__init__.py b/coffeebuddy/ui/user/__init__.py index 7f161c5..49fd027 100644 --- a/coffeebuddy/ui/user/__init__.py +++ b/coffeebuddy/ui/user/__init__.py @@ -33,13 +33,13 @@ def post(): try: user.tag = escapefromhex(request.form["tag"]) user.tag2 = escapefromhex(request.form["tag2"]) - user.name = request.form["last_name"] - user.prename = request.form["first_name"] + user.name = request.form["name"] + user.prename = request.form["prename"] user.email = request.form["email"] - user.option_oneswipe = "oneswipe" in request.form + user.option_oneswipe = request.form["option_oneswipe"] == "true" if flask_login.current_user.is_authenticated: - user.enabled = "enabled" in request.form + user.enabled = request.form["enabled"] == "true" balance = float(request.form["balance"]) if not math.isclose(balance, user.balance): user.update_balance(balance) diff --git a/coffeebuddy/ui/user/templates/edituser.html b/coffeebuddy/ui/user/templates/edituser.html index b715dca..097c721 100644 --- a/coffeebuddy/ui/user/templates/edituser.html +++ b/coffeebuddy/ui/user/templates/edituser.html @@ -82,10 +82,21 @@ function submit_edituser() { const form = $('#edituser-form'); - user = {}; + /* beautify ignore:start */ + user = { + {% for key in user.serialize() -%} + {{ key }}: undefined, + {%- endfor %} + }; + /* beautify ignore:end */ form.find('input').map(function() { user[$(this).attr('name')] = $(this).val(); }); + for (const key in user) { + const item = form.find(`input[name='${key}']`); + user[key] = item.attr('type') == 'checkbox' ? item[0].checked : item.val(); + } + console.log(user); $.post(window.location.href, user, (data) => { console.log(data); @@ -150,105 +161,115 @@

{{ "Edit User" if user.id else "Add User" }}

class="btn btn-secondary" onclick="updatetag(1)" value="Update Tag"> - -
-
- - - Enter UID as HEX-String, e.g. 01020304 or - 01 02 03 04 - - -
-
-
- -
-
- +
+
+ + + Enter UID as HEX-String, e.g. 01020304 or + 01 02 03 04 + +
-
E-Mail address could not be found.
-
-
- -
- -
-
- - -
-
- - -
-
-
-
-

Admin settings

-
-
- - +
+ +
+
+ +
+
E-Mail address could not be found.
+
+
+
-
- -
- +
+ + +
+
+ + -
-
EUR
+ onclick="simple_keyboard_process(this)"> +
+
+
+
+

Options

+
+ +
-
-
- +
+
+

Admin settings

+
+
+ + +
+
+
+ +
+ +
+
EUR
+
+
+
+
+
+ {% endblock main_content %} {% block post_body %} @@ -262,9 +283,9 @@

Admin settings

aria-hidden="true">