Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,12 @@ No known bugs at this time.
## Authors
Alexa Orrico - [Github](https://github.com/alexaorrico) / [Twitter](https://twitter.com/alexa_orrico)
Jennifer Huang - [Github](https://github.com/jhuang10123) / [Twitter](https://twitter.com/earthtojhuang)
Ibrahim Tijani - [Github](https://github.com/teebabs521) / [Twitter](https://twitter.com/teejayibrahim)

## What's New in v3 by Ibrahim Tijani?
- Improved API functionality
- Optimized database queries
- Bug fixes and performance improvements
Second part of Airbnb: Joann Vuong
## License
Public Domain. No copy write protection.
Binary file added __pycache__/console.cpython-34.pyc
Binary file not shown.
Empty file added api/__init__.py
Empty file.
Empty file added api/v1/__init__.py
Empty file.
22 changes: 22 additions & 0 deletions api/v1/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/python3
"""Flask App for the AirBnB API"""
from flask import Flask, jsonify
from models import storage
from api.v1.views import app_views
import os

app = Flask(__name__)

# Register the Blueprint
app.register_blueprint(app_views)

@app.teardown_appcontext
def teardown_db(exception):
"""Closes storage session"""
storage.close()

if __name__ == "__main__":
host = os.getenv("HBNB_API_HOST", "0.0.0.0")
port = int(os.getenv("HBNB_API_PORT", 5000))
app.run(host=host, port=port, threaded=True)

10 changes: 10 additions & 0 deletions api/v1/views/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/python3
"""Blueprint for API"""
from flask import Blueprint

app_views = Blueprint("app_views", __name__, url_prefix="/api/v1")

# Import all views (PEP8 will complain, ignore it)
from api.v1.views.index import *


28 changes: 28 additions & 0 deletions api/v1/views/index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/python3
"""Index route for API"""
from flask import jsonify
from api.v1.views import app_views

@app_views.route('/status', methods=['GET'], strict_slashes=False)
def status():
"""Returns the API status"""
return jsonify({"status": "OK"})


"""Index route for API"""
from flask import jsonify
from api.v1.views import app_views
from models import storage

@app_views.route('/stats', methods=['GET'], strict_slashes=False)
def stats():
"""Retrieve the number of each object by type"""
stats = {
"amenities": storage.count("Amenity"),
"cities": storage.count("City"),
"places": storage.count("Place"),
"reviews": storage.count("Review"),
"states": storage.count("State"),
"users": storage.count("User")
}
return jsonify(stats)
1 change: 1 addition & 0 deletions file.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"Place.f7a17a63-208e-49ad-a40e-708874c1c93c": {"updated_at": "2025-02-16T11:06:50.539769", "created_at": "2025-02-16T11:06:50.539769", "id": "f7a17a63-208e-49ad-a40e-708874c1c93c", "__class__": "Place"}, "Amenity.7ccabb88-435f-4d15-a774-c6b71bbc4050": {"updated_at": "2025-02-16T11:06:50.539734", "created_at": "2025-02-16T11:06:50.539734", "id": "7ccabb88-435f-4d15-a774-c6b71bbc4050", "__class__": "Amenity"}, "Review.23c00ba9-920f-4ed5-be9a-c52a27a289a1": {"updated_at": "2025-02-16T11:06:50.539685", "created_at": "2025-02-16T11:06:50.539685", "id": "23c00ba9-920f-4ed5-be9a-c52a27a289a1", "__class__": "Review"}, "City.3284d804-24a2-44f3-81c0-7094c2c9ba07": {"updated_at": "2025-02-16T11:06:50.539703", "created_at": "2025-02-16T11:06:50.539703", "id": "3284d804-24a2-44f3-81c0-7094c2c9ba07", "__class__": "City"}, "State.e7288338-429e-4d3e-bc52-7e2b6aa86972": {"updated_at": "2025-02-16T11:06:50.539719", "created_at": "2025-02-16T11:06:50.539719", "id": "e7288338-429e-4d3e-bc52-7e2b6aa86972", "__class__": "State"}, "User.c52fbd04-a9ed-4e0e-88c3-abaf453ad041": {"updated_at": "2025-02-16T11:06:50.539749", "created_at": "2025-02-16T11:06:50.539749", "id": "c52fbd04-a9ed-4e0e-88c3-abaf453ad041", "__class__": "User"}, "BaseModel.22d5bb1c-57d9-409e-be54-220b1def189e": {"created_at": "2025-02-16T11:06:50.539663", "id": "22d5bb1c-57d9-409e-be54-220b1def189e", "updated_at": "2025-02-16T11:06:50.539663", "__class__": "BaseModel"}}
Binary file added models/__pycache__/__init__.cpython-34.pyc
Binary file not shown.
Binary file added models/__pycache__/amenity.cpython-34.pyc
Binary file not shown.
Binary file added models/__pycache__/base_model.cpython-34.pyc
Binary file not shown.
Binary file added models/__pycache__/city.cpython-34.pyc
Binary file not shown.
Binary file added models/__pycache__/place.cpython-34.pyc
Binary file not shown.
Binary file added models/__pycache__/review.cpython-34.pyc
Binary file not shown.
Binary file added models/__pycache__/state.cpython-34.pyc
Binary file not shown.
Binary file added models/__pycache__/user.cpython-34.pyc
Binary file not shown.
Binary file added models/engine/__pycache__/__init__.cpython-34.pyc
Binary file not shown.
Binary file not shown.
Binary file not shown.
71 changes: 71 additions & 0 deletions models/engine/db_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,74 @@ def reload(self):
def close(self):
"""call remove() method on the private session attribute"""
self.__session.remove()


#!/usr/bin/python3
"""Database Storage"""
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy import create_engine
from models.base_model import Base
from models.user import User
from models.state import State
from models.city import City
from models.amenity import Amenity
from models.place import Place
from models.review import Review
import os


class DBStorage:
"""Database storage engine"""
__engine = None
__session = None

def __init__(self):
"""Initialize the engine"""
self.__engine = create_engine('mysql+mysqldb://{}:{}@{}/{}'.format(
os.getenv('HBNB_MYSQL_USER'),
os.getenv('HBNB_MYSQL_PWD'),
os.getenv('HBNB_MYSQL_HOST'),
os.getenv('HBNB_MYSQL_DB')),
pool_pre_ping=True)

if os.getenv('HBNB_ENV') == 'test':
Base.metadata.drop_all(self.__engine)

def all(self, cls=None):
"""Query all objects or specific class"""
if cls:
return {obj.id: obj for obj in self.__session.query(cls).all()}
else:
objects = {}
for cls in [State, City, User, Place, Review, Amenity]:
for obj in self.__session.query(cls).all():
objects[obj.id] = obj
return objects

def new(self, obj):
"""Add new object"""
self.__session.add(obj)

def save(self):
"""Commit changes to database"""
self.__session.commit()

def delete(self, obj=None):
"""Delete an object"""
if obj:
self.__session.delete(obj)

def reload(self):
"""Reload session"""
Base.metadata.create_all(self.__engine)
session_factory = sessionmaker(bind=self.__engine, expire_on_commit=False)
self.__session = scoped_session(session_factory)

def get(self, cls, id):
"""Retrieve one object by class and ID"""
return self.__session.query(cls).filter_by(id=id).first()

def count(self, cls=None):
"""Count number of objects in storage"""
return len(self.all(cls))

54 changes: 54 additions & 0 deletions models/engine/file_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,57 @@ def delete(self, obj=None):
def close(self):
"""call reload() method for deserializing the JSON file to objects"""
self.reload()


#!/usr/bin/python3
"""File Storage"""
import json
from models.base_model import BaseModel
from models.user import User
from models.state import State
from models.city import City
from models.amenity import Amenity
from models.place import Place
from models.review import Review


class FileStorage:
"""Serializes instances to a JSON file & deserializes back to instances"""
__file_path = "file.json"
__objects = {}

def all(self, cls=None):
"""Returns the dictionary __objects"""
if cls is None:
return self.__objects
return {key: val for key, val in self.__objects.items() if isinstance(val, cls)}

def new(self, obj):
"""Sets in __objects the obj with key <obj class name>.id"""
self.__objects["{}.{}".format(obj.__class__.__name__, obj.id)] = obj

def save(self):
"""Serializes __objects to the JSON file (path: __file_path)"""
obj_dict = {key: val.to_dict() for key, val in self.__objects.items()}
with open(self.__file_path, "w") as f:
json.dump(obj_dict, f)

def reload(self):
"""Deserializes the JSON file to __objects"""
try:
with open(self.__file_path, "r") as f:
obj_dict = json.load(f)
for key, val in obj_dict.items():
class_name = val["__class__"]
self.__objects[key] = eval(class_name)(**val)
except FileNotFoundError:
pass

def get(self, cls, id):
"""Retrieve one object by class and ID"""
return self.__objects.get("{}.{}".format(cls.__name__, id), None)

def count(self, cls=None):
"""Count number of objects in storage"""
return len(self.all(cls))

Binary file added tests/__pycache__/__init__.cpython-34.pyc
Binary file not shown.
Binary file added tests/__pycache__/test_console.cpython-34.pyc
Binary file not shown.
18 changes: 18 additions & 0 deletions tests/test_api/test_states.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import unittest
import json
from api.v1.app import app

class TestStateAPI(unittest.TestCase):
def setUp(self):
"""Set up test client"""
self.client = app.test_client()

def test_get_states(self):
"""Test GET request to /api/v1/states"""
response = self.client.get('/api/v1/states')
self.assertEqual(response.status_code, 200)
self.assertIsInstance(response.json, list)

if __name__ == '__main__':
unittest.main()

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
36 changes: 36 additions & 0 deletions tests/test_models/test_engine/test_db_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,39 @@ def test_new(self):
@unittest.skipIf(models.storage_t != 'db', "not testing db storage")
def test_save(self):
"""Test that save properly saves objects to file.json"""

#!/usr/bin/python3
"""Unittest for DBStorage"""
import unittest
from models.engine.db_storage import DBStorage
from models.state import State
from models import storage


class TestDBStorage(unittest.TestCase):
"""Test the DBStorage class"""

def setUp(self):
"""Set up test environment"""
self.storage = DBStorage()
self.storage.reload()
self.state = State(name="Nevada")
self.storage.new(self.state)
self.storage.save()

def test_get(self):
"""Test retrieving an object"""
obj = self.storage.get(State, self.state.id)
self.assertEqual(obj, self.state)

def test_count(self):
"""Test counting objects"""
count = self.storage.count()
self.assertGreater(count, 0)
state_count = self.storage.count(State)
self.assertGreaterEqual(state_count, 1)


if __name__ == "__main__":
unittest.main()

37 changes: 37 additions & 0 deletions tests/test_models/test_engine/test_file_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,40 @@ def test_save(self):
with open("file.json", "r") as f:
js = f.read()
self.assertEqual(json.loads(string), json.loads(js))




#!/usr/bin/python3
"""Unittest for FileStorage"""
import unittest
from models.engine.file_storage import FileStorage
from models.state import State


class TestFileStorage(unittest.TestCase):
"""Test the FileStorage class"""

def setUp(self):
"""Set up test environment"""
self.storage = FileStorage()
self.state = State(name="California")
self.storage.new(self.state)
self.storage.save()

def test_get(self):
"""Test retrieving an object"""
obj = self.storage.get(State, self.state.id)
self.assertEqual(obj, self.state)

def test_count(self):
"""Test counting objects"""
count = self.storage.count()
self.assertGreater(count, 0)
state_count = self.storage.count(State)
self.assertGreaterEqual(state_count, 1)


if __name__ == "__main__":
unittest.main()