From 42f40ad9a0ae4e1ba79b99c788db5a80b3969c9a Mon Sep 17 00:00:00 2001 From: Jurn Wubben Date: Wed, 25 Jun 2025 11:35:13 +0200 Subject: [PATCH] Finished user interface. Added mobile-ish support. Added homepage. Added viewpage. Fixed some scrapers --- app/forms.py | 1 - app/scrapers.py | 8 +- app/templates/base.html | 92 +++++----- app/templates/edit.html | 352 +++++++++++++++++++++++++++------------ app/templates/index.html | 73 ++++++++ app/templates/view.html | 95 +++++++---- app/views.py | 3 +- instance/application.db | Bin 12288 -> 20480 bytes 8 files changed, 433 insertions(+), 191 deletions(-) diff --git a/app/forms.py b/app/forms.py index 6197d7b..b85c80e 100644 --- a/app/forms.py +++ b/app/forms.py @@ -48,7 +48,6 @@ class CheckItem(FlaskForm): class DeleteItem(FlaskForm): index = HiddenField() - it_del_submit = SubmitField("Delete item") def parseHiddenIndex(field: HiddenField, array: list[Any]) -> int | None: diff --git a/app/scrapers.py b/app/scrapers.py index ca99499..34bda9d 100644 --- a/app/scrapers.py +++ b/app/scrapers.py @@ -80,7 +80,7 @@ class GenericScraper(ScraperLike): price = soup.select_one(self._priceQuery) image = soup.select_one(self._imageQuery) - if name is None or price is None or image is None: + if name is None or image is None: raise ScrapeError( f"Failed to scrape site. Invalid webpage or queries: N:{name},P:{price},I:{image}" ) @@ -88,7 +88,11 @@ class GenericScraper(ScraperLike): name = name.text.strip() image = image.get("src") try: - x = self.priceParser(price.text) + if price is None: + price = "0" + else: + price = price.text + x = self.priceParser(price) reg = search(r"([0-9]+)(?:(?:\.|,)([0-9]+))?", x) if not reg: raise ValueError diff --git a/app/templates/base.html b/app/templates/base.html index 83340ad..f3ac209 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -14,50 +14,54 @@ {% endblock head %} - + + {% block aboveNavbar %} + {% endblock aboveNavbar %} - {% block content %} - {% endblock content %} +
+ + + {% block content %} + {% endblock content %} +
diff --git a/app/templates/edit.html b/app/templates/edit.html index bef1766..1d877de 100644 --- a/app/templates/edit.html +++ b/app/templates/edit.html @@ -1,125 +1,263 @@ {% set cpath = url_for("edit", id=wishlist.editId) %} {% extends "base.html" %} - +{% block middleNav %} + +{% endblock middleNav %} +{% block middleNavPhone %} +
  • View wishlist
  • +{% endblock middleNavPhone %} +
  • View wishlist
  • {% block content %} -
    -

    Edit '{{wishlist.title}}'

    - Manage your wishlist details and items -
    -
    - {{ form_wl_editinfo.hidden_tag() }} - {{ form_wl_editinfo.title.label }} - {{ form_wl_editinfo.title(placeholder=wishlist.title) }} - - {{ form_wl_editinfo.description.label }} - {{ form_wl_editinfo.description(placeholder=wishlist.description) }} - - {{ form_wl_editinfo.wl_edit_submit() }} -
    -
    -

    Urls

    - +
    + {{ form_wl_reseturls.hidden_tag() }} {{ form_wl_reseturls.wl_reset_submit(class="btn btn-soft btn-warning") + }} +
    + +
    + +

    Add/Delete items

    +
      +
    • + Create item + + + +
    • + {% for value in wishlist.items %} +
    • +
      + +
      +
      {{ value.title }}
      +

      {{ value.description }}

      +
      + {{ form_it_delete.csrf_token }} + {{ form_it_delete.index(value=loop.index) }} + +
      +
    • + {% endfor %} +
    +
    + + +
    - + + + {% endblock content %} diff --git a/app/templates/index.html b/app/templates/index.html index 94d9808..52b9159 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -1 +1,74 @@ {% extends "base.html" %} + +{% block aboveNavbar %} + +
    +
    +
    +
    +

    Hello there

    +

    + Welcome to WishThat. The place to create and share wishlists online. +

    + +
    +
    +
    + +{% endblock aboveNavbar %} + +{% block content %} +
    +

    Why Use Wishthat?

    +
    +
    +
    +

    Avoid Duplicate Purchases

    +

    Our system helps you keep track of what has been purchased, ensuring that you don't buy the same item twice.

    +
    +
    +
    +
    +

    No Account Needed

    +

    Start creating wishlists immediately without the hassle of signing up or logging in.

    +
    +
    +
    +
    +

    Price and Image Scraping

    +

    We scrape websites for the latest prices and images, making sure you don't have to painstakingly create wish items manually!

    +
    +
    +
    +
    +

    Easy to Use

    +

    Our user-friendly interface allows you to create and manage your wishlists effortlessly.

    +
    +
    +
    +
    +

    Fully Open Source

    +

    Wishthat is fully open-source and FOSS, allowing anyone to check our security.

    +
    +
    +
    +
    +

    Mobile friendly design

    +

    The software has been designed with mobile friendlyness in mind. Meaning that your phone addicted friends may enjoy this site as well.

    +
    +
    +
    + + + +
    +
    +

    © 2025 jsw. All rights reserved.

    +
    +
    +
    + +{% endblock content %} diff --git a/app/templates/view.html b/app/templates/view.html index 432990b..cb0e3ba 100644 --- a/app/templates/view.html +++ b/app/templates/view.html @@ -1,50 +1,76 @@ {% extends "base.html" %} - {% block content %} +
    + +
    +

    {{wishlist.title}}

    +

    {{wishlist.description}}

    +
    -

    {{wishlist.title}}

    -{{wishlist.description}} +
    + {% for item in wishlist.items %} +
    +
    + {{ item.title }} +
    +
    +

    {{ item.title }}

    +

    {{ item.description }}

    +
    +
    {{ "€" ~ item.price if not item.bought }} +
    + + {{ form.csrf_token }} + {{ form.num(value=loop.index) }} +
    +
    +
    +
    + {% endfor %} +
    +
    -edit - - - -

    Are you sure you bought this product. You won't be able to undo this.

    -
    - - -
    + + +
    + + - {% endblock content %} diff --git a/app/views.py b/app/views.py index 0a81987..fabb07e 100644 --- a/app/views.py +++ b/app/views.py @@ -85,6 +85,7 @@ def edit(id: str): return redirect(url_for("edit", id=wishlist.editId)) elif form_it_new.validate_on_submit() and form_it_new.it_new_submit.data: + print("NEW") f = form_it_new price = f.price.data if f.price.data != None else 0 @@ -107,7 +108,7 @@ def edit(id: str): db.session.commit() return redirect(url_for("edit", id=id)) - elif form_it_delete.validate_on_submit() and form_it_delete.it_del_submit.data: + elif form_it_delete.validate_on_submit() and form_it_delete.index.data: index = parseHiddenIndex(form_it_delete.index, wishlist.items) if index == None: return abort(400) diff --git a/instance/application.db b/instance/application.db index d3dec6517c4314420e8ddce17051f8229440973b..b7835f895378c740c095c00921ad09ab922413d3 100644 GIT binary patch literal 20480 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