diff --git a/.envrc b/.envrc index 3550a30..4d3e59f 100644 --- a/.envrc +++ b/.envrc @@ -1 +1,2 @@ use flake +export FLASK_APP=app \ No newline at end of file diff --git a/.gitignore b/.gitignore index 92b2793..a4b73fe 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ .direnv +__pycache__ diff --git a/app/__init__.py b/app/__init__.py index 3fa7218..42a5f46 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -2,12 +2,9 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) - -# Configuration of application, see configuration.py, choose one and uncomment. -# app.config.from_object('configuration.ProductionConfig') app.config.from_object("app.configuration.DevelopmentConfig") -# app.config.from_object('configuration.TestingConfig') - db = SQLAlchemy(app) # flask-sqlalchemy from app import views, models +with app.app_context(): + db.create_all() \ No newline at end of file diff --git a/app/__pycache__/__init__.cpython-312.pyc b/app/__pycache__/__init__.cpython-312.pyc deleted file mode 100644 index e5a887e..0000000 Binary files a/app/__pycache__/__init__.cpython-312.pyc and /dev/null differ diff --git a/app/__pycache__/configuration.cpython-312.pyc b/app/__pycache__/configuration.cpython-312.pyc deleted file mode 100644 index cdd7c0d..0000000 Binary files a/app/__pycache__/configuration.cpython-312.pyc and /dev/null differ diff --git a/app/__pycache__/models.cpython-312.pyc b/app/__pycache__/models.cpython-312.pyc deleted file mode 100644 index 6218407..0000000 Binary files a/app/__pycache__/models.cpython-312.pyc and /dev/null differ diff --git a/app/__pycache__/views.cpython-312.pyc b/app/__pycache__/views.cpython-312.pyc deleted file mode 100644 index 2ab1285..0000000 Binary files a/app/__pycache__/views.cpython-312.pyc and /dev/null differ diff --git a/app/configuration.py b/app/configuration.py index 129bb0a..092b4a8 100644 --- a/app/configuration.py +++ b/app/configuration.py @@ -2,8 +2,7 @@ class Config(object): DEBUG = False TESTING = False SQLALCHEMY_DATABASE_URI = "sqlite:///application.db" - BOOTSTRAP_FONTAWESOME = True - SECRET_KEY = "MINHACHAVESECRETA" + SECRET_KEY = "yessir" CSRF_ENABLED = True SQLALCHEMY_TRACK_MODIFICATIONS = True @@ -15,6 +14,5 @@ class Config(object): class DevelopmentConfig(Config): DEBUG = True - class TestingConfig(Config): TESTING = True diff --git a/app/forms.py b/app/forms.py new file mode 100644 index 0000000..452ad00 --- /dev/null +++ b/app/forms.py @@ -0,0 +1,30 @@ +from flask_wtf import FlaskForm +from wtforms import StringField, SubmitField, IntegerField, HiddenField +from wtforms.validators import DataRequired + +class NewWishlist(FlaskForm): + title = StringField("Title:", validators=[DataRequired()]) + description = StringField("Description:", validators=[DataRequired()]) + submit = SubmitField("Submit") + +# Each submit needs a different page fot it to work on the same page. +class DeleteWishlist(FlaskForm): + wl_del_submit = SubmitField("Delete wishlist") + +class EditWishlistInfo(FlaskForm): + title = StringField("Title:", validators=[DataRequired()]) + description = StringField("Description:", validators=[DataRequired()]) + wl_edit_submit = SubmitField("Submit") + +class ResetWishlistUrls(FlaskForm): + wl_reset_submit = SubmitField("Reset urls") + +class NewItem(FlaskForm): + title = StringField("Title:", validators=[DataRequired()]) + description = StringField("Description:", validators=[DataRequired()]) + price = IntegerField("Price:", validators=[DataRequired()]) + it_new_submit = SubmitField("Submit") + +class DeleteItem(FlaskForm): + index = HiddenField() + it_del_submit = SubmitField("Delete item") diff --git a/app/models.py b/app/models.py index 60113cf..00ecd18 100644 --- a/app/models.py +++ b/app/models.py @@ -1,20 +1,35 @@ +from typing import List from app import db - +from sqlalchemy.orm import Mapped, mapped_column, RelationshipProperty +from sqlalchemy import Uuid, String, Text +from uuid import uuid4 as uuid class Item(db.Model): - id = db.Column(db.Integer, primary_key=True) - title = db.Column(db.String(250)) - description = db.Column(db.Text) - price = db.Column(db.Float) - bought = db.Column(db.Boolean) + def __init__(self, title: str, description: str, price: float): + self.wishlist_id = None + self.title = title + self.description = description + self.price = price + self.bought = False + id: Mapped[int] = mapped_column(primary_key=True) + wishlist_id: Mapped[int | None] = mapped_column(db.ForeignKey("wishlist.id")) + title: Mapped[str] = mapped_column(db.String(250)) + description: Mapped[str] = mapped_column(db.Text) + price: Mapped[float] = mapped_column() + bought: Mapped[bool] = mapped_column() class Wishlist(db.Model): - id = db.Column(db.Integer, primary_key=True) - editId = db.Column(db.Uuid) - viewId = db.Column(db.Uuid) - title = db.Column(db.String(250)) - description = db.Column(db.Text) + def __init__(self, title: str, description: str): + self.editId = uuid() + self.viewId = uuid() + self.title = title + self.description = description - itemIds = db.Column(db.ARRAY(db.Integer)) # Store item IDs as an array - items = db.relationship("Item", primaryjoin="Wishlist.itemIds") + id: Mapped[int] = mapped_column(primary_key=True) + editId: Mapped[Uuid] = mapped_column(Uuid) + viewId: Mapped[Uuid] = mapped_column(Uuid) + title: Mapped[str] = mapped_column(String(250)) + description: Mapped[str] = mapped_column(Text) + + items: Mapped[List["Item"]] = db.relationship("Item", backref="post") \ No newline at end of file diff --git a/app/templates/edit.html b/app/templates/edit.html new file mode 100644 index 0000000..e3cd676 --- /dev/null +++ b/app/templates/edit.html @@ -0,0 +1,69 @@ +{% set cpath = url_for("edit", id=wishlist.editId) %} + +

Change name

+
+ {{ form_wl_editinfo.hidden_tag() }} + + {{ form_wl_editinfo.title.label }} + {{ form_wl_editinfo.title() }} + + {{ form_wl_editinfo.description.label }} + {{ form_wl_editinfo.description() }} + + {{ form_wl_editinfo.wl_edit_submit() }} +
+ +

Reset urls

+ + + +
+ {{ form_wl_reseturls.hidden_tag() }} + {{ form_wl_reseturls.wl_reset_submit() }} +
+ +
+

Delete wishlist

+
+ {{ form_wl_delete.hidden_tag() }} + {{ form_wl_delete.wl_del_submit() }} +
+ +
+

New item

+
+ {{ form_it_new.hidden_tag() }} + + {{ form_it_new.title.label }} + {{ form_it_new.title() }} + + {{ form_it_new.description.label }} + {{ form_it_new.description() }} + + {{ form_it_new.price.label }} + {{ form_it_new.price() }} + + {{ form_it_new.it_new_submit() }} +
+ +
+

Delete items

+ \ No newline at end of file diff --git a/app/templates/new.html b/app/templates/new.html new file mode 100644 index 0000000..5667c9e --- /dev/null +++ b/app/templates/new.html @@ -0,0 +1,11 @@ +
+ {{ form.hidden_tag() }} + + {{ form.title.label }} + {{ form.title() }} + + {{ form.description.label }} + {{ form.description() }} + + {{ form.submit() }} +
\ No newline at end of file diff --git a/app/templates/view.html b/app/templates/view.html new file mode 100644 index 0000000..448bfb0 --- /dev/null +++ b/app/templates/view.html @@ -0,0 +1,10 @@ +

{{wishlist.title}}

