master
py 386 lines 16.3 KB
Raw
1 from datetime import datetime
2
3 from flask import Flask, jsonify,render_template, request
4
5 from sqlalchemy import desc
6 from sqlalchemy.exc import IntegrityError, PendingRollbackError
7
8 import ai_request
9 from data_models import db, Author, Book
10
11 # Create Instance of Flask
12 app = Flask(__name__)
13
14 # Configure Database
15 app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///data/library.sqlite"
16
17
18 # Connect Flask to Database
19 db.init_app(app)
20
21 @app.route("/", methods=["GET","POST"])
22 def home():
23 """
24 Route to home page with POST to sort the books by title, author or year
25 :return:
26 """
27 if request.method == "POST":
28 sort_by = request.form.get("options")
29 if sort_by == "title":
30 sort_by = getattr(Book, 'title',None)
31 elif sort_by == "author":
32 sort_by = getattr(Author, 'name',None)
33 elif sort_by == "year":
34 sort_by = getattr(Book, 'publication_year',None)
35 elif sort_by == "rating":
36 sort_by = getattr(Book, 'rating',None)
37 descending = request.form.get("descending")
38 if descending:
39 books = db.session.query(Book.id,Book.isbn,Book.title,
40 Author.name, Book.author_id,
41 Book.publication_year, Book.rating).join(Author) \
42 .order_by(desc(sort_by)).all()
43 else:
44 books = db.session.query(Book.id,Book.isbn,Book.title,
45 Author.name, Book.author_id,
46 Book.publication_year, Book.rating).join(Author) \
47 .order_by(sort_by).all()
48 return render_template("home.html", books=books)
49 else:
50 books = db.session.query(Book.id,Book.isbn,Book.title,
51 Author.name, Book.author_id,
52 Book.publication_year, Book.rating).join(Author).all()
53
54 return render_template("home.html", books=books)
55
56
57 @app.route("/add_author", methods=["GET", "POST"])
58 def add_author():
59 """
60 Route to add author with POST or search author/s with GET
61 :return:
62 """
63 if request.method == "GET":
64 name = request.args.get("name","")
65 if name:
66 authors = db.session.query(Author) \
67 .filter(Author.name.contains('%'+name+'%')) \
68 .all()
69 output = []
70 # Convert query results to Dictionary to return as JSON
71 for author in authors:
72 author = dict({'name': author.name, \
73 'birth_date': author.birth_date.strftime('%Y-%m-%d'), \
74 'date_of_death': author.date_of_death.strftime( '%Y-%m-%d') \
75 if author.date_of_death else None})
76 output.append(author)
77 return jsonify(output), 200
78 else:
79 return render_template("add_author.html")
80 ### POST ---------------------------------------------------------------
81 elif request.method == "POST":
82 if not request.form["name"].strip() or not request.form["birthdate"]:
83 return render_template("add_author.html", success=False,
84 error="Please enter a name and birthdate!"), 401
85 name = request.form["name"].strip()
86 birthdate = datetime.strptime(request.form["birthdate"], "%Y-%m-%d")
87 if request.form["date_of_death"]:
88 date_of_death = datetime.strptime(request.form["date_of_death"], "%Y-%m-%d")
89 author = Author(name=name, birth_date=birthdate, date_of_death=date_of_death)
90 else:
91 author = Author(name=name, birth_date=birthdate)
92 try:
93 db.session.add(author)
94 db.session.commit()
95 return render_template("add_author.html", success=True)
96 except Exception as e: # For Debugging and Testing catch all Exceptions
97 print(e.__class__())
98 return render_template("add_author.html", success=False),401
99
100 # Add Book Route ---------------------------------------------------
101 @app.route("/add_book", methods=["GET", "POST"])
102 def add_book():
103 """
104 Route to add book with POST or search book/s with GET
105 :return:
106 """
107 if request.method == "GET":
108 title = request.args.get("title", "")
109 year = request.args.get("year", "")
110 isbn = request.args.get("isbn", "")
111 rating = request.args.get("rating", "")
112 if title:
113 books = db.session.query(Book) \
114 .filter(Book.title.contains('%' + title + '%')) \
115 .all()
116 output = []
117 # Convert query results to Dictionary to return as JSON
118 for book in books:
119 book = dict({'title': book.title,
120 'year': book.publication_year,
121 'rating': book.rating})
122 output.append(book)
123 return jsonify(output), 200
124 elif year:
125 books = db.session.query(Book) \
126 .filter(Book.publication_year.contains('%' + year + '%')) \
127 .all()
128 output = []
129 # Convert query results to Dictionary to return as JSON
130 for book in books:
131 book = dict({'title': book.title, \
132 'year': book.publication_year})
133 output.append(book)
134 return jsonify(output), 200
135 elif isbn:
136 books = db.session.query(Book) \
137 .filter(Book.isbn.contains('%' + isbn + '%')) \
138 .all()
139 output = []
140 # Convert query results to Dictionary to return as JSON
141 for book in books:
142 book = dict({'title': book.title, \
143 'year': book.publication_year})
144 output.append(book)
145 return jsonify(output), 200
146 elif rating:
147 books = db.session.query(Book) \
148 .filter(Book.rating.contains(rating)) \
149 .all()
150 output = []
151 # Convert query results to Dictionary to return as JSON
152 for book in books:
153 book = dict({'title': book.title, \
154 'year': book.publication_year})
155 output.append(book)
156 return jsonify(output), 200
157 else:
158 authors = db.session.query(Author).all()
159 return render_template("add_book.html", authors=authors)
160 ### POST ---------------------------------------------------------------
161 elif request.method == "POST":
162 title = request.form["title"]
163 year = request.form["year"]
164 isbn = request.form["isbn"] if request.form["isbn"] else None
165 author_id = request.form["author"]
166 rating = request.form["rating"]
167 try:
168 book = Book(title=title, publication_year=year,
169 isbn=isbn, author_id=author_id , rating=rating)
170 db.session.add(book)
171 db.session.commit()
172 authors = db.session.query(Author).all()
173 return render_template("add_book.html"
174 , success=True, authors=authors)
175 except IntegrityError:
176 db.session.rollback()
177 authors = db.session.query(Author).all()
178 return render_template("add_book.html"
179 , success=False, authors=authors
180 , error="Entry already exists, check ISBN and/or whole book to"
181 "assure uniqueness!"
182 ""),401
183 except PendingRollbackError:
184 db.session.rollback()
185 authors = db.session.query(Author).all()
186 return render_template("add_book.html"
187 , success=False, authors=authors
188 , error="Could not add book to database"
189 ""),401
190 except Exception as e: # For Debugging and Testing catch all Exceptions
191 db.session.rollback()
192 authors = db.session.query(Author).all()
193 return render_template("add_book.html"
194 , success=False, error="Something went wrong:" ,
195 authors=authors),401
196
197
198 # Bonus 5 add recommendation route----------------------------------
199 @app.route('/add_recommendation', methods=['POST'])
200 def add_recommendation():
201 """
202 Route to add AI recommendation via POST
203 :return:
204 """
205 books = db.session.query(Book.id, Book.isbn, Book.title,
206 Author.name, Book.author_id, Book.publication_year,
207 Book.rating).join(Author).all()
208 if request.method != "POST":
209 return render_template("add_recommendation.html", books=books)
210 author = Author.query.filter(Author.name==request.form["author"]).first()
211 if not author:
212 birth_date = datetime.strptime(request.form["birthday"], "%Y-%m-%d")
213 if request.form["died"]:
214 date_of_death = datetime.strptime(request.form["died"], "%Y-%m-%d")
215 author = Author(name=request.form["author"],
216 birth_date=birth_date,date_of_death=date_of_death)
217 db.session.add(author)
218 db.session.commit()
219
220 else:
221 author = Author(name=request.form["author"], birth_date=birth_date)
222 db.session.add(author)
223 db.session.commit()
224
225 try:
226 new_author = Author.query.filter(Author.name==author.name).first()
227 book = Book(isbn=request.form["isbn"], title=request.form["title"],
228 publication_year=request.form["year"],
229 author_id=new_author.id)
230 db.session.add(book)
231 db.session.commit()
232 new_books = db.session.query(Book.id, Book.isbn, Book.title,
233 Author.name, Book.author_id, Book.publication_year,
234 Book.rating).join(Author).all()
235 return render_template("home.html", books=new_books, success=True)
236 except Exception as e: # For Debugging and Testing catch all Exceptions
237 print("AN ERROR HAS OCCURED: ",e)
238 return render_template("home.html", books=books, success=False)
239
240
241 @app.route('/search', methods=['POST'])
242 def search():
243 """
244 Route to search books with POST and any search term containing title, author or year
245 :return:
246 """
247 title = request.form['search']
248 title = '%' + title + '%'
249 books = db.session.query(Book.id,Book.isbn,Book.title,
250 Author.name, Book.author_id, Book.publication_year) \
251 .join(Author).filter(Book.title.contains(title) \
252 | Author.name.contains(title) | Book.publication_year \
253 .contains(title)).all()
254 if len(books) == 0:
255 return render_template("home.html", error=True)
256 return render_template("home.html", books=books)
257
258 # Bonus 2 -----------------------------------------------
259 @app.route('/book/<int:book_id>/delete', methods=['POST'])
260 def delete_book(book_id):
261 """
262 Route to delete book with given id and author if it is the last book
263 :param book_id:
264 :return:
265 """
266 if request.method != "POST" or request.form.get("confirmation","") != "yes":
267 if request.method == "POST" and request.form.get("confirmation","") != "no":
268 book = [Book.query.get(book_id)]
269 return render_template("home.html",books=book,book_confirmation=book_id)
270 books = db.session.query(Book.id, Book.isbn, Book.title,
271 Author.name, Book.author_id,
272 Book.publication_year, Book.rating).join(Author).all()
273 return render_template("home.html",books=books)
274 book = Book.query.get(book_id)
275 if book:
276 author_id = book.author_id
277 db.session.delete(book)
278 db.session.commit()
279 books_auth=db.session.query(Book.title).filter(Book.author_id == author_id ).all()
280 if len(books_auth) == 0:
281 author = Author.query.get(author_id)
282 db.session.delete(author)
283 db.session.commit()
284 books = db.session.query(Book.id,Book.isbn,Book.title,
285 Author.name, Book.author_id,
286 Book.publication_year, Book.rating).join(Author).all()
287 return render_template('home.html',books=books,deleted=True)
288 else:
289 books = db.session.query(Book.id,Book.isbn,Book.title,
290 Author.name, Book.author_id,
291 Book.publication_year, Book.rating).join(Author).all()
292 return render_template('home.html',books=books,deleted=False)
293
294 # Bonus 2------------------------------------------------
295 @app.route('/author/<int:author_id>/delete', methods=['POST'])
296 def delete_author(author_id):
297 """
298 Route to delete author with given id
299 :param author_id:
300 :return:
301 """
302 if request.method != "POST" or request.form.get("confirmation","") != "yes":
303
304 if request.method == "POST" and request.form.get("confirmation","") != "no":
305 books = db.session.query(Book).filter(Book.author_id == author_id).all()
306 return render_template("home.html",books=books,auth_confirmation=author_id)
307 books = db.session.query(Book.id, Book.isbn, Book.title,
308 Author.name, Book.author_id,
309 Book.publication_year, Book.rating).join(Author).all()
310 return render_template("home.html",books=books)
311 author = Author.query.get(author_id)
312 if author:
313 db.session.delete(author)
314 db.session.commit()
315 books = db.session.query(Book.id,Book.isbn,Book.title,
316 Author.name, Book.author_id,
317 Book.publication_year, Book.rating).join(Author).all()
318 return render_template('home.html',books=books,auth_deleted=True)
319 else:
320 books = db.session.query(Book.id,Book.isbn,Book.title,
321 Author.name, Book.author_id,
322 Book.publication_year, Book.rating).join(Author).all()
323 return render_template('home.html',books=books,auth_deleted=False)
324
325 # BONUS 3------------------------------------------------
326 @app.route('/author/<int:author_id>', methods=['GET'])
327 def author(author_id):
328 """
329 Route to display author details with given id
330 :param author_id:
331 :return:
332 """
333 author = Author.query.get(author_id)
334 return render_template("details_author.html", author=author)
335
336
337 @app.route('/book/<int:book_id>', methods=['GET'])
338 def book(book_id):
339 """
340 Route to display book details with given id
341 :param book_id:
342 :return:
343 """
344 book = db.session.query(Book.isbn,Book.title, \
345 Book.publication_year,Author.name, Book.rating) \
346 .join(Author).filter(Book.id == book_id).one()._mapping
347 return render_template("details_book.html", book=book)
348
349 ## BONUS 4-------------------------------------------
350 @app.route('/book/rating/<int:book_id>', methods=['POST'])
351 def rate_book(book_id):
352 """
353 Route to rate book with given id
354 :param book_id:
355 :return:
356 """
357 rating = request.form['rating']
358 book = Book.query.get(book_id)
359 book.rating = rating
360 db.session.commit()
361 books = db.session.query(Book.id,Book.isbn,Book.title,
362 Author.name, Book.author_id,
363 Book.publication_year, Book.rating).join(Author).all()
364 return render_template('home.html',books=books, rated=True)
365
366
367 # Bonus 5 ------------------------------------------------
368 @app.route("/get_ai_recommendation", methods=["GET"])
369 def get_ai_recommendation():
370 """
371 Route to get AI recommendation
372 :return:
373 """
374 books = db.session.query( Book.title, Book.publication_year,
375 Author.name, Book.rating).join(Author).all()
376 dataset = ""
377 for book in books:
378 dataset += str(book)
379 return render_template("ai_recomendation.html",
380 recomendation=ai_request.ai_request(dataset))
381
382 app.run(host="0.0.0.0", port=5002,debug=True)
383
384 # Only needed to create datatables at the beginning of the project
385 # with app.app_context():
386 # db.create_all()