Refactoring and adding API connection

parent 7209211d
from sqlalchemy.orm import Session
from fastapi import HTTPException
from .models import BookDB
from .schemas import BookCreate, Book
def create_book(db: Session, book: BookCreate):
db_book = BookDB(**book.dict())
try:
db.add(db_book)
db.commit()
db.refresh(db_book)
return db_book
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
def get_books(db: Session, skip: int = 0, limit: int = 100):
return db.query(BookDB).offset(skip).limit(limit).all()
def get_book(db: Session, book_id: int):
db_book = db.query(BookDB).filter(BookDB.id == book_id).first()
if db_book is None:
raise HTTPException(status_code=404, detail="Book not found")
return db_book
def update_book(db: Session, book_id: int, book: BookCreate):
db_book = db.query(BookDB).filter(BookDB.id == book_id).first()
if db_book is None:
raise HTTPException(status_code=404, detail="Book not found")
for key, value in book.dict().items():
setattr(db_book, key, value)
try:
db.commit()
db.refresh(db_book)
return db_book
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
def delete_book(db: Session, book_id: int):
db_book = db.query(BookDB).filter(BookDB.id == book_id).first()
if db_book is None:
raise HTTPException(status_code=404, detail="Book not found")
try:
db.delete(db_book)
db.commit()
return {"message": "Book deleted successfully"}
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
\ No newline at end of file
from sqlalchemy import Column, Integer, String
from database import Base
class BookDB(Base):
__tablename__ = "books"
id = Column(Integer, primary_key=True, index=True)
title = Column(String, index=True)
author = Column(String, index=True)
owner = Column(Integer)
\ No newline at end of file
from pydantic import BaseModel
from typing import Optional
class BookBase(BaseModel):
title: str
author: Optional[str] = None
owner: int
class BookCreate(BookBase):
pass
class Book(BookBase):
id: int
class Config:
from_attributes = True
\ No newline at end of file
from sqlalchemy.orm import Session
from fastapi import HTTPException
from datetime import date
from .models import LoanDB
from .schemas import LoanCreate, Loan
from book.models import BookDB
def create_loan(db: Session, loan: LoanCreate):
db_loan = LoanDB(**loan.dict())
try:
db.add(db_loan)
db.commit()
db.refresh(db_loan)
return db_loan
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
def get_loans(db: Session, skip: int = 0, limit: int = 100):
return db.query(LoanDB).offset(skip).limit(limit).all()
def get_loan(db: Session, user_id: int, book_id: int, start_date: date):
db_loan = db.query(LoanDB).filter(
LoanDB.id_user == user_id,
LoanDB.id_book == book_id,
LoanDB.start == start_date
).first()
if db_loan is None:
raise HTTPException(status_code=404, detail="Loan not found")
return db_loan
def update_loan(db: Session, user_id: int, book_id: int, start_date: date, loan: LoanCreate):
db_loan = db.query(LoanDB).filter(
LoanDB.id_user == user_id,
LoanDB.id_book == book_id,
LoanDB.start == start_date
).first()
if db_loan is None:
raise HTTPException(status_code=404, detail="Loan not found")
for key, value in loan.dict().items():
setattr(db_loan, key, value)
try:
db.commit()
db.refresh(db_loan)
return db_loan
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
def delete_loan(db: Session, user_id: int, book_id: int, start_date: date):
db_loan = db.query(LoanDB).filter(
LoanDB.id_user == user_id,
LoanDB.id_book == book_id,
LoanDB.start == start_date
).first()
if db_loan is None:
raise HTTPException(status_code=404, detail="Loan not found")
try:
db.delete(db_loan)
db.commit()
return {"message": "Loan deleted successfully"}
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
def get_available_books(db: Session):
subquery = db.query(LoanDB.id_book).filter(LoanDB.status != 'ended').subquery()
available_books = db.query(BookDB).filter(BookDB.id.notin_(subquery)).all()
return available_books
\ No newline at end of file
from sqlalchemy import Column, Integer, Date, Enum
from database import Base
from .schemas import LoanStatus
class LoanDB(Base):
__tablename__ = "loans"
id_user = Column(Integer, primary_key=True, index=True)
id_book = Column(Integer, primary_key=True, index=True)
status = Column(Enum(LoanStatus), default=LoanStatus.reserved)
start = Column(Date, nullable=True)
end = Column(Date, nullable=True)
\ No newline at end of file
from pydantic import BaseModel
from datetime import date
from typing import Optional
from enum import Enum
class LoanStatus(str, Enum):
reserved = "reserved"
borrowed = "borrowed"
returned = "returned"
class LoanBase(BaseModel):
id_user: int
id_book: int
status: LoanStatus = LoanStatus.reserved
start: Optional[date] = None
end: Optional[date] = None
class LoanCreate(LoanBase):
pass
class Loan(LoanBase):
class Config:
from_attributes = True
\ No newline at end of file
from sqlalchemy.orm import Session
from fastapi import HTTPException
from passlib.context import CryptContext
from .models import UserDB
from .schemas import UserCreate, User
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
def create_user(db: Session, user: UserCreate):
db_user = db.query(UserDB).filter(UserDB.email == user.email).first()
if db_user:
raise HTTPException(status_code=400, detail="Email already registered")
hashed_password = pwd_context.hash(user.password)
db_user = UserDB(
email=user.email,
password=hashed_password,
role=user.role
)
try:
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
def get_users(db: Session, skip: int = 0, limit: int = 100):
return db.query(UserDB).offset(skip).limit(limit).all()
def get_user(db: Session, user_id: int):
db_user = db.query(UserDB).filter(UserDB.id == user_id).first()
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
return db_user
def update_user(db: Session, user_id: int, user: UserCreate):
db_user = db.query(UserDB).filter(UserDB.id == user_id).first()
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
if user.email != db_user.email:
existing_user = db.query(UserDB).filter(UserDB.email == user.email).first()
if existing_user:
raise HTTPException(status_code=400, detail="Email already registered")
db_user.email = user.email
db_user.password = pwd_context.hash(user.password)
db_user.role = user.role
try:
db.commit()
db.refresh(db_user)
return db_user
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
def delete_user(db: Session, user_id: int):
db_user = db.query(UserDB).filter(UserDB.id == user_id).first()
if db_user is None:
raise HTTPException(status_code=404, detail="User not found")
try:
db.delete(db_user)
db.commit()
return {"message": "User deleted successfully"}
except Exception as e:
db.rollback()
raise HTTPException(status_code=400, detail=str(e))
\ No newline at end of file
from sqlalchemy import Column, Integer, String
from database import Base
class UserDB(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True)
password = Column(String)
role = Column(Integer, default=0)
\ No newline at end of file
from pydantic import BaseModel, EmailStr
class UserBase(BaseModel):
email: EmailStr
role: int = 0
class UserCreate(UserBase):
password: str
class User(UserBase):
id: int
class Config:
from_attributes = True
\ No newline at end of file
import BookList from "@/app/components/booklist"; import { useState, useEffect } from 'react';
import BookList from '../components/booklist';
export default function Home() { export default function Page() {
const [books, setBooks] = useState([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchBooks = async () => {
try {
setLoading(true);
// Replace with your actual API endpoint
const response = await fetch('https://localhost:8000/books');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();
setBooks(data);
} catch (err) {
setError(err.message);
console.error('Error fetching books:', err);
} finally {
setLoading(false);
}
};
fetchBooks();
}, []);
if (loading) {
return ( return (
<BookList/> <div className="flex justify-center items-center min-h-screen">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
</div>
); );
}
if (error) {
return (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mx-auto max-w-md mt-10">
<p>Error loading books: {error}</p>
<p>Please try again later</p>
</div>
);
}
return <BookList books={books} />;
} }
\ No newline at end of file
import Navbar from './components/navbar'; import Navbar from '../components/navbar';
import './globals.css'; import './globals.css';
export const metadata = { export const metadata = {
......
// Grid layout component that fetches and displays books // Grid layout component that fetches and displays books
"use client"; "use client";
import { useState, useEffect } from 'react'; import PropTypes from 'prop-types';
import Book from "./book"; import Book from "./book";
export default function BookList () { export default function BookList ({ books }) {
const [books, setBooks] = useState([]); if (!books) {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchBooks = async () => {
try {
setLoading(true);
/*
// Replace with your actual API endpoint
const response = await fetch('https://api.example.com/books');
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
const data = await response.json();*/
const data = [
{id: 1, title: "Lord of the rings", author: "JRR Tolkien"},
{id: 2, title: "Artemisa", author: "Andy Weir"},
{id: 3, title: "Dune", author: "Orson Scott Card"}
];
setBooks(data);
} catch (err) {
setError(err.message);
console.error('Error fetching books:', err);
} finally {
setLoading(false);
}
};
fetchBooks();
}, []);
if (loading) {
return ( return (
<div className="flex justify-center items-center min-h-screen"> <div className="flex justify-center items-center min-h-screen">
<div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div> <div className="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500"></div>
...@@ -46,11 +12,10 @@ export default function BookList () { ...@@ -46,11 +12,10 @@ export default function BookList () {
); );
} }
if (error) { if (books.length === 0) {
return ( return (
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mx-auto max-w-md mt-10"> <div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mx-auto max-w-md mt-10">
<p>Error loading books: {error}</p> <p>No books found.</p>
<p>Please try again later</p>
</div> </div>
); );
} }
...@@ -59,9 +24,6 @@ export default function BookList () { ...@@ -59,9 +24,6 @@ export default function BookList () {
<div className="container mx-auto px-4 py-8"> <div className="container mx-auto px-4 py-8">
<h1 className="text-2xl font-bold mb-6">Book Collection</h1> <h1 className="text-2xl font-bold mb-6">Book Collection</h1>
{books.length === 0 ? (
<p className="text-gray-600">No books found.</p>
) : (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6"> <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
{books.map((book) => ( {books.map((book) => (
<Book <Book
...@@ -71,7 +33,10 @@ export default function BookList () { ...@@ -71,7 +33,10 @@ export default function BookList () {
/> />
))} ))}
</div> </div>
)}
</div> </div>
); );
}; };
BookList.propTypes = {
books: PropTypes.array.isRequired,
};
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment