├── .gitignore ├── README.md ├── codes ├── ch01 │ └── main.py ├── ch02 │ ├── admin │ │ └── manager.py │ ├── audit_log.txt │ ├── background.py │ ├── feedback │ │ └── post.py │ ├── handler_exceptions.py │ ├── login │ │ └── user.py │ ├── main.py │ ├── places │ │ └── destination.py │ ├── request_log.txt │ ├── tourist │ │ └── visit.py │ └── utility.py ├── ch03 │ ├── api │ │ ├── admin.py │ │ ├── admin_mcontainer.py │ │ ├── complaints.py │ │ ├── keywords.py │ │ ├── login.py │ │ ├── posts.py │ │ ├── recipes.py │ │ └── users.py │ ├── containers │ │ ├── multiple_containers.py │ │ └── single_container.py │ ├── dependencies │ │ ├── global_transactions.py │ │ ├── posts.py │ │ └── users.py │ ├── main.py │ ├── model │ │ ├── classifications.py │ │ ├── posts.py │ │ ├── recipes.py │ │ └── users.py │ ├── repository │ │ ├── admin.py │ │ ├── aggregates.py │ │ ├── complaints.py │ │ ├── factory.py │ │ ├── keywords.py │ │ ├── login.py │ │ ├── posts.py │ │ ├── recipes.py │ │ └── users.py │ └── service │ │ ├── complaints.py │ │ ├── factory.py │ │ ├── posts.py │ │ ├── recipe_utilities.py │ │ └── recipes.py ├── ch04 │ ├── ch04 │ │ ├── configuration │ │ │ ├── config.py │ │ │ └── erp_settings.properties │ │ ├── controller │ │ │ └── university.py │ │ ├── faculty_mgt │ │ │ ├── controllers │ │ │ │ ├── admin.py │ │ │ │ ├── assignments.py │ │ │ │ └── books.py │ │ │ ├── faculty_main.py │ │ │ ├── models │ │ │ │ ├── data │ │ │ │ │ ├── faculty.py │ │ │ │ │ └── facultydb.py │ │ │ │ └── request │ │ │ │ │ ├── assignment.py │ │ │ │ │ ├── faculty.py │ │ │ │ │ └── library.py │ │ │ ├── repository │ │ │ │ ├── assignments.py │ │ │ │ ├── faculty.py │ │ │ │ ├── login.py │ │ │ │ └── signup.py │ │ │ └── services │ │ │ │ ├── assignments.py │ │ │ │ ├── faculty.py │ │ │ │ ├── login.py │ │ │ │ └── signup.py │ │ ├── gateway │ │ │ └── api_router.py │ │ ├── library_mgt │ │ │ ├── controllers │ │ │ │ ├── admin.py │ │ │ │ └── management.py │ │ │ ├── library_main.py │ │ │ ├── models │ │ │ │ ├── data │ │ │ │ │ ├── library.py │ │ │ │ │ └── librarydb.py │ │ │ │ └── request │ │ │ │ │ └── library.py │ │ │ ├── repository │ │ │ │ ├── books.py │ │ │ │ ├── issuance.py │ │ │ │ └── reservations.py │ │ │ └── services │ │ │ │ ├── books.py │ │ │ │ ├── issuance.py │ │ │ │ └── reservations.py │ │ ├── main.py │ │ └── student_mgt │ │ │ ├── controllers │ │ │ ├── admin.py │ │ │ ├── assignments.py │ │ │ └── reservations.py │ │ │ ├── models │ │ │ ├── data │ │ │ │ ├── students.py │ │ │ │ └── studentsdb.py │ │ │ └── request │ │ │ │ ├── assignment.py │ │ │ │ ├── library.py │ │ │ │ └── students.py │ │ │ ├── repository │ │ │ ├── login.py │ │ │ ├── signup.py │ │ │ └── students.py │ │ │ ├── services │ │ │ ├── login.py │ │ │ ├── signup.py │ │ │ └── students.py │ │ │ └── student_main.py │ ├── faculty │ │ ├── configuration │ │ │ ├── config.py │ │ │ └── erp_settings.properties │ │ ├── controllers │ │ │ ├── admin.py │ │ │ ├── assignments.py │ │ │ └── books.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ ├── faculty.py │ │ │ │ ├── facultydb.py │ │ │ │ └── library.py │ │ │ └── request │ │ │ │ ├── assignment.py │ │ │ │ ├── faculty.py │ │ │ │ └── library.py │ │ ├── repository │ │ │ ├── assignments.py │ │ │ ├── faculty.py │ │ │ ├── login.py │ │ │ └── signup.py │ │ └── services │ │ │ ├── assignments.py │ │ │ ├── faculty.py │ │ │ ├── login.py │ │ │ └── signup.py │ ├── library │ │ ├── configuration │ │ │ ├── config.py │ │ │ └── erp_settings.properties │ │ ├── controllers │ │ │ ├── admin.py │ │ │ └── management.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ ├── library.py │ │ │ │ └── librarydb.py │ │ │ └── request │ │ │ │ └── library.py │ │ ├── repository │ │ │ ├── books.py │ │ │ ├── issuance.py │ │ │ └── reservations.py │ │ └── services │ │ │ ├── books.py │ │ │ ├── issuance.py │ │ │ └── reservations.py │ └── student │ │ ├── configuration │ │ ├── config.py │ │ └── erp_settings.properties │ │ ├── controllers │ │ ├── admin.py │ │ ├── assignments.py │ │ └── reservations.py │ │ ├── main.py │ │ ├── models │ │ ├── data │ │ │ ├── library.py │ │ │ ├── students.py │ │ │ └── studentsdb.py │ │ └── request │ │ │ ├── assignment.py │ │ │ ├── library.py │ │ │ └── students.py │ │ ├── repository │ │ ├── login.py │ │ ├── signup.py │ │ └── students.py │ │ └── services │ │ ├── login.py │ │ ├── signup.py │ │ └── students.py ├── ch05a │ ├── api │ │ ├── admin.py │ │ ├── login.py │ │ ├── members.py │ │ └── trainers.py │ ├── cqrs │ │ ├── commands.py │ │ ├── handlers.py │ │ ├── queries.py │ │ └── trainers │ │ │ ├── command │ │ │ ├── create_handlers.py │ │ │ ├── delete_handlers.py │ │ │ └── update_handlers.py │ │ │ └── query │ │ │ └── query_handlers.py │ ├── database │ │ ├── fcms-erd.png │ │ └── fcms.sql │ ├── db_config │ │ ├── gino_connect.py │ │ ├── pony_connect.py │ │ └── sqlalchemy_connect.py │ ├── main.py │ ├── models │ │ ├── data │ │ │ ├── gino_models.py │ │ │ ├── pony_models.py │ │ │ └── sqlalchemy_models.py │ │ └── requests │ │ │ ├── attendance.py │ │ │ ├── login.py │ │ │ ├── members.py │ │ │ ├── signup.py │ │ │ └── trainers.py │ ├── readme.txt │ ├── repository │ │ ├── gino │ │ │ └── trainers.py │ │ ├── pony │ │ │ └── members.py │ │ └── sqlalchemy │ │ │ ├── login.py │ │ │ └── signup.py │ └── requirements.txt ├── ch05b │ ├── api │ │ ├── attendance.py │ │ ├── gym.py │ │ └── login.py │ ├── database │ │ └── fcms-erd.png │ ├── db_config │ │ ├── peewee_connect.py │ │ └── sqlalchemy_async_connect.py │ ├── main.py │ ├── models │ │ ├── data │ │ │ ├── peewee_models.py │ │ │ └── sqlalchemy_async_models.py │ │ └── requests │ │ │ ├── attendance.py │ │ │ ├── gym.py │ │ │ └── login.py │ ├── readme.txt │ ├── repository │ │ ├── peewee │ │ │ └── login.py │ │ └── sqlalchemy │ │ │ ├── attendance.py │ │ │ └── gym.py │ └── requirements.txt ├── ch06 │ ├── api │ │ ├── book.py │ │ ├── buyer.py │ │ ├── buyer_async.py │ │ ├── cart.py │ │ ├── login.py │ │ ├── order.py │ │ ├── profile.py │ │ ├── purchase.py │ │ ├── receipt.py │ │ └── reference.py │ ├── database │ │ ├── UML design.png │ │ └── obrs_db.zip │ ├── db_config │ │ ├── beanie_config.py │ │ ├── mongoengine_config.py │ │ ├── mongoframe_config.py │ │ ├── motor_config.py │ │ ├── odmantic_config.py │ │ └── pymongo_config.py │ ├── main.py │ ├── models │ │ ├── data │ │ │ ├── beanie.py │ │ │ ├── mongoengine.py │ │ │ ├── mongoframe.py │ │ │ ├── odmantic.py │ │ │ └── pymongo.py │ │ └── request │ │ │ ├── buyer.py │ │ │ ├── category.py │ │ │ ├── login.py │ │ │ ├── order.py │ │ │ ├── profile.py │ │ │ └── purchase.py │ ├── readme.txt │ ├── repository │ │ ├── beanie │ │ │ ├── cart.py │ │ │ ├── order.py │ │ │ └── receipt.py │ │ ├── mongoengine │ │ │ ├── book.py │ │ │ ├── login.py │ │ │ └── profile.py │ │ ├── mongoframe │ │ │ ├── book.py │ │ │ └── reference.py │ │ ├── motor │ │ │ └── buyer.py │ │ ├── odmantic │ │ │ └── purchase.py │ │ └── pymongo │ │ │ └── buyer.py │ └── requirements.txt ├── ch07 │ ├── ch07a │ │ ├── api │ │ │ ├── admin.py │ │ │ ├── auction.py │ │ │ ├── bid.py │ │ │ ├── login.py │ │ │ └── profile.py │ │ ├── database │ │ │ └── soas.sql │ │ ├── db_config │ │ │ └── sqlalchemy_connect.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ └── sqlalchemy_models.py │ │ │ └── request │ │ │ │ ├── auctions.py │ │ │ │ ├── bids.py │ │ │ │ ├── login.py │ │ │ │ ├── profile.py │ │ │ │ ├── signup.py │ │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── auctions.py │ │ │ ├── bids.py │ │ │ ├── login.py │ │ │ ├── profile.py │ │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ │ └── secure.py │ ├── ch07b │ │ ├── api │ │ │ ├── admin.py │ │ │ ├── auction.py │ │ │ ├── bid.py │ │ │ ├── login.py │ │ │ └── profile.py │ │ ├── database │ │ │ └── soas.sql │ │ ├── db_config │ │ │ └── sqlalchemy_connect.py │ │ ├── generate_hash.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ └── sqlalchemy_models.py │ │ │ └── request │ │ │ │ ├── auctions.py │ │ │ │ ├── bids.py │ │ │ │ ├── login.py │ │ │ │ ├── profile.py │ │ │ │ ├── signup.py │ │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── auctions.py │ │ │ ├── bids.py │ │ │ ├── login.py │ │ │ ├── profile.py │ │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ │ └── secure.py │ ├── ch07c │ │ ├── api │ │ │ ├── admin.py │ │ │ ├── auction.py │ │ │ ├── bid.py │ │ │ ├── login.py │ │ │ └── profile.py │ │ ├── database │ │ │ └── soas.sql │ │ ├── db_config │ │ │ └── sqlalchemy_connect.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ └── sqlalchemy_models.py │ │ │ └── request │ │ │ │ ├── auctions.py │ │ │ │ ├── bids.py │ │ │ │ ├── login.py │ │ │ │ ├── profile.py │ │ │ │ ├── signup.py │ │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── auctions.py │ │ │ ├── bids.py │ │ │ ├── login.py │ │ │ ├── profile.py │ │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ │ └── secure.py │ ├── ch07d │ │ ├── api │ │ │ ├── admin.py │ │ │ ├── auction.py │ │ │ ├── bid.py │ │ │ ├── login.py │ │ │ └── profile.py │ │ ├── database │ │ │ └── soas.sql │ │ ├── db_config │ │ │ └── sqlalchemy_connect.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ └── sqlalchemy_models.py │ │ │ └── request │ │ │ │ ├── auctions.py │ │ │ │ ├── bids.py │ │ │ │ ├── login.py │ │ │ │ ├── profile.py │ │ │ │ ├── signup.py │ │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── auctions.py │ │ │ ├── bids.py │ │ │ ├── login.py │ │ │ ├── profile.py │ │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ │ └── secure.py │ ├── ch07e │ │ ├── api │ │ │ ├── admin.py │ │ │ ├── auction.py │ │ │ ├── bid.py │ │ │ ├── login.py │ │ │ └── profile.py │ │ ├── database │ │ │ └── soas.sql │ │ ├── db_config │ │ │ └── sqlalchemy_connect.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ └── sqlalchemy_models.py │ │ │ └── request │ │ │ │ ├── auctions.py │ │ │ │ ├── bids.py │ │ │ │ ├── login.py │ │ │ │ ├── profile.py │ │ │ │ ├── signup.py │ │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── auctions.py │ │ │ ├── bids.py │ │ │ ├── login.py │ │ │ ├── permission.py │ │ │ ├── profile.py │ │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ │ └── secure.py │ ├── ch07f │ │ ├── api │ │ │ ├── admin.py │ │ │ ├── auction.py │ │ │ ├── bid.py │ │ │ ├── login.py │ │ │ └── profile.py │ │ ├── database │ │ │ └── soas.sql │ │ ├── db_config │ │ │ └── sqlalchemy_connect.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ └── sqlalchemy_models.py │ │ │ └── request │ │ │ │ ├── auctions.py │ │ │ │ ├── bids.py │ │ │ │ ├── login.py │ │ │ │ ├── profile.py │ │ │ │ ├── signup.py │ │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── auctions.py │ │ │ ├── bids.py │ │ │ ├── login.py │ │ │ ├── permission.py │ │ │ ├── profile.py │ │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ │ └── secure.py │ ├── ch07g │ │ ├── api │ │ │ ├── admin.py │ │ │ └── login.py │ │ ├── database │ │ │ └── soas.sql │ │ ├── db_config │ │ │ └── sqlalchemy_connect.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ └── sqlalchemy_models.py │ │ │ └── request │ │ │ │ ├── login.py │ │ │ │ ├── signup.py │ │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── login.py │ │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ │ └── secure.py │ ├── ch07h │ │ ├── api │ │ │ ├── admin.py │ │ │ └── login.py │ │ ├── app.env │ │ ├── database │ │ │ └── soas.sql │ │ ├── db_config │ │ │ └── sqlalchemy_connect.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ └── sqlalchemy_models.py │ │ │ └── request │ │ │ │ ├── login.py │ │ │ │ ├── signup.py │ │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── login.py │ │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ │ └── secure.py │ ├── ch07i │ │ ├── api │ │ │ ├── admin.py │ │ │ └── login.py │ │ ├── database │ │ │ └── soas.sql │ │ ├── db_config │ │ │ └── sqlalchemy_connect.py │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ └── sqlalchemy_models.py │ │ │ └── request │ │ │ │ ├── login.py │ │ │ │ ├── signup.py │ │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── login.py │ │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ │ └── secure.py │ └── ch07j │ │ ├── api │ │ ├── admin.py │ │ └── login.py │ │ ├── database │ │ └── soas.sql │ │ ├── db_config │ │ └── sqlalchemy_connect.py │ │ ├── main.py │ │ ├── models │ │ ├── data │ │ │ └── sqlalchemy_models.py │ │ └── request │ │ │ ├── login.py │ │ │ ├── signup.py │ │ │ └── tokens.py │ │ ├── readme.txt │ │ ├── repository │ │ ├── login.py │ │ ├── permission.py │ │ └── signup.py │ │ ├── requirements.txt │ │ └── security │ │ └── secure.py ├── ch08 │ ├── api │ │ ├── admin.py │ │ ├── billing.py │ │ ├── content.py │ │ ├── customer.py │ │ ├── login.py │ │ ├── messenger.py │ │ ├── publication.py │ │ ├── sales.py │ │ ├── subscription.py │ │ └── vendor.py │ ├── celery_test.py │ ├── cert.pem │ ├── config │ │ └── db │ │ │ └── gino_db.py │ ├── data │ │ └── billing-2022-03-16.csv │ ├── database │ │ └── nsms.sql │ ├── key.pem │ ├── main.py │ ├── models │ │ ├── data │ │ │ └── nsms.py │ │ └── request │ │ │ ├── admin.py │ │ │ ├── billing.py │ │ │ ├── content.py │ │ │ ├── customer.py │ │ │ ├── login.py │ │ │ ├── messenger.py │ │ │ ├── publication.py │ │ │ ├── sales.py │ │ │ ├── subscription.py │ │ │ └── vendor.py │ ├── readme.txt │ ├── repository │ │ ├── admin.py │ │ ├── billing.py │ │ ├── content.py │ │ ├── customer.py │ │ ├── login.py │ │ ├── messenger.py │ │ ├── publication.py │ │ ├── sales.py │ │ ├── subscription.py │ │ └── vendor.py │ ├── requirements.txt │ └── services │ │ ├── admin.py │ │ ├── billing.py │ │ ├── login.py │ │ ├── sales.py │ │ └── subscription.py ├── ch09 │ ├── api │ │ ├── keyword.py │ │ ├── login.py │ │ ├── question.py │ │ ├── restaurant.py │ │ ├── route_decrypt.py │ │ ├── route_extract.py │ │ └── route_transform.py │ ├── config │ │ └── db.py │ ├── database │ │ └── orrs_db.zip │ ├── files │ │ ├── file.txt │ │ ├── logo.jpg │ │ ├── questions.txt │ │ └── sample.mp4 │ ├── main.py │ ├── models │ │ ├── data │ │ │ ├── orrs.py │ │ │ └── ratings_enum.py │ │ ├── documentation │ │ │ └── response.py │ │ └── request │ │ │ ├── ambiance_rate.py │ │ │ ├── feedback.py │ │ │ ├── food_rate.py │ │ │ ├── keyword.py │ │ │ ├── login.py │ │ │ ├── profile.py │ │ │ ├── question.py │ │ │ ├── restaurant.py │ │ │ └── secured_messages.py │ ├── readme.txt │ ├── repository │ │ ├── keyword.py │ │ ├── login.py │ │ ├── question.py │ │ ├── restaurant.py │ │ └── session.py │ ├── requirements.txt │ ├── static │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ └── js │ │ │ ├── bootstrap.bundle.js │ │ │ ├── bootstrap.bundle.js.map │ │ │ ├── bootstrap.bundle.min.js │ │ │ ├── bootstrap.bundle.min.js.map │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.js.map │ │ │ ├── bootstrap.min.js │ │ │ ├── bootstrap.min.js.map │ │ │ └── jquery-3.6.0.js │ ├── templates │ │ ├── layout.html │ │ ├── page.html │ │ ├── upload_file.html │ │ └── users.html │ ├── test │ │ ├── __init__.py │ │ ├── test_login.py │ │ ├── test_restaurants.py │ │ └── test_route_extract.py │ └── util │ │ ├── auth_session.py │ │ ├── custom_request.py │ │ ├── custom_routes.py │ │ └── json_date.py ├── ch10 │ ├── ch10-mongo │ │ ├── api │ │ │ ├── officer.py │ │ │ ├── survey_graphene_login.py │ │ │ ├── survey_graphene_profile.py │ │ │ ├── survey_neo4j.py │ │ │ └── survey_workflow.py │ │ ├── config │ │ │ ├── pccs.py │ │ │ └── pcss_neo4j.py │ │ ├── database │ │ │ └── pccs_db.zip │ │ ├── files │ │ │ ├── survey.csv │ │ │ └── survey.xlsx │ │ ├── main.py │ │ ├── models │ │ │ ├── data │ │ │ │ ├── pccs_beanie.py │ │ │ │ └── pccs_graphql.py │ │ │ └── request │ │ │ │ ├── pccs_general.py │ │ │ │ └── pccs_neo4j.py │ │ ├── readme.txt │ │ ├── repository │ │ │ ├── choices.py │ │ │ ├── login.py │ │ │ ├── profile.py │ │ │ ├── question.py │ │ │ └── respondent.py │ │ ├── requirements.txt │ │ └── services │ │ │ └── tasks.py │ └── ch10-relational │ │ ├── README.md │ │ ├── app.py │ │ ├── conftest.py │ │ ├── countries.csv │ │ ├── data.json │ │ ├── files │ │ ├── sample.csv │ │ └── survey_data.csv │ │ ├── main.py │ │ ├── piccolo_conf.py │ │ ├── piccolo_conf_test.py │ │ ├── requirements.txt │ │ ├── static │ │ ├── favicon.ico │ │ └── main.css │ │ ├── survey │ │ ├── __init__.py │ │ ├── api │ │ │ ├── answer.py │ │ │ ├── choices.py │ │ │ ├── data_analysis.py │ │ │ ├── data_files.py │ │ │ ├── data_plots.py │ │ │ ├── data_stats.py │ │ │ ├── education.py │ │ │ ├── graphql.py │ │ │ ├── location.py │ │ │ ├── login.py │ │ │ ├── mynumpy.py │ │ │ ├── occupation.py │ │ │ ├── profile.py │ │ │ ├── question.py │ │ │ └── respondent.py │ │ ├── models.py │ │ ├── piccolo_app.py │ │ ├── piccolo_migrations │ │ │ ├── 2022-06-09T18-08-51-592478.py │ │ │ ├── 2022-06-09T19-26-00-511909.py │ │ │ └── __init__.py │ │ ├── repository │ │ │ ├── answers.py │ │ │ ├── choices.py │ │ │ ├── education.py │ │ │ ├── location.py │ │ │ ├── login.py │ │ │ ├── occupation.py │ │ │ ├── profile.py │ │ │ ├── questions.py │ │ │ └── respondent.py │ │ └── tables.py │ │ └── templates │ │ ├── render_survey.html │ │ └── upload_survey.html └── ch11 │ ├── api │ ├── login.py │ ├── officials.py │ └── players.py │ ├── ch11_django │ ├── __init__.py │ ├── asgi.py │ ├── settings.py │ ├── urls.py │ └── wsgi.py │ ├── ch11_flask │ ├── api │ │ ├── __init__.py │ │ └── schedule.py │ └── app.py │ ├── config │ └── db.py │ ├── main.py │ ├── manage.py │ ├── models │ └── data.py │ ├── readme.txt │ ├── repository │ ├── login.py │ ├── officials.py │ └── players.py │ ├── requirements.txt │ └── sports │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── migrations │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py ├── docs ├── .nojekyll ├── README.md ├── _sidebar.md ├── contents │ ├── ch01.md │ ├── ch02.md │ ├── ch03.md │ ├── ch04.md │ ├── ch05.md │ ├── ch06.md │ ├── ch07.md │ ├── ch08.md │ ├── ch09.md │ ├── ch10.md │ ├── ch11.md │ └── images │ │ └── ch10-01-upload-survey-form.png └── index.html └── requirements.txt /codes/ch02/audit_log.txt: -------------------------------------------------------------------------------- 1 | tourist 0d5d1cd4-0979-11ec-b5c4-b4d5bd98aef8 executed login at 2021-08-30 18:00:39.445809 2 | tourist 16009511-0984-11ec-a3bf-b4d5bd98aef8 executed login at 2021-08-30 19:19:28.316680 3 | tourist 94458494-0986-11ec-86c1-b4d5bd98aef8 executed login at 2021-08-30 19:37:30.267336 -------------------------------------------------------------------------------- /codes/ch02/background.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | 3 | 4 | def audit_log_transaction(touristId: str, message=""): 5 | with open("audit_log.txt", mode="a") as logfile: 6 | content = f"tourist {touristId} executed {message} at {datetime.now()}\t\n" 7 | logfile.write(content) 8 | -------------------------------------------------------------------------------- /codes/ch02/handler_exceptions.py: -------------------------------------------------------------------------------- 1 | from fastapi import HTTPException 2 | 3 | 4 | class PostFeedbackException(HTTPException): 5 | def __init__(self, detail: str, status_code: int): 6 | self.status_code = status_code 7 | self.detail = detail 8 | 9 | 10 | class PostRatingException(HTTPException): 11 | def __init__(self, detail: str, status_code: int): 12 | self.status_code = status_code 13 | self.detail = detail 14 | -------------------------------------------------------------------------------- /codes/ch02/utility.py: -------------------------------------------------------------------------------- 1 | async def check_post_owner(feedbacks, fid, touristId): 2 | return feedbacks[fid].tourist_id == touristId 3 | -------------------------------------------------------------------------------- /codes/ch03/api/admin.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter, Depends 2 | from fastapi.encoders import jsonable_encoder 3 | 4 | import sys 5 | from dependency_injector.wiring import inject, Provide 6 | 7 | from repository.admin import AdminRepository 8 | from containers.single_container import Container 9 | 10 | router = APIRouter() 11 | 12 | 13 | @router.get("/admin/login/details/list") 14 | @inject 15 | def list_login_details(adminservice: AdminRepository = Depends(Provide[Container.adminservice])): 16 | login_details_json = jsonable_encoder(adminservice.query_login_details()) 17 | return login_details_json 18 | 19 | 20 | @router.get("/admin/user/profiles/list") 21 | @inject 22 | def list_user_profiles(adminservice: AdminRepository = Depends(Provide[Container.adminservice])): 23 | user_profiles_json = jsonable_encoder(adminservice.query_user_profiles()) 24 | return user_profiles_json 25 | 26 | 27 | container = Container() 28 | container.wire(modules=[sys.modules[__name__]]) 29 | -------------------------------------------------------------------------------- /codes/ch03/api/admin_mcontainer.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter, Depends 2 | from fastapi.encoders import jsonable_encoder 3 | 4 | import sys 5 | from dependency_injector.wiring import inject, Provide 6 | 7 | from repository.admin import AdminRepository 8 | from containers.multiple_containers import RecipeAppContainer 9 | 10 | router = APIRouter() 11 | 12 | 13 | @router.get("/admin/logs/visitors/list") 14 | @inject 15 | def list_logs_visitors( 16 | adminservice: AdminRepository = Depends(Provide[RecipeAppContainer.admincontainer.adminservice])): 17 | logs_visitors_json = jsonable_encoder(adminservice.query_logs_visitor()) 18 | return logs_visitors_json 19 | 20 | 21 | container = RecipeAppContainer() 22 | container.wire(modules=[sys.modules[__name__]]) 23 | -------------------------------------------------------------------------------- /codes/ch03/api/complaints.py: -------------------------------------------------------------------------------- 1 | from uuid import UUID 2 | 3 | from fastapi import APIRouter 4 | from fastapi.encoders import jsonable_encoder 5 | from fastapi.responses import JSONResponse 6 | from lagom import Container 7 | from lagom.integrations.fast_api import FastApiIntegration 8 | 9 | from repository.complaints import BadRecipeRepository 10 | 11 | container = Container() 12 | container[BadRecipeRepository] = BadRecipeRepository() 13 | # container[BadRecipeRepository] = Singleton(BadRecipeRepository) #another way 14 | 15 | router = APIRouter() 16 | deps = FastApiIntegration(container, request_singletons=[BadRecipeRepository]) 17 | 18 | 19 | @router.post("/complaint/recipe") 20 | def report_recipe(rid: UUID, complaintservice=deps.depends(BadRecipeRepository)): 21 | complaintservice.add_bad_recipe(rid) 22 | return JSONResponse(content={"message": "reported bad recipe"}, status_code=201) 23 | 24 | 25 | @router.get("/complaint/list/all") 26 | def list_defective_recipes(complaintservice=deps.depends(BadRecipeRepository)): 27 | defects_list = jsonable_encoder(complaintservice.query_bad_recipes()) 28 | return defects_list 29 | -------------------------------------------------------------------------------- /codes/ch03/api/posts.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter, Depends 2 | from fastapi.encoders import jsonable_encoder 3 | 4 | from dependencies.posts import check_feedback_length 5 | from model.classifications import RecipeRating 6 | from model.posts import Post 7 | from service.factory import get_post_service 8 | from uuid import UUID 9 | from datetime import date 10 | 11 | router = APIRouter() 12 | 13 | 14 | async def create_post(id: UUID, feedback: str, rating: RecipeRating, userId: UUID, date_posted: date): 15 | post = {"id": id, "feedback": feedback, "rating": rating, "userId": userId, "date_posted": date_posted} 16 | return post 17 | 18 | 19 | @router.post("/posts/insert", dependencies=[Depends(check_feedback_length)]) 20 | async def insert_post_feedback(post=Depends(create_post), handler=Depends(get_post_service)): 21 | print('hello') 22 | post_dict = jsonable_encoder(post) 23 | 24 | post_obj = Post(**post_dict) 25 | 26 | handler.add_post(post_obj) 27 | return post 28 | -------------------------------------------------------------------------------- /codes/ch03/api/recipes.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter, Depends 2 | from service.factory import get_recipe_service 3 | from pydantic import BaseModel 4 | from fastapi.encoders import jsonable_encoder 5 | from fastapi.responses import JSONResponse 6 | 7 | from model.recipes import Recipe 8 | from model.classifications import Category, Origin 9 | from typing import List 10 | from uuid import UUID 11 | 12 | 13 | class IngredientReq(BaseModel): 14 | id: UUID 15 | name: str 16 | qty: int 17 | measure: str 18 | 19 | 20 | class RecipeReq(BaseModel): 21 | id: UUID 22 | name: str 23 | ingredients: List[IngredientReq] 24 | cat: Category 25 | orig: Origin 26 | 27 | 28 | router = APIRouter() 29 | 30 | 31 | @router.post("/recipes/insert") 32 | def insert_recipe(recipe: RecipeReq, handler=Depends(get_recipe_service)): 33 | json_dict = jsonable_encoder(recipe) 34 | rec = Recipe(**json_dict) 35 | handler.add_recipe(rec) 36 | return JSONResponse(content=json_dict, status_code=200) 37 | 38 | 39 | @router.get("/recipes/list/all") 40 | def get_all_recipes(handler=Depends(get_recipe_service)): 41 | return handler.get_recipes() 42 | -------------------------------------------------------------------------------- /codes/ch03/containers/multiple_containers.py: -------------------------------------------------------------------------------- 1 | from dependency_injector import containers, providers 2 | 3 | from repository.login import LoginRepository 4 | from repository.admin import AdminRepository 5 | from repository.keywords import KeywordRepository 6 | 7 | 8 | class KeywordsContainer(containers.DeclarativeContainer): 9 | keywordservice = providers.Factory(KeywordRepository) 10 | 11 | 12 | class AdminContainer(containers.DeclarativeContainer): 13 | adminservice = providers.Singleton(AdminRepository) 14 | 15 | 16 | class LoginContainer(containers.DeclarativeContainer): 17 | loginservice = providers.Factory(LoginRepository) 18 | 19 | 20 | class RecipeAppContainer(containers.DeclarativeContainer): 21 | keywordcontainer = providers.Container(KeywordsContainer) 22 | admincontainer = providers.Container(AdminContainer) 23 | logincontainer = providers.Container(LoginContainer) 24 | -------------------------------------------------------------------------------- /codes/ch03/containers/single_container.py: -------------------------------------------------------------------------------- 1 | from dependency_injector import containers, providers 2 | 3 | from repository.users import login_details 4 | from repository.login import LoginRepository 5 | from repository.admin import AdminRepository 6 | from repository.keywords import KeywordRepository 7 | from service.recipe_utilities import get_recipe_names 8 | 9 | 10 | class Container(containers.DeclarativeContainer): 11 | loginservice = providers.Factory(LoginRepository) 12 | adminservice = providers.Singleton(AdminRepository) 13 | keywordservice = providers.Factory(KeywordRepository) 14 | recipe_util = providers.Callable(get_recipe_names) 15 | login_repo = providers.Dict(login_details) 16 | -------------------------------------------------------------------------------- /codes/ch03/dependencies/global_transactions.py: -------------------------------------------------------------------------------- 1 | from fastapi import Request 2 | from uuid import uuid1 3 | 4 | service_paths_log = dict() 5 | 6 | 7 | def log_transaction(request: Request): 8 | service_paths_log[uuid1()] = request.url.path 9 | -------------------------------------------------------------------------------- /codes/ch03/dependencies/posts.py: -------------------------------------------------------------------------------- 1 | from fastapi import Request, HTTPException 2 | 3 | 4 | def check_feedback_length(request: Request): 5 | feedback = request.query_params["feedback"] 6 | if len(feedback) < 20: 7 | raise HTTPException(status_code=403, detail="length of feedback should not be lower than 20") 8 | -------------------------------------------------------------------------------- /codes/ch03/dependencies/users.py: -------------------------------------------------------------------------------- 1 | from fastapi import Request, HTTPException 2 | from repository.aggregates import stats_user_type 3 | import json 4 | 5 | 6 | def count_user_by_type(request: Request): 7 | # 创建用户的更新频率 8 | try: 9 | count = stats_user_type[request.query_params.get("type")] 10 | count += 1 11 | stats_user_type[request.query_params.get("type")] = count 12 | print(json.dumps(stats_user_type)) 13 | except: 14 | stats_user_type[request.query_params.get("type")] = 1 15 | 16 | 17 | def check_credential_error(request: Request): 18 | try: 19 | username = request.query_params.get("username") 20 | password = request.query_params.get("password") 21 | if username == password: 22 | raise HTTPException(status_code=403, detail="username should not be equal to password") 23 | except: 24 | raise HTTPException(status_code=500, detail="encountered internal problems") 25 | -------------------------------------------------------------------------------- /codes/ch03/main.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | from fastapi import FastAPI, Depends 3 | 4 | from api import recipes, users, posts, login, admin, keywords, admin_mcontainer, complaints 5 | from dependencies.global_transactions import log_transaction 6 | 7 | app = FastAPI(dependencies=[Depends(log_transaction)]) 8 | 9 | app.include_router(recipes.router, prefix="/ch03") 10 | app.include_router(users.router, prefix="/ch03") 11 | app.include_router(posts.router, prefix="/ch03") 12 | app.include_router(login.router, prefix="/ch03") 13 | app.include_router(admin.router, prefix="/ch03") 14 | app.include_router(keywords.router, prefix="/ch03") 15 | app.include_router(admin_mcontainer.router, prefix="/ch03") 16 | app.include_router(complaints.router, prefix="/ch03") 17 | 18 | 19 | @app.get("/ch03") 20 | def index(): 21 | return {"message": "Cooking Recipe Rating Prototype!"} 22 | 23 | 24 | if __name__ == '__main__': 25 | uvicorn.run(app='main:app', reload=True) 26 | -------------------------------------------------------------------------------- /codes/ch03/model/classifications.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Category(str, Enum): 5 | breakfast = "breakfast" 6 | lunch = "lunch" 7 | dinner = "dinner" 8 | appetizer = "appetizer" 9 | salad = "salad" 10 | entree = "entree" 11 | side_dish = "side_dish" 12 | pastry = "pastry" 13 | dessert = "dessert" 14 | snack = "snack" 15 | soup = "soup" 16 | holiday = "holiday" 17 | vegetarian = "vegetarian" 18 | cookbook = "cookbook" 19 | 20 | 21 | class Origin(str, Enum): 22 | asian = "asian" 23 | mediterranean = "mediterranean" 24 | mid_eastern = "mid_eastern" 25 | african = "african" 26 | pacific = "pacific" 27 | south_american = "south_american" 28 | north_american = "south_american" 29 | european = "european" 30 | jewish = "jewish" 31 | carribean = "carribean" 32 | 33 | 34 | class UserType(str, Enum): 35 | admin = "admin" 36 | user = "user" 37 | guest = "guest" 38 | 39 | 40 | class RecipeRating(str, Enum): 41 | one = "1" 42 | two = "2" 43 | three = "3" 44 | four = "4" 45 | five = "5" 46 | -------------------------------------------------------------------------------- /codes/ch03/model/posts.py: -------------------------------------------------------------------------------- 1 | from uuid import UUID 2 | from datetime import date 3 | from model.classifications import RecipeRating 4 | 5 | 6 | class Post: 7 | def __init__(self, id: UUID, feedback: str, rating: RecipeRating, userId: UUID, date_posted: date): 8 | self.id = id 9 | self.feedback = feedback 10 | self.rating = rating 11 | self.userId = userId 12 | self.date_posted = date_posted 13 | -------------------------------------------------------------------------------- /codes/ch03/model/recipes.py: -------------------------------------------------------------------------------- 1 | from uuid import UUID 2 | from model.classifications import Category, Origin 3 | from typing import List 4 | 5 | 6 | class Ingredient: 7 | def __init__(self, id: UUID, name: str, qty: float, measure: str): 8 | self.id = id 9 | self.name = name 10 | self.qty = qty 11 | self.measure = measure 12 | 13 | 14 | class Recipe: 15 | def __init__(self, id: UUID, name: str, ingredients: List[Ingredient], cat: Category, orig: Origin): 16 | self.id = id 17 | self.name = name 18 | self.ingredients = ingredients 19 | self.cat = cat 20 | self.orig = orig 21 | -------------------------------------------------------------------------------- /codes/ch03/repository/admin.py: -------------------------------------------------------------------------------- 1 | from repository.users import login_details, user_profiles 2 | from repository.login import logs_visitor 3 | 4 | 5 | class AdminRepository: 6 | 7 | def __init__(self): 8 | pass 9 | 10 | def query_login_details(self): 11 | return list(login_details.values()) 12 | 13 | def query_user_profiles(self): 14 | return list(user_profiles.values()) 15 | 16 | def query_logs_visitor(self): 17 | return list(logs_visitor.values()) 18 | -------------------------------------------------------------------------------- /codes/ch03/repository/aggregates.py: -------------------------------------------------------------------------------- 1 | stats_user_type = dict() 2 | -------------------------------------------------------------------------------- /codes/ch03/repository/complaints.py: -------------------------------------------------------------------------------- 1 | from uuid import UUID 2 | from repository.recipes import recipes 3 | 4 | recipe_bad = dict() 5 | 6 | 7 | class BadRecipeRepository: 8 | def __init__(self): 9 | pass 10 | 11 | def add_bad_recipe(self, id: UUID): 12 | recipe_bad[id] = id 13 | 14 | def query_bad_recipes(self): 15 | return list(recipe_bad.values()) 16 | -------------------------------------------------------------------------------- /codes/ch03/repository/factory.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from repository.recipes import RecipeRepository 3 | from repository.posts import PostRepository 4 | from repository.admin import AdminRepository 5 | from repository.keywords import KeywordRepository 6 | from repository.complaints import BadRecipeRepository 7 | 8 | 9 | def get_recipe_repo(repo=Depends(RecipeRepository)): 10 | return repo 11 | 12 | 13 | def get_post_repo(repo=Depends(PostRepository)): 14 | return repo 15 | 16 | 17 | def get_users_repo(repo=Depends(AdminRepository)): 18 | return repo 19 | 20 | 21 | def get_keywords(keywords=Depends(KeywordRepository)): 22 | return keywords 23 | 24 | 25 | def get_bad_recipes(repo=Depends(BadRecipeRepository)): 26 | return repo 27 | -------------------------------------------------------------------------------- /codes/ch03/repository/keywords.py: -------------------------------------------------------------------------------- 1 | from uuid import UUID 2 | from typing import List 3 | 4 | keywords_recipe = dict() 5 | 6 | 7 | class KeywordRepository: 8 | 9 | def __init__(self): 10 | pass 11 | 12 | def insert_keywords(self, id: UUID, keywords: List[str]): 13 | keywords_recipe[id] = keywords 14 | 15 | def add_keywords(self, id: UUID, keyword: str): 16 | if keywords_recipe.get(id) is None: 17 | keywords = list() 18 | keywords.append(keyword) 19 | keywords_recipe[id] = keywords 20 | else: 21 | keywords = keywords_recipe[id] 22 | keywords.append(keyword) 23 | keywords_recipe[id] = keywords 24 | 25 | def query_keywords(self, id: UUID): 26 | return keywords_recipe[id] 27 | 28 | def query_all_keywords(self): 29 | return dict(keywords_recipe.items()) 30 | -------------------------------------------------------------------------------- /codes/ch03/repository/login.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | logs_visitor = dict() 4 | 5 | 6 | class LoginRepository: 7 | def __init__(self): 8 | pass 9 | 10 | def login_audit(self, username: str, password: str): 11 | logs_visitor[username] = date.today() 12 | -------------------------------------------------------------------------------- /codes/ch03/repository/posts.py: -------------------------------------------------------------------------------- 1 | from model.posts import Post 2 | 3 | posts = dict() 4 | 5 | 6 | class PostRepository: 7 | def __init__(self): 8 | pass 9 | 10 | def insert_post(self, post: Post): 11 | posts[post.id] = post 12 | 13 | def query_posts(self): 14 | return list(posts.values()) 15 | -------------------------------------------------------------------------------- /codes/ch03/repository/users.py: -------------------------------------------------------------------------------- 1 | login_details = dict() 2 | user_profiles = dict() 3 | 4 | -------------------------------------------------------------------------------- /codes/ch03/service/complaints.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from repository.factory import get_bad_recipes 3 | from uuid import UUID 4 | 5 | 6 | class BadRecipeService: 7 | 8 | def __init__(self, recipes=Depends(get_bad_recipes)): 9 | self.recipes = recipes 10 | 11 | def report_bad_recipe(self, id: UUID): 12 | self.recipes.add_bad_recipe(id) 13 | 14 | def get_bad_recipes(self): 15 | return self.recipes.query_bad_recipes() 16 | -------------------------------------------------------------------------------- /codes/ch03/service/factory.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from service.recipes import RecipeService 3 | from service.posts import PostService 4 | from service.complaints import BadRecipeService 5 | 6 | 7 | def get_recipe_service(repo=Depends(RecipeService)): 8 | return repo 9 | 10 | 11 | def get_post_service(repo=Depends(PostService)): 12 | return repo 13 | 14 | 15 | def get_complaint_service(repo=Depends(BadRecipeService)): 16 | return repo 17 | -------------------------------------------------------------------------------- /codes/ch03/service/posts.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from model.posts import Post 3 | from repository.factory import get_post_repo 4 | 5 | 6 | class PostService: 7 | 8 | def __init__(self, repo=Depends(get_post_repo)): 9 | self.repo = repo 10 | 11 | def add_post(self, post: Post): 12 | self.repo.insert_post(post) 13 | 14 | def get_posts(self): 15 | return self.repo.query_posts() 16 | -------------------------------------------------------------------------------- /codes/ch03/service/recipe_utilities.py: -------------------------------------------------------------------------------- 1 | from repository.recipes import recipes 2 | from uuid import UUID 3 | 4 | 5 | def get_recipe_names(): 6 | recipes_list = [val.name for val in recipes.values()] 7 | return recipes_list 8 | 9 | 10 | def get_recipe_ingredients(rid: UUID): 11 | ingredients = recipes[rid].ingredients 12 | return ingredients 13 | -------------------------------------------------------------------------------- /codes/ch03/service/recipes.py: -------------------------------------------------------------------------------- 1 | from fastapi import Depends 2 | from model.recipes import Recipe 3 | from repository.factory import get_recipe_repo 4 | 5 | 6 | class RecipeService: 7 | 8 | def __init__(self, repo=Depends(get_recipe_repo)): 9 | self.repo = repo 10 | 11 | def get_recipes(self): 12 | return self.repo.query_recipes() 13 | 14 | def add_recipe(self, recipe: Recipe): 15 | self.repo.insert_recipe(recipe) 16 | -------------------------------------------------------------------------------- /codes/ch04/ch04/configuration/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import date 3 | 4 | from pydantic_settings import BaseSettings 5 | 6 | 7 | class FacultySettings(BaseSettings): 8 | application: str = 'Faculty Management System' 9 | webmaster: str = 'sjctrags@university.com' 10 | created: date = '2021-11-10' 11 | 12 | 13 | class LibrarySettings(BaseSettings): 14 | application: str = 'Library Management System' 15 | webmaster: str = 'sjctrags@university.com' 16 | created: date = '2021-11-10' 17 | 18 | 19 | class StudentSettings(BaseSettings): 20 | application: str = 'Student Management System' 21 | webmaster: str = 'sjctrags@university.com' 22 | created: date = '2021-11-10' 23 | 24 | 25 | class ServerSettings(BaseSettings): 26 | production_server: str 27 | prod_port: int 28 | development_server: str 29 | dev_port: int 30 | 31 | class Config: 32 | env_file = os.getcwd() + '/configuration/erp_settings.properties' 33 | -------------------------------------------------------------------------------- /codes/ch04/ch04/configuration/erp_settings.properties: -------------------------------------------------------------------------------- 1 | production_server=prodserver100 2 | prod_port=9000 3 | development_server=devserver200 4 | dev_port=10000 5 | 6 | -------------------------------------------------------------------------------- /codes/ch04/ch04/controller/university.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router = APIRouter() 4 | 5 | 6 | @router.get("/university/{portal_id}") 7 | def access_portal(portal_id: int): 8 | return {'message': 'University ERP Systems'} 9 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/faculty_main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Depends 2 | 3 | from configuration.config import FacultySettings, ServerSettings 4 | from faculty_mgt.controllers import admin, assignments, books 5 | 6 | faculty_app = FastAPI() 7 | faculty_app.include_router(admin.router) 8 | faculty_app.include_router(assignments.router) 9 | faculty_app.include_router(books.router) 10 | 11 | 12 | def build_config(): 13 | return FacultySettings() 14 | 15 | 16 | def fetch_config(): 17 | return ServerSettings() 18 | 19 | 20 | @faculty_app.get('/index') 21 | def index_faculty(config: FacultySettings = Depends(build_config), fconfig: ServerSettings = Depends(fetch_config)): 22 | return { 23 | 'project_name': config.application, 24 | 'webmaster': config.webmaster, 25 | 'created': config.created, 26 | 'production_server': fconfig.production_server, 27 | 'prod_port': fconfig.prod_port 28 | } 29 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/models/data/facultydb.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from faculty_mgt.models.data.faculty import Faculty, Assignment, Login, Signup, StudentBin 4 | 5 | faculty_tbl: Dict[int, Faculty] = dict() 6 | faculty_assignments_tbl: Dict[int, Assignment] = dict() 7 | faculty_login_tbl: Dict[int, Login] = dict() 8 | faculty_signup_tbl: Dict[int, Signup] = dict() 9 | student_bin_tbl: Dict[int, StudentBin] = dict() 10 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/models/request/assignment.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class AssignmentRequest(BaseModel): 8 | bin_id: int 9 | assgn_id: int 10 | title: str 11 | date_completed: Optional[datetime] = None 12 | date_due: datetime 13 | rating: Optional[float] = None 14 | course: str 15 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/models/request/faculty.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | from faculty_mgt.models.data.faculty import Major 6 | 7 | 8 | class SignupReq(BaseModel): 9 | faculty_id: int 10 | username: str 11 | password: str 12 | 13 | 14 | class FacultyReq(BaseModel): 15 | faculty_id: int 16 | fname: str 17 | lname: str 18 | mname: str 19 | age: int 20 | major: Major 21 | department: str 22 | 23 | 24 | class FacultyDetails(BaseModel): 25 | fname: Optional[str] = None 26 | lname: Optional[str] = None 27 | mname: Optional[str] = None 28 | age: Optional[int] = None 29 | major: Optional[Major] = None 30 | department: Optional[str] = None 31 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/models/request/library.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | from library_mgt.models.data.library import Classification 7 | 8 | 9 | class BookReq(BaseModel): 10 | book_id: int 11 | title: str 12 | classification: Classification 13 | author: str 14 | year_published: datetime 15 | edition: int 16 | 17 | 18 | class BookDetails(BaseModel): 19 | title: Optional[str] = None 20 | classification: Optional[Classification] = None 21 | author: Optional[str] = None 22 | year_published: Optional[datetime] = None 23 | edition: Optional[int] = None 24 | 25 | 26 | class BookRequestReq(BaseModel): 27 | book_id: int 28 | request_date: datetime 29 | status: bool 30 | 31 | 32 | class BookIssuanceReq(BaseModel): 33 | req_id: int 34 | approved_by: str 35 | approved_date: datetime 36 | 37 | 38 | class BookReturnReq(BaseModel): 39 | issue_id: int 40 | returned_date: datetime 41 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/repository/login.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from faculty_mgt.models.data.faculty import Login 4 | from faculty_mgt.models.data.facultydb import faculty_signup_tbl, faculty_login_tbl 5 | 6 | 7 | class FacultyLoginRepository: 8 | 9 | def insert_login(self, sign_id: int) -> bool: 10 | try: 11 | account = faculty_signup_tbl[sign_id] 12 | login = Login(user_id=account.sign_id, faculty_id=account.faculty_id, username=account.username, 13 | password=account.password) 14 | faculty_signup_tbl[account.faculty_id] = login 15 | except: 16 | return False 17 | return True 18 | 19 | def update_password_userid(self, user_id: int, newpass: str) -> bool: 20 | try: 21 | login = faculty_login_tbl[user_id] 22 | login.password = newpass 23 | except: 24 | return False 25 | return True 26 | 27 | def delete_login(self, user_id: int) -> bool: 28 | try: 29 | del faculty_login_tbl[user_id] 30 | except: 31 | return False 32 | return True 33 | 34 | def get_all_login(self) -> List[Login]: 35 | return faculty_login_tbl.values(); 36 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/repository/signup.py: -------------------------------------------------------------------------------- 1 | from faculty_mgt.models.data.faculty import Signup 2 | from faculty_mgt.models.data.facultydb import faculty_signup_tbl 3 | 4 | 5 | class FacultySignupRepository: 6 | 7 | def add_item(self, item: Signup): 8 | try: 9 | faculty_signup_tbl[item.sign_id] = item 10 | except: 11 | return False 12 | return True 13 | 14 | def remove_item(self, sign_id: int): 15 | try: 16 | del faculty_signup_tbl[sign_id] 17 | except: 18 | return False 19 | return True 20 | 21 | def get_item(self, sign_id: int): 22 | try: 23 | account = faculty_signup_tbl[sign_id] 24 | except: 25 | return None 26 | return account 27 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/services/faculty.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from faculty_mgt.models.data.faculty import Faculty 4 | from faculty_mgt.repository.faculty import FacultyRepository 5 | 6 | 7 | class FacultyService: 8 | 9 | def __init__(self): 10 | self.repo: FacultyRepository = FacultyRepository() 11 | 12 | def add_faculty(self, faculty: Faculty): 13 | result = self.repo.insert_faculty(faculty) 14 | return result 15 | 16 | def update_faculty(self, faculty_id: int, details: Dict[str, Any]): 17 | result = self.repo.update_faculty(faculty_id, details) 18 | return result 19 | 20 | def remove_faculty(self, faculty_id: int): 21 | result = self.repo.delete_faculty(faculty_id) 22 | return result 23 | 24 | def list_faculty(self): 25 | return self.repo.get_all_faculty() 26 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/services/login.py: -------------------------------------------------------------------------------- 1 | from faculty_mgt.models.data.faculty import Login 2 | from faculty_mgt.repository.login import FacultyLoginRepository 3 | 4 | 5 | class FacultyLoginService: 6 | 7 | def __init__(self): 8 | self.repo: FacultyLoginRepository = FacultyLoginRepository() 9 | 10 | def add_faculty_login(self, login: Login): 11 | result = self.repo.insert_login(login) 12 | return result 13 | 14 | def update_login_password(self, user_id: int, newpass: str): 15 | result = self.repo.update_password(user_id, newpass) 16 | return result 17 | 18 | def remove_faculty_login(self, user_id: int): 19 | result = self.repo.delete_login(user_id) 20 | return result 21 | 22 | def get_faculty_login(self, username): 23 | return self.repo.get_login(username) 24 | 25 | def list_login(self): 26 | return self.repo.get_all_login() 27 | -------------------------------------------------------------------------------- /codes/ch04/ch04/faculty_mgt/services/signup.py: -------------------------------------------------------------------------------- 1 | from faculty_mgt.models.data.faculty import Signup 2 | from faculty_mgt.repository.signup import FacultySignupRepository 3 | 4 | 5 | class FacultySignupService: 6 | def __init__(self): 7 | self.repo: FacultySignupRepository = FacultySignupRepository() 8 | 9 | def add_signup(self, signup: Signup): 10 | result = self.repo.insert_item(signup) 11 | return result 12 | 13 | def get_signup(self, sign_id: int): 14 | result = self.repo.get_item(sign_id) 15 | return result 16 | 17 | def remove_signup(self, sign_id: int): 18 | result = self.repo.delete_item(sign_id) 19 | return result 20 | -------------------------------------------------------------------------------- /codes/ch04/ch04/gateway/api_router.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from fastapi import Request 4 | 5 | logger = logging.getLogger('uvicorn.access') 6 | 7 | 8 | def call_api_gateway(request: Request): 9 | portal_id = request.path_params['portal_id'] 10 | print(request.path_params) 11 | if portal_id == str(1): 12 | raise RedirectStudentPortalException() 13 | elif portal_id == str(2): 14 | raise RedirectFacultyPortalException() 15 | elif portal_id == str(3): 16 | raise RedirectLibraryPortalException() 17 | 18 | 19 | class RedirectStudentPortalException(Exception): 20 | pass 21 | 22 | 23 | class RedirectFacultyPortalException(Exception): 24 | pass 25 | 26 | 27 | class RedirectLibraryPortalException(Exception): 28 | pass 29 | -------------------------------------------------------------------------------- /codes/ch04/ch04/library_mgt/library_main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Depends 2 | 3 | from configuration.config import LibrarySettings 4 | from library_mgt.controllers import admin, management 5 | 6 | library_app = FastAPI() 7 | library_app.include_router(admin.router) 8 | library_app.include_router(management.router) 9 | 10 | 11 | def build_config(): 12 | return LibrarySettings() 13 | 14 | 15 | @library_app.get('/index') 16 | def index_library(config: LibrarySettings = Depends(build_config)): 17 | return { 18 | 'project_name': config.application, 19 | 'webmaster': config.webmaster, 20 | 'created': config.created 21 | } 22 | -------------------------------------------------------------------------------- /codes/ch04/ch04/library_mgt/models/data/librarydb.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from library_mgt.models.data.library import Book, BookRequest, BookIssuance 4 | 5 | book_tbl: Dict[int, Book] = dict() 6 | book_request_tbl: Dict[int, BookRequest] = dict() 7 | book_issuance_tbl: Dict[int, BookIssuance] = dict() 8 | -------------------------------------------------------------------------------- /codes/ch04/ch04/library_mgt/models/request/library.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | from library_mgt.models.data.library import Classification 7 | 8 | 9 | class BookReq(BaseModel): 10 | book_id: int 11 | title: str 12 | classification: Classification 13 | author: str 14 | year_published: datetime 15 | edition: int 16 | 17 | 18 | class BookDetails(BaseModel): 19 | title: Optional[str] = None 20 | classification: Optional[Classification] = None 21 | author: Optional[str] = None 22 | year_published: Optional[datetime] = None 23 | edition: Optional[int] = None 24 | 25 | 26 | class BookRequestReq(BaseModel): 27 | book_id: int 28 | request_date: datetime 29 | status: bool 30 | 31 | 32 | class BookIssuanceReq(BaseModel): 33 | req_id: int 34 | approved_by: str 35 | approved_date: datetime 36 | 37 | 38 | class BookReturnReq(BaseModel): 39 | issue_id: int 40 | returned_date: datetime 41 | -------------------------------------------------------------------------------- /codes/ch04/ch04/library_mgt/repository/books.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | from typing import Dict, Any 3 | 4 | from fastapi.encoders import jsonable_encoder 5 | 6 | from library_mgt.models.data.library import Book 7 | from library_mgt.models.data.librarydb import book_tbl 8 | 9 | 10 | class BookRepository: 11 | 12 | def insert_book(self, book: Book) -> bool: 13 | try: 14 | book_tbl[book.book_id] = book 15 | except: 16 | return False 17 | return True 18 | 19 | def update_book(self, book_id: int, details: Dict[str, Any]) -> bool: 20 | try: 21 | profile = book_tbl[book_id] 22 | profile_enc = jsonable_encoder(profile) 23 | profile_dict = dict(profile_enc) 24 | profile_dict.update(details) 25 | book_tbl[book_id] = namedtuple("Book", profile_dict.keys())(*profile_dict.values()) 26 | except: 27 | return False 28 | return True 29 | 30 | def delete_book(self, book_id: int) -> bool: 31 | try: 32 | del book_tbl[book_id] 33 | except: 34 | return False 35 | return True 36 | 37 | def get_all_books(self): 38 | return book_tbl 39 | -------------------------------------------------------------------------------- /codes/ch04/ch04/library_mgt/repository/reservations.py: -------------------------------------------------------------------------------- 1 | from library_mgt.models.data.library import BookRequest 2 | from library_mgt.models.data.librarydb import book_request_tbl 3 | 4 | 5 | class BookRequestRepository: 6 | 7 | def insert_request(self, request: BookRequest): 8 | try: 9 | book_request_tbl[request.req_id] = request 10 | except: 11 | return False 12 | return True 13 | 14 | def update_requested_book(self, req_id: int, book_id: int): 15 | try: 16 | request = book_request_tbl[req_id] 17 | request.book_id = book_id 18 | except: 19 | return False 20 | return True 21 | 22 | def delete_request(self, req_id: int): 23 | try: 24 | del book_request_tbl[req_id] 25 | except: 26 | return False 27 | return True 28 | 29 | def get_all_requests(self): 30 | return book_request_tbl 31 | -------------------------------------------------------------------------------- /codes/ch04/ch04/library_mgt/services/books.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from library_mgt.models.data.library import Book 4 | from library_mgt.repository.books import BookRepository 5 | 6 | 7 | class BookService: 8 | 9 | def __init__(self): 10 | self.repo: BookRepository = BookRepository() 11 | 12 | def add_book(self, book: Book): 13 | result = self.repo.insert_book(book) 14 | return result 15 | 16 | def update_book(self, book_id: int, details: Dict[str, Any]): 17 | result = self.repo.update_book(book_id, details) 18 | return result 19 | 20 | def remove_book(self, book_id: int): 21 | result = self.repo.delete_book(book_id) 22 | return result 23 | 24 | def list_book(self): 25 | return self.repo.get_all_books() 26 | -------------------------------------------------------------------------------- /codes/ch04/ch04/library_mgt/services/reservations.py: -------------------------------------------------------------------------------- 1 | from library_mgt.models.data.library import BookRequest 2 | from library_mgt.repository.reservations import BookRequestRepository 3 | 4 | 5 | class BookRequestService: 6 | 7 | def __init__(self): 8 | self.repo: BookRequestRepository = BookRequestRepository() 9 | 10 | def add_book_request(self, book_request: BookRequest): 11 | result = self.repo.insert_request(book_request) 12 | return result 13 | 14 | def update_book_request(self, req_id: int, book_id: int): 15 | result = self.repo.update_requested_book(req_id, book_id) 16 | return result 17 | 18 | def remove_book_request(self, req_id: int): 19 | result = self.repo.delete_request(req_id) 20 | return result 21 | 22 | def list_book_request(self): 23 | return self.repo.get_all_requests() 24 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/controllers/assignments.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import httpx 4 | from fastapi import APIRouter 5 | from fastapi.encoders import jsonable_encoder 6 | 7 | from student_mgt.models.request.assignment import AssignmentRequest 8 | 9 | router = APIRouter() 10 | 11 | 12 | @router.get('/assignment/list') 13 | async def list_assignments(): 14 | with httpx.Client() as client: 15 | response = await client.get("http://localhost:8000/ch04/faculty/assignments/list") 16 | return response.json() 17 | 18 | 19 | @router.post('/assignment/submit') 20 | def submit_assignment(assignment: AssignmentRequest): 21 | with httpx.Client() as client: 22 | response = client.post("http://localhost:8000/ch04/faculty/assignments/student/submit", 23 | data=json.dumps(jsonable_encoder(assignment))) 24 | return response.content 25 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/controllers/reservations.py: -------------------------------------------------------------------------------- 1 | from json import dumps 2 | 3 | import httpx 4 | from fastapi import APIRouter 5 | from fastapi.encoders import jsonable_encoder 6 | 7 | from student_mgt.models.request.library import BookIssuanceReq 8 | 9 | router = APIRouter() 10 | 11 | 12 | @router.get('/access/book') 13 | def access_book(): 14 | with httpx.Client() as client: 15 | response = client.get("http://localhost:8000/ch04/library/book/list") 16 | return response.json() 17 | 18 | 19 | @router.get('/reserve/book') 20 | def reserve_book(book: BookIssuanceReq): 21 | with httpx.Client() as client: 22 | response = client.post("http://localhost:8000/ch04/library/book/issuance", 23 | data={"book": dumps(jsonable_encoder(book))}) 24 | return response.content 25 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/models/data/studentsdb.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from student_mgt.models.data.students import Login, Student, Signup 4 | 5 | students_tbl: Dict[int, Student] = dict() 6 | stud_login_tbl: Dict[int, Login] = dict() 7 | stud_signup_tbl: Dict[int, Signup] = dict() 8 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/models/request/assignment.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class AssignmentRequest(BaseModel): 8 | bin_id: int 9 | assgn_id: int 10 | title: str 11 | date_completed: Optional[datetime] = None 12 | date_due: datetime 13 | rating: Optional[float] = None 14 | course: str 15 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/models/request/library.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | from library_mgt.models.data.library import Classification 7 | 8 | 9 | class BookReq(BaseModel): 10 | book_id: int 11 | title: str 12 | classification: Classification 13 | author: str 14 | year_published: datetime 15 | edition: int 16 | 17 | 18 | class BookDetails(BaseModel): 19 | title: Optional[str] = None 20 | classification: Optional[Classification] = None 21 | author: Optional[str] = None 22 | year_published: Optional[datetime] = None 23 | edition: Optional[int] = None 24 | 25 | 26 | class BookRequestReq(BaseModel): 27 | book_id: int 28 | request_date: datetime 29 | status: bool 30 | 31 | 32 | class BookIssuanceReq(BaseModel): 33 | req_id: int 34 | approved_by: str 35 | approved_date: datetime 36 | 37 | 38 | class BookReturnReq(BaseModel): 39 | issue_id: int 40 | returned_date: datetime 41 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/models/request/students.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | from student_mgt.models.data.students import StudentStatus, Major 6 | 7 | 8 | class SignupReq(BaseModel): 9 | stud_id: int 10 | username: str 11 | password: str 12 | 13 | 14 | class StudentReq(BaseModel): 15 | stud_id: int 16 | fname: str 17 | lname: str 18 | mname: str 19 | age: int 20 | major: Major 21 | department: str 22 | status: StudentStatus 23 | 24 | 25 | class StudentDetails(BaseModel): 26 | fname: Optional[str] = None 27 | lname: Optional[str] = None 28 | mname: Optional[str] = None 29 | age: Optional[int] = None 30 | major: Optional[Major] = None 31 | department: Optional[str] = None 32 | status: Optional[StudentStatus] = None 33 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/repository/signup.py: -------------------------------------------------------------------------------- 1 | from student_mgt.models.data.students import Signup 2 | from student_mgt.models.data.studentsdb import stud_signup_tbl 3 | 4 | 5 | class StudentSignupRepository: 6 | 7 | def insert_item(self, item: Signup): 8 | try: 9 | stud_signup_tbl[item.sign_id] = item 10 | except: 11 | return False 12 | return True 13 | 14 | def delete_item(self, sign_id: int): 15 | try: 16 | del stud_signup_tbl[sign_id] 17 | except: 18 | return False 19 | return True 20 | 21 | def get_item(self, sign_id: int): 22 | try: 23 | account = stud_signup_tbl[sign_id] 24 | except: 25 | return None 26 | return account 27 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/services/login.py: -------------------------------------------------------------------------------- 1 | from student_mgt.models.data.students import Login 2 | from student_mgt.repository.login import StudentLoginRepository 3 | 4 | 5 | class StudentLoginService: 6 | 7 | def __init__(self): 8 | self.repo: StudentLoginRepository = StudentLoginRepository() 9 | 10 | def add_student_login(self, login: Login): 11 | result = self.repo.insert_login(login) 12 | return result 13 | 14 | def update_login_password(self, user_id: int, newpass: str): 15 | result = self.repo.update_password(user_id, newpass) 16 | return result 17 | 18 | def remove_student_login(self, user_id: int): 19 | result = self.repo.delete_login(user_id) 20 | return result 21 | 22 | def get_student_login(self, username): 23 | return self.repo.get_login(username) 24 | 25 | def list_login(self): 26 | return self.repo.get_all_login() 27 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/services/signup.py: -------------------------------------------------------------------------------- 1 | from student_mgt.models.data.students import Signup 2 | from student_mgt.repository.signup import StudentSignupRepository 3 | 4 | 5 | class StudentSignupService: 6 | 7 | def __init__(self): 8 | self.repo: StudentSignupRepository = StudentSignupRepository() 9 | 10 | def add_signup(self, signup: Signup): 11 | result = self.repo.insert_item(signup) 12 | return result 13 | 14 | def get_signup(self, sign_id: int): 15 | result = self.repo.get_item(sign_id) 16 | return result 17 | 18 | def remove_signup(self, sign_id: int): 19 | result = self.repo.delete_item(sign_id) 20 | return result 21 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/services/students.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from student_mgt.models.data.students import Student 4 | from student_mgt.repository.students import StudentRepository 5 | 6 | 7 | class StudentService: 8 | 9 | def __init__(self): 10 | self.repo: StudentRepository = StudentRepository() 11 | 12 | def add_student(self, student: Student): 13 | result = self.repo.insert_student(student) 14 | return result 15 | 16 | def update_student(self, stud_id: int, details: Dict[str, Any]): 17 | result = self.repo.update_student(stud_id, details) 18 | return result 19 | 20 | def remove_student(self, stud_id: int): 21 | result = self.repo.delete_student(stud_id) 22 | return result 23 | 24 | def list_students(self): 25 | return self.repo.get_all_students() 26 | -------------------------------------------------------------------------------- /codes/ch04/ch04/student_mgt/student_main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Depends 2 | 3 | from configuration.config import StudentSettings, ServerSettings 4 | from student_mgt.controllers import reservations, admin, assignments 5 | 6 | student_app = FastAPI() 7 | student_app.include_router(reservations.router) 8 | student_app.include_router(admin.router) 9 | student_app.include_router(assignments.router) 10 | 11 | 12 | def build_config(): 13 | return StudentSettings() 14 | 15 | 16 | def fetch_config(): 17 | return ServerSettings() 18 | 19 | 20 | @student_app.get('/index') 21 | def index_student(config: StudentSettings = Depends(build_config), fconfig: ServerSettings = Depends(fetch_config)): 22 | return { 23 | 'project_name': config.application, 24 | 'webmaster': config.webmaster, 25 | 'created': config.created, 26 | 'development_server': fconfig.development_server, 27 | 'dev_port': fconfig.dev_port 28 | } 29 | -------------------------------------------------------------------------------- /codes/ch04/faculty/configuration/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import date 3 | 4 | from pydantic import BaseSettings 5 | 6 | 7 | class FacultySettings(BaseSettings): 8 | application: str = 'Faculty Management System' 9 | webmaster: str = 'sjctrags@university.com' 10 | created: date = '2021-11-10' 11 | 12 | 13 | class ServerSettings(BaseSettings): 14 | production_server: str 15 | prod_port: int 16 | development_server: str 17 | dev_port: int 18 | 19 | class Config: 20 | env_file = os.getcwd() + '/configuration/erp_settings.properties' 21 | -------------------------------------------------------------------------------- /codes/ch04/faculty/configuration/erp_settings.properties: -------------------------------------------------------------------------------- 1 | production_server=prodserver100 2 | prod_port=9000 3 | development_server=devserver200 4 | dev_port=10000 5 | 6 | -------------------------------------------------------------------------------- /codes/ch04/faculty/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Depends 2 | 3 | from configuration.config import FacultySettings, ServerSettings 4 | from controllers import admin, assignments, books 5 | 6 | app = FastAPI() 7 | app.include_router(admin.router, prefix="/ch04/faculty") 8 | app.include_router(assignments.router, prefix="/ch04/faculty") 9 | app.include_router(books.router, prefix="/ch04/faculty") 10 | 11 | 12 | def build_config(): 13 | return FacultySettings() 14 | 15 | 16 | def fetch_config(): 17 | return ServerSettings() 18 | 19 | 20 | @app.get('/index') 21 | def index_faculty(config: FacultySettings = Depends(build_config), fconfig: ServerSettings = Depends(fetch_config)): 22 | return { 23 | 'project_name': config.application, 24 | 'webmaster': config.webmaster, 25 | 'created': config.created, 26 | 'production_server': fconfig.production_server, 27 | 'prod_port': fconfig.prod_port 28 | } 29 | -------------------------------------------------------------------------------- /codes/ch04/faculty/models/data/facultydb.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from models.data.faculty import Faculty, Assignment, Login, Signup, StudentBin 4 | 5 | faculty_tbl: Dict[int, Faculty] = dict() 6 | faculty_assignments_tbl: Dict[int, Assignment] = dict() 7 | faculty_login_tbl: Dict[int, Login] = dict() 8 | faculty_signup_tbl: Dict[int, Signup] = dict() 9 | student_bin_tbl: Dict[int, StudentBin] = dict() 10 | -------------------------------------------------------------------------------- /codes/ch04/faculty/models/data/library.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Classification(str, Enum): 5 | Non_Fiction = 'Non-Fiction' 6 | Fiction = 'Fiction' 7 | Science = 'Science' 8 | Technology = 'Technology' 9 | History = 'History' 10 | Arts = 'Arts' 11 | Music = 'Music' 12 | Travels = 'Travels' 13 | Food = 'Food' 14 | Engineering = 'Engineering' 15 | -------------------------------------------------------------------------------- /codes/ch04/faculty/models/request/assignment.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class AssignmentRequest(BaseModel): 8 | bin_id: int 9 | assgn_id: int 10 | title: str 11 | date_completed: Optional[datetime] = None 12 | date_due: datetime 13 | rating: Optional[float] = None 14 | course: str 15 | -------------------------------------------------------------------------------- /codes/ch04/faculty/models/request/faculty.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from models.data.faculty import Major 4 | from pydantic import BaseModel 5 | 6 | 7 | class SignupReq(BaseModel): 8 | faculty_id: int 9 | username: str 10 | password: str 11 | 12 | 13 | class FacultyReq(BaseModel): 14 | faculty_id: int 15 | fname: str 16 | lname: str 17 | mname: str 18 | age: int 19 | major: Major 20 | department: str 21 | 22 | 23 | class FacultyDetails(BaseModel): 24 | fname: Optional[str] = None 25 | lname: Optional[str] = None 26 | mname: Optional[str] = None 27 | age: Optional[int] = None 28 | major: Optional[Major] = None 29 | department: Optional[str] = None 30 | -------------------------------------------------------------------------------- /codes/ch04/faculty/models/request/library.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from models.data.library import Classification 5 | from pydantic import BaseModel 6 | 7 | 8 | class BookReq(BaseModel): 9 | book_id: int 10 | title: str 11 | classification: Classification 12 | author: str 13 | year_published: datetime 14 | edition: int 15 | 16 | 17 | class BookDetails(BaseModel): 18 | title: Optional[str] = None 19 | classification: Optional[Classification] = None 20 | author: Optional[str] = None 21 | year_published: Optional[datetime] = None 22 | edition: Optional[int] = None 23 | 24 | 25 | class BookRequestReq(BaseModel): 26 | book_id: int 27 | request_date: datetime 28 | status: bool 29 | 30 | 31 | class BookIssuanceReq(BaseModel): 32 | req_id: int 33 | approved_by: str 34 | approved_date: datetime 35 | 36 | 37 | class BookReturnReq(BaseModel): 38 | issue_id: int 39 | returned_date: datetime 40 | -------------------------------------------------------------------------------- /codes/ch04/faculty/repository/faculty.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from fastapi.encoders import jsonable_encoder 4 | from models.data.faculty import Faculty 5 | from models.data.facultydb import faculty_tbl 6 | 7 | 8 | class FacultyRepository: 9 | 10 | def insert_faculty(self, faculty: Faculty) -> bool: 11 | try: 12 | faculty_tbl[faculty.faculty_id] = faculty 13 | except: 14 | return False 15 | return True 16 | 17 | def update_faculty(self, faculty_id: int, details: Dict[str, Any]) -> bool: 18 | try: 19 | profile = faculty_tbl[faculty_id] 20 | profile_enc = jsonable_encoder(profile) 21 | profile_dict = dict(profile_enc) 22 | profile_dict.update(details) 23 | faculty_tbl[faculty_id] = Faculty(**profile_dict) 24 | 25 | except: 26 | return False 27 | return True 28 | 29 | def delete_faculty(self, user_id: int) -> bool: 30 | try: 31 | del faculty_tbl[user_id] 32 | except: 33 | return False 34 | return True 35 | 36 | def get_all_faculty(self): 37 | return faculty_tbl 38 | -------------------------------------------------------------------------------- /codes/ch04/faculty/repository/login.py: -------------------------------------------------------------------------------- 1 | from models.data.faculty import Login 2 | from models.data.facultydb import faculty_login_tbl 3 | 4 | 5 | class FacultyLoginRepository: 6 | 7 | def insert_login(self, login: Login) -> bool: 8 | try: 9 | faculty_login_tbl[login.user_id] = login 10 | except: 11 | return False 12 | return True 13 | 14 | def update_password_userid(self, user_id: int, newpass: str) -> bool: 15 | try: 16 | login = faculty_login_tbl[user_id] 17 | login.password = newpass 18 | except: 19 | return False 20 | return True 21 | 22 | def delete_login(self, user_id: int) -> bool: 23 | try: 24 | del faculty_login_tbl[user_id] 25 | except: 26 | return False 27 | return True 28 | 29 | def get_login(self, username: str): 30 | try: 31 | login = [v for v in faculty_login_tbl.values() if v.username == username] 32 | if not len(login) == 0: 33 | return login[0] 34 | else: 35 | return None 36 | except: 37 | return None 38 | 39 | def get_all_login(self): 40 | return faculty_login_tbl 41 | -------------------------------------------------------------------------------- /codes/ch04/faculty/repository/signup.py: -------------------------------------------------------------------------------- 1 | from models.data.faculty import Signup 2 | from models.data.facultydb import faculty_signup_tbl 3 | 4 | 5 | class FacultySignupRepository: 6 | 7 | def add_item(self, item: Signup): 8 | try: 9 | faculty_signup_tbl[item.sign_id] = item 10 | except: 11 | return False 12 | return True 13 | 14 | def remove_item(self, sign_id: int): 15 | try: 16 | del faculty_signup_tbl[sign_id] 17 | except: 18 | return False 19 | return True 20 | 21 | def get_item(self, sign_id: int): 22 | try: 23 | account = faculty_signup_tbl[sign_id] 24 | except: 25 | return None 26 | return account 27 | -------------------------------------------------------------------------------- /codes/ch04/faculty/services/faculty.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.faculty import Faculty 4 | from repository.faculty import FacultyRepository 5 | 6 | 7 | class FacultyService: 8 | 9 | def __init__(self): 10 | self.repo: FacultyRepository = FacultyRepository() 11 | 12 | def add_faculty(self, faculty: Faculty): 13 | result = self.repo.insert_faculty(faculty) 14 | return result 15 | 16 | def update_faculty(self, faculty_id: int, details: Dict[str, Any]): 17 | result = self.repo.update_faculty(faculty_id, details) 18 | return result 19 | 20 | def remove_faculty(self, faculty_id: int): 21 | result = self.repo.delete_faculty(faculty_id) 22 | return result 23 | 24 | def list_faculty(self): 25 | return self.repo.get_all_faculty() 26 | -------------------------------------------------------------------------------- /codes/ch04/faculty/services/login.py: -------------------------------------------------------------------------------- 1 | from models.data.faculty import Login 2 | 3 | from repository.login import FacultyLoginRepository 4 | 5 | 6 | class FacultyLoginService: 7 | 8 | def __init__(self): 9 | self.repo: FacultyLoginRepository = FacultyLoginRepository() 10 | 11 | def add_faculty_login(self, login: Login): 12 | result = self.repo.insert_login(login) 13 | return result 14 | 15 | def update_login_password(self, user_id: int, newpass: str): 16 | result = self.repo.update_password_userid(user_id, newpass) 17 | return result 18 | 19 | def remove_faculty_login(self, user_id: int): 20 | result = self.repo.delete_login(user_id) 21 | return result 22 | 23 | def get_faculty_login(self, username: str): 24 | return self.repo.get_login(username) 25 | 26 | def list_login(self): 27 | return self.repo.get_all_login() 28 | -------------------------------------------------------------------------------- /codes/ch04/faculty/services/signup.py: -------------------------------------------------------------------------------- 1 | from models.data.faculty import Signup 2 | from repository.signup import FacultySignupRepository 3 | 4 | 5 | class FacultySignupService: 6 | def __init__(self): 7 | self.repo: FacultySignupRepository = FacultySignupRepository() 8 | 9 | def add_signup(self, signup: Signup): 10 | result = self.repo.add_item(signup) 11 | return result 12 | 13 | def get_signup(self, sign_id: int): 14 | result = self.repo.get_item(sign_id) 15 | return result 16 | 17 | def remove_signup(self, sign_id: int): 18 | result = self.repo.remove_item(sign_id) 19 | return result 20 | -------------------------------------------------------------------------------- /codes/ch04/library/configuration/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import date 3 | 4 | from pydantic import BaseSettings 5 | 6 | 7 | class LibrarySettings(BaseSettings): 8 | application: str = 'Library Management System' 9 | webmaster: str = 'sjctrags@university.com' 10 | created: date = '2021-11-10' 11 | 12 | 13 | class ServerSettings(BaseSettings): 14 | production_server: str 15 | prod_port: int 16 | development_server: str 17 | dev_port: int 18 | 19 | class Config: 20 | env_file = os.getcwd() + '/configuration/erp_settings.properties' 21 | -------------------------------------------------------------------------------- /codes/ch04/library/configuration/erp_settings.properties: -------------------------------------------------------------------------------- 1 | production_server=prodserver100 2 | prod_port=9000 3 | development_server=devserver200 4 | dev_port=10000 5 | 6 | -------------------------------------------------------------------------------- /codes/ch04/library/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Depends 2 | 3 | from configuration.config import LibrarySettings 4 | from controllers import admin, management 5 | 6 | app = FastAPI() 7 | app.include_router(admin.router, prefix="/ch04/library") 8 | app.include_router(management.router, prefix="/ch04/library") 9 | 10 | 11 | def build_config(): 12 | return LibrarySettings() 13 | 14 | 15 | @app.get('/index') 16 | def index_library(config: LibrarySettings = Depends(build_config)): 17 | return { 18 | 'project_name': config.application, 19 | 'webmaster': config.webmaster, 20 | 'created': config.created 21 | } 22 | -------------------------------------------------------------------------------- /codes/ch04/library/models/data/librarydb.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from models.data.library import Book, BookRequest, BookIssuance 4 | 5 | book_tbl: Dict[int, Book] = dict() 6 | book_request_tbl: Dict[int, BookRequest] = dict() 7 | book_issuance_tbl: Dict[int, BookIssuance] = dict() 8 | -------------------------------------------------------------------------------- /codes/ch04/library/models/request/library.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from models.data.library import Classification 5 | from pydantic import BaseModel 6 | 7 | 8 | class BookReq(BaseModel): 9 | book_id: int 10 | title: str 11 | classification: Classification 12 | author: str 13 | year_published: datetime 14 | edition: int 15 | 16 | 17 | class BookDetails(BaseModel): 18 | title: Optional[str] = None 19 | classification: Optional[Classification] = None 20 | author: Optional[str] = None 21 | year_published: Optional[datetime] = None 22 | edition: Optional[int] = None 23 | 24 | 25 | class BookRequestReq(BaseModel): 26 | book_id: int 27 | request_date: datetime 28 | status: bool 29 | 30 | 31 | class BookIssuanceReq(BaseModel): 32 | req_id: int 33 | approved_by: str 34 | approved_date: datetime 35 | 36 | 37 | class BookReturnReq(BaseModel): 38 | issue_id: int 39 | returned_date: datetime 40 | -------------------------------------------------------------------------------- /codes/ch04/library/repository/books.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from fastapi.encoders import jsonable_encoder 4 | from models.data.library import Book 5 | from models.data.librarydb import book_tbl 6 | 7 | 8 | class BookRepository: 9 | 10 | def insert_book(self, book: Book) -> bool: 11 | try: 12 | book_tbl[book.book_id] = book 13 | except: 14 | return False 15 | return True 16 | 17 | def update_book(self, book_id: int, details: Dict[str, Any]) -> bool: 18 | try: 19 | profile = book_tbl[book_id] 20 | profile_enc = jsonable_encoder(profile) 21 | profile_dict = dict(profile_enc) 22 | profile_dict.update(details) 23 | book_tbl[book_id] = Book(**profile_dict) 24 | except: 25 | return False 26 | return True 27 | 28 | def delete_book(self, book_id: int) -> bool: 29 | try: 30 | del book_tbl[book_id] 31 | except: 32 | return False 33 | return True 34 | 35 | def get_all_books(self): 36 | return book_tbl 37 | -------------------------------------------------------------------------------- /codes/ch04/library/repository/reservations.py: -------------------------------------------------------------------------------- 1 | from models.data.library import BookRequest 2 | from models.data.librarydb import book_request_tbl 3 | 4 | 5 | class BookRequestRepository: 6 | 7 | def insert_request(self, request: BookRequest): 8 | try: 9 | book_request_tbl[request.req_id] = request 10 | except: 11 | return False 12 | return True 13 | 14 | def update_requested_book(self, req_id: int, book_id: int): 15 | try: 16 | request = book_request_tbl[req_id] 17 | request.book_id = book_id 18 | except: 19 | return False 20 | return True 21 | 22 | def delete_request(self, req_id: int): 23 | try: 24 | del book_request_tbl[req_id] 25 | except: 26 | return False 27 | return True 28 | 29 | def get_all_requests(self): 30 | return book_request_tbl 31 | -------------------------------------------------------------------------------- /codes/ch04/library/services/books.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.library import Book 4 | from repository.books import BookRepository 5 | 6 | 7 | class BookService: 8 | 9 | def __init__(self): 10 | self.repo: BookRepository = BookRepository() 11 | 12 | def add_book(self, book: Book): 13 | result = self.repo.insert_book(book) 14 | return result 15 | 16 | def update_book(self, book_id: int, details: Dict[str, Any]): 17 | result = self.repo.update_book(book_id, details) 18 | return result 19 | 20 | def remove_book(self, book_id: int): 21 | result = self.repo.delete_book(book_id) 22 | return result 23 | 24 | def list_book(self): 25 | return self.repo.get_all_books() 26 | -------------------------------------------------------------------------------- /codes/ch04/library/services/reservations.py: -------------------------------------------------------------------------------- 1 | from models.data.library import BookRequest 2 | from repository.reservations import BookRequestRepository 3 | 4 | 5 | class BookRequestService: 6 | 7 | def __init__(self): 8 | self.repo: BookRequestRepository = BookRequestRepository() 9 | 10 | def add_book_request(self, book_request: BookRequest): 11 | result = self.repo.insert_request(book_request) 12 | return result 13 | 14 | def update_book_request(self, req_id: int, book_id: int): 15 | result = self.repo.update_requested_book(req_id, book_id) 16 | return result 17 | 18 | def remove_book_request(self, req_id: int): 19 | result = self.repo.delete_request(req_id) 20 | return result 21 | 22 | def list_book_request(self): 23 | return self.repo.get_all_requests() 24 | -------------------------------------------------------------------------------- /codes/ch04/student/configuration/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from datetime import date 3 | 4 | from pydantic import BaseSettings 5 | 6 | 7 | class StudentSettings(BaseSettings): 8 | application: str = 'Student Management System' 9 | webmaster: str = 'sjctrags@university.com' 10 | created: date = '2021-11-10' 11 | 12 | 13 | class ServerSettings(BaseSettings): 14 | production_server: str 15 | prod_port: int 16 | development_server: str 17 | dev_port: int 18 | 19 | class Config: 20 | env_file = os.getcwd() + '/configuration/erp_settings.properties' 21 | -------------------------------------------------------------------------------- /codes/ch04/student/configuration/erp_settings.properties: -------------------------------------------------------------------------------- 1 | production_server=prodserver100 2 | prod_port=9000 3 | development_server=devserver200 4 | dev_port=10000 5 | 6 | -------------------------------------------------------------------------------- /codes/ch04/student/controllers/assignments.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import httpx 4 | from fastapi import APIRouter 5 | from fastapi.encoders import jsonable_encoder 6 | from models.request.assignment import AssignmentRequest 7 | 8 | router = APIRouter() 9 | 10 | 11 | @router.get('/assignment/list') 12 | async def list_assignments(): 13 | async with httpx.AsyncClient() as client: 14 | result = await client.get("http://localhost:8002/ch04/faculty/assignments/list") 15 | return result.json() 16 | 17 | 18 | @router.post('/assignment/submit') 19 | def submit_assignment(assignment: AssignmentRequest): 20 | with httpx.Client() as client: 21 | response = client.post("http://localhost:8002/ch04/faculty/assignments/student/submit", 22 | data=json.dumps(jsonable_encoder(assignment))) 23 | return response.content 24 | -------------------------------------------------------------------------------- /codes/ch04/student/controllers/reservations.py: -------------------------------------------------------------------------------- 1 | from json import dumps 2 | 3 | import httpx 4 | from fastapi import APIRouter 5 | from fastapi.encoders import jsonable_encoder 6 | from models.request.library import BookIssuanceReq 7 | 8 | router = APIRouter() 9 | 10 | 11 | @router.get('/access/book') 12 | def access_book(): 13 | with httpx.Client() as client: 14 | response = client.get("http://localhost:8001/ch04/library/book/list") 15 | return response.json() 16 | 17 | 18 | @router.post('/reserve/book') 19 | def reserve_book(book: BookIssuanceReq): 20 | with httpx.Client() as client: 21 | response = client.post("http://localhost:8001/ch04/library/book/issuance", data=dumps(jsonable_encoder(book))) 22 | return response.content 23 | -------------------------------------------------------------------------------- /codes/ch04/student/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI, Depends 2 | 3 | from configuration.config import StudentSettings, ServerSettings 4 | from controllers import reservations, admin, assignments 5 | 6 | app = FastAPI() 7 | app.include_router(reservations.router, prefix="/ch04/student") 8 | app.include_router(admin.router, prefix="/ch04/student") 9 | app.include_router(assignments.router, prefix="/ch04/student") 10 | 11 | 12 | def build_config(): 13 | return StudentSettings() 14 | 15 | 16 | def fetch_config(): 17 | return ServerSettings() 18 | 19 | 20 | @app.get('/index') 21 | def index_student(config: StudentSettings = Depends(build_config), fconfig: ServerSettings = Depends(fetch_config)): 22 | return { 23 | 'project_name': config.application, 24 | 'webmaster': config.webmaster, 25 | 'created': config.created, 26 | 'development_server': fconfig.development_server, 27 | 'dev_port': fconfig.dev_port 28 | } 29 | -------------------------------------------------------------------------------- /codes/ch04/student/models/data/library.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class Classification(str, Enum): 5 | Non_Fiction = 'Non-Fiction' 6 | Fiction = 'Fiction' 7 | Science = 'Science' 8 | Technology = 'Technology' 9 | History = 'History' 10 | Arts = 'Arts' 11 | Music = 'Music' 12 | Travels = 'Travels' 13 | Food = 'Food' 14 | Engineering = 'Engineering' 15 | -------------------------------------------------------------------------------- /codes/ch04/student/models/data/studentsdb.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from models.data.students import Login, Student, Signup 4 | 5 | students_tbl: Dict[int, Student] = dict() 6 | stud_login_tbl: Dict[int, Login] = dict() 7 | stud_signup_tbl: Dict[int, Signup] = dict() 8 | -------------------------------------------------------------------------------- /codes/ch04/student/models/request/assignment.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class AssignmentRequest(BaseModel): 8 | bin_id: int 9 | assgn_id: int 10 | title: str 11 | date_completed: Optional[datetime] = None 12 | date_due: datetime 13 | rating: Optional[float] = None 14 | course: str 15 | -------------------------------------------------------------------------------- /codes/ch04/student/models/request/library.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime 2 | from typing import Optional 3 | 4 | from models.data.library import Classification 5 | from pydantic import BaseModel 6 | 7 | 8 | class BookReq(BaseModel): 9 | book_id: int 10 | title: str 11 | classification: Classification 12 | author: str 13 | year_published: datetime 14 | edition: int 15 | 16 | 17 | class BookDetails(BaseModel): 18 | title: Optional[str] = None 19 | classification: Optional[Classification] = None 20 | author: Optional[str] = None 21 | year_published: Optional[datetime] = None 22 | edition: Optional[int] = None 23 | 24 | 25 | class BookRequestReq(BaseModel): 26 | book_id: int 27 | request_date: datetime 28 | status: bool 29 | 30 | 31 | class BookIssuanceReq(BaseModel): 32 | req_id: int 33 | approved_by: str 34 | approved_date: datetime 35 | 36 | 37 | class BookReturnReq(BaseModel): 38 | issue_id: int 39 | returned_date: datetime 40 | -------------------------------------------------------------------------------- /codes/ch04/student/models/request/students.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from models.data.students import StudentStatus, Major 4 | from pydantic import BaseModel 5 | 6 | 7 | class SignupReq(BaseModel): 8 | stud_id: int 9 | username: str 10 | password: str 11 | 12 | 13 | class StudentReq(BaseModel): 14 | stud_id: int 15 | fname: str 16 | lname: str 17 | mname: str 18 | age: int 19 | major: Major 20 | department: str 21 | status: StudentStatus 22 | 23 | 24 | class StudentDetails(BaseModel): 25 | fname: Optional[str] = None 26 | lname: Optional[str] = None 27 | mname: Optional[str] = None 28 | age: Optional[int] = None 29 | major: Optional[Major] = None 30 | department: Optional[str] = None 31 | status: Optional[StudentStatus] = None 32 | -------------------------------------------------------------------------------- /codes/ch04/student/repository/login.py: -------------------------------------------------------------------------------- 1 | from models.data.students import Login 2 | from models.data.studentsdb import stud_login_tbl 3 | 4 | 5 | class StudentLoginRepository: 6 | 7 | def insert_login(self, login: Login) -> bool: 8 | try: 9 | stud_login_tbl[login.user_id] = login 10 | except: 11 | return False 12 | return True 13 | 14 | def update_password(self, user_id: int, newpass: str) -> bool: 15 | try: 16 | login = stud_login_tbl[user_id] 17 | login.password = newpass 18 | except: 19 | return False 20 | return True 21 | 22 | def delete_login(self, user_id: int) -> bool: 23 | try: 24 | del stud_login_tbl[user_id] 25 | except: 26 | return False 27 | return True 28 | 29 | def get_login(self, username: str): 30 | list_login = [account for account in stud_login_tbl.values() if account.username == username] 31 | if not len(list_login) == 0: 32 | return list_login[0] 33 | else: 34 | return None 35 | 36 | def get_all_login(self): 37 | return stud_login_tbl 38 | -------------------------------------------------------------------------------- /codes/ch04/student/repository/signup.py: -------------------------------------------------------------------------------- 1 | from models.data.students import Signup 2 | from models.data.studentsdb import stud_signup_tbl 3 | 4 | 5 | class StudentSignupRepository: 6 | 7 | def insert_item(self, item: Signup): 8 | try: 9 | stud_signup_tbl[item.sign_id] = item 10 | except: 11 | return False 12 | return True 13 | 14 | def delete_item(self, sign_id: int): 15 | try: 16 | del stud_signup_tbl[sign_id] 17 | except: 18 | return False 19 | return True 20 | 21 | def get_item(self, sign_id: int): 22 | try: 23 | account = stud_signup_tbl[sign_id] 24 | except: 25 | return None 26 | return account 27 | -------------------------------------------------------------------------------- /codes/ch04/student/repository/students.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from fastapi.encoders import jsonable_encoder 4 | from models.data.students import Student 5 | from models.data.studentsdb import students_tbl 6 | 7 | 8 | class StudentRepository: 9 | 10 | def insert_student(self, student: Student) -> bool: 11 | try: 12 | students_tbl[student.stud_id] = student 13 | except: 14 | return False 15 | return True 16 | 17 | def update_student(self, stud_id: int, details: Dict[str, Any]) -> bool: 18 | try: 19 | profile = students_tbl[stud_id] 20 | profile_enc = jsonable_encoder(profile) 21 | profile_dict = dict(profile_enc) 22 | profile_dict.update(details) 23 | students_tbl[stud_id] = Student(**profile_dict) 24 | except: 25 | return False 26 | return True 27 | 28 | def delete_student(self, user_id: int) -> bool: 29 | try: 30 | del students_tbl[user_id] 31 | except: 32 | return False 33 | return True 34 | 35 | def get_all_students(self): 36 | return students_tbl 37 | -------------------------------------------------------------------------------- /codes/ch04/student/services/login.py: -------------------------------------------------------------------------------- 1 | from models.data.students import Login 2 | 3 | from repository.login import StudentLoginRepository 4 | 5 | 6 | class StudentLoginService: 7 | 8 | def __init__(self): 9 | self.repo: StudentLoginRepository = StudentLoginRepository() 10 | 11 | def add_student_login(self, login: Login): 12 | result = self.repo.insert_login(login) 13 | return result 14 | 15 | def update_login_password(self, user_id: int, newpass: str): 16 | result = self.repo.update_password(user_id, newpass) 17 | return result 18 | 19 | def remove_student_login(self, user_id: int): 20 | result = self.repo.delete_login(user_id) 21 | return result 22 | 23 | def get_student_login(self, username): 24 | return self.repo.get_login(username) 25 | 26 | def list_login(self): 27 | return self.repo.get_all_login() 28 | -------------------------------------------------------------------------------- /codes/ch04/student/services/signup.py: -------------------------------------------------------------------------------- 1 | from models.data.students import Signup 2 | from repository.signup import StudentSignupRepository 3 | 4 | 5 | class StudentSignupService: 6 | 7 | def __init__(self): 8 | self.repo: StudentSignupRepository = StudentSignupRepository() 9 | 10 | def add_signup(self, signup: Signup): 11 | result = self.repo.insert_item(signup) 12 | return result 13 | 14 | def get_signup(self, sign_id: int): 15 | result = self.repo.get_item(sign_id) 16 | return result 17 | 18 | def remove_signup(self, sign_id: int): 19 | result = self.repo.delete_item(sign_id) 20 | return result 21 | -------------------------------------------------------------------------------- /codes/ch04/student/services/students.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.students import Student 4 | from repository.students import StudentRepository 5 | 6 | 7 | class StudentService: 8 | 9 | def __init__(self): 10 | self.repo: StudentRepository = StudentRepository() 11 | 12 | def add_student(self, student: Student): 13 | result = self.repo.insert_student(student) 14 | return result 15 | 16 | def update_student(self, stud_id: int, details: Dict[str, Any]): 17 | result = self.repo.update_student(stud_id, details) 18 | return result 19 | 20 | def remove_student(self, stud_id: int): 21 | result = self.repo.delete_student(stud_id) 22 | return result 23 | 24 | def list_students(self): 25 | return self.repo.get_all_students() 26 | -------------------------------------------------------------------------------- /codes/ch05a/cqrs/commands.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | 4 | class ProfileTrainerCommand: 5 | 6 | def __init__(self): 7 | self._details: Dict[str, Any] = dict() 8 | 9 | @property 10 | def details(self): 11 | return self._details 12 | 13 | @details.setter 14 | def details(self, details): 15 | self._details = details 16 | -------------------------------------------------------------------------------- /codes/ch05a/cqrs/handlers.py: -------------------------------------------------------------------------------- 1 | class IQueryHandler: 2 | pass 3 | 4 | 5 | class ICommandHandler: 6 | pass 7 | -------------------------------------------------------------------------------- /codes/ch05a/cqrs/queries.py: -------------------------------------------------------------------------------- 1 | from typing import List 2 | 3 | from models.data.gino_models import Profile_Trainers 4 | 5 | 6 | class ProfileTrainerListQuery: 7 | 8 | def __init__(self): 9 | self._records: List[Profile_Trainers] = list() 10 | 11 | @property 12 | def records(self): 13 | return self._records 14 | 15 | @records.setter 16 | def records(self, records): 17 | self._records = records 18 | 19 | 20 | class ProfileTrainerRecordQuery: 21 | 22 | def __init__(self): 23 | self._record: Profile_Trainers = None 24 | 25 | @property 26 | def record(self): 27 | return self._record 28 | 29 | @record.setter 30 | def record(self, record): 31 | self._record = record 32 | -------------------------------------------------------------------------------- /codes/ch05a/cqrs/trainers/command/create_handlers.py: -------------------------------------------------------------------------------- 1 | from cqrs.commands import ProfileTrainerCommand 2 | from cqrs.handlers import ICommandHandler 3 | from repository.gino.trainers import TrainerRepository 4 | 5 | 6 | class AddTrainerCommandHandler(ICommandHandler): 7 | 8 | def __init__(self): 9 | self.repo: TrainerRepository = TrainerRepository() 10 | 11 | async def handle(self, command: ProfileTrainerCommand) -> bool: 12 | result = await self.repo.insert_trainer(command.details) 13 | return result 14 | -------------------------------------------------------------------------------- /codes/ch05a/cqrs/trainers/command/delete_handlers.py: -------------------------------------------------------------------------------- 1 | from cqrs.commands import ProfileTrainerCommand 2 | from cqrs.handlers import ICommandHandler 3 | from repository.gino.trainers import TrainerRepository 4 | 5 | 6 | class DeleteTrainerCommandHandler(ICommandHandler): 7 | 8 | def __init__(self): 9 | self.repo: TrainerRepository = TrainerRepository() 10 | 11 | async def handle(self, command: ProfileTrainerCommand) -> bool: 12 | result = await self.repo.delete_trainer(command.details.get("id")) 13 | return result 14 | -------------------------------------------------------------------------------- /codes/ch05a/cqrs/trainers/command/update_handlers.py: -------------------------------------------------------------------------------- 1 | from cqrs.commands import ProfileTrainerCommand 2 | from cqrs.handlers import ICommandHandler 3 | from repository.gino.trainers import TrainerRepository 4 | 5 | 6 | class UpdateTrainerCommandHandler(ICommandHandler): 7 | 8 | def __init__(self): 9 | self.repo: TrainerRepository = TrainerRepository() 10 | 11 | async def handle(self, command: ProfileTrainerCommand) -> bool: 12 | result = await self.repo.update_trainer(command.details) 13 | return result 14 | -------------------------------------------------------------------------------- /codes/ch05a/cqrs/trainers/query/query_handlers.py: -------------------------------------------------------------------------------- 1 | from cqrs.handlers import IQueryHandler 2 | from cqrs.queries import ProfileTrainerListQuery, ProfileTrainerRecordQuery 3 | from repository.gino.trainers import TrainerRepository 4 | 5 | 6 | class ListTrainerQueryHandler(IQueryHandler): 7 | def __init__(self): 8 | self.repo: TrainerRepository = TrainerRepository() 9 | self.query: ProfileTrainerListQuery = ProfileTrainerListQuery() 10 | 11 | async def handle(self) -> ProfileTrainerListQuery: 12 | data = await self.repo.get_all_member(); 13 | self.query.records = data 14 | return self.query 15 | 16 | 17 | class RecordTrainerQueryHandler(IQueryHandler): 18 | def __init__(self): 19 | self.repo: TrainerRepository = TrainerRepository() 20 | self.query: ProfileTrainerRecordQuery = ProfileTrainerRecordQuery() 21 | 22 | async def handle(self, id) -> ProfileTrainerListQuery: 23 | data = await self.repo.get_member(id); 24 | self.query.record = data 25 | return self.query 26 | -------------------------------------------------------------------------------- /codes/ch05a/database/fcms-erd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch05a/database/fcms-erd.png -------------------------------------------------------------------------------- /codes/ch05a/db_config/gino_connect.py: -------------------------------------------------------------------------------- 1 | from gino import Gino 2 | 3 | db = Gino() 4 | -------------------------------------------------------------------------------- /codes/ch05a/db_config/pony_connect.py: -------------------------------------------------------------------------------- 1 | from pony.orm import Database 2 | 3 | db = Database("postgres", host="localhost", port="5433", user="postgres", password="admin2255", database="fcms") 4 | -------------------------------------------------------------------------------- /codes/ch05a/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:root@localhost:5432/fcms" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | -------------------------------------------------------------------------------- /codes/ch05a/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from api import admin, members, trainers, login 4 | 5 | app = FastAPI() 6 | app.include_router(admin.router, prefix='/ch05') 7 | app.include_router(members.router, prefix='/ch05') 8 | app.include_router(trainers.router, prefix='/ch05') 9 | app.include_router(login.router, prefix='/ch05') 10 | -------------------------------------------------------------------------------- /codes/ch05a/models/requests/attendance.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class AttendanceMemberReq(BaseModel): 7 | id: int 8 | member_id: int 9 | timeout: int 10 | timein: int 11 | date_log: date 12 | -------------------------------------------------------------------------------- /codes/ch05a/models/requests/login.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class LoginReq(BaseModel): 7 | id: int 8 | username: str 9 | password: str 10 | date_approved: date 11 | user_type: int 12 | 13 | class Config: 14 | orm_mode = True 15 | -------------------------------------------------------------------------------- /codes/ch05a/models/requests/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch05a/models/requests/trainers.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class ProfileTrainersReq(BaseModel): 5 | id: int 6 | firstname: str 7 | lastname: str 8 | age: int 9 | position: str 10 | tenure: float 11 | shift: int 12 | 13 | class Config: 14 | orm_mode = True 15 | -------------------------------------------------------------------------------- /codes/ch05a/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Fitness Club Management System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: December 26, 2021 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an application designed to manage transactions in a gym center. 10 | This system allows scheduling of gym customers to available gym classes like 11 | aerobics, boxing, circuit, pilates, etc. It also maps gym trainers to classes 12 | where registered gym-goers are registered. As part of the control and tracking 13 | mechanism, the prototype manages the attendance of the trainers and gym-goers. 14 | 15 | This application uses the FastAPI framework driven by Python 3.8. 16 | This application now involves data storage, the relational database called 17 | PostgreSQL 13. 18 | 19 | This is PART 1 of the application that focuses on SQLAlchemy, Gino, and Pony ORM. 20 | 21 | The ERD design (.png) and the database schema backup (.sql) 22 | are in the /database folder of this project. 23 | 24 | The requirements.txt will guide you with the dependencies. Just install by running: 25 | pip install -r requirements.txt -------------------------------------------------------------------------------- /codes/ch05a/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | asyncpg==0.26.0 3 | click==8.1.3 4 | colorama==0.4.5 5 | fastapi==0.78.0 6 | gino==1.0.1 7 | greenlet==1.1.2 8 | h11==0.13.0 9 | idna==3.3 10 | pony==0.7.16 11 | psycopg2==2.9.3 12 | pydantic==1.9.1 13 | python-multipart==0.0.5 14 | six==1.16.0 15 | sniffio==1.2.0 16 | SQLAlchemy==1.3.24 17 | starlette==0.19.1 18 | typing_extensions==4.3.0 19 | uvicorn==0.18.2 20 | -------------------------------------------------------------------------------- /codes/ch05b/database/fcms-erd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch05b/database/fcms-erd.png -------------------------------------------------------------------------------- /codes/ch05b/db_config/peewee_connect.py: -------------------------------------------------------------------------------- 1 | from peewee import PostgresqlDatabase, _ConnectionState 2 | from contextvars import ContextVar 3 | 4 | db_state_default = {"closed": None, "conn": None, "ctx": None, "transactions": None} 5 | db_state = ContextVar("db_state", default=db_state_default.copy()) 6 | 7 | 8 | class PeeweeConnectionState(_ConnectionState): 9 | def __init__(self, **kwargs): 10 | super().__setattr__("_state", db_state) 11 | super().__init__(**kwargs) 12 | 13 | def __setattr__(self, name, value): 14 | self._state.get()[name] = value 15 | 16 | def __getattr__(self, name): 17 | return self._state.get()[name] 18 | 19 | db = PostgresqlDatabase( 20 | 'fcms2', 21 | user='postgres', 22 | password='admin2255', 23 | host='localhost', 24 | port=5433, 25 | ) 26 | 27 | db._state = PeeweeConnectionState() -------------------------------------------------------------------------------- /codes/ch05b/db_config/sqlalchemy_async_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession 2 | from sqlalchemy.orm import declarative_base, sessionmaker 3 | 4 | DB_URL = "postgresql+asyncpg://postgres:admin2255@localhost:5433/fcms" 5 | engine = create_async_engine(DB_URL, future=True, echo=True) 6 | AsynSessionFactory = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) 7 | Base = declarative_base() -------------------------------------------------------------------------------- /codes/ch05b/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from api import login, attendance, gym 4 | 5 | app = FastAPI() 6 | app.include_router(login.router, prefix='/ch05') 7 | app.include_router(attendance.router, prefix='/ch05') 8 | app.include_router(gym.router, prefix='/ch05') 9 | 10 | -------------------------------------------------------------------------------- /codes/ch05b/models/requests/attendance.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from datetime import date 3 | 4 | class AttendanceMemberReq(BaseModel): 5 | id: int 6 | member_id: int 7 | timeout:str 8 | timein:str 9 | date_log:date -------------------------------------------------------------------------------- /codes/ch05b/models/requests/gym.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from datetime import date 3 | 4 | class GymClassReq(BaseModel): 5 | 6 | id: int 7 | name: str 8 | member_id: int 9 | trainer_id: int 10 | approved : int 11 | 12 | 13 | -------------------------------------------------------------------------------- /codes/ch05b/models/requests/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | from datetime import date 3 | 4 | class LoginReq(BaseModel): 5 | id : int 6 | username: str 7 | password: str 8 | date_approved:date 9 | user_type:int 10 | 11 | class Config: 12 | orm_mode = True 13 | 14 | -------------------------------------------------------------------------------- /codes/ch05b/requirements.txt: -------------------------------------------------------------------------------- 1 | aiopg==1.3.4 2 | anyio==3.6.1 3 | async-timeout==4.0.2 4 | asyncpg==0.26.0 5 | click==8.1.3 6 | colorama==0.4.5 7 | fastapi==0.78.0 8 | greenlet==1.1.2 9 | h11==0.13.0 10 | idna==3.3 11 | peewee==3.15.1 12 | psycopg2-binary==2.9.3 13 | pydantic==1.9.1 14 | python-multipart==0.0.5 15 | six==1.16.0 16 | sniffio==1.2.0 17 | SQLAlchemy==1.4.39 18 | starlette==0.19.1 19 | typing_extensions==4.3.0 20 | uvicorn==0.18.2 21 | -------------------------------------------------------------------------------- /codes/ch06/database/UML design.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch06/database/UML design.png -------------------------------------------------------------------------------- /codes/ch06/database/obrs_db.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch06/database/obrs_db.zip -------------------------------------------------------------------------------- /codes/ch06/db_config/beanie_config.py: -------------------------------------------------------------------------------- 1 | from beanie import init_beanie 2 | from motor.motor_asyncio import AsyncIOMotorClient 3 | 4 | from models.data.beanie import Cart, Order, Receipt 5 | 6 | 7 | async def db_connect(): 8 | global client 9 | client = AsyncIOMotorClient(f"mongodb://localhost:27017/obrs") 10 | await init_beanie(client.obrs, document_models=[Cart, Order, Receipt]) 11 | 12 | 13 | async def db_disconnect(): 14 | client.close() 15 | -------------------------------------------------------------------------------- /codes/ch06/db_config/mongoengine_config.py: -------------------------------------------------------------------------------- 1 | from mongoengine import connect 2 | 3 | 4 | def create_db(): 5 | global db 6 | db = connect(db="obrs", host="localhost", port=27017) 7 | 8 | 9 | def disconnect_db(): 10 | db.close() 11 | -------------------------------------------------------------------------------- /codes/ch06/db_config/mongoframe_config.py: -------------------------------------------------------------------------------- 1 | from mongoframes import Frame 2 | from pymongo import MongoClient 3 | 4 | 5 | def create_db_client(): 6 | Frame._client = MongoClient('mongodb://localhost:27017/obrs') 7 | 8 | 9 | def disconnect_db_client(): 10 | Frame._client.close() 11 | -------------------------------------------------------------------------------- /codes/ch06/db_config/motor_config.py: -------------------------------------------------------------------------------- 1 | from motor.motor_asyncio import AsyncIOMotorClient 2 | 3 | 4 | def create_async_db(): 5 | global client 6 | client = AsyncIOMotorClient(str("localhost:27017")) 7 | 8 | 9 | def create_db_collections(): 10 | db = client.obrs 11 | buyers = db["buyer"] 12 | users = db["login"] 13 | return {"users": users, "buyers": buyers} 14 | 15 | 16 | def close_async_db(): 17 | client.close() 18 | -------------------------------------------------------------------------------- /codes/ch06/db_config/odmantic_config.py: -------------------------------------------------------------------------------- 1 | from motor.motor_asyncio import AsyncIOMotorClient 2 | from odmantic import AIOEngine 3 | 4 | 5 | def create_db_connection(): 6 | global client_od 7 | client_od = AsyncIOMotorClient(f"mongodb://localhost:27017/") 8 | 9 | 10 | def create_db_engine(): 11 | engine = AIOEngine(motor_client=client_od, database="obrs") 12 | return engine 13 | 14 | 15 | def close_db_connection(): 16 | client_od.close() 17 | -------------------------------------------------------------------------------- /codes/ch06/db_config/pymongo_config.py: -------------------------------------------------------------------------------- 1 | from pymongo import MongoClient 2 | 3 | 4 | def create_db_collections(): 5 | client = MongoClient('mongodb://localhost:27017/') 6 | try: 7 | db = client.obrs 8 | buyers = db.buyer 9 | users = db.login 10 | yield {"users": users, "buyers": buyers} 11 | finally: 12 | client.close() 13 | -------------------------------------------------------------------------------- /codes/ch06/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from api import book, buyer, buyer_async, cart, receipt, order, login, profile, purchase, reference 4 | 5 | app = FastAPI() 6 | app.include_router(purchase.router, prefix="/ch06") 7 | app.include_router(buyer.router, prefix="/ch06") 8 | app.include_router(buyer_async.router, prefix="/ch06") 9 | app.include_router(receipt.router, prefix="/ch06") 10 | app.include_router(order.router, prefix="/ch06") 11 | app.include_router(cart.router, prefix="/ch06") 12 | app.include_router(login.router, prefix="/ch06") 13 | app.include_router(profile.router, prefix="/ch06") 14 | app.include_router(book.router, prefix="/ch06") 15 | app.include_router(reference.router, prefix="/ch06") 16 | -------------------------------------------------------------------------------- /codes/ch06/models/data/mongoframe.py: -------------------------------------------------------------------------------- 1 | from mongoframes import Frame, SubFrame 2 | 3 | 4 | class Book(Frame): 5 | _fields = { 6 | 'id ', 7 | 'isbn', 8 | 'author', 9 | 'date_published', 10 | 'title', 11 | 'edition', 12 | 'price', 13 | 'category' 14 | } 15 | _collection = "book" 16 | 17 | 18 | class Category(SubFrame): 19 | _fields = { 20 | 'id', 21 | 'name', 22 | 'description', 23 | 'date_added' 24 | } 25 | 26 | _collection = "category" 27 | 28 | 29 | class Reference(Frame): 30 | _fields = { 31 | 'id', 32 | 'name', 33 | 'description', 34 | 'categories' 35 | } 36 | 37 | _collection = "reference" 38 | -------------------------------------------------------------------------------- /codes/ch06/models/data/odmantic.py: -------------------------------------------------------------------------------- 1 | from bson import datetime 2 | 3 | from odmantic import Model 4 | 5 | 6 | class Purchase(Model): 7 | purchase_id: int 8 | buyer_id: int 9 | book_id: int 10 | items: int 11 | price: float 12 | date_purchased: datetime.datetime 13 | 14 | class Config: 15 | collection = "purchase" 16 | -------------------------------------------------------------------------------- /codes/ch06/models/request/category.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | from typing import List, Any, Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class CategoryReq(BaseModel): 8 | id: int 9 | name: str 10 | description: str 11 | date_added: date 12 | 13 | 14 | class ReferenceReq(BaseModel): 15 | id: int 16 | name: str 17 | description: str 18 | date_added: date 19 | categories: List[Any] = list() 20 | 21 | 22 | class BookReq(BaseModel): 23 | id: int 24 | isbn: str 25 | author: str 26 | title: str 27 | edition: int 28 | date_published: date 29 | price: float 30 | category: Optional[CategoryReq] = None 31 | -------------------------------------------------------------------------------- /codes/ch06/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | -------------------------------------------------------------------------------- /codes/ch06/models/request/order.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class OrderReq(BaseModel): 7 | id: int 8 | user_id: int 9 | date_ordered: date 10 | 11 | 12 | class ReceiptReq(BaseModel): 13 | id: int 14 | date_receipt: date 15 | total: float 16 | payment_mode: int 17 | order_id: int 18 | 19 | 20 | class CartReq(BaseModel): 21 | id: int 22 | book_id: int 23 | user_id: int 24 | qty: int 25 | date_carted: date 26 | discount: float 27 | -------------------------------------------------------------------------------- /codes/ch06/models/request/profile.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class UserProfileReq(BaseModel): 7 | firstname: str 8 | lastname: str 9 | middlename: str 10 | position: str 11 | date_approved: date 12 | status: bool 13 | level: int 14 | login_id: int 15 | 16 | 17 | class BookForSaleReq(BaseModel): 18 | id: int 19 | isbn: str 20 | author: str 21 | date_published: date 22 | title: str 23 | edition: int 24 | price: float 25 | -------------------------------------------------------------------------------- /codes/ch06/models/request/purchase.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class PurchaseReq(BaseModel): 7 | purchase_id: int 8 | buyer_id: int 9 | book_id: int 10 | items: int 11 | price: float 12 | date_purchased: date 13 | -------------------------------------------------------------------------------- /codes/ch06/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Online Book Reselling System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: January 10, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an online book repository that accepts used books for 10 | cataloging. The books are classified according to the genre and given details 11 | for profiling. Users can purchase from this book catalogs, and all purchases 12 | have receipts. All order, payment, and purchasing transactions are recorded 13 | for auditing purposes. In totality, this prototype can be a basis for 14 | an e-commerce platform for used book exchange and sale. 15 | 16 | This application uses the FastAPI framework driven by Python 3.8. 17 | This application now involves data storage, the NoSQL database called MongoDB 5x. 18 | The collection structure and design (.png) is in the /database folder of this project. 19 | There is also the backup of the collection used by this project. 20 | 21 | The requirements.txt will guide you with the dependencies. Just install by running: 22 | pip install -r requirements.txt 23 | -------------------------------------------------------------------------------- /codes/ch06/repository/mongoengine/login.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.mongoengine import Login 4 | 5 | 6 | class LoginRepository: 7 | 8 | def insert_login(self, details: Dict[str, Any]) -> bool: 9 | try: 10 | login = Login(**details) 11 | login.save() 12 | except Exception as e: 13 | print(e) 14 | return False 15 | return True 16 | 17 | def update_password(self, id: int, newpass: str) -> bool: 18 | try: 19 | login = Login.objects(id=id).get() 20 | login.update(password=newpass) 21 | except: 22 | return False 23 | return True 24 | 25 | def delete_login(self, id: int) -> bool: 26 | try: 27 | login = Login.objects(id=id).get() 28 | login.delete() 29 | except: 30 | return False 31 | return True 32 | 33 | def get_all_login(self): 34 | login = Login.objects() 35 | login_list = [l.to_json() for l in login] 36 | return login_list 37 | 38 | def get_login(self, id: int): 39 | login = Login.objects(id=id).get() 40 | return login.to_json() 41 | -------------------------------------------------------------------------------- /codes/ch06/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | beanie==1.11.6 3 | blinker==1.4 4 | click==8.1.3 5 | colorama==0.4.5 6 | Faker==13.15.0 7 | fastapi==0.78.0 8 | h11==0.13.0 9 | idna==3.3 10 | mongoengine==0.24.1 11 | MongoFrames==1.3.6 12 | motor==3.0.0 13 | multidict==6.0.2 14 | odmantic==0.5.0 15 | pydantic==1.9.1 16 | pymongo==4.1.1 17 | python-dateutil==2.8.2 18 | python-multipart==0.0.5 19 | six==1.16.0 20 | sniffio==1.2.0 21 | starlette==0.19.1 22 | toml==0.10.2 23 | typing_extensions==4.3.0 24 | uvicorn==0.18.2 25 | yarl==1.7.2 26 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/main.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | from fastapi import FastAPI 3 | 4 | from api import admin, login, profile, auction, bid 5 | 6 | app = FastAPI() 7 | 8 | app.include_router(admin.router, prefix="/ch07") 9 | app.include_router(login.router, prefix="/ch07") 10 | app.include_router(profile.router, prefix="/ch07") 11 | app.include_router(auction.router, prefix="/ch07") 12 | app.include_router(bid.router, prefix="/ch07") 13 | 14 | 15 | @app.get("/index") 16 | def index(): 17 | return {"content": "welcome"} 18 | 19 | 20 | if __name__ == '__main__': 21 | uvicorn.run(app='main:app', reload=True) 22 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/models/request/auctions.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class AuctionsReq(BaseModel): 7 | id: int 8 | name: str 9 | details: str 10 | type_id: int 11 | max_price: float 12 | min_price: float 13 | buyout_price: float 14 | created_date: date 15 | updated_date: date 16 | condition: str 17 | profile_id: int 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/models/request/bids.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class BidsReq(BaseModel): 7 | id: int 8 | auction_id: int 9 | profile_id: int 10 | created_date: date 11 | updated_date: date 12 | price: float 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/models/request/profile.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class ProfileReq(BaseModel): 7 | id: int 8 | firstname: str 9 | lastname: str 10 | age: int 11 | membership_date: date 12 | member_type: str 13 | login_id: int 14 | status: int 15 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Token(BaseModel): 7 | access_token: str 8 | token_type: str 9 | 10 | 11 | class TokenData(BaseModel): 12 | username: Optional[str] = None 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: February 15, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | click==8.1.3 3 | colorama==0.4.5 4 | fastapi==0.78.0 5 | greenlet==1.1.2 6 | h11==0.13.0 7 | idna==3.3 8 | passlib==1.7.4 9 | psycopg2==2.9.3 10 | pydantic==1.9.1 11 | python-multipart==0.0.5 12 | six==1.16.0 13 | sniffio==1.2.0 14 | SQLAlchemy==1.4.39 15 | starlette==0.19.1 16 | typing_extensions==4.3.0 17 | uvicorn==0.18.2 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07a/security/secure.py: -------------------------------------------------------------------------------- 1 | from secrets import compare_digest 2 | 3 | from fastapi.security import HTTPBasic 4 | from fastapi.security import HTTPBasicCredentials 5 | from models.data.sqlalchemy_models import Login 6 | from passlib.context import CryptContext 7 | 8 | # 设置加密编码 9 | crypt_context = CryptContext(schemes=["sha256_crypt", "md5_crypt"]) 10 | 11 | http_basic = HTTPBasic() 12 | 13 | 14 | def get_password_hash(password): 15 | return crypt_context.hash(password) 16 | 17 | 18 | def verify_password(plain_password, hashed_password): 19 | return crypt_context.verify(plain_password, hashed_password) 20 | 21 | 22 | def authenticate(credentials: HTTPBasicCredentials, account: Login): 23 | try: 24 | # 比较凭证 25 | is_username = compare_digest(credentials.username, account.username) 26 | is_password = compare_digest(credentials.password, account.username) 27 | verified_password = verify_password(credentials.password, account.passphrase) 28 | return verified_password and is_username and is_password 29 | except Exception as e: 30 | print(e) 31 | return False 32 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/generate_hash.py: -------------------------------------------------------------------------------- 1 | from base64 import urlsafe_b64encode 2 | 3 | h = urlsafe_b64encode(b"sjctrags:sjctrags") 4 | print(h) 5 | # c2pjdHJhZ3M6c2pjdHJhZ3M= 6 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from api import admin, login, profile, auction, bid 4 | 5 | app = FastAPI() 6 | 7 | app.include_router(admin.router, prefix="/ch07") 8 | app.include_router(login.router, prefix="/ch07") 9 | app.include_router(profile.router, prefix="/ch07") 10 | app.include_router(auction.router, prefix="/ch07") 11 | app.include_router(bid.router, prefix="/ch07") 12 | 13 | 14 | @app.get("/index") 15 | def index(): 16 | return {"content": "welcome"} 17 | 18 | # ch07b 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/models/request/auctions.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class AuctionsReq(BaseModel): 7 | id: int 8 | name: str 9 | details: str 10 | type_id: int 11 | max_price: float 12 | min_price: float 13 | buyout_price: float 14 | created_date: date 15 | updated_date: date 16 | condition: str 17 | profile_id: int 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/models/request/bids.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class BidsReq(BaseModel): 7 | id: int 8 | auction_id: int 9 | profile_id: int 10 | created_date: date 11 | updated_date: date 12 | price: float 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/models/request/profile.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class ProfileReq(BaseModel): 7 | id: int 8 | firstname: str 9 | lastname: str 10 | age: int 11 | membership_date: date 12 | member_type: str 13 | login_id: int 14 | status: int 15 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Token(BaseModel): 7 | access_token: str 8 | token_type: str 9 | 10 | 11 | class TokenData(BaseModel): 12 | username: Optional[str] = None 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: February 15, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07b/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | click==8.1.3 3 | colorama==0.4.5 4 | fastapi==0.78.0 5 | greenlet==1.1.2 6 | h11==0.13.0 7 | idna==3.3 8 | passlib==1.7.4 9 | psycopg2==2.9.3 10 | pydantic==1.9.1 11 | python-multipart==0.0.5 12 | six==1.16.0 13 | sniffio==1.2.0 14 | SQLAlchemy==1.4.39 15 | starlette==0.19.1 16 | typing_extensions==4.3.0 17 | uvicorn==0.18.2 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/main.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | from fastapi import FastAPI 3 | 4 | from api import admin, login, profile, auction, bid 5 | 6 | app = FastAPI() 7 | 8 | app.include_router(admin.router, prefix="/ch07") 9 | app.include_router(login.router, prefix="/ch07") 10 | app.include_router(profile.router, prefix="/ch07") 11 | app.include_router(auction.router, prefix="/ch07") 12 | app.include_router(bid.router, prefix="/ch07") 13 | 14 | 15 | @app.get("/index") 16 | def index(): 17 | return {"content": "welcome"} 18 | 19 | 20 | # ch07c 21 | if __name__ == '__main__': 22 | uvicorn.run(app='main:app', reload=True) 23 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/models/request/auctions.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class AuctionsReq(BaseModel): 7 | id: int 8 | name: str 9 | details: str 10 | type_id: int 11 | max_price: float 12 | min_price: float 13 | buyout_price: float 14 | created_date: date 15 | updated_date: date 16 | condition: str 17 | profile_id: int 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/models/request/bids.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class BidsReq(BaseModel): 7 | id: int 8 | auction_id: int 9 | profile_id: int 10 | created_date: date 11 | updated_date: date 12 | price: float 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/models/request/profile.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class ProfileReq(BaseModel): 7 | id: int 8 | firstname: str 9 | lastname: str 10 | age: int 11 | membership_date: date 12 | member_type: str 13 | login_id: int 14 | status: int 15 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Token(BaseModel): 7 | access_token: str 8 | token_type: str 9 | 10 | 11 | class TokenData(BaseModel): 12 | username: Optional[str] = None 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: February 15, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07c/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | click==8.1.3 3 | colorama==0.4.5 4 | fastapi==0.78.0 5 | greenlet==1.1.2 6 | h11==0.13.0 7 | idna==3.3 8 | passlib==1.7.4 9 | psycopg2==2.9.3 10 | pydantic==1.9.1 11 | python-multipart==0.0.5 12 | six==1.16.0 13 | sniffio==1.2.0 14 | SQLAlchemy==1.4.39 15 | starlette==0.19.1 16 | typing_extensions==4.3.0 17 | uvicorn==0.18.2 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from api import admin, login, profile, auction, bid 4 | 5 | app = FastAPI() 6 | 7 | app.include_router(admin.router, prefix="/ch07") 8 | app.include_router(login.router, prefix="/ch07") 9 | app.include_router(profile.router, prefix="/ch07") 10 | app.include_router(auction.router, prefix="/ch07") 11 | app.include_router(bid.router, prefix="/ch07") 12 | 13 | 14 | @app.get("/index") 15 | def index(): 16 | return {"content": "welcome"} 17 | 18 | # ch07c 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/models/request/auctions.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class AuctionsReq(BaseModel): 7 | id: int 8 | name: str 9 | details: str 10 | type_id: int 11 | max_price: float 12 | min_price: float 13 | buyout_price: float 14 | created_date: date 15 | updated_date: date 16 | condition: str 17 | profile_id: int 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/models/request/bids.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class BidsReq(BaseModel): 7 | id: int 8 | auction_id: int 9 | profile_id: int 10 | created_date: date 11 | updated_date: date 12 | price: float 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/models/request/profile.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class ProfileReq(BaseModel): 7 | id: int 8 | firstname: str 9 | lastname: str 10 | age: int 11 | membership_date: date 12 | member_type: str 13 | login_id: int 14 | status: int 15 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic.dataclasses import dataclass 4 | 5 | 6 | @dataclass 7 | class Token: 8 | access_token: str 9 | token_type: str 10 | 11 | 12 | @dataclass 13 | class TokenData: 14 | username: Optional[str] = None 15 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: February 15, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07d/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | click==8.1.3 3 | colorama==0.4.5 4 | ecdsa==0.18.0 5 | fastapi==0.78.0 6 | greenlet==1.1.2 7 | h11==0.13.0 8 | idna==3.3 9 | passlib==1.7.4 10 | psycopg2==2.9.3 11 | pyasn1==0.4.8 12 | pydantic==1.9.1 13 | python-jose==3.3.0 14 | python-multipart==0.0.5 15 | rsa==4.8 16 | six==1.16.0 17 | sniffio==1.2.0 18 | SQLAlchemy==1.4.39 19 | starlette==0.19.1 20 | typing_extensions==4.3.0 21 | uvicorn==0.18.2 22 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from api import admin, login, profile, auction, bid 4 | 5 | app = FastAPI() 6 | 7 | app.include_router(admin.router, prefix="/ch07") 8 | app.include_router(login.router, prefix="/ch07") 9 | app.include_router(profile.router, prefix="/ch07") 10 | app.include_router(auction.router, prefix="/ch07") 11 | app.include_router(bid.router, prefix="/ch07") 12 | 13 | 14 | @app.get("/index") 15 | def index(): 16 | return {"content": "welcome"} 17 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/models/request/auctions.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class AuctionsReq(BaseModel): 7 | id: int 8 | name: str 9 | details: str 10 | type_id: int 11 | max_price: float 12 | min_price: float 13 | buyout_price: float 14 | created_date: date 15 | updated_date: date 16 | condition: str 17 | profile_id: int 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/models/request/bids.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class BidsReq(BaseModel): 7 | id: int 8 | auction_id: int 9 | profile_id: int 10 | created_date: date 11 | updated_date: date 12 | price: float 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/models/request/profile.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class ProfileReq(BaseModel): 7 | id: int 8 | firstname: str 9 | lastname: str 10 | age: int 11 | membership_date: date 12 | member_type: str 13 | login_id: int 14 | status: int 15 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from dataclasses import field 2 | from typing import List, Optional 3 | 4 | from pydantic.dataclasses import dataclass 5 | 6 | 7 | @dataclass 8 | class Token(): 9 | access_token: str 10 | token_type: str 11 | 12 | 13 | @dataclass 14 | class TokenData(): 15 | username: Optional[str] = None 16 | scopes: List[str] = field(default_factory=lambda: []) 17 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: February 15, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07e/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | click==8.1.3 3 | colorama==0.4.5 4 | ecdsa==0.18.0 5 | fastapi==0.78.0 6 | greenlet==1.1.2 7 | h11==0.13.0 8 | idna==3.3 9 | passlib==1.7.4 10 | psycopg2==2.9.3 11 | pyasn1==0.4.8 12 | pydantic==1.9.1 13 | python-jose==3.3.0 14 | python-multipart==0.0.5 15 | rsa==4.8 16 | six==1.16.0 17 | sniffio==1.2.0 18 | SQLAlchemy==1.4.39 19 | starlette==0.19.1 20 | typing_extensions==4.3.0 21 | uvicorn==0.18.2 22 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from api import admin, login, profile, auction, bid 4 | 5 | app = FastAPI() 6 | 7 | app.include_router(admin.router, prefix="/ch07") 8 | app.include_router(login.router, prefix="/ch07") 9 | app.include_router(profile.router, prefix="/ch07") 10 | app.include_router(auction.router, prefix="/ch07") 11 | app.include_router(bid.router, prefix="/ch07") 12 | 13 | 14 | @app.get("/index") 15 | def index(): 16 | return {"content": "welcome"} 17 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/models/request/auctions.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class AuctionsReq(BaseModel): 7 | id: int 8 | name: str 9 | details: str 10 | type_id: int 11 | max_price: float 12 | min_price: float 13 | buyout_price: float 14 | created_date: date 15 | updated_date: date 16 | condition: str 17 | profile_id: int 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/models/request/bids.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class BidsReq(BaseModel): 7 | id: int 8 | auction_id: int 9 | profile_id: int 10 | created_date: date 11 | updated_date: date 12 | price: float 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/models/request/profile.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class ProfileReq(BaseModel): 7 | id: int 8 | firstname: str 9 | lastname: str 10 | age: int 11 | membership_date: date 12 | member_type: str 13 | login_id: int 14 | status: int 15 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Token(BaseModel): 7 | access_token: str 8 | token_type: str 9 | 10 | 11 | class TokenData(BaseModel): 12 | username: Optional[str] = None 13 | scopes: List[str] = [] 14 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: March 10, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07f/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | click==8.1.3 3 | colorama==0.4.5 4 | ecdsa==0.18.0 5 | fastapi==0.78.0 6 | greenlet==1.1.2 7 | h11==0.13.0 8 | idna==3.3 9 | passlib==1.7.4 10 | psycopg2==2.9.3 11 | pyasn1==0.4.8 12 | pydantic==1.9.1 13 | python-jose==3.3.0 14 | python-multipart==0.0.5 15 | rsa==4.8 16 | six==1.16.0 17 | sniffio==1.2.0 18 | SQLAlchemy==1.4.39 19 | starlette==0.19.1 20 | typing_extensions==4.3.0 21 | uvicorn==0.18.2 22 | -------------------------------------------------------------------------------- /codes/ch07/ch07g/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07g/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.requests import Request 3 | from fastapi.responses import JSONResponse 4 | 5 | from api import admin, login 6 | from security.secure import AuthError 7 | 8 | app = FastAPI() 9 | 10 | app.include_router(admin.router, prefix="/ch07") 11 | app.include_router(login.router, prefix="/ch07") 12 | 13 | 14 | @app.get("/index") 15 | def index(): 16 | return {"content": "welcome"} 17 | 18 | 19 | @app.exception_handler(AuthError) 20 | def handle_auth_error(request: Request, ex: AuthError): 21 | return JSONResponse(status_code=ex.status_code, content=ex.error) 22 | -------------------------------------------------------------------------------- /codes/ch07/ch07g/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07g/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07g/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Token(BaseModel): 7 | access_token: str 8 | token_type: str 9 | 10 | 11 | class TokenData(BaseModel): 12 | username: Optional[str] = None 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07g/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: March 15, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07g/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | certifi==2022.6.15 3 | charset-normalizer==2.1.0 4 | click==8.1.3 5 | colorama==0.4.5 6 | ecdsa==0.18.0 7 | fastapi==0.78.0 8 | greenlet==1.1.2 9 | h11==0.13.0 10 | idna==3.3 11 | passlib==1.7.4 12 | psycopg2==2.9.3 13 | pyasn1==0.4.8 14 | pydantic==1.9.1 15 | PyJWT==2.4.0 16 | python-jose==3.3.0 17 | python-multipart==0.0.5 18 | requests==2.28.1 19 | rsa==4.8 20 | six==1.16.0 21 | sniffio==1.2.0 22 | SQLAlchemy==1.4.39 23 | starlette==0.19.1 24 | typing_extensions==4.3.0 25 | urllib3==1.26.10 26 | uvicorn==0.18.2 27 | -------------------------------------------------------------------------------- /codes/ch07/ch07h/app.env: -------------------------------------------------------------------------------- 1 | [Okta] 2 | OKTA_CLIENT_ID=0oa3tvejee5UPt7QZ5d7 3 | OKTA_CLIENT_SECRET=LA4WP8lACWKu4Ke9fReol0fNSUvxsxTvGLZdDS5- 4 | OKTA_ISSUER=https://dev-5180227.okta.com/oauth2/default 5 | OKTA_AUDIENCE=api://default 6 | ALGORITHMS = RS256 -------------------------------------------------------------------------------- /codes/ch07/ch07h/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07h/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from api import admin, login 4 | 5 | app = FastAPI() 6 | 7 | app.include_router(admin.router, prefix="/ch07") 8 | app.include_router(login.router, prefix="/ch07") 9 | 10 | 11 | @app.get("/index") 12 | def index(): 13 | return {"content": "welcome"} 14 | 15 | # ch07h 16 | -------------------------------------------------------------------------------- /codes/ch07/ch07h/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07h/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07h/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Token(BaseModel): 7 | access_token: str 8 | token_type: str 9 | 10 | 11 | class TokenData(BaseModel): 12 | username: Optional[str] = None 13 | 14 | 15 | class Message(BaseModel): 16 | sent_from: str 17 | sent_to: str 18 | msg: str 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07h/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: April 3, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07h/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | certifi==2022.6.15 3 | charset-normalizer==2.1.0 4 | click==8.1.3 5 | colorama==0.4.5 6 | ecdsa==0.18.0 7 | fastapi==0.78.0 8 | greenlet==1.1.2 9 | h11==0.12.0 10 | httpcore==0.15.0 11 | httpx==0.23.0 12 | idna==3.3 13 | okta-jwt==1.3.5 14 | passlib==1.7.4 15 | psycopg2==2.9.3 16 | pyasn1==0.4.8 17 | pydantic==1.9.1 18 | PyJWT==2.4.0 19 | python-jose==3.3.0 20 | python-multipart==0.0.5 21 | requests==2.28.1 22 | rfc3986==1.5.0 23 | six==1.16.0 24 | sniffio==1.2.0 25 | SQLAlchemy==1.4.39 26 | starlette==0.19.1 27 | typing_extensions==4.3.0 28 | urllib3==1.26.10 29 | uvicorn==0.18.2 30 | -------------------------------------------------------------------------------- /codes/ch07/ch07i/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07i/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from fastapi.middleware.cors import CORSMiddleware 3 | from fastapi.middleware.trustedhost import TrustedHostMiddleware 4 | from fastapi.requests import Request 5 | from fastapi.responses import JSONResponse 6 | 7 | from api import admin, login 8 | from security.secure import AuthError 9 | 10 | app = FastAPI() 11 | 12 | origins = [ 13 | "https://gzky.live", 14 | 15 | "https://google.com", 16 | 17 | "http://localhost:8080", 18 | "http://localhost:8000", 19 | ] 20 | 21 | app.add_middleware( 22 | CORSMiddleware, 23 | allow_origins=origins, 24 | allow_credentials=True, 25 | allow_methods=["*"], 26 | allow_headers=["*"], 27 | ) 28 | 29 | app.add_middleware( 30 | TrustedHostMiddleware, allowed_hosts=["example.com", "*.example.com", "localhost"] 31 | ) 32 | 33 | app.include_router(admin.router, prefix="/ch07") 34 | app.include_router(login.router, prefix="/ch07") 35 | 36 | 37 | @app.get("/index") 38 | def index(): 39 | return {"content": "welcome"} 40 | 41 | 42 | @app.exception_handler(AuthError) 43 | def handle_auth_error(request: Request, ex: AuthError): 44 | return JSONResponse(status_code=ex.status_code, content=ex.error) 45 | 46 | # ch07i 47 | -------------------------------------------------------------------------------- /codes/ch07/ch07i/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07i/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07i/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Token(BaseModel): 7 | access_token: str 8 | token_type: str 9 | 10 | 11 | class TokenData(BaseModel): 12 | username: Optional[str] = None 13 | -------------------------------------------------------------------------------- /codes/ch07/ch07i/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: April 3, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07i/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | certifi==2022.6.15 3 | cffi==1.15.1 4 | charset-normalizer==2.1.0 5 | click==8.1.3 6 | colorama==0.4.5 7 | cryptography==37.0.4 8 | fastapi==0.78.0 9 | greenlet==1.1.2 10 | h11==0.13.0 11 | idna==3.3 12 | passlib==1.7.4 13 | psycopg2==2.9.3 14 | pyasn1==0.4.8 15 | pycparser==2.21 16 | pydantic==1.9.1 17 | PyJWT==2.4.0 18 | python-multipart==0.0.5 19 | requests==2.28.1 20 | rsa==4.8 21 | six==1.16.0 22 | sniffio==1.2.0 23 | SQLAlchemy==1.4.39 24 | starlette==0.19.1 25 | typing_extensions==4.3.0 26 | urllib3==1.26.10 27 | uvicorn==0.18.2 28 | -------------------------------------------------------------------------------- /codes/ch07/ch07j/db_config/sqlalchemy_connect.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import sessionmaker 4 | 5 | DB_URL = "postgresql://postgres:admin2255@localhost:5433/soas" 6 | 7 | engine = create_engine(DB_URL) 8 | SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) 9 | 10 | Base = declarative_base() 11 | 12 | 13 | def sess_db(): 14 | db = SessionFactory() 15 | try: 16 | yield db 17 | finally: 18 | db.close() 19 | -------------------------------------------------------------------------------- /codes/ch07/ch07j/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from starlette.middleware import Middleware 3 | from starlette.middleware.authentication import AuthenticationMiddleware 4 | 5 | from api import admin, login 6 | from security.secure import UsernameAuthBackend 7 | 8 | middleware = [Middleware(AuthenticationMiddleware, backend=UsernameAuthBackend("sjctrags"))] 9 | app = FastAPI(middleware=middleware) 10 | 11 | app.include_router(admin.router, prefix="/ch07") 12 | app.include_router(login.router, prefix="/ch07") 13 | 14 | 15 | @app.get("/index") 16 | def index(): 17 | return {"content": "welcome"} 18 | -------------------------------------------------------------------------------- /codes/ch07/ch07j/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | username: str 6 | password: str 7 | -------------------------------------------------------------------------------- /codes/ch07/ch07j/models/request/signup.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class SignupReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | 9 | class Config: 10 | orm_mode = True 11 | -------------------------------------------------------------------------------- /codes/ch07/ch07j/models/request/tokens.py: -------------------------------------------------------------------------------- 1 | from typing import List, Optional 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class Token(BaseModel): 7 | access_token: str 8 | token_type: str 9 | 10 | 11 | class TokenData(BaseModel): 12 | username: Optional[str] = None 13 | scopes: List[str] = [] 14 | -------------------------------------------------------------------------------- /codes/ch07/ch07j/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Secured Online Auction System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: April 3, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is an auction system that accepts any products from auctioneers 10 | for bidding. The application should determine the highest price bid to sell a 11 | product. The prototype is secured using various approaches to securing 12 | FastAPI microservice applications. 13 | 14 | This application uses the FastAPI framework driven by Python 3.8. 15 | This application now involves data storage using PostgreSQL 13. 16 | The backup database schema is in the /database folder of the project. 17 | 18 | The requirements.txt will guide you with the dependencies. Just install by running: 19 | pip install -r requirements.txt 20 | -------------------------------------------------------------------------------- /codes/ch07/ch07j/requirements.txt: -------------------------------------------------------------------------------- 1 | anyio==3.6.1 2 | cffi==1.15.1 3 | click==8.1.3 4 | colorama==0.4.5 5 | cryptography==37.0.4 6 | ecdsa==0.18.0 7 | fastapi==0.78.0 8 | greenlet==1.1.2 9 | h11==0.13.0 10 | idna==3.3 11 | passlib==1.7.4 12 | psycopg2==2.9.3 13 | pyasn1==0.4.8 14 | pycparser==2.21 15 | pydantic==1.9.1 16 | PyJWT==2.4.0 17 | python-jose==3.3.0 18 | python-multipart==0.0.5 19 | rsa==4.8 20 | six==1.16.0 21 | sniffio==1.2.0 22 | SQLAlchemy==1.4.39 23 | starlette==0.19.1 24 | typing_extensions==4.3.0 25 | uvicorn==0.18.2 26 | -------------------------------------------------------------------------------- /codes/ch08/api/content.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | from fastapi.responses import JSONResponse 3 | 4 | from models.request.content import ContentReq 5 | from repository.content import ContentRepository 6 | 7 | router = APIRouter() 8 | 9 | 10 | @router.post("/content/add") 11 | async def add_content(req: ContentReq): 12 | content_dict = req.dict(exclude_unset=True) 13 | repo = ContentRepository() 14 | result = await repo.insert_content(content_dict) 15 | if result == True: 16 | return req 17 | else: 18 | return JSONResponse(content={'message': 'update trainer profile problem encountered'}, status_code=500) 19 | 20 | 21 | @router.get("/content/list") 22 | async def list_content(): 23 | repo = ContentRepository() 24 | result = await repo.get_all_content() 25 | return result 26 | -------------------------------------------------------------------------------- /codes/ch08/api/publication.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | from fastapi.responses import JSONResponse 3 | 4 | from models.request.publication import PublicationReq 5 | from repository.publication import PublicationRepository 6 | 7 | router = APIRouter() 8 | 9 | 10 | @router.post("/publication/add") 11 | async def add_publication(req: PublicationReq): 12 | publication_dict = req.dict(exclude_unset=True) 13 | repo = PublicationRepository() 14 | result = await repo.insert_publication(publication_dict) 15 | if result == True: 16 | return req 17 | else: 18 | return JSONResponse(content={'message': 'update trainer profile problem encountered'}, status_code=500) 19 | 20 | 21 | @router.get("/publication/list") 22 | async def list_publication(): 23 | repo = PublicationRepository() 24 | result = await repo.get_all_publication() 25 | return result 26 | -------------------------------------------------------------------------------- /codes/ch08/api/vendor.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | from fastapi.responses import JSONResponse 3 | 4 | from models.request.vendor import VendorReq 5 | from repository.vendor import VendorRepository 6 | 7 | router = APIRouter() 8 | 9 | 10 | @router.post("/vendor/add") 11 | async def add_vendor(req: VendorReq): 12 | vendor_dict = req.dict(exclude_unset=True) 13 | repo = VendorRepository() 14 | result = await repo.insert_vendor(vendor_dict) 15 | if result == True: 16 | return req 17 | else: 18 | return JSONResponse(content={'message': 'update trainer profile problem encountered'}, status_code=500) 19 | 20 | 21 | @router.get("/vendor/list") 22 | async def list_vendor(): 23 | repo = VendorRepository() 24 | result = await repo.get_all_vendor() 25 | return result 26 | -------------------------------------------------------------------------------- /codes/ch08/celery_test.py: -------------------------------------------------------------------------------- 1 | import uvicorn 2 | 3 | original_callback = uvicorn.main.callback 4 | 5 | 6 | def callback(**kwargs): 7 | from celery.contrib.testing.worker import start_worker 8 | import services.billing 9 | 10 | with start_worker(services.billing.celery, perform_ping_check=False, loglevel="info"): 11 | original_callback(**kwargs) 12 | 13 | 14 | uvicorn.main.callback = callback 15 | 16 | if __name__ == "__main__": 17 | uvicorn.main() 18 | -------------------------------------------------------------------------------- /codes/ch08/config/db/gino_db.py: -------------------------------------------------------------------------------- 1 | from gino import Gino 2 | 3 | db = Gino() 4 | -------------------------------------------------------------------------------- /codes/ch08/data/billing-2022-03-16.csv: -------------------------------------------------------------------------------- 1 | 2022-03-16;Manila Bulletin;MB-13456;800000.0;10002022-03-16; 2 | 3 | 2022-03-16;Manila Bulletin;MB-13456;800000.0;1000 4 | -------------------------------------------------------------------------------- /codes/ch08/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | 3 | from api import login, admin, vendor, customer, billing, messenger, publication, content, sales, subscription 4 | from config.db.gino_db import db 5 | 6 | app = FastAPI() 7 | 8 | 9 | @app.on_event("startup") 10 | async def initialize(): 11 | engine = await db.set_bind("postgresql+asyncpg://postgres:admin2255@localhost:5433/nsms") 12 | 13 | 14 | @app.on_event("shutdown") 15 | async def destroy(): 16 | engine, db.bind = db.bind, None 17 | await engine.close() 18 | 19 | 20 | app.include_router(login.router, prefix='/ch08') 21 | app.include_router(admin.router, prefix='/ch08') 22 | app.include_router(vendor.router, prefix='/ch08') 23 | app.include_router(customer.router, prefix='/ch08') 24 | app.include_router(billing.router, prefix='/ch08') 25 | app.include_router(messenger.router, prefix='/ch08') 26 | app.include_router(publication.router, prefix='/ch08') 27 | app.include_router(content.router, prefix='/ch08') 28 | app.include_router(sales.router, prefix='/ch08') 29 | app.include_router(subscription.router, prefix='/ch08') 30 | -------------------------------------------------------------------------------- /codes/ch08/models/request/admin.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class AdminReq(BaseModel): 7 | id: int 8 | firstname: str 9 | lastname: str 10 | age: int 11 | date_started: date 12 | status: int 13 | login_id: int 14 | birthday: date 15 | -------------------------------------------------------------------------------- /codes/ch08/models/request/billing.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class BillingReq(BaseModel): 7 | id: int 8 | payable: float 9 | approved_by: str 10 | date_approved: date 11 | date_billed: date 12 | received_by: str 13 | date_received: date 14 | total_issues: int 15 | vendor_id: int 16 | admin_id: int 17 | -------------------------------------------------------------------------------- /codes/ch08/models/request/content.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class ContentReq(BaseModel): 7 | id: int 8 | publication_id: int 9 | headline: str 10 | content: str 11 | content_type: str 12 | date_published: date 13 | -------------------------------------------------------------------------------- /codes/ch08/models/request/customer.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class CustomerReq(BaseModel): 7 | id: int 8 | firstname: str 9 | lastname: str 10 | age: int 11 | birthday: date 12 | date_subscribed: date 13 | status: int 14 | subscription_type: int 15 | login_id: int 16 | -------------------------------------------------------------------------------- /codes/ch08/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | id: int 6 | username: str 7 | password: str 8 | user_type: int 9 | -------------------------------------------------------------------------------- /codes/ch08/models/request/messenger.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class MessengerReq(BaseModel): 7 | id: int 8 | firstname: str 9 | lastname: str 10 | salary: float 11 | date_employed: date 12 | status: int 13 | vendor_id: int 14 | -------------------------------------------------------------------------------- /codes/ch08/models/request/publication.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class PublicationReq(BaseModel): 5 | id: int 6 | name: str 7 | type: str 8 | vendor_id: int 9 | messenger_id: int 10 | -------------------------------------------------------------------------------- /codes/ch08/models/request/sales.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class SalesReq(BaseModel): 7 | id: int 8 | publication_id: int 9 | copies_issued: int 10 | copies_sold: int 11 | date_issued: date 12 | revenue: float 13 | profit: float 14 | -------------------------------------------------------------------------------- /codes/ch08/models/request/subscription.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class SubscriptionReq(BaseModel): 7 | id: int 8 | customer_id: int 9 | branch: str 10 | price: float 11 | qty: int 12 | date_purchased: date 13 | -------------------------------------------------------------------------------- /codes/ch08/models/request/vendor.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class VendorReq(BaseModel): 7 | id: int 8 | rep_firstname: str 9 | rep_lastname: str 10 | rep_id: str 11 | rep_date_employed: date 12 | account_name: str 13 | account_number: str 14 | date_consigned: date 15 | login_id: int 16 | -------------------------------------------------------------------------------- /codes/ch08/repository/login.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.nsms import Login 4 | 5 | 6 | class LoginRepository: 7 | 8 | async def insert_login(self, details: Dict[str, Any]) -> bool: 9 | try: 10 | await Login.create(**details) 11 | except Exception as e: 12 | print(e) 13 | return False 14 | return True 15 | 16 | async def update_login(self, id: int, details: Dict[str, Any]) -> bool: 17 | try: 18 | login = await Login.get(id) 19 | # await Login.update.values(**details).where(Login.id == id).gino.status() 20 | await login.update(**details).apply() 21 | except: 22 | return False 23 | return True 24 | 25 | async def delete_login(self, id: int) -> bool: 26 | try: 27 | login = await Login.get(id) 28 | await login.delete() 29 | # await Login.delete.where(Login.id == id).gino.status() 30 | except Exception as e: 31 | return False 32 | return True 33 | 34 | async def get_all_login(self): 35 | return await Login.query.gino.all() 36 | 37 | async def get_login(self, id: int): 38 | return await Login.get(id) 39 | -------------------------------------------------------------------------------- /codes/ch08/requirements.txt: -------------------------------------------------------------------------------- 1 | asyncpg==0.26.0 2 | distlib==0.3.6 3 | filelock==3.8.0 4 | gino==1.0.1 5 | greenlet==1.1.3 6 | numpy==1.23.2 7 | platformdirs==2.5.2 8 | SQLAlchemy==1.3.24 9 | virtualenv==20.16.3 10 | -------------------------------------------------------------------------------- /codes/ch08/services/login.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | 4 | @asyncio.coroutine 5 | def build_user_list(query_list): 6 | user_list = [] 7 | for record in query_list: 8 | yield from asyncio.sleep(2) 9 | user_list.append(" ".join([str(record.id), record.username, record.password])) 10 | return user_list 11 | 12 | 13 | async def count_login(query_list): 14 | await asyncio.sleep(2) 15 | return len(query_list) 16 | -------------------------------------------------------------------------------- /codes/ch08/services/sales.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | import rx 4 | from rx.disposable import Disposable 5 | 6 | from repository.sales import SalesRepository 7 | 8 | 9 | async def process_list(observer): 10 | repo = SalesRepository() 11 | result = await repo.get_all_sales() 12 | 13 | for item in result: 14 | record = " ".join([str(item.publication_id), str(item.copies_issued), str(item.date_issued), str(item.revenue), 15 | str(item.profit), str(item.copies_sold)]) 16 | cost = item.copies_issued * 5.0 17 | projected_profit = cost - item.revenue 18 | diff_err = projected_profit - item.profit 19 | if diff_err <= 0: 20 | observer.on_next(record) 21 | else: 22 | observer.on_error(record) 23 | observer.on_completed() 24 | 25 | 26 | def create_observable(loop): 27 | def evaluate_profit(observer, scheduler): 28 | task = asyncio.ensure_future(process_list(observer), loop=loop) 29 | return Disposable(lambda: task.cancel()) 30 | 31 | return rx.create(evaluate_profit) 32 | -------------------------------------------------------------------------------- /codes/ch09/api/route_decrypt.py: -------------------------------------------------------------------------------- 1 | from cryptography.fernet import Fernet 2 | from fastapi import APIRouter, Depends, Request 3 | from passlib.context import CryptContext 4 | 5 | from models.request.secured_messages import EncLoginReq, EncRestaurantReq 6 | from util.auth_session import get_current_user 7 | from util.custom_routes import DecryptContentRoute 8 | 9 | router = APIRouter() 10 | router.route_class = DecryptContentRoute 11 | 12 | key = Fernet.generate_key() 13 | pwd_context = CryptContext( 14 | schemes=["pbkdf2_sha256"], 15 | default="pbkdf2_sha256", 16 | pbkdf2_sha256__default_rounds=30000 17 | ) 18 | 19 | 20 | @router.post("/login/decrypt/details") 21 | async def send_decrypt_login(enc_data: EncLoginReq, req: Request, user: str = Depends(get_current_user)): 22 | return {"data": req.state.dec_data} 23 | 24 | 25 | @router.post("/restaurant/decrypt/details") 26 | async def send_decrypt_login(enc_data: EncRestaurantReq, req: Request, user: str = Depends(get_current_user)): 27 | return {"data": req.state.dec_data} 28 | -------------------------------------------------------------------------------- /codes/ch09/api/route_transform.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from fastapi import APIRouter, Depends, File, UploadFile 4 | 5 | from util.auth_session import get_current_user 6 | from util.custom_routes import FileStreamRoute 7 | 8 | router = APIRouter() 9 | router.route_class = FileStreamRoute 10 | 11 | 12 | @router.post("/files/") 13 | async def create_file(file: Optional[bytes] = File(...), user: str = Depends(get_current_user)): 14 | return {"file_size": len(file)} 15 | 16 | 17 | @router.post("/files/upload") 18 | async def create_file_2(file: Optional[UploadFile] = File(...), user: str = Depends(get_current_user)): 19 | print(file.content_type) 20 | fs = await file.read() 21 | return {"file_size": len(fs)} 22 | -------------------------------------------------------------------------------- /codes/ch09/config/db.py: -------------------------------------------------------------------------------- 1 | from motor.motor_asyncio import AsyncIOMotorClient 2 | from odmantic import AIOEngine 3 | 4 | 5 | def create_db_connection(): 6 | global client_od 7 | client_od = AsyncIOMotorClient(f"mongodb://localhost:27017/") 8 | 9 | 10 | def create_db_engine(): 11 | engine = AIOEngine(motor_client=client_od, database="orrs") 12 | return engine 13 | 14 | 15 | def close_db_connection(): 16 | client_od.close() 17 | -------------------------------------------------------------------------------- /codes/ch09/database/orrs_db.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch09/database/orrs_db.zip -------------------------------------------------------------------------------- /codes/ch09/files/file.txt: -------------------------------------------------------------------------------- 1 | ggfdgdfgdg -------------------------------------------------------------------------------- /codes/ch09/files/logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch09/files/logo.jpg -------------------------------------------------------------------------------- /codes/ch09/files/questions.txt: -------------------------------------------------------------------------------- 1 | What is your favorite menu? 2 | How often do you eat here for dinner? 3 | How often do you eat here for breakfast? 4 | How often do you eat here for lunch? 5 | -------------------------------------------------------------------------------- /codes/ch09/files/sample.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch09/files/sample.mp4 -------------------------------------------------------------------------------- /codes/ch09/models/data/ratings_enum.py: -------------------------------------------------------------------------------- 1 | from enum import Enum 2 | 3 | 4 | class FoodRatingScale(int, Enum): 5 | FIVE_STAR = 5 6 | FOUR_STAR = 4 7 | THREE_STAR = 3 8 | TWO_STAR = 2 9 | ONE_STAR = 1 10 | 11 | 12 | class AmbianceRatingScale(int, Enum): 13 | STRONGLY_AGREE = 7 14 | AGREE = 6 15 | SOMEWHAT_AGREE = 5 16 | FINE = 4 17 | SOMEWHAT_DISAGREE = 3 18 | DISAGREE = 2 19 | STRONGLY_DISAGREE = 1 20 | -------------------------------------------------------------------------------- /codes/ch09/models/documentation/response.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class Error500Model(BaseModel): 5 | message: str = "Video file is invalid." 6 | -------------------------------------------------------------------------------- /codes/ch09/models/request/ambiance_rate.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | from models.data.ratings_enum import AmbianceRatingScale 6 | 7 | 8 | class AmbianceRateReq(BaseModel): 9 | question_id: int 10 | rate: AmbianceRatingScale 11 | date_rated: date 12 | profile_id: int 13 | -------------------------------------------------------------------------------- /codes/ch09/models/request/feedback.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class FeedbackReq(BaseModel): 7 | message: str 8 | date_rated: date 9 | profile_id: int 10 | -------------------------------------------------------------------------------- /codes/ch09/models/request/food_rate.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | from models.data.ratings_enum import FoodRatingScale 6 | 7 | 8 | class FoodRateReq(BaseModel): 9 | rate: FoodRatingScale 10 | date_rated: date 11 | profile_id: int 12 | -------------------------------------------------------------------------------- /codes/ch09/models/request/keyword.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class KeywordReq(BaseModel): 5 | word: str 6 | weight: int 7 | -------------------------------------------------------------------------------- /codes/ch09/models/request/login.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class LoginReq(BaseModel): 5 | login_id: int 6 | username: str 7 | password: str 8 | -------------------------------------------------------------------------------- /codes/ch09/models/request/profile.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class ProfileReq(BaseModel): 7 | firstname: str 8 | lastname: str 9 | middlename: str 10 | date_signed: date 11 | age: int 12 | date_signed: date 13 | occupation: str 14 | birthday: date 15 | address: str 16 | -------------------------------------------------------------------------------- /codes/ch09/models/request/question.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class QuestionReq(BaseModel): 7 | question_id: int 8 | statement: str 9 | date_added: date 10 | profile_id: int 11 | -------------------------------------------------------------------------------- /codes/ch09/models/request/restaurant.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | from typing import Optional 3 | 4 | from pydantic import BaseModel 5 | 6 | 7 | class RestaurantReq(BaseModel): 8 | restaurant_id: int 9 | name: str 10 | branch: Optional[str] = None 11 | address: str 12 | province: str 13 | date_signed: date 14 | city: str 15 | country: str 16 | zipcode: int 17 | -------------------------------------------------------------------------------- /codes/ch09/models/request/secured_messages.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class EncLoginReq(BaseModel): 5 | enc_login: str 6 | key: str 7 | 8 | 9 | class EncRestaurantReq(BaseModel): 10 | enc_login: str 11 | key: str 12 | -------------------------------------------------------------------------------- /codes/ch09/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Online Restaurant Review System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: May 25, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | This prototype is a feedback and rating system designed for various restaurants. 10 | Users are required to answer survey questions regarding the restaurant's ambiance, 11 | menu, and hospitality. Aside from survey systems, the application can provide a 12 | nominal and numerical approach to the rating system. Overall, the prototype can 13 | be a foundation for a scalable survey system. 14 | 15 | This application uses the FastAPI framework driven by Python 3.8. 16 | This application now involves data storage using MongoDb 5.x. 17 | The backup database schema is in the /database folder of the project. 18 | 19 | The requirements.txt will guide you with the dependencies. Just install by running: 20 | pip install -r requirements.txt 21 | 22 | -------------------------------------------------------------------------------- /codes/ch09/requirements.txt: -------------------------------------------------------------------------------- 1 | aiodns==3.0.0 2 | aiofiles==0.8.0 3 | aiohttp==3.8.1 4 | aiosignal==1.2.0 5 | anyio==3.6.1 6 | asgiref==3.5.2 7 | async-timeout==4.0.2 8 | atomicwrites==1.4.1 9 | attrs==21.4.0 10 | backports.zoneinfo==0.2.1 11 | Brotli==1.0.9 12 | caio==0.9.6 13 | cchardet==2.1.7 14 | certifi==2022.6.15 15 | cffi==1.15.i-normalizer==2.1.0 16 | click==8.1.3 17 | colorama==0.4.5 18 | cryptography==37.0.4 19 | distro==1.7.0 20 | ecdsa==0.18.0 21 | fastapi==0.78.0 22 | frozenlist==1.3.1 23 | h11==0.13.0 24 | idna==3.3 25 | iniconfig==1.1.1 26 | itsdangerous==2.1.2 27 | Jinja2==3.1.2 28 | MarkupSafe==2.1.1 29 | motor==3.0.0 30 | multidict==6.0.2 31 | odmantic==0.5.0 32 | orjson==3.7.7 33 | packaging==21.3 34 | passlib==1.7.4 35 | Pillow==9.2.0 36 | pluggy==1.0.0 37 | py==1.11.0 38 | pyasn1==0.4.8 39 | pycares==4.2.1 40 | pycparser==2.21 41 | pydantic==1.9.1 42 | pymongo==4.1.1 43 | pyparsing==3.0.9 44 | pytest==7.1.2 45 | python-jose==3.3.0 46 | python-multipart==0.0.5 47 | requests==2.28.1 48 | rsa==4.8 49 | six==1.16.0 50 | sniffio==1.2.0 51 | sqlparse==0.4.2 52 | starlette==0.19.1 53 | tomli==2.0.1 54 | typing_extensions==4.3.0 55 | tzdata==2022.1 56 | ujson==5.4.0 57 | urllib3==1.26.11 58 | uvicorn==0.18.2 59 | yarl==1.8.1 60 | -------------------------------------------------------------------------------- /codes/ch09/templates/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | {% block content %} 17 | {% endblock content %} 18 | 19 | 20 | -------------------------------------------------------------------------------- /codes/ch09/templates/page.html: -------------------------------------------------------------------------------- 1 |

