def save_transaction(cls, user_id, isbns, prices, quantities): transactions = [] email_trans = [] for isbn, price, quantity in zip(isbns, prices, quantities): book = BooksModel.find_by_isbn(isbn) cls.check_stock(book, quantity) transaction = TransactionsModel(user_id, isbn, price, quantity) transactions.append(transaction.json()) email_trans.append(transaction.email_text()) db.session.add(transaction) user = UsersModel.find_by_id(user_id) book_library = LibraryModel.find_by_id_and_isbn( user.id, transaction.isbn) if book_library: # if the book was already in library if book_library.library_type == LibraryType.WishList: # if it was in the wish list book_library.library_type = LibraryType.Bought # change it to bought book_library.state = State.Pending else: # if it wasnt in the library, enter it entry = LibraryModel(book.isbn, user.id, LibraryType.Bought, State.Pending) db.session.add(entry) cls.it_transaction += 1 db.session.commit() cls.send_email(user_id, email_trans) return transactions
def test_basic_put_book(self): with self.app.app_context(): self.basic_setup() res = self.client.post( "/api/book", data=self.data_old, headers={ "Authorization": 'Basic ' + base64.b64encode( (self.token + ":").encode('ascii')).decode('ascii') }) self.assertEqual(201, res.status_code) self.assertEqual( BooksModel.find_by_isbn(self.isbn).json(), json.loads(res.data)) res = self.client.put( f"/api/book/{self.isbn}", data=self.data_new, headers={ "Authorization": 'Basic ' + base64.b64encode( (self.token + ":").encode('ascii')).decode('ascii') }) self.assertEqual(200, res.status_code)
def test_post_book_with_minimum_attributes(self): with self.app.app_context(): self.admin_setup() isbn = 9780553803716 data = { "isbn": isbn, "stock": 10, "precio": 7.79, "titulo": "Foundation", } res = self.client.post( "/api/book", data=data, headers={ "Authorization": 'Basic ' + base64.b64encode( (self.token + ":").encode('ascii')).decode('ascii') }) self.assertEqual(201, res.status_code) self.assertEqual( BooksModel.find_by_isbn(isbn).json(), json.loads(res.data)) res = self.client.post( "/api/book", data=data, headers={ "Authorization": 'Basic ' + base64.b64encode( (self.token + ":").encode('ascii')).decode('ascii') }) self.assertEqual(409, res.status_code)
def get(self, isbn): data = parse_reviews() with lock: book = BooksModel.find_by_isbn(isbn) if not book: return {"message": f"Book with ['isbn':{isbn}] not found"}, 404 return {"book": book.json(**data)}, 200
def test_basic_put_book_vendible(self): with self.app.app_context(): self.basic_setup() data_new = { "sinopsis": self.sinopsis, "precio": 8.60, "stock": 9, "vendible": False } res = self.client.post( "/api/book", data=self.data_old, headers={ "Authorization": 'Basic ' + base64.b64encode( (self.token + ":").encode('ascii')).decode('ascii') }) self.assertEqual(201, res.status_code) self.assertEqual( BooksModel.find_by_isbn(self.isbn).json(), json.loads(res.data)) res = self.client.put( f"/api/book/{self.isbn}", data=self.data_new, headers={ "Authorization": 'Basic ' + base64.b64encode( (self.token + ":").encode('ascii')).decode('ascii') }) self.assertEqual(200, res.status_code)
def json(self): _ignore = self.isbn # Forces execution to parse properly the class, fixing the bug of transient data atr = self.__dict__.copy() del atr["_sa_instance_state"] atr['date'] = self.date.strftime('%d-%m-%Y') atr['book'] = BooksModel.find_by_isbn(atr['isbn']).json() return atr
def post(self, email): data = parse_entry() with lock: user = check_user(email) if not BooksModel.find_by_isbn(data['isbn']): return { "message": f"Book with ['isbn': {data['isbn']}] Not Found" }, 404 if LibraryModel.find_by_id_and_isbn(user.id, data['isbn']) is not None: return { "message": f"Entry with ['email': {email}, 'isbn': {data['isbn']}] already exists" }, 409 data['user_id'] = user.id try: entry = LibraryModel(**data) entry.save_to_db() except Exception as e: return {"message": str(e)}, 500 return entry.json(), 201
def test_model_add(self): with self.app.app_context(): date = datetime.now() book = BooksModel(1, 1, 1.0, "titulo", "autor", "editorial", "sinposis", "url", date) book.save_to_db() self.assertEqual(book, BooksModel.find_by_isbn(book.isbn))
def test_post_book(self): with self.app.app_context(): self.admin_setup() sinopsis = "For twelve thousand years the Galactic Empire has ruled supreme. Now it is dying. But only " \ "Hari Seldon, creator of the revolutionary science of psychohistory, can see into the future " \ "-- to a dark age of ignorance, barbarism, and warfare that will last thirty thousand years. " \ "To preserve knowledge and save mankind, Seldon gathers the best minds in the Empire -- both " \ "scientists and scholars -- and brings them to a bleak planet at the edge of the Galaxy to " \ "serve as a beacon of hope for a future generations. He calls his sanctuary the " \ "Foundation.\nBut soon the fledgling Foundation finds itself at the mercy of corrupt warlords " \ "rising in the wake of the receding Empire. Mankind's last best hope is faced with an " \ "agonizing choice: submit to the barbarians and be overrun -- or fight them and be destroyed. " isbn = 9780553803716 data = { "isbn": isbn, "stock": 10, "precio": 7.79, "titulo": "Foundation", "autor": "Isaac Asimov", "editorial": "Bantam Books", "sinopsis": sinopsis, "url_imagen": "https://i.gr-assets.com/images/S/compressed.photo.goodreads.com/books/1417900846l" "/29579.jpg", "fecha_de_publicacion": "2001-06-01" } res = self.client.post( "/api/book", data=data, headers={ "Authorization": 'Basic ' + base64.b64encode( (self.token + ":").encode('ascii')).decode('ascii') }) self.assertEqual(201, res.status_code) self.assertEqual( BooksModel.find_by_isbn(isbn).json(), json.loads(res.data)) res = self.client.post( "/api/book", data=data, headers={ "Authorization": 'Basic ' + base64.b64encode( (self.token + ":").encode('ascii')).decode('ascii') }) self.assertEqual(409, res.status_code)
def json(self): """ Returns a dictionary with paris of string of name of attribute and it's value. In case of Enum it just returns the name of the enum object (Enum.name). """ _ignore = self.isbn # Forces execution to parse properly the class, fixing the bug of transient data atr = self.__dict__.copy() atr['book'] = BooksModel.find_by_isbn(self.isbn).json() del atr['isbn'] del atr["_sa_instance_state"] return { atr: value if not isinstance(value, Enum) else value.name for atr, value in atr.items() }
def check_keys(email, isbn): user = check_user(email) book = BooksModel.find_by_isbn(isbn) if book is None: abort(404, message={"message": f"Book with ['isbn': {isbn}] Not Found"}) library = LibraryModel.find_by_id_and_isbn(user.id, isbn) if library is None: abort(404, message={ "message": f"Entry with ['email': {email}, 'isbn': {isbn}] Not Found" }) return library
def put(self, isbn): data = parse_book(minimal=True) check_constraints_book(data) with lock: book = BooksModel.find_by_isbn(isbn) if book is None: return { "message": "Book with ['isbn': " + str(isbn) + "] Not Found" }, 404 try: book.update_from_db(data) except Exception as e: return {"message": str(e)}, 500 return {"book": book.json()}, 200
def test_model_update(self): with self.app.app_context(): book = BooksModel(1, 1, 1, "test") book.save_to_db() book2 = BooksModel(2, 1, 1, "test2") book2.save_to_db() entry = LibraryModel(book.isbn, 1, LibraryType.Bought, State.Finished) entry.save_to_db() data = {"isbn": book2.isbn, "user_id": 2, "state": "Reading", "visible": True, "library_type": "WishList"} entry.update_from_db(data) expected_json = data expected_json["book"] = BooksModel.find_by_isbn(book2.isbn).json() del expected_json["isbn"] self.assertEqual(expected_json, entry.json())
def save_to_db(self): if self.score < 1 or self.score > 5: raise ValueError( "Invalid value for score attribute: Value must be an integer from 1 to 5, both included." ) if ReviewsModel.find_by_isbn_user_id(self.isbn, self.user_id) is not None: raise Exception( f"Given user already posted a review. Did you meant to update it?" ) if UsersModel.find_by_id(self.user_id) is None: raise Exception("User with given id doesn't exist") if BooksModel.find_by_isbn(self.isbn) is None: raise Exception("Book with given isbn doesn't exist") ScoresModel.add_review(self) db.session.add(self) db.session.commit()
def post(self): data = parse_book() check_constraints_book(data) with lock: book = BooksModel.find_by_isbn(data["isbn"]) if book: return { "message": f"A book with same isbn {data['isbn']} already exists" }, 409 try: del data['vendible'] # always set to True when post book = BooksModel(**data) book.save_to_db() except Exception as e: return {"message": str(e)}, 500 return book.json(), 201
def get(self): parser = reqparse.RequestParser(bundle_errors=True) parser.add_argument( 'numBooks', type=int, required=False, help="In this field goes the number of the books to show") data = parser.parse_args() isbns = TransactionsModel.best_sellers() return { 'books': list( islice( filter( lambda book: book['vendible'], map( lambda x: BooksModel.find_by_isbn(x).json( score=True), isbns)), data['numBooks'])) }, 200
def post(self): data = parse_transaction() with lock: user = UsersModel.find_by_email(data['email']) if user is None: return {"message": f"User with ['email': {data['email']}] Not Found"}, 404 if user != g.user: return {"message": "Invalid transaction, can only post yours"}, 401 for isbn, quantity in zip(data['isbns'], data['quantities']): book = BooksModel.find_by_isbn(isbn) if book is None: return {"message": "Book with ['isbn': " + str(isbn) + "] Not Found"}, 404 if quantity > book.stock: return {"message": "Not enough stock for book with 'isbn': " + str(isbn) + "only " + str(book.stock) + " available"}, 404 try: transactions = TransactionsModel.save_transaction(user.id, data['isbns'], data['prices'], data['quantities']) except Exception as ex: return {'message': str(ex)}, 500 return {'transactions': transactions}, 201
def delete(self, isbn): with lock: book = BooksModel.find_by_isbn(isbn) if book is None: return { "message": f"Book with ['isbn': {isbn}] Not Found" }, 404 if not book.vendible: return { "message": f"Book with ['isbn': {isbn}] was previously removed" }, 409 try: book.delete_from_db() except Exception as e: return {"message": str(e)}, 500 return {"message": f"Book with ['isbn': {isbn}] deleted"}, 200
def check_user_and_book(user_model, isbn, ignore_if_admin=False): if not user_model: abort(404, message={"message": f"User Not Found"}) if not BooksModel.find_by_isbn(isbn): abort(404, message={"message": f"Book with ['isbn': {isbn}] Not Found"}) if ignore_if_admin: # First statement checks if the role is user and that it doesn't try to modify an other user # Second statement checks if the user who wants to modify it's not and Admin if (g.user.role is not Roles.User or g.user != user_model) and g.user.role is not Roles.Admin: abort(401, message={ "message": "Invalid user to remove, can only be yourself" }) else: if g.user != user_model: abort(401, message={ "message": "Invalid user to remove, can only be yourself" })
def post_book_invalid(self, data): res = self.client.post("/api/book", data=data, headers={ "Authorization": 'Basic ' + base64.b64encode((self.token + ":").encode('ascii')).decode('ascii') }) self.assertEqual(400, res.status_code) self.assertIsNone(BooksModel.find_by_isbn(data["isbn"]))
def save_to_db(self): if BooksModel.find_by_isbn(self.isbn) is None: raise Exception("Book with isbn doesn't exist") db.session.add(self) db.session.commit()