Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
Arturo Montejo Ráez
/
WBT2425_0
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
20
Merge Requests
0
Pipelines
Wiki
Snippets
Settings
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
314105a1
authored
Mar 18, 2025
by
Arturo Montejo Ráez
Browse files
Options
_('Browse Files')
Download
Email Patches
Plain Diff
GET /book/available working
parent
513e30a1
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
127 additions
and
114 deletions
fastapi/book/models.py
fastapi/database.py
fastapi/loan/crud.py
fastapi/loan/models.py
fastapi/main.py
fastapi/user/models.py
fastapi/webapp.sql
react/src/app/available/page.js
react/src/config.js
fastapi/book/models.py
View file @
314105a1
# Description: Book model for SQLAlchemy ORM
#
from
sqlalchemy
import
ForeignKey
from
sqlalchemy.orm
import
relationship
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
__tablename__
=
"book"
id
=
Column
(
Integer
,
primary_key
=
True
,
index
=
True
,
autoincrement
=
True
)
owner
=
Column
(
Integer
,
ForeignKey
(
'user.id'
),
nullable
=
False
)
title
=
Column
(
String
(
80
),
nullable
=
False
)
author
=
Column
(
String
(
80
),
nullable
=
True
)
# Relationships
owner_rel
=
relationship
(
"UserDB"
,
back_populates
=
"books"
)
loans
=
relationship
(
"LoanDB"
,
back_populates
=
"book_rel"
)
\ No newline at end of file
fastapi/database.py
View file @
314105a1
from
sqlalchemy
import
create_engine
,
ForeignKey
,
Date
,
Enum
as
SQLEnum
from
sqlalchemy
import
create_engine
from
sqlalchemy.ext.declarative
import
declarative_base
from
sqlalchemy.orm
import
sessionmaker
,
relationship
from
sqlalchemy
import
Column
,
Integer
,
String
,
SmallInteger
from
enum
import
Enum
from
sqlalchemy.orm
import
sessionmaker
# Database configuration
SQLALCHEMY_DATABASE_URL
=
"mysql+pymysql://webapp:Ej]mMiSZCr7)BzAp@localhost/webapp"
...
...
@@ -11,50 +9,6 @@ engine = create_engine(SQLALCHEMY_DATABASE_URL)
SessionLocal
=
sessionmaker
(
autocommit
=
False
,
autoflush
=
False
,
bind
=
engine
)
Base
=
declarative_base
()
# Enum for loan status
class
LoanStatus
(
str
,
Enum
):
reserved
=
"reserved"
started
=
"started"
ended
=
"ended"
# SQLAlchemy Models
class
UserDB
(
Base
):
__tablename__
=
"user"
id
=
Column
(
Integer
,
primary_key
=
True
,
index
=
True
,
autoincrement
=
True
)
email
=
Column
(
String
(
50
),
unique
=
True
,
nullable
=
False
)
password
=
Column
(
String
(
256
),
nullable
=
False
)
role
=
Column
(
SmallInteger
,
nullable
=
False
,
default
=
0
)
# Relationships
books
=
relationship
(
"BookDB"
,
back_populates
=
"owner_rel"
)
loans
=
relationship
(
"LoanDB"
,
back_populates
=
"user"
)
class
BookDB
(
Base
):
__tablename__
=
"book"
id
=
Column
(
Integer
,
primary_key
=
True
,
index
=
True
,
autoincrement
=
True
)
owner
=
Column
(
Integer
,
ForeignKey
(
'user.id'
),
nullable
=
False
)
title
=
Column
(
String
(
80
),
nullable
=
False
)
author
=
Column
(
String
(
80
),
nullable
=
True
)
# Relationships
owner_rel
=
relationship
(
"UserDB"
,
back_populates
=
"books"
)
loans
=
relationship
(
"LoanDB"
,
back_populates
=
"book"
)
class
LoanDB
(
Base
):
__tablename__
=
"loan"
id_user
=
Column
(
Integer
,
ForeignKey
(
'user.id'
,
ondelete
=
'CASCADE'
,
onupdate
=
'CASCADE'
),
primary_key
=
True
)
id_book
=
Column
(
Integer
,
ForeignKey
(
'book.id'
,
ondelete
=
'CASCADE'
,
onupdate
=
'CASCADE'
),
primary_key
=
True
)
status
=
Column
(
SQLEnum
(
LoanStatus
),
nullable
=
False
,
default
=
LoanStatus
.
reserved
)
start
=
Column
(
Date
,
primary_key
=
True
,
nullable
=
True
)
end
=
Column
(
Date
,
nullable
=
True
)
# Relationships
user
=
relationship
(
"UserDB"
,
back_populates
=
"loans"
)
book
=
relationship
(
"BookDB"
,
back_populates
=
"loans"
)
# Database Dependency
def
get_db
():
db
=
SessionLocal
()
...
...
fastapi/loan/crud.py
View file @
314105a1
...
...
@@ -67,6 +67,6 @@ def delete_loan(db: Session, user_id: int, book_id: int, start_date: date):
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
.
not
in_
(
subquery
))
.
all
()
subquery
=
db
.
query
(
LoanDB
.
id_book
)
.
filter
(
LoanDB
.
status
==
'available
'
)
.
subquery
()
available_books
=
db
.
query
(
BookDB
)
.
filter
(
BookDB
.
id
.
in_
(
subquery
))
.
all
()
return
available_books
\ No newline at end of file
fastapi/loan/models.py
View file @
314105a1
from
sqlalchemy
import
Column
,
Integer
,
Date
,
Enum
# Description: Loan models for SQLAlchemy ORM.
#
from
sqlalchemy
import
Column
,
Integer
,
Date
,
ForeignKey
,
Enum
from
sqlalchemy.orm
import
relationship
from
database
import
Base
from
.schemas
import
LoanStatus
class
LoanDB
(
Base
):
__tablename__
=
"loan
s
"
id_user
=
Column
(
Integer
,
primary_key
=
True
,
index
=
True
)
id_book
=
Column
(
Integer
,
primary_key
=
True
,
index
=
True
)
__tablename__
=
"loan"
id_user
=
Column
(
Integer
,
ForeignKey
(
'user.id'
),
primary_key
=
True
,
index
=
True
)
id_book
=
Column
(
Integer
,
ForeignKey
(
'book.id'
),
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
end
=
Column
(
Date
,
nullable
=
True
)
# Relationships
user_rel
=
relationship
(
"UserDB"
,
back_populates
=
"loans"
)
book_rel
=
relationship
(
"BookDB"
,
back_populates
=
"loans"
)
\ No newline at end of file
fastapi/main.py
View file @
314105a1
...
...
@@ -11,68 +11,68 @@ from book.schemas import Book # Import Book schema
app
=
FastAPI
()
# User CRUD Operations
@app.post
(
"/user
s
/"
,
response_model
=
user_schemas
.
User
)
@app.post
(
"/user/"
,
response_model
=
user_schemas
.
User
)
def
create_user
(
user
:
user_schemas
.
UserCreate
,
db
:
Session
=
Depends
(
get_db
)):
return
user_crud
.
create_user
(
db
,
user
)
@app.get
(
"/user
s
/"
,
response_model
=
List
[
user_schemas
.
User
])
@app.get
(
"/user/"
,
response_model
=
List
[
user_schemas
.
User
])
def
read_users
(
skip
:
int
=
0
,
limit
:
int
=
100
,
db
:
Session
=
Depends
(
get_db
)):
return
user_crud
.
get_users
(
db
,
skip
,
limit
)
@app.get
(
"/user
s
/{user_id}"
,
response_model
=
user_schemas
.
User
)
@app.get
(
"/user/{user_id}"
,
response_model
=
user_schemas
.
User
)
def
read_user
(
user_id
:
int
,
db
:
Session
=
Depends
(
get_db
)):
return
user_crud
.
get_user
(
db
,
user_id
)
@app.put
(
"/user
s
/{user_id}"
,
response_model
=
user_schemas
.
User
)
@app.put
(
"/user/{user_id}"
,
response_model
=
user_schemas
.
User
)
def
update_user
(
user_id
:
int
,
user
:
user_schemas
.
UserCreate
,
db
:
Session
=
Depends
(
get_db
)):
return
user_crud
.
update_user
(
db
,
user_id
,
user
)
@app.delete
(
"/user
s
/{user_id}"
)
@app.delete
(
"/user/{user_id}"
)
def
delete_user
(
user_id
:
int
,
db
:
Session
=
Depends
(
get_db
)):
return
user_crud
.
delete_user
(
db
,
user_id
)
# Book CRUD Operations
@app.post
(
"/book
s
/"
,
response_model
=
book_schemas
.
Book
)
@app.post
(
"/book/"
,
response_model
=
book_schemas
.
Book
)
def
create_book
(
book
:
book_schemas
.
BookCreate
,
db
:
Session
=
Depends
(
get_db
)):
return
book_crud
.
create_book
(
db
,
book
)
@app.get
(
"/book
s
/"
,
response_model
=
List
[
book_schemas
.
Book
])
@app.get
(
"/book/"
,
response_model
=
List
[
book_schemas
.
Book
])
def
read_books
(
skip
:
int
=
0
,
limit
:
int
=
100
,
db
:
Session
=
Depends
(
get_db
)):
return
book_crud
.
get_books
(
db
,
skip
,
limit
)
@app.get
(
"/books/{book_id}"
,
response_model
=
book_schemas
.
Book
)
@app.get
(
"/book/available"
,
response_model
=
List
[
book_schemas
.
Book
])
def
get_available_books
(
db
:
Session
=
Depends
(
get_db
)):
return
loan_crud
.
get_available_books
(
db
)
@app.get
(
"/book/{book_id}"
,
response_model
=
book_schemas
.
Book
)
def
read_book
(
book_id
:
int
,
db
:
Session
=
Depends
(
get_db
)):
return
book_crud
.
get_book
(
db
,
book_id
)
@app.put
(
"/book
s
/{book_id}"
,
response_model
=
book_schemas
.
Book
)
@app.put
(
"/book/{book_id}"
,
response_model
=
book_schemas
.
Book
)
def
update_book
(
book_id
:
int
,
book
:
book_schemas
.
BookCreate
,
db
:
Session
=
Depends
(
get_db
)):
return
book_crud
.
update_book
(
db
,
book_id
,
book
)
@app.delete
(
"/book
s
/{book_id}"
)
@app.delete
(
"/book/{book_id}"
)
def
delete_book
(
book_id
:
int
,
db
:
Session
=
Depends
(
get_db
)):
return
book_crud
.
delete_book
(
db
,
book_id
)
# Loan CRUD Operations
@app.post
(
"/loan
s
/"
,
response_model
=
loan_schemas
.
Loan
)
@app.post
(
"/loan/"
,
response_model
=
loan_schemas
.
Loan
)
def
create_loan
(
loan
:
loan_schemas
.
LoanCreate
,
db
:
Session
=
Depends
(
get_db
)):
return
loan_crud
.
create_loan
(
db
,
loan
)
@app.get
(
"/loan
s
/"
,
response_model
=
List
[
loan_schemas
.
Loan
])
@app.get
(
"/loan/"
,
response_model
=
List
[
loan_schemas
.
Loan
])
def
read_loans
(
skip
:
int
=
0
,
limit
:
int
=
100
,
db
:
Session
=
Depends
(
get_db
)):
return
loan_crud
.
get_loans
(
db
,
skip
,
limit
)
@app.get
(
"/loan
s
/{user_id}/{book_id}/{start_date}"
,
response_model
=
loan_schemas
.
Loan
)
@app.get
(
"/loan/{user_id}/{book_id}/{start_date}"
,
response_model
=
loan_schemas
.
Loan
)
def
read_loan
(
user_id
:
int
,
book_id
:
int
,
start_date
:
date
,
db
:
Session
=
Depends
(
get_db
)):
return
loan_crud
.
get_loan
(
db
,
user_id
,
book_id
,
start_date
)
@app.put
(
"/loan
s
/{user_id}/{book_id}/{start_date}"
,
response_model
=
loan_schemas
.
Loan
)
@app.put
(
"/loan/{user_id}/{book_id}/{start_date}"
,
response_model
=
loan_schemas
.
Loan
)
def
update_loan
(
user_id
:
int
,
book_id
:
int
,
start_date
:
date
,
loan
:
loan_schemas
.
LoanCreate
,
db
:
Session
=
Depends
(
get_db
)):
return
loan_crud
.
update_loan
(
db
,
user_id
,
book_id
,
start_date
,
loan
)
@app.delete
(
"/loan
s
/{user_id}/{book_id}/{start_date}"
)
@app.delete
(
"/loan/{user_id}/{book_id}/{start_date}"
)
def
delete_loan
(
user_id
:
int
,
book_id
:
int
,
start_date
:
date
,
db
:
Session
=
Depends
(
get_db
)):
return
loan_crud
.
delete_loan
(
db
,
user_id
,
book_id
,
start_date
)
@app.get
(
"/books/available"
,
response_model
=
List
[
Book
])
def
get_available_books
(
db
:
Session
=
Depends
(
get_db
)):
return
loan_crud
.
get_available_books
(
db
)
\ No newline at end of file
return
loan_crud
.
delete_loan
(
db
,
user_id
,
book_id
,
start_date
)
\ No newline at end of file
fastapi/user/models.py
View file @
314105a1
from
sqlalchemy
import
Column
,
Integer
,
String
# Description: User models for SQLAlchemy ORM.
#
from
sqlalchemy.orm
import
relationship
from
sqlalchemy
import
Column
,
Integer
,
String
,
SmallInteger
from
database
import
Base
# SQLAlchemy Models
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
__tablename__
=
"user"
id
=
Column
(
Integer
,
primary_key
=
True
,
index
=
True
,
autoincrement
=
True
)
email
=
Column
(
String
(
50
),
unique
=
True
,
nullable
=
False
)
password
=
Column
(
String
(
256
),
nullable
=
False
)
role
=
Column
(
SmallInteger
,
nullable
=
False
,
default
=
0
)
# Relationships
books
=
relationship
(
"BookDB"
,
back_populates
=
"owner_rel"
)
loans
=
relationship
(
"LoanDB"
,
back_populates
=
"user_rel"
)
\ No newline at end of file
fastapi/webapp.sql
View file @
314105a1
...
...
@@ -2,10 +2,10 @@
-- version 5.2.1deb3
-- https://www.phpmyadmin.net/
--
--
Host
: localhost:3306
--
Generation Time: Feb 19, 2025 at 08:30 PM
--
Server version
: 10.11.8-MariaDB-0ubuntu0.24.04.1
--
PHP Version
: 8.3.6
--
Servidor
: localhost:3306
--
Tiempo de generación: 18-03-2025 a las 16:21:19
--
Versión del servidor
: 10.11.8-MariaDB-0ubuntu0.24.04.1
--
Versión de PHP
: 8.3.6
SET
SQL_MODE
=
"NO_AUTO_VALUE_ON_ZERO"
;
START
TRANSACTION
;
...
...
@@ -18,13 +18,13 @@ SET time_zone = "+00:00";
/*!40101 SET NAMES utf8mb4 */
;
--
--
Database
: `webapp`
--
Base de datos
: `webapp`
--
-- --------------------------------------------------------
--
--
Table structure for table
`book`
--
Estructura de tabla para la tabla
`book`
--
CREATE
TABLE
`book`
(
...
...
@@ -34,16 +34,27 @@ CREATE TABLE `book` (
`author`
varchar
(
80
)
DEFAULT
NULL
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=
utf8mb4
COLLATE
=
utf8mb4_general_ci
;
--
-- Volcado de datos para la tabla `book`
--
INSERT
INTO
`book`
(
`id`
,
`owner`
,
`title`
,
`author`
)
VALUES
(
1
,
1
,
'The Lord of the Rings'
,
'J. R. R. Tolkien'
),
(
2
,
1
,
'Seven Eves'
,
'Neil Stephenson'
),
(
3
,
1
,
'The Martian'
,
'Andy Weir'
),
(
4
,
1
,
'Hyperion'
,
'Dan Simons'
),
(
5
,
1
,
'Cyberiade'
,
'Stanislaw Lem'
);
-- --------------------------------------------------------
--
--
Table structure for table
`loan`
--
Estructura de tabla para la tabla
`loan`
--
CREATE
TABLE
`loan`
(
`id_user`
int
(
10
)
UNSIGNED
NOT
NULL
,
`id_book`
int
(
10
)
UNSIGNED
NOT
NULL
,
`status`
enum
(
'
reserved'
,
'on loan'
,
'available
'
)
NOT
NULL
DEFAULT
'available'
,
`status`
enum
(
'
available'
,
'on loan'
,
'reserved
'
)
NOT
NULL
DEFAULT
'available'
,
`start`
date
DEFAULT
NULL
,
`end`
date
DEFAULT
NULL
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=
utf8mb4
COLLATE
=
utf8mb4_general_ci
;
...
...
@@ -51,7 +62,7 @@ CREATE TABLE `loan` (
-- --------------------------------------------------------
--
--
Table structure for table
`user`
--
Estructura de tabla para la tabla
`user`
--
CREATE
TABLE
`user`
(
...
...
@@ -62,50 +73,64 @@ CREATE TABLE `user` (
)
ENGINE
=
InnoDB
DEFAULT
CHARSET
=
utf8mb4
COLLATE
=
utf8mb4_general_ci
;
--
--
Indexes for dumped tables
--
Volcado de datos para la tabla `user`
--
INSERT
INTO
`user`
(
`id`
,
`email`
,
`password`
,
`role`
)
VALUES
(
1
,
'arturo@example.com'
,
'$2b$12$tiA9GnLxn2xhGXT7E.hq9uDI/RMWwpyH1FzJGbBgrtgCAAREvYFUe'
,
0
);
--
-- Índices para tablas volcadas
--
-- Indexes for table `book`
--
-- Indices de la tabla `book`
--
ALTER
TABLE
`book`
ADD
PRIMARY
KEY
(
`id`
);
ADD
PRIMARY
KEY
(
`id`
),
ADD
KEY
`owner`
(
`owner`
);
--
-- Ind
exes for table
`loan`
-- Ind
ices de la tabla
`loan`
--
ALTER
TABLE
`loan`
ADD
UNIQUE
KEY
`id_user`
(
`id_user`
,
`id_book`
,
`start`
);
--
-- Ind
exes for table
`user`
-- Ind
ices de la tabla
`user`
--
ALTER
TABLE
`user`
ADD
PRIMARY
KEY
(
`id`
),
ADD
UNIQUE
KEY
`email`
(
`email`
);
--
-- AUTO_INCREMENT
for dumped table
s
-- AUTO_INCREMENT
de las tablas volcada
s
--
--
-- AUTO_INCREMENT
for table
`book`
-- AUTO_INCREMENT
de la tabla
`book`
--
ALTER
TABLE
`book`
MODIFY
`id`
int
(
10
)
UNSIGNED
NOT
NULL
AUTO_INCREMENT
;
MODIFY
`id`
int
(
10
)
UNSIGNED
NOT
NULL
AUTO_INCREMENT
,
AUTO_INCREMENT
=
6
;
--
-- AUTO_INCREMENT
for table
`user`
-- AUTO_INCREMENT
de la tabla
`user`
--
ALTER
TABLE
`user`
MODIFY
`id`
int
(
10
)
UNSIGNED
NOT
NULL
AUTO_INCREMENT
;
MODIFY
`id`
int
(
10
)
UNSIGNED
NOT
NULL
AUTO_INCREMENT
,
AUTO_INCREMENT
=
2
;
--
-- Restricciones para tablas volcadas
--
--
--
Constraints for dumped tables
--
Filtros para la tabla `book`
--
ALTER
TABLE
`book`
ADD
CONSTRAINT
`book_ibfk_1`
FOREIGN
KEY
(
`owner`
)
REFERENCES
`user`
(
`id`
)
ON
DELETE
CASCADE
ON
UPDATE
CASCADE
;
--
--
Constraints for table
`loan`
--
Filtros para la tabla
`loan`
--
ALTER
TABLE
`loan`
ADD
CONSTRAINT
`loan_ibfk_1`
FOREIGN
KEY
(
`id_user`
)
REFERENCES
`user`
(
`id`
)
ON
DELETE
CASCADE
ON
UPDATE
CASCADE
,
...
...
react/src/app/available/page.js
View file @
314105a1
"use client"
;
import
{
useState
,
useEffect
}
from
'react'
;
import
BookList
from
'../components/booklist'
;
import
BookList
from
'../../components/booklist'
;
import
config
from
'../../config'
;
export
default
function
Page
()
{
const
[
books
,
setBooks
]
=
useState
([]);
...
...
@@ -10,8 +13,7 @@ export default function Page() {
const
fetchBooks
=
async
()
=>
{
try
{
setLoading
(
true
);
// Replace with your actual API endpoint
const
response
=
await
fetch
(
'https://localhost:8000/books'
);
const
response
=
await
fetch
(
`
${
config
.
apiBaseUrl
}
/books/available`
);
if
(
!
response
.
ok
)
{
throw
new
Error
(
`HTTP error! Status:
${
response
.
status
}
`
);
...
...
react/src/config.js
0 → 100644
View file @
314105a1
const
config
=
{
apiBaseUrl
:
'http://localhost:8000'
,
};
export
default
config
;
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment