@leroysheep / BookAlchemy / commits / ab03a6e8b0

fixed the CRUD methods and checked for bugs, optimized the html code and user handling

fixed the CRUD methods and checked for bugs, optimized the html code and user handling

Lee Roy Stevenson committed Apr 6, 2025 at 05:26 UTC ab03a6e8b01ec4c95002863fd0ccc2ebbad9732b
8 files changed +109 -33
ai_request.py
+3 -1
@@ -28,7 +28,9 @@ def ai_request(data_string):
28 "year": "some year",
29 "isbn": "some isbn with only numbers please",
30 "birthday": "author's birthday" as python datetime object with format "YYYY-MM-DD",
31 - "died": "author's deathday" as pythondatetime object withformat "YYYY-MM-DD" or Null if still alive},
31 + "died": "author's deathday" as pythondatetime object \
32 + withformat "YYYY-MM-DD" or
33 + Null if still alive},
34 "reasoning": "your reasoning text"}
35 """
36 )
app.py
+52 -15
@@ -1,7 +1,10 @@
1 from datetime import datetime
2 +
3 +from click import prompt
4 from flask import Flask, jsonify,render_template, request
5
6 from sqlalchemy import desc
7 +from sqlalchemy.exc import IntegrityError, OperationalError, PendingRollbackError
8
9 import ai_request
10 from data_models import db, Author, Book
@@ -77,7 +80,10 @@ def add_author():
80 return render_template("add_author.html")
81 ### POST ---------------------------------------------------------------
82 elif request.method == "POST":
80 - name = request.form["name"]
83 + if not request.form["name"].strip() or not request.form["birthdate"]:
84 + return render_template("add_author.html", success=False,
85 + error="Please enter a name and birthdate!"), 401
86 + name = request.form["name"].strip()
87 birthdate = datetime.strptime(request.form["birthdate"], "%Y-%m-%d")
88 if request.form["date_of_death"]:
89 date_of_death = datetime.strptime(request.form["date_of_death"], "%Y-%m-%d")
@@ -89,8 +95,8 @@ def add_author():
95 db.session.commit()
96 return render_template("add_author.html", success=True)
97 except Exception as e: # For Debugging and Testing catch all Exceptions
92 - print(e)
93 - return render_template("add_author.html", success=False)
98 + print(e.__class__())
99 + return render_template("add_author.html", success=False),401
100
101 # Add Book Route ---------------------------------------------------
102 @app.route("/add_book", methods=["GET", "POST"])
@@ -150,26 +156,45 @@ def add_book():
156 output.append(book)
157 return jsonify(output), 200
158 else:
153 - return render_template("add_book.html")
159 + authors = db.session.query(Author).all()
160 + return render_template("add_book.html", authors=authors)
161 ### POST ---------------------------------------------------------------
162 elif request.method == "POST":
163 title = request.form["title"]
164 year = request.form["year"]
165 isbn = request.form["isbn"] if request.form["isbn"] else None
159 - author = request.form["author"]
166 + author_id = request.form["author"]
167 rating = request.form["rating"]
168 try:
162 - author_id = db.session.query(Author.id) \
163 - .filter(Author.name.contains('%' + author + '%')) \
164 - .one()[0]
169 book = Book(title=title, publication_year=year,
170 isbn=isbn, author_id=author_id , rating=rating)
171 db.session.add(book)
172 db.session.commit()
169 - return render_template("add_book.html", success=True)
173 + authors = db.session.query(Author).all()
174 + return render_template("add_book.html"
175 + , success=True, authors=authors)
176 + except IntegrityError:
177 + db.session.rollback()
178 + authors = db.session.query(Author).all()
179 + return render_template("add_book.html"
180 + , success=False, authors=authors
181 + , error="Entry already exists, check ISBN and/or whole book to"
182 + "assure uniqueness!"
183 + ""),401
184 + except PendingRollbackError:
185 + db.session.rollback()
186 + authors = db.session.query(Author).all()
187 + return render_template("add_book.html"
188 + , success=False, authors=authors
189 + , error="Could not add book to database"
190 + ""),401
191 except Exception as e: # For Debugging and Testing catch all Exceptions
171 - print(e)
172 - return render_template("add_book.html", success=False)
192 + db.session.rollback()
193 + authors = db.session.query(Author).all()
194 + return render_template("add_book.html"
195 + , success=False, error="Something went wrong:" ,
196 + authors=authors),401
197 +
198
199 # Bonus 5 add recommendation route----------------------------------
200 @app.route('/add_recommendation', methods=['POST'])
@@ -239,10 +264,13 @@ def delete_book(book_id):
264 :param book_id:
265 :return:
266 """
242 - if request.method != "POST":
243 - books = db.session.query(Book.id,Book.isbn,Book.title,
244 - Author.name, Book.author_id,
245 - Book.publication_year, Book.rating).join(Author).all()
267 + if request.method != "POST" or request.form.get("confirmation","") != "yes":
268 + if request.method == "POST" and request.form.get("confirmation","") != "no":
269 + book = [Book.query.get(book_id)]
270 + return render_template("home.html",books=book,book_confirmation=book_id)
271 + books = db.session.query(Book.id, Book.isbn, Book.title,
272 + Author.name, Book.author_id,
273 + Book.publication_year, Book.rating).join(Author).all()
274 return render_template("home.html",books=books)
275 book = Book.query.get(book_id)
276 if book:
@@ -272,6 +300,15 @@ def delete_author(author_id):
300 :param author_id:
301 :return:
302 """
303 + if request.method != "POST" or request.form.get("confirmation","") != "yes":
304 +
305 + if request.method == "POST" and request.form.get("confirmation","") != "no":
306 + books = db.session.query(Book).filter(Book.author_id == author_id).all()
307 + return render_template("home.html",books=books,auth_confirmation=author_id)
308 + books = db.session.query(Book.id, Book.isbn, Book.title,
309 + Author.name, Book.author_id,
310 + Book.publication_year, Book.rating).join(Author).all()
311 + return render_template("home.html",books=books)
312 author = Author.query.get(author_id)
313 if author:
314 db.session.delete(author)
data_models.py
+1 -1
@@ -25,7 +25,7 @@ class Author(db.Model):
25 class Book(db.Model):
26 __tablename__ = 'books'
27 id = db.Column(db.Integer, primary_key=True, autoincrement=True)
28 - isbn = db.Column(db.String(13))
28 + isbn = db.Column(db.String(13), unique=True)
29 title = db.Column(db.String(100))
30 publication_year = db.Column(db.Integer)
31 author_id = db.Column(db.Integer, db.ForeignKey('authors.id', ondelete='CASCADE'), nullable=False)
instance/data/library.sqlite
Binary files a/instance/data/library.sqlite and b/instance/data/library.sqlite differ
templates/add_author.html
+1 -1
@@ -12,7 +12,7 @@
12 {% if success %}
13 <h2>Author added successfully!</h2>
14 {% elif success==False %}
15 - <h2>Author not added, please try again!</h2>
15 + <h2>Author not added! {{ error }}</h2>
16 {% endif %}
17 <form action="/add_author" method="POST">
18 <label for="name">Author Name:</label>
templates/add_book.html
+8 -3
@@ -12,12 +12,12 @@
12 {% if success %}
13 <h2>Book added successfully!</h2>
14 {% elif success==False %}
15 - <h2>Book not added, please try again!</h2>
15 + <h2>{{ error }}</h2>
16 {% endif %}
17 <form action="/add_book" method="POST">
18
19 <label for="isbn">ISBN:</label>
20 - <input type="number" id="isbn" name="isbn" ><br><br>
20 + <input type="string" id="isbn" name="isbn" ><br><br>
21
22 <label for="title">Book Title:</label>
23 <input type="text" id="title" name="title" required><br><br>
@@ -26,7 +26,12 @@
26 <input type="number" id="year" name="year" required><br><br>
27
28 <label for="author">Author:</label>
29 - <input type="text" id="author" name="author" required><br><br>
29 + <select id="author" name="author" required>
30 + {% for author in authors %}
31 + <option value="{{ author.id }}">{{ author.name }}</option>
32 + {% endfor %}
33 + </select>
34 + <br><br>
35
36 <label for="rating">Rating:</label>
37 <input type="number" id="rating" name="rating" step="0.1" min="0.0" max="10.0"><br><br>
templates/ai_recomendation.html
+13 -5
@@ -17,20 +17,28 @@
17 <input type="hidden" name="title" value="{{ recomendation['book']['title'] }}">
18 <input type="hidden" name="author" value="{{ recomendation['book']['author'] }}">
19 <input type="hidden" name="year" value="{{ recomendation['book']['year'] }}">
20 - <input type="hidden" name="birthday" value="{{ recomendation['book']['birthday'] }}">
20 + <input type="hidden" name="birthday"
21 + value="{{ recomendation['book']['birthday'] }}">
22 {% if recomendation['book']['died'] %}
22 - <input type="hidden" name="died" value="{{ recomendation['book']['died'] }}">
23 + <input type="hidden" name="died" value="{{ recomendation['book']['died'] }}">
24 + {% elif not recomendation['book']['died'] %}
25 + <input type="hidden" name="died" value="">
26 {% endif %}
27 <button type="submit" class="btn btn-primary">✨ Add to My Library</button>
28 </form>
26 - <a href="/get_ai_recommendation" class="btn btn-primary"><button>🔄 New Recomendation</button></a>
29 + <a href="/get_ai_recommendation" class="btn btn-primary">
30 + <button>🔄 New Recomendation</button></a>
31 </nav>
32 </header>
33 <section class="book-card2">
34 <p class="details">🗓 Published: {{ recomendation['book']['year'] }}</p>
35 <p class="details">📚 ISBN: {{ recomendation['book']['isbn'] }}</p>
32 - <a href="https://openlibrary.org/isbn/{{ recomendation['book']['isbn'] }}" target="_blank">
33 - <img src="https://covers.openlibrary.org/b/isbn/{{ recomendation['book']['isbn'] }}-M.jpg" class="cover" alt="Book Cover">
36 + <a href="https://openlibrary.org/isbn/{{ recomendation['book']['isbn'] }}"
37 + target="_blank">
38 + <img src="https://covers.openlibrary.org/b/isbn/
39 + {{ recomendation['book']['isbn'] }}-M.jpg"
40 + class="cover"
41 + alt="Book Cover">
42 </a><br>
43 <div class="description">Reasoning: {{ recomendation['reasoning'] }} </div> <br>
44
templates/home.html
+31 -7
@@ -66,26 +66,50 @@
66 {% for book in books %}
67 <div class="book-card">
68 <h3>
69 - <a href="/book/{{ book.id }}" class="book-link">{{ book.title }} </a><a href="/author/{{ book.author_id }}" class="author-link"><span>by {{ book.name }}</span></a></h3>
69 + <a href="/book/{{ book.id }}" class="book-link">{{ book.title }} </a>
70 + <a href="/author/{{ book.author_id }}" class="author-link">
71 + <span>by {{ book.name }}</span></a></h3>
72 + {% if auth_confirmation == book.author_id %}
73 + <form action="/author/{{ book.author_id }}/delete"
74 + method="POST">
75 + <p>Are you sure you want to delete all books by
76 + this author and the author itself?
77 + </p>
78 + <button type="submit" name="confirmation" value="yes">Yes</button>
79 + <button type="submit" name="confirmation" value="no">No</button>
80 + </form>
81 + {% else %}
82 <form action="/author/{{ book.author_id }}/delete" method="POST">
71 - <button class="delete-btn" title="Delete Author" value="Delete">🗑Delete Author</button>
83 + <button class="delete-btn" title="Delete Author" value="Delete">
84 + 🗑Delete Author</button>
85 </form>
86 + {% endif %}
87 <p>📅 Year: {{ book.publication_year }}</p>
88 {% if book.isbn %}
89 <a href="https://openlibrary.org/isbn/{{ book.isbn }}" target="_blank">
76 - <img src="https://covers.openlibrary.org/b/isbn/{{ book.isbn }}-M.jpg" alt="Book Cover">
90 + <img src="https://covers.openlibrary.org/b/isbn/{{ book.isbn }}-M.jpg"
91 + alt="Book Cover">
92 </a>
93 {% endif %}
94 <footer>
95 <form action="/book/rating/{{ book.id }}" method="POST">
96 <label for="rating">Rating:</label>
82 - <input type="number" id="rating" name="rating" step="0.1" min="0.0" max="10.0" value="{{ book.rating }}" required>
97 + <input type="number" id="rating" name="rating" step="0.1" min="0.0"
98 + max="10.0" value="{{ book.rating }}" required>
99 <input type="submit" value="Rate">
100 </form>
101 </footer>
86 - <form action="/book/{{ book.id }}/delete" method="POST">
87 - <button class="delete-btn">🗑 Delete Book</button>
88 - </form>
102 + {% if book_confirmation == book.id %}
103 + <form action="/book/{{ book.id }}/delete" method="POST">
104 + <p>Are you sure you want to delete this book?</p>
105 + <button type="submit" name="confirmation" value="yes">Yes</button>
106 + <button type="submit" name="confirmation" value="no">No</button>
107 + </form>
108 + {% else %}
109 + <form action="/book/{{ book.id }}/delete" method="POST">
110 + <button class="delete-btn">🗑 Delete Book</button>
111 + </form>
112 + {% endif %}
113 </div>
114 {% endfor %}
115 </div>