+{{wishlist.description}} + +edit + + \ No newline at end of file diff --git a/app/views.py b/app/views.py index cd8117f..ce6d1b4 100644 --- a/app/views.py +++ b/app/views.py @@ -1,7 +1,108 @@ -from flask import url_for, redirect, render_template, flash, g, session -from app import app +from flask import url_for, redirect, render_template +from app import app, db +from app.forms import ( + NewWishlist, + DeleteWishlist, + EditWishlistInfo, + ResetWishlistUrls, + NewItem, + DeleteItem, +) +from app.models import Wishlist, Item +from uuid import UUID, uuid4 as uuid @app.route("/") def index(): return "hello" + + +@app.route("/new", methods=["GET", "POST"]) +def new(): + form = NewWishlist() + if form.validate_on_submit(): + wishlist = Wishlist(form.title.data, form.description.data) + db.session.add(wishlist) + db.session.commit() + + return redirect(url_for("view", id=wishlist.viewId)) + + return render_template("new.html", form=form) + + +@app.route("/edit/", methods=["GET", "POST"]) +def edit(id: str): + wishlist: Wishlist = db.one_or_404( + db.select(Wishlist).filter_by(editId=UUID(id)), + description="Failed to get wishlist. Are you sure this is the correct url?", + ) + + form_wl_delete = DeleteWishlist() + form_wl_editinfo = EditWishlistInfo() + form_wl_reseturls = ResetWishlistUrls() + form_it_new = NewItem() + form_it_delete = DeleteItem() + + # Each submit needs a different page fot it to work on the same page. + if form_wl_delete.validate_on_submit() and form_wl_delete.wl_del_submit.data: + for i in wishlist.items: + db.session.delete(i) + db.session.delete(wishlist) + db.session.commit() + + return redirect(url_for("index")) + elif form_wl_editinfo.validate_on_submit() and form_wl_editinfo.wl_edit_submit.data: + wishlist.title = form_wl_editinfo.title.data + wishlist.description = form_wl_editinfo.description.data + db.session.commit() + + return redirect(url_for("edit", id=id)) + elif form_wl_reseturls.validate_on_submit() and form_wl_reseturls.wl_reset_submit.data: + wishlist.editId = uuid() + wishlist.viewId = uuid() + db.session.commit() + + return redirect(url_for("edit", id=wishlist.editId)) + elif form_it_new.validate_on_submit() and form_it_new.it_new_submit.data: + f = form_it_new + item = Item( + f.title.data, + f.description.data, + f.price.data + ) + wishlist.items.append(item) + 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: + print(form_it_delete.index.data) + data = form_it_delete.index.data + i = int(data) if data != None else 0 + if i + 1 > len(wishlist.items): + return "Invalid item to delete", 400 + + wishlist.items.remove(wishlist.items[i]) + db.session.commit() + + return redirect(url_for("edit", id=id)) + + + return render_template( + "edit.html", + wishlist=wishlist, + form_wl_delete=form_wl_delete, + form_wl_editinfo=form_wl_editinfo, + form_wl_reseturls=form_wl_reseturls, + form_it_new=form_it_new, + form_it_delete=form_it_delete, + ) + + +@app.route("/view/") +def view(id: str): + wishlist = db.one_or_404( + db.select(Wishlist).filter_by(viewId=UUID(id)), + description="Failed to get wishlist. Are you sure this is the correct url?", + ) + + return render_template("view.html", wishlist=wishlist) diff --git a/flake.nix b/flake.nix index 6fa056c..a97daa2 100644 --- a/flake.nix +++ b/flake.nix @@ -14,7 +14,7 @@ { nativeBuildInputs = [ (pkgs.python3.withPackages - (x: [x.flask x.flask-wtf x.wtforms x.flask-sqlalchemy])) + (x: [x.flask x.flask-wtf x.wtforms x.flask-sqlalchemy x.uuid])) pkgs.entr ]; }; diff --git a/instance/application.db b/instance/application.db new file mode 100644 index 0000000..8580d3a Binary files /dev/null and b/instance/application.db differ