1+ import os
2+ 3+ import json
4+ 5+ from flask import Flask , session , render_template , request , jsonify
6+ from flask_session import Session
7+ from sqlalchemy import create_engine
8+ from sqlalchemy .orm import scoped_session , sessionmaker
9+ 10+ from classes import User , Book
11+ 12+ import requests
13+ 14+ app = Flask (__name__ )
15+ 16+ # Check for environment variable
17+ if not os .getenv ("DATABASE_URL" ):
18+ raise RuntimeError ("DATABASE_URL is not set" )
19+ 20+ # Configure session to use filesystem
21+ app .config ["SESSION_PERMANENT" ] = False
22+ app .config ["SESSION_TYPE" ] = "filesystem"
23+ Session (app )
24+ 25+ # Set up database
26+ engine = create_engine (os .getenv ("DATABASE_URL" ))
27+ db = scoped_session (sessionmaker (bind = engine ))
28+ 29+ 30+ @app .route ("/" )
31+ def index ():
32+ if session ["user" ] is None :
33+ return login ()
34+ else :
35+ return render_template ("index.html" )
36+ 37+ 38+ @app .route ("/login" , methods = ["GET" , "POST" ])
39+ def login ():
40+ 41+ if request .method == "POST" :
42+ 43+ username = request .form .get ("username" )
44+ password = request .form .get ("password" )
45+ result = db .execute ("SELECT id, name, email, username, password FROM users WHERE username=:username AND password=:password" , {"username" : username , "password" : password }).fetchone ()
46+ if result is None :
47+ return render_template ("error.html" , message = "Username or password incorrect" )
48+ else :
49+ user = User (result .id , result .name , result .email , result .username , result .password )
50+ 51+ 52+ if user :
53+ session ["user" ] = user
54+ return render_template ("index.html" )
55+ 56+ return render_template ("login.html" )
57+ 58+ 59+ @app .route ("/register" , methods = ["GET" , "POST" ])
60+ def register ():
61+ if request .method == 'GET' :
62+ return render_template ("register.html" )
63+ else :
64+ name = request .form .get ("name" )
65+ username = request .form .get ("username" )
66+ email = request .form .get ("email" )
67+ password = request .form .get ("password" )
68+ db .execute ("INSERT INTO users(name, email, username, password) VALUES (:name, :email, :username, :password)" , {"name" : name , "email" : email , "username" : username , "password" : password })
69+ db .commit ()
70+ return render_template ("login.html" )
71+ 72+ 73+ @app .route ("/layout" )
74+ def layout ():
75+ return render_template ("layout.html" )
76+ 77+ 78+ @app .route ("/logout" )
79+ def logout ():
80+ """ Logout the user and clean the cache session"""
81+ session ["user" ] = None
82+ return render_template ("login.html" )
83+ 84+ 85+ @app .route ("/books" , methods = ["GET" , "POST" ])
86+ def books ():
87+ if session ["user" ] is None :
88+ return login ()
89+ 90+ """ If the request is GET, render the page of search to the user with no books"""
91+ if request .method == "GET" :
92+ return render_template ("books.html" )
93+ else :
94+ """ If the request is POST, do the search with the text provided by the user"""
95+ text = "%" + request .form .get ("search-text" )+ "%"
96+ books = db .execute ("SELECT * FROM books WHERE (isbn LIKE :isbn OR title LIKE :title OR author LIKE :author OR year LIKE :year)" , {"isbn" :text , "title" :text , "author" :text , "year" :text }).fetchall ()
97+ return render_template ("books.html" , books = books )
98+ 99+ 100+ @app .route ("/details/<string:isbn>" , methods = ["GET" , "POST" ])
101+ def details (isbn ):
102+ if session ["user" ] is None :
103+ return login ()
104+ """ Give all the details about the book"""
105+ book = Book ()
106+ 107+ book .isbn , book .title , book .author , book .year , book .reviews_count , book .average_rating = db .execute ("SELECT isbn, title, author, year, reviews_count, average_rating FROM books WHERE isbn = :isbn" , {"isbn" : isbn }).fetchone ()
108+ 109+ if book .average_rating == 0 or book .reviews_count == 0 :
110+ book_aux = api_intern (isbn )
111+ 112+ book .average_rating = book_aux ["books" ][0 ]["average_rating" ]
113+ book .reviews_count = book_aux ["books" ][0 ]["reviews_count" ]
114+ db .execute ("UPDATE books SET average_rating = :average_rating, reviews_count = :reviews_count WHERE isbn=:isbn" , {"isbn" : isbn , "average_rating" : float (book .average_rating ), "reviews_count" : int (book .reviews_count )})
115+ 116+ db .commit ()
117+ if request .method == "GET" :
118+ return render_template ("details.html" , book = book )
119+ else :
120+ return "POST DETAILS"
121+ 122+ 123+ @app .route ("/api/<string:isbn>" , methods = ["GET" ])
124+ def api (isbn ):
125+ """ Give all the details about the book"""
126+ if request .method == "GET" :
127+ res = db .execute ("SELECT title, author, year, isbn, reviews_count, average_rating FROM books WHERE isbn = :isbn" , {"isbn" : isbn }).fetchone ()
128+ book = Book ()
129+ 130+ if res is None :
131+ return render_template ("error.html" , message = "404 book not found" ), 404
132+ 133+ book .title , book .author , book .year , book .isbn , book .reviews_count , book .average_rating = res
134+ if res .reviews_count == 0 or res .average_rating == 0 :
135+ book_aux = api_intern (isbn )
136+ book .average_rating = book_aux ["books" ][0 ]["average_rating" ]
137+ book .reviews_count = book_aux ["books" ][0 ]["reviews_count" ]
138+ 139+ response = {"title" : book .title , "author" : book .author , "year" : book .year , "isbn" : book .isbn , "review_count" : book .reviews_count , "average_score" : book .average_rating }
140+ return jsonify (response )
141+ 142+ 143+ def api_intern (isbn ):
144+ """ Give all the details about the book"""
145+ res = requests .get ("https://www.goodreads.com/book/review_counts.json" , params = {"key" : "tG3fNOMnNgw8HsbsI1Rhdg" , "isbns" : isbn })
146+ 147+ return res .json ()
148+ 149+ 150+ """ Route to submit and see the reviews from one book"""
151+ @app .route ("/review/<string:isbn>" , methods = ["GET" , "POST" ])
152+ def review (isbn ):
153+ if session ["user" ] is None :
154+ return login ()
155+ 156+ """ Render form to the user submit a review """
157+ book = db .execute ("SELECT * FROM books WHERE isbn= :isbn"
158+ , {"isbn" : isbn }).fetchone ()
159+ if request .method == "POST" :
160+ review = request .form .get ("review" )
161+ score = request .form .get ("score" )
162+ """ Calculating new average rating and number of reviews from the book """
163+ average_rating = (book .average_rating + float (score ))/ 2
164+ reviews_count = book .reviews_count + 1
165+ comments = db .execute ("SELECT * FROM reviews WHERE author_id= :author_id AND book_isbn= :book_isbn" , {"author_id" : session ["user" ].id , "book_isbn" : isbn }).fetchone ()
166+ 167+ """ Checks if the user already made a comment to this book """
168+ if comments is not None :
169+ return render_template ("error.html" , message = "You already posted a comment to this book" )
170+ 171+ db .execute ("INSERT INTO reviews(review, score, author_id, book_isbn) VALUES (:review, :score, :author_id, :book_isbn)" , {"review" : review , "score" : score , "author_id" : session ["user" ].id , "book_isbn" : isbn })
172+ db .execute ("UPDATE books SET average_rating = :average_rating, reviews_count = :reviews_count WHERE isbn=:isbn" , {"isbn" : isbn , "average_rating" : average_rating , "reviews_count" : reviews_count })
173+ 174+ db .commit ()
175+ 176+ reviews = db .execute ("SELECT * FROM reviews WHERE book_isbn= :isbn"
177+ , {"isbn" : isbn }).fetchall ()
178+ return render_template ("review.html" , book = book , reviews = reviews )
0 commit comments