2 | Welcome to FastAPI Starter. 3 |

4 | {{data.page}} -------------------------------------------------------------------------------- /codes/ch09/templates/upload_file.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block content %} 4 |
5 |

Upload Logo (PNG or PNG)

6 |
7 |
8 | 9 | 10 |
11 | 12 |
13 |
14 | {% endblock %} -------------------------------------------------------------------------------- /codes/ch09/templates/users.html: -------------------------------------------------------------------------------- 1 | {% extends "layout.html" %} 2 | 3 | {% block content %} 4 |
5 |

List of users

6 |

This is a Boostrap 4 table applied to JinjaTemplate.

7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% for login in data %} 18 | 19 | 20 | 21 | 22 | 23 | 24 | {% endfor%} 25 | 26 |
Login IDUsernamePasswordPassphrase
{{ login.login_id}}{{ login.username}}{{ login.password}}{{ login.passphrase}}
27 |
28 | {% endblock %} -------------------------------------------------------------------------------- /codes/ch09/test/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch09/test/__init__.py -------------------------------------------------------------------------------- /codes/ch09/test/test_login.py: -------------------------------------------------------------------------------- 1 | from fastapi.testclient import TestClient 2 | from motor.motor_asyncio import AsyncIOMotorClient 3 | from odmantic import AIOEngine 4 | 5 | from config.db import create_db_engine 6 | from main import app 7 | from models.data.orrs import Login 8 | from util.auth_session import get_current_user 9 | 10 | client = TestClient(app) 11 | 12 | 13 | def db_connect(): 14 | client_od = AsyncIOMotorClient(f"mongodb://localhost:27017/") 15 | engine = AIOEngine(motor_client=client_od, database="orrs_test") 16 | return engine 17 | 18 | 19 | async def get_user(): 20 | return Login( 21 | **{"username": "sjctrags", "login_id": 101, "password": "sjctrags", "passphrase": None, "profile": None}) 22 | 23 | 24 | app.dependency_overrides[get_current_user] = get_user 25 | app.dependency_overrides[create_db_engine] = db_connect 26 | 27 | 28 | def test_list_login(): 29 | response = client.get("/ch09/login/list/all") 30 | assert response.status_code == 201 31 | -------------------------------------------------------------------------------- /codes/ch09/test/test_restaurants.py: -------------------------------------------------------------------------------- 1 | from fastapi.testclient import TestClient 2 | 3 | from api import restaurant 4 | 5 | client = TestClient(restaurant.router) 6 | 7 | 8 | def test_restaurant_index(): 9 | response = client.get("/restaurant/index") 10 | assert response.status_code == 200 11 | assert response.text == "The Restaurants" 12 | -------------------------------------------------------------------------------- /codes/ch09/test/test_route_extract.py: -------------------------------------------------------------------------------- 1 | from fastapi.testclient import TestClient 2 | 3 | from main import app 4 | from models.data.orrs import Login 5 | from util.auth_session import get_current_user 6 | 7 | client = TestClient(app) 8 | 9 | 10 | async def get_user(): 11 | return Login( 12 | **{"username": "sjctrags", "login_id": 101, "password": "sjctrags", "passphrase": None, "profile": None}) 13 | 14 | 15 | app.dependency_overrides[get_current_user] = get_user 16 | 17 | 18 | def test_rating_top_three(): 19 | response = client.post("/ch09/rating/top/three", json={ 20 | "rate1": 10.0, 21 | "rate2": 20.0, 22 | "rate3": 30.0 23 | 24 | }) 25 | assert response.status_code == 200 26 | assert response.json() == {"stats": { 27 | "sum": 60.0, 28 | "average": 20.0 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /codes/ch09/util/json_date.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, date 2 | 3 | 4 | def json_datetime_serializer(obj): 5 | if isinstance(obj, (datetime, date)): 6 | return obj.strftime('%Y-%m-%dT%H:%M:%S.%f') 7 | raise TypeError("The type %s not serializable." % type(obj)) 8 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/config/pccs.py: -------------------------------------------------------------------------------- 1 | from beanie import init_beanie 2 | from motor.motor_asyncio import AsyncIOMotorClient 3 | 4 | from models.data.pccs_beanie import Login, Profile 5 | 6 | 7 | async def db_connect(): 8 | global client 9 | client = AsyncIOMotorClient(f"mongodb://localhost:27017/pccs") 10 | await init_beanie(client.pccs, document_models=[Login, Profile]) 11 | 12 | 13 | async def db_close(): 14 | client.close() 15 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/config/pcss_neo4j.py: -------------------------------------------------------------------------------- 1 | from neo4j import GraphDatabase 2 | 3 | uri = "bolt://127.0.0.1:7687" 4 | driver = GraphDatabase.driver(uri, auth=("neo4j", "admin2255")) 5 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/database/pccs_db.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch10/ch10-mongo/database/pccs_db.zip -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/files/survey.csv: -------------------------------------------------------------------------------- 1 | ,Questions,Answers 2 | 0,q1,20 3 | 1,q2,30 4 | 2,q3,40 5 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/files/survey.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch10/ch10-mongo/files/survey.xlsx -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/main.py: -------------------------------------------------------------------------------- 1 | from fastapi import FastAPI 2 | from starlette_graphene3 import GraphQLApp, make_playground_handler 3 | 4 | from api import survey_graphene_login, survey_graphene_profile, survey_neo4j, survey_workflow 5 | from config.pccs import db_connect, db_close 6 | 7 | app = FastAPI() 8 | app.include_router(survey_neo4j.router, prefix="/ch10") 9 | app.include_router(survey_workflow.router, prefix="/ch10") 10 | app.mount("/ch10/graphql/login", GraphQLApp(survey_graphene_login.schema, on_get=make_playground_handler())) 11 | app.mount("/ch10/graphql/profile", GraphQLApp(survey_graphene_profile.schema, on_get=make_playground_handler())) 12 | 13 | 14 | @app.on_event("startup") 15 | async def initialize(): 16 | await db_connect() 17 | 18 | 19 | @app.on_event("shutdown") 20 | async def destroy(): 21 | await db_close() 22 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/models/request/pccs_general.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class SurveyDataResult(BaseModel): 7 | results: Dict[str, int] 8 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/models/request/pccs_neo4j.py: -------------------------------------------------------------------------------- 1 | from datetime import date 2 | 3 | from pydantic import BaseModel 4 | 5 | 6 | class LocationReq(BaseModel): 7 | name: str 8 | city: str 9 | state: str 10 | country: str 11 | 12 | 13 | class ProfileReq(BaseModel): 14 | name: str 15 | fname: str 16 | lname: str 17 | age: int 18 | position: str 19 | official_id: int 20 | date_employed: date 21 | 22 | 23 | class RespondentReq(BaseModel): 24 | name: str 25 | fname: str 26 | lname: str 27 | age: int 28 | birthday: date 29 | gender: str 30 | salary_estimate: float 31 | marital: bool 32 | 33 | 34 | class LinkAdminLoc(BaseModel): 35 | date_assigned: date 36 | duration: int 37 | 38 | 39 | class LinkRespondentLoc(BaseModel): 40 | address: str 41 | tax_id: int 42 | 43 | 44 | class LinkAdminRespondent(BaseModel): 45 | survey_id: int 46 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/repository/choices.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.pccs_beanie import Choices 4 | 5 | 6 | class ChoicesRepository: 7 | 8 | async def add_choice(self, details: Dict[str, Any]) -> bool: 9 | try: 10 | choices = Choices(**details) 11 | await choices.insert() 12 | except Exception as e: 13 | print(e) 14 | return None 15 | return choices 16 | 17 | async def update_choice(self, id: int, details: Dict[str, Any]) -> bool: 18 | try: 19 | choices = await Choices.get(id) 20 | await choices.set({**details}) 21 | except: 22 | return None 23 | return choices 24 | 25 | async def delete_choice(self, id: int) -> bool: 26 | try: 27 | choices = await Choices.get(id) 28 | await choices.delete() 29 | except: 30 | return None 31 | return choices 32 | 33 | async def get_all_choice(self): 34 | return await Choices.find_all().to_list() 35 | 36 | async def get_choice(self, id: int): 37 | return await Choices.get(id) 38 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/repository/login.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.pccs_beanie import Login 4 | 5 | 6 | class LoginRepository: 7 | 8 | async def add_login(self, details: Dict[str, Any]) -> bool: 9 | try: 10 | login = Login(**details) 11 | await login.insert() 12 | except Exception as e: 13 | print(e) 14 | return None 15 | return login 16 | 17 | async def change_password(self, username: str, new_password: str) -> bool: 18 | try: 19 | login = await Login.find_one(Login.username == username) 20 | await login.set({Login.password: new_password}) 21 | except: 22 | return None 23 | return login 24 | 25 | async def delete_login(self, id: int) -> bool: 26 | try: 27 | login = await Login.get(id) 28 | await login.delete() 29 | except: 30 | return None 31 | return login 32 | 33 | async def get_all_login(self): 34 | return await Login.find_all().to_list() 35 | 36 | async def get_login(self, id: int): 37 | return await Login.get(id) 38 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/repository/profile.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.pccs_beanie import Profile 4 | 5 | 6 | class ProfileRepository: 7 | 8 | async def add_profile(self, details: Dict[str, Any]) -> bool: 9 | try: 10 | profile = Profile(**details) 11 | await profile.insert() 12 | except Exception as e: 13 | print(e) 14 | return None 15 | return profile 16 | 17 | async def update_profile(self, id: int, details: Dict[str, Any]) -> bool: 18 | try: 19 | profile = await Profile.get(id) 20 | await profile.set({**details}) 21 | except: 22 | return None 23 | return profile 24 | 25 | async def delete_profile(self, id: int) -> bool: 26 | try: 27 | profile = await Profile.get(id) 28 | await profile.delete() 29 | except: 30 | return None 31 | return profile 32 | 33 | async def get_all_profile(self): 34 | return await Profile.find_all().to_list() 35 | 36 | async def get_profile(self, id: int): 37 | return await Profile.get(id) 38 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/repository/question.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.pccs_beanie import Question 4 | 5 | 6 | class QuestionRepository: 7 | 8 | async def add_question(self, details: Dict[str, Any]) -> bool: 9 | try: 10 | question = Question(**details) 11 | await question.insert() 12 | except Exception as e: 13 | print(e) 14 | return None 15 | return question 16 | 17 | async def update_question(self, id: int, details: Dict[str, Any]) -> bool: 18 | try: 19 | question = await Question.get(id) 20 | await question.set({**details}) 21 | except: 22 | return None 23 | return question 24 | 25 | async def delete_question(self, id: int) -> bool: 26 | try: 27 | question = await Question.get(id) 28 | await question.delete() 29 | except: 30 | return None 31 | return question 32 | 33 | async def get_all_question(self): 34 | return await Question.find_all().to_list() 35 | 36 | async def get_question(self, id: int): 37 | return await Question.get(id) 38 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/repository/respondent.py: -------------------------------------------------------------------------------- 1 | from typing import Dict, Any 2 | 3 | from models.data.pccs_beanie import Respondent 4 | 5 | 6 | class RespondentRepository: 7 | 8 | async def add_respondent(self, details: Dict[str, Any]) -> bool: 9 | try: 10 | respondent = Respondent(**details) 11 | await respondent.insert() 12 | except Exception as e: 13 | print(e) 14 | return None 15 | return respondent 16 | 17 | async def update_respondent(self, id: int, details: Dict[str, Any]) -> bool: 18 | try: 19 | respondent = await Respondent.get(id) 20 | await respondent.set({**details}) 21 | except: 22 | return None 23 | return respondent 24 | 25 | async def delete_respondent(self, id: int) -> bool: 26 | try: 27 | respondent = await Respondent.get(id) 28 | await respondent.delete() 29 | except: 30 | return None 31 | return respondent 32 | 33 | async def get_all_respondent(self): 34 | return await Respondent.find_all().to_list() 35 | 36 | async def get_respondent(self, id: int): 37 | return await Respondent.get(id) 38 | -------------------------------------------------------------------------------- /codes/ch10/ch10-mongo/requirements.txt: -------------------------------------------------------------------------------- 1 | amqp==5.1.1 2 | aniso8601==9.0.1 3 | anyio==3.6.1 4 | async-timeout==4.0.2 5 | asyncio==3.4.3 6 | beanie==1.11.6 7 | billiard==3.6.4.0 8 | celery==5.2.7 9 | click==8.1.3 10 | click-didyoumean==0.3.0 11 | click-plugins==1.1.1 12 | click-repl==0.2.0 13 | colorama==0.4.5 14 | cycler==0.11.0 15 | Deprecated==1.2.13 16 | et-xmlfile==1.1.0 17 | fastapi==0.79.0 18 | flower==1.1.0 19 | fonttools==4.34.4 20 | graphene==3.1 21 | graphql-core==3.2.1 22 | graphql-relay==3.2.0 23 | h11==0.13.0 24 | humanize==4.2.3 25 | idna==3.3 26 | kiwisolver==1.4.3 27 | kombu==5.2.4 28 | matplotlib==3.5.2 29 | motor==3.0.0 30 | multidict==6.0.2 31 | neo4j==4.4.5 32 | numpy==1.23.1 33 | openpyxl==3.0.10 34 | packaging==21.3 35 | pandas==1.4.3 36 | Pillow==9.2.0 37 | prometheus-client==0.14.1 38 | prompt-toolkit==3.0.30 39 | pydantic==1.9.1 40 | pymongo==4.1.1 41 | pyparsing==3.0.9 42 | python-dateutil==2.8.2 43 | python-multipart==0.0.5 44 | pytz==2022.1 45 | redis==4.3.4 46 | six==1.16.0 47 | sniffio==1.2.0 48 | starlette==0.19.1 49 | starlette-graphene3==0.6.0 50 | toml==0.10.2 51 | tornado==6.2 52 | typing_extensions==4.3.0 53 | uvicorn==0.18.2 54 | vine==5.0.0 55 | wcwidth==0.2.5 56 | wrapt==1.14.1 57 | yarl==1.7.2 58 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/README.md: -------------------------------------------------------------------------------- 1 | # piccolo_project 2 | 3 | ## Setup 4 | 5 | ### Install requirements 6 | 7 | ```bash 8 | pip install -r requirements.txt 9 | ``` 10 | 11 | ### Getting started guide 12 | 13 | ```bash 14 | python main.py 15 | ``` 16 | 17 | ### Running tests 18 | 19 | ```bash 20 | piccolo tester run 21 | ``` -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from piccolo.utils.warnings import colored_warning 5 | 6 | 7 | def pytest_configure(*args): 8 | if os.environ.get("PICCOLO_TEST_RUNNER") != "True": 9 | colored_warning( 10 | "\n\n" 11 | "We recommend running Piccolo tests using the " 12 | "`piccolo tester run` command, which wraps Pytest, and makes " 13 | "sure the test database is being used. " 14 | "To stop this warning, modify conftest.py." 15 | "\n\n" 16 | ) 17 | sys.exit(1) 18 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/countries.csv: -------------------------------------------------------------------------------- 1 | ID,First Name,Last Name,Age,Gender,Married? 2 | 3,Juan,Luna,32,1990-11-10,M,3,10,10000.0,Anzons Plaza,Tondo,12,4,PUP,False,0 3 | 4,Zeta,Ngo,30,1992-09-01,F,6,20,40000.0,LNHS,113 Real St.,13,6,Eastern Visayas State College,True,5 4 | 5,Jim,Chu,40,1982-05-11,M,6,13,60000.0,HSBC,Bangkal St.,15,6,UP Diliman,True,4 5 | 6,Larry,Santos,33,1991-03-22,M,8,16,55000.0,Makati Science High School,6754 Poblacion,15,7,TIP,False,1 6 | 7,Gene,Chua,23,1999-06-20,F,5,7,9600.0,Makati Science High School,Sampaloc,12,3,Soro-Soro High School,True,7 7 | 8,Larson,Alcala,55,1969-02-10,M,4,30,22600.0,NAPOLCOM,Pandacan,12,4,Pandacan Colleges,True,4 8 | 9,Stella,Marquez,45,1977-07-05,F,9,32,82600.0,DOST,123 Pioneer St,1,7,Up Diliman,True,3 9 | 10,John,Cruz,39,1983-10-15,M,5,23,8600.0,Zeus Merchandize,Soro Soro Ilaya,3,3,Mababang Paaralan ng Tibag,False,6 10 | 11,Liza,Muring,38,1984-08-28,F,11,26,33000.0,Alipay Bistro,178 Vietnam Village,11,6,Palawan College,True,2 11 | 12,Samuel,Relli,34,1988-04-27,M,10,11,89000.0,The Survey Inc,Little Baguio,9,8,UPLB,True,3 12 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "columns": [ 3 | 0, 4 | 1, 5 | 2 6 | ], 7 | "index": [ 8 | 0, 9 | 1 10 | ], 11 | "data": [ 12 | [ 13 | 1, 14 | 2, 15 | 3 16 | ], 17 | [ 18 | 4, 19 | 5, 20 | 6 21 | ] 22 | ] 23 | } -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/files/sample.csv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch10/ch10-relational/files/sample.csv -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/main.py: -------------------------------------------------------------------------------- 1 | if __name__ == "__main__": 2 | import uvicorn 3 | 4 | uvicorn.run("app:app", port=8002, reload=True) 5 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/piccolo_conf.py: -------------------------------------------------------------------------------- 1 | from piccolo.conf.apps import AppRegistry 2 | from piccolo.engine.postgres import PostgresEngine 3 | 4 | DB = PostgresEngine( 5 | config={ 6 | "database": "pccs", 7 | "user": "postgres", 8 | "password": "root", 9 | "host": "localhost", 10 | "port": 5432, 11 | } 12 | ) 13 | 14 | APP_REGISTRY = AppRegistry( 15 | apps=["survey.piccolo_app", "piccolo_admin.piccolo_app"] 16 | ) 17 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/piccolo_conf_test.py: -------------------------------------------------------------------------------- 1 | from piccolo_conf import * # noqa 2 | 3 | DB = PostgresEngine( 4 | config={ 5 | "database": "piccolo_project_test", 6 | "user": "postgres", 7 | "password": "root", 8 | "host": "localhost", 9 | "port": 5432, 10 | } 11 | ) 12 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/requirements.txt: -------------------------------------------------------------------------------- 1 | aiofiles==0.8.0 2 | anyio==3.6.1 3 | asyncpg==0.26.0 4 | black==22.6.0 5 | certifi==2022.6.15 6 | click==8.1.3 7 | colorama==0.4.5 8 | cycler==0.11.0 9 | docstring-parser==0.12 10 | et-xmlfile==1.1.0 11 | fastapi==0.79.0 12 | fonttools==4.34.4 13 | h11==0.12.0 14 | h2==4.1.0 15 | hpack==4.0.0 16 | httpcore==0.15.0 17 | httpx==0.23.0 18 | hypercorn==0.13.2 19 | hyperframe==6.0.1 20 | idna==3.3 21 | inflection==0.5.1 22 | Jinja2==3.1.2 23 | kiwisolver==1.4.4 24 | MarkupSafe==2.1.1 25 | matplotlib==3.5.2 26 | mpmath==1.2.1 27 | mypy-extensions==0.4.3 28 | numpy==1.23.1 29 | openpyxl==3.0.10 30 | orjson==3.7.11 31 | packaging==21.3 32 | pandas==1.4.3 33 | pathspec==0.9.0 34 | piccolo==0.80.2 35 | piccolo-admin==0.24.0 36 | piccolo-api==0.39.0 37 | Pillow==9.2.0 38 | platformdirs==2.5.2 39 | priority==2.0.0 40 | pydantic==1.9.1 41 | PyJWT==2.4.0 42 | pyparsing==3.0.9 43 | python-dateutil==2.8.2 44 | python-multipart==0.0.5 45 | pytz==2022.1 46 | rfc3986==1.5.0 47 | scipy==1.9.0 48 | six==1.16.0 49 | sniffio==1.2.0 50 | starlette==0.19.1 51 | sympy==1.10.1 52 | targ==0.3.7 53 | toml==0.10.2 54 | tomli==2.0.1 55 | typing_extensions==4.3.0 56 | ujson==5.4.0 57 | uvicorn==0.18.2 58 | wsproto==1.1.0 59 | XlsxWriter==3.0.3 60 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch10/ch10-relational/static/favicon.ico -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/survey/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch10/ch10-relational/survey/__init__.py -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/survey/api/graphql.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | from piccolo_api.crud.endpoints import PiccoloCRUD 3 | from piccolo_api.fastapi.endpoints import FastAPIWrapper 4 | 5 | from survey.tables import Login, Profile 6 | 7 | router = APIRouter() 8 | 9 | FastAPIWrapper( 10 | "/login/", 11 | router, 12 | PiccoloCRUD(Login, read_only=False), 13 | ) 14 | 15 | FastAPIWrapper( 16 | "/profile/", 17 | router, 18 | PiccoloCRUD(Profile, read_only=False), 19 | ) 20 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/survey/models.py: -------------------------------------------------------------------------------- 1 | from piccolo_api.crud.serializers import create_pydantic_model 2 | 3 | from survey.tables import Answers, Education, Question, Profile, Login, Location, Occupation, Respondent, Choices 4 | 5 | OccupationReq = create_pydantic_model(Occupation) 6 | LoginReq = create_pydantic_model(Login) 7 | LocationReq = create_pydantic_model(Location) 8 | QuestionReq = create_pydantic_model(Question) 9 | AnswersReq = create_pydantic_model(Answers) 10 | EducationReq = create_pydantic_model(Education) 11 | ProfileReq = create_pydantic_model(Profile) 12 | RespondentReq = create_pydantic_model(Respondent) 13 | ChoicesReq = create_pydantic_model(Choices) 14 | 15 | weights = [{"1": 10, "2": 20, "3": 30, "4": 40, "5": 50}, 16 | {"6": 10, "7": 20, "8": 30}, {"9": 10, "10": 20, "11": 30}, 17 | {"12": 10, "13": 20, "14": 30, "15": 40}, {"16": 20, "17": 10}, 18 | {"18": 20, "19": 10}, {"20": 20, "21": 10}, {"22": 20, "23": 10}, {"24": 40, "25": 30, "26": 20, "27": 10}, 19 | {"28": 20, "29": 10}, {"30": 40, "31": 30, "32": 20, "33": 10}, {"34": 30, "35": 20, "36": 10}, 20 | {"37": 20, "38": 10}] 21 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/survey/piccolo_app.py: -------------------------------------------------------------------------------- 1 | """ 2 | Import all of the Tables subclasses in your app here, and register them with 3 | the APP_CONFIG. 4 | """ 5 | 6 | import os 7 | 8 | from piccolo.conf.apps import AppConfig 9 | from survey.tables import Answers, Education, Question, Profile, Login, Location, Occupation, Respondent, Choices 10 | 11 | CURRENT_DIRECTORY = os.path.dirname(os.path.abspath(__file__)) 12 | 13 | APP_CONFIG = AppConfig( 14 | app_name="survey", 15 | migrations_folder_path=os.path.join( 16 | CURRENT_DIRECTORY, "piccolo_migrations" 17 | ), 18 | table_classes=[Answers, Education, Question, Choices, Profile, Login, Location, 19 | Occupation, Respondent], 20 | migration_dependencies=[], 21 | commands=[], 22 | ) 23 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/survey/piccolo_migrations/2022-06-09T19-26-00-511909.py: -------------------------------------------------------------------------------- 1 | from piccolo.apps.migrations.auto.migration_manager import MigrationManager 2 | from piccolo.columns.column_types import Varchar 3 | from piccolo.columns.indexes import IndexMethod 4 | 5 | ID = "2022-06-09T19:26:00:511909" 6 | VERSION = "0.75.0" 7 | DESCRIPTION = "" 8 | 9 | 10 | async def forwards(): 11 | manager = MigrationManager( 12 | migration_id=ID, app_name="survey", description=DESCRIPTION 13 | ) 14 | 15 | manager.add_column( 16 | table_class_name="Respondent", 17 | tablename="respondent", 18 | column_name="gender", 19 | db_column_name="gender", 20 | column_class_name="Varchar", 21 | column_class=Varchar, 22 | params={ 23 | "length": 1, 24 | "default": "", 25 | "null": False, 26 | "primary_key": False, 27 | "unique": False, 28 | "index": False, 29 | "index_method": IndexMethod.btree, 30 | "choices": None, 31 | "db_column_name": None, 32 | "secret": False, 33 | }, 34 | ) 35 | 36 | return manager 37 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/survey/piccolo_migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch10/ch10-relational/survey/piccolo_migrations/__init__.py -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/templates/render_survey.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Render Survey Data 6 | 7 | 8 |

DataFrame representation:

9 | 10 | {{ data|safe }} 11 | 12 | -------------------------------------------------------------------------------- /codes/ch10/ch10-relational/templates/upload_survey.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Upload Survey Data 6 | 7 | 8 |

Online Periodic Survey System

9 | 10 |
11 | 12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /codes/ch11/ch11_django/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch11/ch11_django/__init__.py -------------------------------------------------------------------------------- /codes/ch11/ch11_django/asgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | ASGI config for ch11_django project. 3 | 4 | It exposes the ASGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/asgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.asgi import get_asgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ch11_django.settings') 15 | 16 | application = get_asgi_application() 17 | -------------------------------------------------------------------------------- /codes/ch11/ch11_django/urls.py: -------------------------------------------------------------------------------- 1 | """ch11_django URL Configuration 2 | 3 | The `urlpatterns` list routes URLs to views. For more information please see: 4 | https://docs.djangoproject.com/en/3.2/topics/http/urls/ 5 | Examples: 6 | Function views 7 | 1. Add an import: from my_app import views 8 | 2. Add a URL to urlpatterns: path('', views.home, name='home') 9 | Class-based views 10 | 1. Add an import: from other_app.views import Home 11 | 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 12 | Including another URLconf 13 | 1. Import the include() function: from django.urls import include, path 14 | 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) 15 | """ 16 | from django.contrib import admin 17 | from django.urls import path 18 | from sports import views 19 | 20 | urlpatterns = [ 21 | path('admin/', admin.site.urls), 22 | path('index/', views.view_index) 23 | ] 24 | -------------------------------------------------------------------------------- /codes/ch11/ch11_django/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for ch11_django project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/3.2/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ch11_django.settings') 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /codes/ch11/ch11_flask/api/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch11/ch11_flask/api/__init__.py -------------------------------------------------------------------------------- /codes/ch11/ch11_flask/api/schedule.py: -------------------------------------------------------------------------------- 1 | from ch11_flask.app import app 2 | 3 | 4 | @app.route("/index") 5 | def testing(): 6 | return "flask integration" 7 | -------------------------------------------------------------------------------- /codes/ch11/ch11_flask/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | app = Flask(__name__) 4 | 5 | if __name__ == '__main__': 6 | app.run() 7 | -------------------------------------------------------------------------------- /codes/ch11/config/db.py: -------------------------------------------------------------------------------- 1 | from motor.motor_asyncio import AsyncIOMotorClient 2 | 3 | 4 | def create_async_db(): 5 | global client 6 | client = AsyncIOMotorClient(str("localhost:27017")) 7 | 8 | 9 | def create_db_collections(): 10 | db = client.osms 11 | 12 | users = db["login"] 13 | players = db["player"] 14 | officials = db["official"] 15 | return {"users": users, "players": players, "officials": officials} 16 | 17 | 18 | def close_async_db(): 19 | client.close() 20 | -------------------------------------------------------------------------------- /codes/ch11/manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """Django's command-line utility for administrative tasks.""" 3 | import os 4 | import sys 5 | 6 | 7 | def main(): 8 | """Run administrative tasks.""" 9 | os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ch11_django.settings') 10 | try: 11 | from django.core.management import execute_from_command_line 12 | except ImportError as exc: 13 | raise ImportError( 14 | "Couldn't import Django. Are you sure it's installed and " 15 | "available on your PYTHONPATH environment variable? Did you " 16 | "forget to activate a virtual environment?" 17 | ) from exc 18 | execute_from_command_line(sys.argv) 19 | 20 | 21 | if __name__ == '__main__': 22 | main() 23 | -------------------------------------------------------------------------------- /codes/ch11/readme.txt: -------------------------------------------------------------------------------- 1 | =========================== Basic Details ================================== 2 | Application Name: Online Sports Management System 3 | Developer: Sherwin John Calleja Tragura 4 | Status: Prototype stage 5 | Date finished: June 18, 2022 6 | 7 | =========================== Description ==================================== 8 | 9 | The prototype is supposed to manage players, officials, and the games they are 10 | involved. It must also create a schedule for the games using various sports 11 | algorithms. But due to time constraints, the implementation focused on the 12 | FastAPI platform creation with some other microservice features like OpenTracing, 13 | Service Registry, Client service discovery, API health checks, and integration 14 | with Flask and Django. 15 | 16 | This project focuses on the FastAPI project. Check the other ch11 projects for the 17 | Docker, Nginx, and Docker Compose deployment directories.. 18 | 19 | This application uses the MongoDB 5.x. 20 | The backup database schema is in the /database folder of the project. 21 | 22 | The requirements.txt will guide you with the dependencies. Just install by running: 23 | pip install -r requirements.txt 24 | 25 | -------------------------------------------------------------------------------- /codes/ch11/sports/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch11/sports/__init__.py -------------------------------------------------------------------------------- /codes/ch11/sports/admin.py: -------------------------------------------------------------------------------- 1 | # Register your models here. 2 | -------------------------------------------------------------------------------- /codes/ch11/sports/apps.py: -------------------------------------------------------------------------------- 1 | from django.apps import AppConfig 2 | 3 | 4 | class SportsConfig(AppConfig): 5 | default_auto_field = 'django.db.models.BigAutoField' 6 | name = 'sports' 7 | -------------------------------------------------------------------------------- /codes/ch11/sports/migrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/codes/ch11/sports/migrations/__init__.py -------------------------------------------------------------------------------- /codes/ch11/sports/models.py: -------------------------------------------------------------------------------- 1 | # Create your models here. 2 | -------------------------------------------------------------------------------- /codes/ch11/sports/tests.py: -------------------------------------------------------------------------------- 1 | # Create your tests here. 2 | -------------------------------------------------------------------------------- /codes/ch11/sports/views.py: -------------------------------------------------------------------------------- 1 | from django.http.request import HttpRequest 2 | from django.http.response import HttpResponse 3 | 4 | 5 | def view_index(req: HttpRequest): 6 | return HttpResponse(content="django integration") 7 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/docs/.nojekyll -------------------------------------------------------------------------------- /docs/_sidebar.md: -------------------------------------------------------------------------------- 1 | * [目录](README.md) 2 | * [第1章 设置FastAPI](contents/ch01.md) 3 | * [第2章 探索核心功能](contents/ch02.md) 4 | * [第3章 依赖注入研究](contents/ch03.md) 5 | * [第4章 构建微服务应用程序](contents/ch04.md) 6 | * [第5章 连接到关系数据库](contents/ch05.md) 7 | * [第6章 使用非关系数据库](contents/ch06.md) 8 | * [第7章 保护REST API的安全](contents/ch07.md) 9 | * [第8章 创建协程、事件和消息驱动的事务](contents/ch08.md) 10 | * [第9章 利用其他高级功能](contents/ch09.md) 11 | * [第10章 解决数值、符号和图形问题](contents/ch10.md) 12 | * [第11章 添加其他微服务功能](contents/ch11.md) -------------------------------------------------------------------------------- /docs/contents/images/ch10-01-upload-survey-form.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Relph1119/fastapi-learning-notes/9f0b42d0578c81d8e3018f2233390eb82dc49e00/docs/contents/images/ch10-01-upload-survey-form.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | fastapi 2 | uvicorn 3 | python-multipart 4 | dependency-injector 5 | lagom 6 | requests 7 | loguru 8 | python-dotenv 9 | SQLAlchemy 10 | psycopg2 11 | aiopg 12 | asyncpg 13 | gino 14 | pony 15 | peewee 16 | pymongo 17 | motor 18 | mongoengine 19 | beanie 20 | odmantic 21 | MongoFrames 22 | passlib 23 | python-jose 24 | cryptography 25 | celery 26 | flower 27 | redis 28 | rx 29 | aiofiles 30 | pytest 31 | piccolo 32 | piccolo-admin 33 | sympy 34 | numpy 35 | pandas 36 | xlsxwriter 37 | matplotlib 38 | scipy 39 | starlette-exporter 40 | opentelemetry-exporter-jaeger 41 | py_eureka_client --------------------------------------------------------------------------------