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>