From 27e03a177b985df87b8ceca83d0708de6cef92e3 Mon Sep 17 00:00:00 2001 From: Damilola-Nuga Date: Mon, 17 Feb 2025 15:53:51 -0800 Subject: [PATCH 1/4] working hard --- console.py | 9 +++++---- models/engine/file_storage.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/console.py b/console.py index 4798f9ac76b..e133363e235 100755 --- a/console.py +++ b/console.py @@ -46,10 +46,10 @@ def _key_value_parser(self, args): else: try: value = int(value) - except: + except Exception: try: value = float(value) - except: + except Exception: continue new_dict[key] = value return new_dict @@ -140,12 +140,12 @@ def do_update(self, arg): if args[2] in integers: try: args[3] = int(args[3]) - except: + except Exception: args[3] = 0 elif args[2] in floats: try: args[3] = float(args[3]) - except: + except Exception: args[3] = 0.0 setattr(models.storage.all()[k], args[2], args[3]) models.storage.all()[k].save() @@ -160,5 +160,6 @@ def do_update(self, arg): else: print("** class doesn't exist **") + if __name__ == '__main__': HBNBCommand().cmdloop() diff --git a/models/engine/file_storage.py b/models/engine/file_storage.py index c8cb8c1764d..d78a9821e5d 100755 --- a/models/engine/file_storage.py +++ b/models/engine/file_storage.py @@ -55,7 +55,7 @@ def reload(self): jo = json.load(f) for key in jo: self.__objects[key] = classes[jo[key]["__class__"]](**jo[key]) - except: + except Exception: pass def delete(self, obj=None): From cc3959f3007bfd2250867a24afdbd9e03ac73e72 Mon Sep 17 00:00:00 2001 From: Damilola-Nuga <58979551+Damilola-Nuga@users.noreply.github.com> Date: Tue, 18 Feb 2025 02:24:14 +0100 Subject: [PATCH 2/4] api stuff --- api/__init__.py | 0 api/v1/__init__.py | 0 api/v1/app.py | 43 +++++ api/v1/views/__init__.py | 17 ++ api/v1/views/amenities.py | 73 +++++++++ api/v1/views/cities.py | 83 ++++++++++ api/v1/views/documentation/amenity/delete.yml | 20 +++ api/v1/views/documentation/amenity/get.yml | 25 +++ api/v1/views/documentation/amenity/get_id.yml | 34 ++++ api/v1/views/documentation/amenity/post.yml | 17 ++ api/v1/views/documentation/amenity/put.yml | 20 +++ api/v1/views/documentation/city/delete.yml | 15 ++ api/v1/views/documentation/city/get.yml | 37 +++++ api/v1/views/documentation/city/get_id.yml | 37 +++++ api/v1/views/documentation/city/post.yml | 26 +++ api/v1/views/documentation/city/put.yml | 22 +++ .../documentation/place_amenity/delete.yml | 20 +++ .../documentation/place_amenity/get_id.yml | 34 ++++ .../documentation/place_amenity/post.yml | 22 +++ api/v1/views/documentation/places/delete.yml | 15 ++ api/v1/views/documentation/places/get.yml | 58 +++++++ api/v1/views/documentation/places/get_id.yml | 58 +++++++ api/v1/views/documentation/places/post.yml | 26 +++ api/v1/views/documentation/places/put.yml | 21 +++ api/v1/views/documentation/places/search.yml | 78 +++++++++ api/v1/views/documentation/reviews/delete.yml | 15 ++ api/v1/views/documentation/reviews/get.yml | 36 +++++ api/v1/views/documentation/reviews/get_id.yml | 36 +++++ api/v1/views/documentation/reviews/post.yml | 29 ++++ api/v1/views/documentation/reviews/put.yml | 25 +++ api/v1/views/documentation/state/delete.yml | 15 ++ api/v1/views/documentation/state/get.yml | 28 ++++ api/v1/views/documentation/state/get_id.yml | 31 ++++ api/v1/views/documentation/state/post.yml | 19 +++ api/v1/views/documentation/state/put.yml | 24 +++ api/v1/views/documentation/user/delete.yml | 15 ++ api/v1/views/documentation/user/get.yml | 34 ++++ api/v1/views/documentation/user/get_id.yml | 42 +++++ api/v1/views/documentation/user/post.yml | 21 +++ api/v1/views/documentation/user/put.yml | 18 +++ api/v1/views/index.py | 29 ++++ api/v1/views/places.py | 150 ++++++++++++++++++ api/v1/views/places_amenities.py | 57 +++++++ api/v1/views/places_reviews.py | 88 ++++++++++ api/v1/views/states.py | 71 +++++++++ api/v1/views/users.py | 75 +++++++++ 46 files changed, 1659 insertions(+) create mode 100644 api/__init__.py create mode 100644 api/v1/__init__.py create mode 100644 api/v1/app.py create mode 100644 api/v1/views/__init__.py create mode 100644 api/v1/views/amenities.py create mode 100644 api/v1/views/cities.py create mode 100644 api/v1/views/documentation/amenity/delete.yml create mode 100644 api/v1/views/documentation/amenity/get.yml create mode 100644 api/v1/views/documentation/amenity/get_id.yml create mode 100644 api/v1/views/documentation/amenity/post.yml create mode 100644 api/v1/views/documentation/amenity/put.yml create mode 100644 api/v1/views/documentation/city/delete.yml create mode 100644 api/v1/views/documentation/city/get.yml create mode 100644 api/v1/views/documentation/city/get_id.yml create mode 100644 api/v1/views/documentation/city/post.yml create mode 100644 api/v1/views/documentation/city/put.yml create mode 100644 api/v1/views/documentation/place_amenity/delete.yml create mode 100644 api/v1/views/documentation/place_amenity/get_id.yml create mode 100644 api/v1/views/documentation/place_amenity/post.yml create mode 100644 api/v1/views/documentation/places/delete.yml create mode 100644 api/v1/views/documentation/places/get.yml create mode 100644 api/v1/views/documentation/places/get_id.yml create mode 100644 api/v1/views/documentation/places/post.yml create mode 100644 api/v1/views/documentation/places/put.yml create mode 100644 api/v1/views/documentation/places/search.yml create mode 100644 api/v1/views/documentation/reviews/delete.yml create mode 100644 api/v1/views/documentation/reviews/get.yml create mode 100644 api/v1/views/documentation/reviews/get_id.yml create mode 100644 api/v1/views/documentation/reviews/post.yml create mode 100644 api/v1/views/documentation/reviews/put.yml create mode 100644 api/v1/views/documentation/state/delete.yml create mode 100644 api/v1/views/documentation/state/get.yml create mode 100644 api/v1/views/documentation/state/get_id.yml create mode 100644 api/v1/views/documentation/state/post.yml create mode 100644 api/v1/views/documentation/state/put.yml create mode 100644 api/v1/views/documentation/user/delete.yml create mode 100644 api/v1/views/documentation/user/get.yml create mode 100644 api/v1/views/documentation/user/get_id.yml create mode 100644 api/v1/views/documentation/user/post.yml create mode 100644 api/v1/views/documentation/user/put.yml create mode 100644 api/v1/views/index.py create mode 100644 api/v1/views/places.py create mode 100644 api/v1/views/places_amenities.py create mode 100644 api/v1/views/places_reviews.py create mode 100644 api/v1/views/states.py create mode 100644 api/v1/views/users.py diff --git a/api/__init__.py b/api/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/api/v1/__init__.py b/api/v1/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/api/v1/app.py b/api/v1/app.py new file mode 100644 index 00000000000..87d80cddbea --- /dev/null +++ b/api/v1/app.py @@ -0,0 +1,43 @@ +#!/usr/bin/python3 +""" +This module contains the principal application +""" +from models import storage +from api.v1.views import app_views +from flask import Flask, make_response, jsonify +from os import getenv +from flask_cors import CORS +from flasgger import Swagger + +app = Flask(__name__) +app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True +app.register_blueprint(app_views) +cors = CORS(app, resources={r"/api/*": {"origins": "0.0.0.0"}}) + + +@app.teardown_appcontext +def close_db(obj): + """ calls methods close() """ + storage.close() + + +@app.errorhandler(404) +def page_not_foun(error): + """ Loads a custom 404 page not found """ + return make_response(jsonify({"error": "Not found"}), 404) + + +app.config['SWAGGER'] = { + 'title': 'AirBnB clone - RESTful API', + 'description': 'This is the api that was created for the hbnb restful api project,\ + all the documentation will be shown below', + 'uiversion': 3} + +Swagger(app) + +if __name__ == "__main__": + + host = getenv('HBNB_API_HOST', default='0.0.0.0') + port = getenv('HBNB_API_PORT', default=5000) + + app.run(host, int(port), threaded=True) diff --git a/api/v1/views/__init__.py b/api/v1/views/__init__.py new file mode 100644 index 00000000000..87a3da99aa7 --- /dev/null +++ b/api/v1/views/__init__.py @@ -0,0 +1,17 @@ + +#!/usr/bin/python3 +"""Init file for views module""" +from flask import Blueprint + + +app_views = Blueprint('app_views', __name__, url_prefix='/api/v1') + + +from api.v1.views.index import * +from api.v1.views.states import * +from api.v1.views.cities import * +from api.v1.views.amenities import * +from api.v1.views.users import * +from api.v1.views.places import * +from api.v1.views.places_reviews import * +from api.v1.views.places_amenities import * diff --git a/api/v1/views/amenities.py b/api/v1/views/amenities.py new file mode 100644 index 00000000000..4e8700ac986 --- /dev/null +++ b/api/v1/views/amenities.py @@ -0,0 +1,73 @@ +#!/usr/bin/python3 +""" +This file contains the Amenity module +""" +from api.v1.views import app_views +from flask import jsonify, abort, request, make_response +from models import storage +from models.amenity import Amenity +from flasgger.utils import swag_from + + +@app_views.route('/amenities', methods=['GET'], strict_slashes=False) +@swag_from('documentation/amenity/get.yml', methods=['GET']) +def get_all_amenities(): + """ get amenities by id """ + all_list = [obj.to_dict() for obj in storage.all(Amenity).values()] + return jsonify(all_list) + + +@app_views.route('/amenities/', methods=['GET'], + strict_slashes=False) +@swag_from('documentation/amenity/get_id.yml', methods=['GET']) +def get_amenity(amenity_id): + """ get amenity by id""" + amenity = storage.get(Amenity, amenity_id) + if amenity is None: + abort(404) + return jsonify(amenity.to_dict()) + + +@app_views.route('/amenities/', methods=['DELETE'], + strict_slashes=False) +@swag_from('documentation/amenity/delete.yml', methods=['DELETE']) +def del_amenity(amenity_id): + """ delete amenity by id""" + amenity = storage.get(Amenity, amenity_id) + if amenity is None: + abort(404) + amenity.delete() + storage.save() + return jsonify({}) + + +@app_views.route('/amenities/', methods=['POST'], + strict_slashes=False) +@swag_from('documentation/amenity/post.yml', methods=['POST']) +def create_obj_amenity(): + """ create new instance """ + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + if 'name' not in request.get_json(): + return make_response(jsonify({"error": "Missing name"}), 400) + js = request.get_json() + obj = Amenity(**js) + obj.save() + return (jsonify(obj.to_dict()), 201) + + +@app_views.route('/amenities/', methods=['PUT'], + strict_slashes=False) +@swag_from('documentation/amenity/put.yml', methods=['PUT']) +def post_amenity(amenity_id): + """ """ + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + obj = storage.get(Amenity, amenity_id) + if obj is None: + abort(404) + for key, value in request.get_json().items(): + if key not in ['id', 'created_at', 'updated_at']: + setattr(obj, key, value) + storage.save() + return jsonify(obj.to_dict()) diff --git a/api/v1/views/cities.py b/api/v1/views/cities.py new file mode 100644 index 00000000000..915eb3fe4ac --- /dev/null +++ b/api/v1/views/cities.py @@ -0,0 +1,83 @@ +#!/usr/bin/python3 +""" +This file contains the City module +""" +from api.v1.views import app_views +from flask import jsonify, abort, request, make_response +from models import storage +from models.state import State +from models.city import City +from flasgger.utils import swag_from + + +@app_views.route('/states//cities', + methods=['GET'], strict_slashes=False) +@swag_from('documentation/city/get.yml', methods=['GET']) +def get_cities(state_id): + """ Gets cities for state_id """ + state = storage.get(State, state_id) + if state is None: + abort(404) + list_cities = [obj.to_dict() for obj in state.cities] + return jsonify(list_cities) + + +@app_views.route('/cities/', methods=['GET'], + strict_slashes=False) +@swag_from('documentation/city/get_id.yml', methods=['GET']) +def get_city(city_id): + """ get city by id""" + city = storage.get(City, city_id) + if city is None: + abort(404) + return jsonify(city.to_dict()) + + +@app_views.route('/cities/', methods=['DELETE'], + strict_slashes=False) +@swag_from('documentation/city/delete.yml', methods=['DELETE']) +def del_city(city_id): + """ delete city by id""" + city = storage.get(City, city_id) + if city is None: + abort(404) + city.delete() + storage.save() + return jsonify({}) + + +@app_views.route('/states//cities', methods=['POST'], + strict_slashes=False) +@swag_from('documentation/city/post.yml', methods=['POST']) +def create_obj_city(state_id): + """ create new instance """ + state = storage.get(State, state_id) + if state is None: + abort(404) + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + if 'name' not in request.get_json(): + return make_response(jsonify({"error": "Missing name"}), 400) + + js = request.get_json() + obj = City(**js) + obj.state_id = state.id + obj.save() + return jsonify(obj.to_dict()), 201 + + +@app_views.route('/cities/', methods=['PUT'], + strict_slashes=False) +@swag_from('documentation/city/put.yml', methods=['PUT']) +def post_city(city_id): + """ """ + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + obj = storage.get(City, city_id) + if obj is None: + abort(404) + for key, value in request.get_json().items(): + if key not in ['id', 'state_id', 'created_at', 'updated_at']: + setattr(obj, key, value) + storage.save() + return jsonify(obj.to_dict()) diff --git a/api/v1/views/documentation/amenity/delete.yml b/api/v1/views/documentation/amenity/delete.yml new file mode 100644 index 00000000000..4f80783eb53 --- /dev/null +++ b/api/v1/views/documentation/amenity/delete.yml @@ -0,0 +1,20 @@ +Removes an amenity by id +--- +tags: + - Amenities +parameters: + - name: place_id + in: path + type: string + required: true + description: the unique id of the place to be delete + - name: amenity_id + in: path + type: string + required: true + description: amenity id to remove +responses: + 404: + description: place not found / amenity not found / amenity not found in place 😳 + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/amenity/get.yml b/api/v1/views/documentation/amenity/get.yml new file mode 100644 index 00000000000..2d09b5cf118 --- /dev/null +++ b/api/v1/views/documentation/amenity/get.yml @@ -0,0 +1,25 @@ +GET method, get all amenities of a place +--- +tags: + - Amenities +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + name: + type: string + description: Place name diff --git a/api/v1/views/documentation/amenity/get_id.yml b/api/v1/views/documentation/amenity/get_id.yml new file mode 100644 index 00000000000..a399f61a88f --- /dev/null +++ b/api/v1/views/documentation/amenity/get_id.yml @@ -0,0 +1,34 @@ +GET method, retrieve a amenity base on amenity_id +--- +tags: + - Amenities +parameters: + - name: amenity_id + in: path + type: string + required: true + description: amenity id +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + name: + type: string + description: Place name + + 404: + description: amenity not found diff --git a/api/v1/views/documentation/amenity/post.yml b/api/v1/views/documentation/amenity/post.yml new file mode 100644 index 00000000000..6ee7742d023 --- /dev/null +++ b/api/v1/views/documentation/amenity/post.yml @@ -0,0 +1,17 @@ +Post a new amenity. +--- +tags: + - Amenities +parameters: + - name: amenity_id + in: body + requires: + - name + properties: + name: + type: string +responses: + 400: + description: Not Valid JSON 😳 + 201: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/amenity/put.yml b/api/v1/views/documentation/amenity/put.yml new file mode 100644 index 00000000000..dfc5bbcce0a --- /dev/null +++ b/api/v1/views/documentation/amenity/put.yml @@ -0,0 +1,20 @@ +Update a amenity instance by id +--- +tags: + - Amenities +parameters: + - name: amenity_id + in: path + type: string + required: true + description: the unique id of the amenity to be update + - name: update_request + in: body + required: true +responses: + 404: + description: State not found 😳 + 400: + description: Not a Valid JSON + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/city/delete.yml b/api/v1/views/documentation/city/delete.yml new file mode 100644 index 00000000000..6660688a609 --- /dev/null +++ b/api/v1/views/documentation/city/delete.yml @@ -0,0 +1,15 @@ +DELETE method, delete place instance by id +--- +tags: + - Cities +parameters: + - name: city_id + in: path + type: string + required: true + description: the unique id of the city to be delete +responses: + 404: + description: City not found 😳 + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/city/get.yml b/api/v1/views/documentation/city/get.yml new file mode 100644 index 00000000000..08906a8182c --- /dev/null +++ b/api/v1/views/documentation/city/get.yml @@ -0,0 +1,37 @@ +GET method, get cities list on the state_id +--- +tags: + - Cities +parameters: + - name: city_id + in: path + type: string + required: true + description: the unique id of the state to be listed +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + name: + type: string + description: Place name + state_id: + type: string + description: city id + + 404: + description: No state linked to id diff --git a/api/v1/views/documentation/city/get_id.yml b/api/v1/views/documentation/city/get_id.yml new file mode 100644 index 00000000000..72fcb489bed --- /dev/null +++ b/api/v1/views/documentation/city/get_id.yml @@ -0,0 +1,37 @@ +GET method, retrieve a city base on state_id +--- +tags: + - Cities +parameters: + - name: city_id + in: path + type: string + required: true + description: the unique id of the city to be listed +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + name: + type: string + description: Place name + state_id: + type: string + description: city id + + 404: + description: City not found diff --git a/api/v1/views/documentation/city/post.yml b/api/v1/views/documentation/city/post.yml new file mode 100644 index 00000000000..f1248409c58 --- /dev/null +++ b/api/v1/views/documentation/city/post.yml @@ -0,0 +1,26 @@ + Post a new city. + --- + tags: + - Cities + parameters: + - state_id: + in: path + type: string + required: true + description: city state id + - name: body_request + in: body + required: true + requires: + - name + properties: + name: + type: string + + responses: + 404: + description: State not found!!!! + 400: + description: Missing name or Not Valid JSON 😳 + 201: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/city/put.yml b/api/v1/views/documentation/city/put.yml new file mode 100644 index 00000000000..848b7cc7105 --- /dev/null +++ b/api/v1/views/documentation/city/put.yml @@ -0,0 +1,22 @@ +Update a city instance by id +--- +tags: + - Cities +parameters: + - name: city_id + in: path + type: string + required: true + description: the unique id of the city to be update + - name: update_request + in: body + required: true + + +responses: + 404: + description: State not found 😳 + 400: + description: Not a Valid JSON + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/place_amenity/delete.yml b/api/v1/views/documentation/place_amenity/delete.yml new file mode 100644 index 00000000000..09f8e877bb7 --- /dev/null +++ b/api/v1/views/documentation/place_amenity/delete.yml @@ -0,0 +1,20 @@ +Removes an amenity by id +--- +tags: + - Place_Amenities +parameters: + - name: place_id + in: path + type: string + required: true + description: the unique id of the place with the amenity to be delete + - name: amenity_id + in: path + type: string + required: true + description: amenity id to remove +responses: + 404: + description: place not found / amenity not found / amenity not found in place 😳 + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/place_amenity/get_id.yml b/api/v1/views/documentation/place_amenity/get_id.yml new file mode 100644 index 00000000000..2fec28b85db --- /dev/null +++ b/api/v1/views/documentation/place_amenity/get_id.yml @@ -0,0 +1,34 @@ +GET method, retrieve a amenities base on place +--- +tags: + - Place_Amenities +parameters: + - name: amenity_id + in: path + type: string + required: true + description: amenity id +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + name: + type: string + description: Place name + + 404: + description: Place not found diff --git a/api/v1/views/documentation/place_amenity/post.yml b/api/v1/views/documentation/place_amenity/post.yml new file mode 100644 index 00000000000..44f70759103 --- /dev/null +++ b/api/v1/views/documentation/place_amenity/post.yml @@ -0,0 +1,22 @@ +Links a review to a place. +--- +tags: + - Place_Amenities +parameters: + - name: place_id + in: path + type: string + required: true + description: Amenity id + - name: amenity_id + in: path + type: string + required: true + description: id of the place to be linked +responses: + 404: + description: Not found + 201: + description: Successful request ✔️ + 201: + description: Amenity already linked to a place diff --git a/api/v1/views/documentation/places/delete.yml b/api/v1/views/documentation/places/delete.yml new file mode 100644 index 00000000000..def87630cb9 --- /dev/null +++ b/api/v1/views/documentation/places/delete.yml @@ -0,0 +1,15 @@ +DELETE method, delete place instance by id +--- +tags: + - Places +parameters: + - name: place_id + in: path + type: string + required: true + description: the unique id of the place to be delete +responses: + 404: + description: Place not found 😳 + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/places/get.yml b/api/v1/views/documentation/places/get.yml new file mode 100644 index 00000000000..619a12a700c --- /dev/null +++ b/api/v1/views/documentation/places/get.yml @@ -0,0 +1,58 @@ +GET method, lists all places of a city +--- +tags: + - Places +parameters: + - name: city_id + in: path + type: string + required: true + description: the unique id of the city to be listed +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + updated_at: + type: string + description: datetime of instance update + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + description: + type: string + description: Place description + latitude: + type: number + description: Place latitude + longitude: + type: number + description: Place longitude + max_guest: + type: integer + description: Max guests + name: + type: string + description: Place name + number_bathrooms: + type: integer + description: Number of bathrooms + number_rooms: + type: integer + description: Number of rooms + price_by_night: + type: number + description: Price by night + user_id: + type: string + description: Owner id + + 404: + description: City not found \ No newline at end of file diff --git a/api/v1/views/documentation/places/get_id.yml b/api/v1/views/documentation/places/get_id.yml new file mode 100644 index 00000000000..61d8c1d01cb --- /dev/null +++ b/api/v1/views/documentation/places/get_id.yml @@ -0,0 +1,58 @@ +GET method, retrieve a place +--- +tags: + - Places +parameters: + - name: place_id + in: path + type: string + required: true + description: the unique id of the place to be listed +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + updated_at: + type: string + description: datetime of instance update + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + description: + type: string + description: Place description + latitude: + type: number + description: Place latitude + longitude: + type: number + description: Place longitude + max_guest: + type: integer + description: Max guests + name: + type: string + description: Place name + number_bathrooms: + type: integer + description: Number of bathrooms + number_rooms: + type: integer + description: Number of rooms + price_by_night: + type: number + description: Price by night + user_id: + type: string + description: Owner id + + 404: + description: City not found diff --git a/api/v1/views/documentation/places/post.yml b/api/v1/views/documentation/places/post.yml new file mode 100644 index 00000000000..57b0c209fc3 --- /dev/null +++ b/api/v1/views/documentation/places/post.yml @@ -0,0 +1,26 @@ + Posts a new state. + --- + tags: + - Places + parameters: + - name: city_id + in: path + required: true + description: city id to be linked + - name: user_id and name + in: body + required: true + requires: + - user_id + - name + properties: + user_id: + type: string + name: + type: string + + responses: + 400: + description: Missing name or Not Valid JSON 😳 + 201: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/places/put.yml b/api/v1/views/documentation/places/put.yml new file mode 100644 index 00000000000..0372c7f8d31 --- /dev/null +++ b/api/v1/views/documentation/places/put.yml @@ -0,0 +1,21 @@ +Update a state instance by id +--- +tags: + - Places +parameters: + - name: place_id + in: path + type: string + required: true + description: the unique id of the place to be update + - name: request + in: body + required: true + +responses: + 404: + description: State not found 😳 + 400: + description: Not a Valid JSON + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/places/search.yml b/api/v1/views/documentation/places/search.yml new file mode 100644 index 00000000000..ce85297e514 --- /dev/null +++ b/api/v1/views/documentation/places/search.yml @@ -0,0 +1,78 @@ +Search places +--- +tags: + - Places +parameters: + - name: user_id and name + in: body + required: false + description: required ids + requieres: + - states + - cities + - amenities + properties: + states: + type: array + items: + type: string + cities: + type: array + items: + type: string + amenities: + type: array + items: + type: string + +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + updated_at: + type: string + description: datetime of instance update + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + description: + type: string + description: Place description + latitude: + type: number + description: Place latitude + longitude: + type: number + description: Place longitude + max_guest: + type: integer + description: Max guests + name: + type: string + description: Place name + number_bathrooms: + type: integer + description: Number of bathrooms + number_rooms: + type: integer + description: Number of rooms + price_by_night: + type: number + description: Price by night + user_id: + type: string + description: Owner id + + 404: + description: Resource not found + + 400: + description: Not a valid JSON \ No newline at end of file diff --git a/api/v1/views/documentation/reviews/delete.yml b/api/v1/views/documentation/reviews/delete.yml new file mode 100644 index 00000000000..01772caa135 --- /dev/null +++ b/api/v1/views/documentation/reviews/delete.yml @@ -0,0 +1,15 @@ +Removes a review by id +--- +tags: + - Reviews +parameters: + - name: review_id + in: path + type: string + required: true + description: the unique id of the review to be delete +responses: + 404: + description: Review not found in place 😳 + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/reviews/get.yml b/api/v1/views/documentation/reviews/get.yml new file mode 100644 index 00000000000..b8879abc6c4 --- /dev/null +++ b/api/v1/views/documentation/reviews/get.yml @@ -0,0 +1,36 @@ +GET method, get all reviews of a place +--- +tags: + - Reviews +parameters: + - name: place_id + in: path + type: string + required: true + description: place id +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + text: + type: string + description: Place description + place_id: + type: string + description: Place id + 404: + description: Place not found \ No newline at end of file diff --git a/api/v1/views/documentation/reviews/get_id.yml b/api/v1/views/documentation/reviews/get_id.yml new file mode 100644 index 00000000000..bfcf3a7de75 --- /dev/null +++ b/api/v1/views/documentation/reviews/get_id.yml @@ -0,0 +1,36 @@ +GET method, retrieve a review +--- +tags: + - Reviews +parameters: + - name: review_id + in: path + type: string + required: true + description: Review id +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + text: + type: string + description: Place description + place_id: + type: string + description: Place id + 404: + description: Place not found diff --git a/api/v1/views/documentation/reviews/post.yml b/api/v1/views/documentation/reviews/post.yml new file mode 100644 index 00000000000..62b04cc9981 --- /dev/null +++ b/api/v1/views/documentation/reviews/post.yml @@ -0,0 +1,29 @@ +Post a new review. +--- +tags: + - Reviews +parameters: + - name: review_id + in: path + type: string + required: true + description: review id + - name: user_id and text + in: body + required: true + requires: + - user_id + - text + properties: + user_id: + type: string + text: + type: string + +responses: + 404: + description: review not found 😳 + 400: + description: Not a Valid JSON + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/reviews/put.yml b/api/v1/views/documentation/reviews/put.yml new file mode 100644 index 00000000000..bc941f3c63d --- /dev/null +++ b/api/v1/views/documentation/reviews/put.yml @@ -0,0 +1,25 @@ +Update a review instance by id +--- +tags: + - Reviews +parameters: + - name: review_id + in: path + type: string + required: true + description: the unique id of the review to be update + - name: update_request + in: body + required: true + requieres: + - parameters + properties: + parameters: + type: string +responses: + 404: + description: review not found 😳 + 400: + description: Not a Valid JSON + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/state/delete.yml b/api/v1/views/documentation/state/delete.yml new file mode 100644 index 00000000000..49f85f6d25e --- /dev/null +++ b/api/v1/views/documentation/state/delete.yml @@ -0,0 +1,15 @@ +DELETE method, delete instance my id +--- +tags: + - States +parameters: + - name: state_id + in: path + type: string + required: true + description: the unique id of the state to delete +responses: + 404: + description: State not found 😳 + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/state/get.yml b/api/v1/views/documentation/state/get.yml new file mode 100644 index 00000000000..816b171f3c9 --- /dev/null +++ b/api/v1/views/documentation/state/get.yml @@ -0,0 +1,28 @@ +GET method, lists all states +--- +tags: + - States +parameters: + - name: no needed + in: path + type: string + required: false + description: lists all states +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + id: + type: string + description: The unique id of the state instance + name: + type: string + description: The State name diff --git a/api/v1/views/documentation/state/get_id.yml b/api/v1/views/documentation/state/get_id.yml new file mode 100644 index 00000000000..b4fa3463b7f --- /dev/null +++ b/api/v1/views/documentation/state/get_id.yml @@ -0,0 +1,31 @@ +GET method, lists state by unique id +--- +tags: + - States +parameters: + - name: state_id + in: path + type: string + required: false + description: the unique id of the state +responses: + 404: + description: State not found + 200: + description: Successful request + schema: + properties: + __class__: + type: string + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: datetime of instance update + id: + type: string + description: The unique id of the state instance + name: + type: string + description: State name diff --git a/api/v1/views/documentation/state/post.yml b/api/v1/views/documentation/state/post.yml new file mode 100644 index 00000000000..4ddf490ab39 --- /dev/null +++ b/api/v1/views/documentation/state/post.yml @@ -0,0 +1,19 @@ + Posts a new state. + --- + tags: + - States + parameters: + - name: request + in: body + required: true + requires: + - name + properties: + name: + type: string + + responses: + 400: + description: Missing name or Not Valid JSON 😳 + 201: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/state/put.yml b/api/v1/views/documentation/state/put.yml new file mode 100644 index 00000000000..11e11944b3e --- /dev/null +++ b/api/v1/views/documentation/state/put.yml @@ -0,0 +1,24 @@ +Update a state instance by id +--- +tags: + - States +parameters: + - name: state_id + in: path + type: string + required: true + description: the unique id of the state to update + - name: request + in: body + required: true + requires: + - name + properties: + name: + type: string + +responses: + 404: + description: State not found 😳 + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/user/delete.yml b/api/v1/views/documentation/user/delete.yml new file mode 100644 index 00000000000..e6111b8c91b --- /dev/null +++ b/api/v1/views/documentation/user/delete.yml @@ -0,0 +1,15 @@ +Removes an user by id +--- +tags: + - Users +parameters: + - name: user_id + in: path + type: string + required: false + description: the unique id of the user +responses: + 404: + description: User not found 😳 + 200: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/user/get.yml b/api/v1/views/documentation/user/get.yml new file mode 100644 index 00000000000..8a249ec8f0b --- /dev/null +++ b/api/v1/views/documentation/user/get.yml @@ -0,0 +1,34 @@ +GET method, get all users +--- +tags: + - Users +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + email: + type: string + description: User email + password: + type: string + description: User password + first_name: + type: string + description: User first name + last_name: + type: string + description: User last name diff --git a/api/v1/views/documentation/user/get_id.yml b/api/v1/views/documentation/user/get_id.yml new file mode 100644 index 00000000000..58a576c16fb --- /dev/null +++ b/api/v1/views/documentation/user/get_id.yml @@ -0,0 +1,42 @@ +GET method, get user by id +--- +tags: + - Users +parameters: + - name: user_id + in: path + type: string + required: true + description: User id to retrieve +responses: + 200: + description: Succsesful resquest + schema: + type: array + items: + properties: + __class__: + type: "string" + created_at: + type: string + description: datetime of instance creation + updated_at: + type: string + description: time of last update of the instance + id: + type: string + description: The unique id of the state instance + email: + type: string + description: User email + password: + type: string + description: User password + first_name: + type: string + description: User first name + last_name: + type: string + description: User last name + 404: + description: User not found! \ No newline at end of file diff --git a/api/v1/views/documentation/user/post.yml b/api/v1/views/documentation/user/post.yml new file mode 100644 index 00000000000..6e95ff2a5f1 --- /dev/null +++ b/api/v1/views/documentation/user/post.yml @@ -0,0 +1,21 @@ +Post a new amenity. +--- +tags: + - Users +parameters: + - name: user and pasword + in: body + required: true + requires: + - email: + - password: + properties: + email: + type: string + password: + type: string +responses: + 400: + description: Missing email/password or Not Valid JSON 😳 + 201: + description: Successful request ✔️ diff --git a/api/v1/views/documentation/user/put.yml b/api/v1/views/documentation/user/put.yml new file mode 100644 index 00000000000..2fa8dacd981 --- /dev/null +++ b/api/v1/views/documentation/user/put.yml @@ -0,0 +1,18 @@ +Update a user instance by id +--- +tags: + - Users +parameters: + - name: user_id + in: path + type: string + required: true + description: the unique id of the user to be update + - name: update_request + in: body + required: true +responses: + 404: + description: User not found 😳 + 200: + description: Successful request ✔️ diff --git a/api/v1/views/index.py b/api/v1/views/index.py new file mode 100644 index 00000000000..6d34db8feb1 --- /dev/null +++ b/api/v1/views/index.py @@ -0,0 +1,29 @@ +#!/usr/bin/python3 +""" +This module contains endpoint(route) status +""" +from models import storage +from flask import Flask +from api.v1.views import app_views +from flask import jsonify + + +@app_views.route('/status', strict_slashes=False) +def status(): + """ + Returns a JSON status + """ + return jsonify({"status": "OK"}) + + +@app_views.route('/stats', strict_slashes=False) +def count(): + """ + Retrieves the number of each objects by type + """ + return jsonify({"amenities": storage.count("Amenity"), + "cities": storage.count("City"), + "places": storage.count("Place"), + "reviews": storage.count("Review"), + "states": storage.count("State"), + "users": storage.count("User")}) diff --git a/api/v1/views/places.py b/api/v1/views/places.py new file mode 100644 index 00000000000..5e32ea3ecae --- /dev/null +++ b/api/v1/views/places.py @@ -0,0 +1,150 @@ +#!/usr/bin/python3 +""" +This file contains the Place module +""" +from api.v1.views import app_views +from flask import jsonify, abort, request, make_response +from models import storage +from models.place import Place +from models.city import City +from models.user import User +from models.amenity import Amenity +from models.state import State +from flasgger.utils import swag_from + + +@app_views.route('/cities//places', + methods=['GET'], strict_slashes=False) +@swag_from('documentation/places/get.yml', methods=['GET']) +def get_all_places(city_id): + """ list cities by id """ + city = storage.get(City, city_id) + if city is None: + abort(404) + places = [obj.to_dict() for obj in city.places] + return jsonify(places) + + +@app_views.route('/places/', methods=['GET'], + strict_slashes=False) +@swag_from('documentation/places/get_id.yml', methods=['GET']) +def get_place(place_id): + """ get place by id """ + place = storage.get(Place, place_id) + if place is None: + abort(404) + return jsonify(place.to_dict()) + + +@app_views.route('/places/', methods=['DELETE'], + strict_slashes=False) +@swag_from('documentation/places/delete.yml', methods=['DELETE']) +def del_place(place_id): + """ delete place by id """ + place = storage.get(Place, place_id) + if place is None: + abort(404) + place.delete() + storage.save() + return jsonify({}) + + +@app_views.route('/cities//places', methods=['POST'], + strict_slashes=False) +@swag_from('documentation/places/post.yml', methods=['POST']) +def create_obj_place(city_id): + """ create new instance """ + city = storage.get(City, city_id) + if city is None: + abort(404) + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + if 'user_id' not in request.get_json(): + return make_response(jsonify({"error": "Missing user_id"}), 400) + if 'name' not in request.get_json(): + return make_response(jsonify({"error": "Missing name"}), 400) + kwargs = request.get_json() + kwargs['city_id'] = city_id + user = storage.get(User, kwargs['user_id']) + if user is None: + abort(404) + obj = Place(**kwargs) + obj.save() + return (jsonify(obj.to_dict()), 201) + + +@app_views.route('/places/', methods=['PUT'], + strict_slashes=False) +@swag_from('documentation/places/put.yml', methods=['PUT']) +def post_place(place_id): + """ update by id """ + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + obj = storage.get(Place, place_id) + if obj is None: + abort(404) + for key, value in request.get_json().items(): + if key not in ['id', 'user_id', 'city_id', 'created_at', 'updated']: + setattr(obj, key, value) + storage.save() + return jsonify(obj.to_dict()) + + +@app_views.route('/places_search', methods=['POST'], + strict_slashes=False) +@swag_from('documentation/places/search.yml', methods=['POST']) +def search_places_by_id(): + """ search places by id """ + if request.get_json() is None: + return make_response(jsonify({"error": "Not a JSON"}), 400) + + data = request.get_json() + + if data and len(data): + states = data.get('states', None) + cities = data.get('cities', None) + amenities = data.get('amenities', None) + + if not data or not len(data) or ( + not states and + not cities and + not amenities): + places = storage.all(Place).values() + list_places = [] + for place in places: + list_places.append(place.to_dict()) + return jsonify(list_places) + + list_places = [] + if states: + states_obj = [storage.get(State, s_id) for s_id in states] + for state in states_obj: + if state: + for city in state.cities: + if city: + for place in city.places: + list_places.append(place) + + if cities: + city_obj = [storage.get(City, c_id) for c_id in cities] + for city in city_obj: + if city: + for place in city.places: + if place not in list_places: + list_places.append(place) + + if amenities: + if not list_places: + list_places = storage.all(Place).values() + amenities_obj = [storage.get(Amenity, a_id) for a_id in amenities] + list_places = [place for place in list_places + if all([am in place.amenities + for am in amenities_obj])] + + places = [] + for p in list_places: + d = p.to_dict() + d.pop('amenities', None) + places.append(d) + + return jsonify(places) diff --git a/api/v1/views/places_amenities.py b/api/v1/views/places_amenities.py new file mode 100644 index 00000000000..2c3dc28c59f --- /dev/null +++ b/api/v1/views/places_amenities.py @@ -0,0 +1,57 @@ +#!/usr/bin/python3 +"""places_amenities.py""" +import os +from api.v1.views import app_views +from flask import abort, jsonify, make_response, request +from models import storage +from models.amenity import Amenity +from models.place import Place +from flasgger.utils import swag_from + + +@app_views.route('/places//amenities', methods=['GET'], + strict_slashes=False) +@swag_from('documentation/place_amenity/get_id.yml', methods=['GET']) +def get_amenities(place_id): + """ retrieves all amenities from a place """ + place = storage.get(Place, place_id) + if place is None: + abort(404) + amenities = [obj.to_dict() for obj in place.amenities] + return jsonify(amenities) + + +@app_views.route('/places//amenities/', + methods=['DELETE'], strict_slashes=False) +@swag_from('documentation/place_amenity/delete.yml', methods=['DELETE']) +def delete_amenity(place_id, amenity_id): + """ delete amenity from place """ + place = storage.get(Place, place_id) + if place is None: + abort(404) + amenity = storage.get(Amenity, amenity_id) + if amenity is None: + abort(404) + if amenity not in place.amenities: + abort(404) + place.amenities.remove(amenity) + storage.save() + return jsonify({}) + + +@app_views.route('/places//amenities/', + methods=['POST'], strict_slashes=False) +@swag_from('documentation/place_amenity/post.yml', methods=['POST']) +def post_amenity2(place_id, amenity_id): + """ post amenity by id """ + place = storage.get(Place, place_id) + if place is None: + abort(404) + amenity = storage.get(Amenity, amenity_id) + if amenity is None: + abort(404) + if amenity in place.amenities: + return (jsonify(amenity.to_dict()), 200) + place.amenities.append(obj) + storage.save() + return (jsonify(amenity.to_dict(), 201)) diff --git a/api/v1/views/places_reviews.py b/api/v1/views/places_reviews.py new file mode 100644 index 00000000000..b8af2a7d683 --- /dev/null +++ b/api/v1/views/places_reviews.py @@ -0,0 +1,88 @@ +#!/usr/bin/python3 +""" +This file contains the Review module +""" +from api.v1.views import app_views +from flask import jsonify, abort, request, make_response +from models import storage +from models.place import Place +from models.review import Review +from models.user import User +from flasgger.utils import swag_from + + +@app_views.route('/places//reviews', + methods=['GET'], strict_slashes=False) +@swag_from('documentation/reviews/get.yml', methods=['GET']) +def get_all_reviews(place_id): + """ get reviews from a spcific place """ + place = storage.get(Place, place_id) + if place is None: + abort(404) + reviews = [obj.to_dict() for obj in place.reviews] + return jsonify(reviews) + + +@app_views.route('/reviews/', methods=['GET'], + strict_slashes=False) +@swag_from('documentation/reviews/get_id.yml', methods=['GET']) +def get_review(review_id): + """ get review by id""" + review = storage.get(Review, review_id) + if review is None: + abort(404) + return jsonify(review.to_dict()) + + +@app_views.route('/reviews/', methods=['DELETE'], + strict_slashes=False) +@swag_from('documentation/reviews/delete.yml', methods=['DELETE']) +def del_review(review_id): + """ delete review by id""" + review = storage.get(Review, review_id) + if review is None: + abort(404) + review.delete() + storage.save() + return jsonify({}) + + +@app_views.route('/places//reviews', methods=['POST'], + strict_slashes=False) +@swag_from('documentation/reviews/post.yml', methods=['POST']) +def create_obj_review(place_id): + """ create new instance """ + place = storage.get(Place, place_id) + if place is None: + abort(404) + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + if 'user_id' not in request.get_json(): + return make_response(jsonify({"error": "Missing user_id"}), 400) + if 'text' not in request.get_json(): + return make_response(jsonify({"error": "Missing text"}), 400) + kwargs = request.get_json() + kwargs['place_id'] = place_id + user = storage.get(User, kwargs['user_id']) + if user is None: + abort(404) + obj = Review(**kwargs) + obj.save() + return (jsonify(obj.to_dict()), 201) + + +@app_views.route('/reviews/', methods=['PUT'], + strict_slashes=False) +@swag_from('documentation/reviews/put.yml', methods=['PUT']) +def post_review(review_id): + """ updates by id """ + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + obj = storage.get(Review, review_id) + if obj is None: + abort(404) + for key, value in request.get_json().items(): + if key not in ['id', 'user_id', 'place_id', 'created_at', 'updated']: + setattr(obj, key, value) + storage.save() + return jsonify(obj.to_dict()) diff --git a/api/v1/views/states.py b/api/v1/views/states.py new file mode 100644 index 00000000000..fc7e318a3d7 --- /dev/null +++ b/api/v1/views/states.py @@ -0,0 +1,71 @@ +#!/usr/bin/python3 +"""State module""" +from api.v1.views import app_views +from flask import jsonify, abort, request, make_response +from models import storage +from models.state import State +from flasgger.utils import swag_from + + +@app_views.route('/states', methods=['GET'], strict_slashes=False) +@swag_from('documentation/state/get.yml', methods=['GET']) +def get_all(): + """ get all by id """ + all_list = [obj.to_dict() for obj in storage.all(State).values()] + return jsonify(all_list) + + +@app_views.route('/states/', methods=['GET'], + strict_slashes=False) +@swag_from('documentation/state/get_id.yml', methods=['GET']) +def get_method_state(state_id): + """ get state by id""" + state = storage.get(State, state_id) + if state is None: + abort(404) + return jsonify(state.to_dict()) + + +@app_views.route('/states/', methods=['DELETE'], + strict_slashes=False) +@swag_from('documentation/state/delete.yml', methods=['DELETE']) +def del_method(state_id): + """ delete state by id""" + state = storage.get(State, state_id) + if state is None: + abort(404) + state.delete() + storage.save() + return jsonify({}) + + +@app_views.route('/states/', methods=['POST'], + strict_slashes=False) +@swag_from('documentation/state/post.yml', methods=['POST']) +def create_obj(): + """ create new instance """ + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + if 'name' not in request.get_json(): + return make_response(jsonify({"error": "Missing name"}), 400) + js = request.get_json() + obj = State(**js) + obj.save() + return jsonify(obj.to_dict()), 201 + + +@app_views.route('/states/', methods=['PUT'], + strict_slashes=False) +@swag_from('documentation/state/put.yml', methods=['PUT']) +def post_method(state_id): + """ post method """ + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + obj = storage.get(State, state_id) + if obj is None: + abort(404) + for key, value in request.get_json().items(): + if key not in ['id', 'created_at', 'updated']: + setattr(obj, key, value) + storage.save() + return jsonify(obj.to_dict()) diff --git a/api/v1/views/users.py b/api/v1/views/users.py new file mode 100644 index 00000000000..ad0fa1c193c --- /dev/null +++ b/api/v1/views/users.py @@ -0,0 +1,75 @@ +#!/usr/bin/python3 +""" +This file contains the User module +""" +from api.v1.views import app_views +from flask import jsonify, abort, request, make_response +from models import storage +from models.user import User +from flasgger.utils import swag_from + + +@app_views.route('/users', methods=['GET'], strict_slashes=False) +@swag_from('documentation/user/get.yml', methods=['GET']) +def get_all_users(): + """ get users by id""" + all_list = [obj.to_dict() for obj in storage.all(User).values()] + return jsonify(all_list) + + +@app_views.route('/users/', methods=['GET'], + strict_slashes=False) +@swag_from('documentation/user/get_id.yml', methods=['GET']) +def get_user(user_id): + """ get user by id""" + user = storage.get(User, user_id) + if user is None: + abort(404) + return jsonify(user.to_dict()) + + +@app_views.route('/users/', methods=['DELETE'], + strict_slashes=False) +@swag_from('documentation/user/delete.yml', methods=['DELETE']) +def del_user(user_id): + """ delete user by id""" + user = storage.get(User, user_id) + if user is None: + abort(404) + user.delete() + storage.save() + return jsonify({}) + + +@app_views.route('/users/', methods=['POST'], + strict_slashes=False) +@swag_from('documentation/user/post.yml', methods=['POST']) +def create_obj_user(): + """ create new instance """ + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + if 'email' not in request.get_json(): + return make_response(jsonify({"error": "Missing email"}), 400) + if 'password'not in request.get_json(): + return make_response(jsonify({"error": "Missing password"}), 400) + js = request.get_json() + obj = User(**js) + obj.save() + return (jsonify(obj.to_dict()), 201) + + +@app_views.route('/users/', methods=['PUT'], + strict_slashes=False) +@swag_from('documentation/user/put.yml', methods=['PUT']) +def post_user(user_id): + """ """ + if not request.get_json(): + return make_response(jsonify({"error": "Not a JSON"}), 400) + obj = storage.get(User, user_id) + if obj is None: + abort(404) + for key, value in request.get_json().items(): + if key not in ['id', 'email', 'created_at', 'updated']: + setattr(obj, key, value) + storage.save() + return jsonify(obj.to_dict()) From 2c2fe352748adc4a952f95b746c2c603c57eea36 Mon Sep 17 00:00:00 2001 From: Damilola-Nuga <58979551+Damilola-Nuga@users.noreply.github.com> Date: Tue, 18 Feb 2025 03:28:53 +0100 Subject: [PATCH 3/4] api2 --- api/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 123 bytes api/v1/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 126 bytes api/v1/__pycache__/app.cpython-38.pyc | Bin 0 -> 1426 bytes api/v1/app.py | 67 ++-- api/v1/views/__init__.py | 14 +- .../views/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 577 bytes api/v1/views/__pycache__/index.cpython-38.pyc | Bin 0 -> 967 bytes api/v1/views/amenities.py | 131 +++---- api/v1/views/cities.py | 153 ++++---- api/v1/views/documentation/amenity/delete.yml | 20 -- api/v1/views/documentation/amenity/get.yml | 25 -- api/v1/views/documentation/amenity/get_id.yml | 34 -- api/v1/views/documentation/amenity/post.yml | 17 - api/v1/views/documentation/amenity/put.yml | 20 -- api/v1/views/documentation/city/delete.yml | 15 - api/v1/views/documentation/city/get.yml | 37 -- api/v1/views/documentation/city/get_id.yml | 37 -- api/v1/views/documentation/city/post.yml | 26 -- api/v1/views/documentation/city/put.yml | 22 -- .../documentation/place_amenity/delete.yml | 20 -- .../documentation/place_amenity/get_id.yml | 34 -- .../documentation/place_amenity/post.yml | 22 -- api/v1/views/documentation/places/delete.yml | 15 - api/v1/views/documentation/places/get.yml | 58 --- api/v1/views/documentation/places/get_id.yml | 58 --- api/v1/views/documentation/places/post.yml | 26 -- api/v1/views/documentation/places/put.yml | 21 -- api/v1/views/documentation/places/search.yml | 78 ----- api/v1/views/documentation/reviews/delete.yml | 15 - api/v1/views/documentation/reviews/get.yml | 36 -- api/v1/views/documentation/reviews/get_id.yml | 36 -- api/v1/views/documentation/reviews/post.yml | 29 -- api/v1/views/documentation/reviews/put.yml | 25 -- api/v1/views/documentation/state/delete.yml | 15 - api/v1/views/documentation/state/get.yml | 28 -- api/v1/views/documentation/state/get_id.yml | 31 -- api/v1/views/documentation/state/post.yml | 19 - api/v1/views/documentation/state/put.yml | 24 -- api/v1/views/documentation/user/delete.yml | 15 - api/v1/views/documentation/user/get.yml | 34 -- api/v1/views/documentation/user/get_id.yml | 42 --- api/v1/views/documentation/user/post.yml | 21 -- api/v1/views/documentation/user/put.yml | 18 - api/v1/views/index.py | 53 +-- api/v1/views/places.py | 329 ++++++++++-------- api/v1/views/places_amenities.py | 155 ++++++--- api/v1/views/places_reviews.py | 148 ++++---- api/v1/views/states.py | 129 ++++--- api/v1/views/users.py | 148 ++++---- 49 files changed, 757 insertions(+), 1543 deletions(-) create mode 100644 api/__pycache__/__init__.cpython-38.pyc create mode 100644 api/v1/__pycache__/__init__.cpython-38.pyc create mode 100644 api/v1/__pycache__/app.cpython-38.pyc create mode 100644 api/v1/views/__pycache__/__init__.cpython-38.pyc create mode 100644 api/v1/views/__pycache__/index.cpython-38.pyc delete mode 100644 api/v1/views/documentation/amenity/delete.yml delete mode 100644 api/v1/views/documentation/amenity/get.yml delete mode 100644 api/v1/views/documentation/amenity/get_id.yml delete mode 100644 api/v1/views/documentation/amenity/post.yml delete mode 100644 api/v1/views/documentation/amenity/put.yml delete mode 100644 api/v1/views/documentation/city/delete.yml delete mode 100644 api/v1/views/documentation/city/get.yml delete mode 100644 api/v1/views/documentation/city/get_id.yml delete mode 100644 api/v1/views/documentation/city/post.yml delete mode 100644 api/v1/views/documentation/city/put.yml delete mode 100644 api/v1/views/documentation/place_amenity/delete.yml delete mode 100644 api/v1/views/documentation/place_amenity/get_id.yml delete mode 100644 api/v1/views/documentation/place_amenity/post.yml delete mode 100644 api/v1/views/documentation/places/delete.yml delete mode 100644 api/v1/views/documentation/places/get.yml delete mode 100644 api/v1/views/documentation/places/get_id.yml delete mode 100644 api/v1/views/documentation/places/post.yml delete mode 100644 api/v1/views/documentation/places/put.yml delete mode 100644 api/v1/views/documentation/places/search.yml delete mode 100644 api/v1/views/documentation/reviews/delete.yml delete mode 100644 api/v1/views/documentation/reviews/get.yml delete mode 100644 api/v1/views/documentation/reviews/get_id.yml delete mode 100644 api/v1/views/documentation/reviews/post.yml delete mode 100644 api/v1/views/documentation/reviews/put.yml delete mode 100644 api/v1/views/documentation/state/delete.yml delete mode 100644 api/v1/views/documentation/state/get.yml delete mode 100644 api/v1/views/documentation/state/get_id.yml delete mode 100644 api/v1/views/documentation/state/post.yml delete mode 100644 api/v1/views/documentation/state/put.yml delete mode 100644 api/v1/views/documentation/user/delete.yml delete mode 100644 api/v1/views/documentation/user/get.yml delete mode 100644 api/v1/views/documentation/user/get_id.yml delete mode 100644 api/v1/views/documentation/user/post.yml delete mode 100644 api/v1/views/documentation/user/put.yml diff --git a/api/__pycache__/__init__.cpython-38.pyc b/api/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c4cb3ac134ca019f9293508203ccba0052582288 GIT binary patch literal 123 zcmWIL<>g`kg4ODwX(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o2Bj-!ZeuDbFcB sIVV3aHNMPPKd~TFKR!M)FS8^*Uaz3?7Kcr4eoARhsvSt@XCP((0B;%?R{#J2 literal 0 HcmV?d00001 diff --git a/api/v1/__pycache__/__init__.cpython-38.pyc b/api/v1/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64e4a10d3e21de33ff290ccbcc9cdd733db0bd3e GIT binary patch literal 126 zcmWIL<>g`kg4ODwX(0MBh(HF6K#l_t7qb9~6oz01O-8?!3`HPe1o2B*-!ZeuDbFcB vIVV3aHNMPPKd~TFzsyiSK0Y%qvm`!Vub}c4hfQvNN@-529Z2(MAZ7pnxO5pX literal 0 HcmV?d00001 diff --git a/api/v1/__pycache__/app.cpython-38.pyc b/api/v1/__pycache__/app.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e578fd06d4c0e84173232ef352150695207eb76 GIT binary patch literal 1426 zcmaJ>OK;mo5a#kBkrX8>e&mHBAbKdEqLAbyy%j|xqk(&|jaa$tWx;Sq5*~d!I^?ftn@@2anTKHVKnU}2SrFjVu1s# zcZ5bjuG+lG{k2Uyuw}e}hienxUd73Lo@Z&IvZ{=qo&3-buQ5Z`QO~YDGpTN#$*RmI zZ+oP64~}1);)~+t zd}R;5q|HiXQv}o_G!P)Gg-AiBL<877+P1MBV3QGc%DN(JOV;Kktw`UF_b)pC6p@8GpV2i(MM)NtD*MNypl+P2Jj|@xlX`)OZYhS*Q3F+OpMAA z!zm@O<&!}&&j!nV{LK6Fw{=HBB6xLPvWd>)o(88;TCUJCy#5toe?r5-5ksSchB5-Y zMDa~@aokmWn3OyR87n08boewr9FI?85TX*uhC_c9991fwREv_oC$(orL<_g-5uvvh zIy(mbO&6eB2WA?>{XRqY2BRZ1fa_mA#;6H=!1xt9ocu(Tbzv#;&K8f9eSt#K)`fNE z;D~#H=#hbI7Rka+K?2-l%x?Hu-Sb=wev2o9#?yQoEy7NjX z>Z_T6gahwAtecGSDrKy;D@i?5YoXI*j;Emsu(T3V;6KNrjRFgmOCv8Dp=A2Y{l2*y zqOm!%ObTF(Iw+*NF$I+5lKT1zX#};Cl?Xt)21;`wazr_&9jQc?Dkf2FGmvy!z*Os5 zuvhs4=0Y#q`JhQ$ztO)@BmSqfie^S%!W91|1&&yhxALZQB#dhOZ;;3$hi^4k`4~Ib j_DPpSc0?k_$G%H^5|UlaXxKo@!{+-$$6aFU_wRoI8;D}A literal 0 HcmV?d00001 diff --git a/api/v1/app.py b/api/v1/app.py index 87d80cddbea..357bfa3c099 100644 --- a/api/v1/app.py +++ b/api/v1/app.py @@ -1,43 +1,50 @@ #!/usr/bin/python3 -""" -This module contains the principal application -""" +'''Contains a Flask web application API. +''' +import os +from flask import Flask, jsonify +from flask_cors import CORS + from models import storage from api.v1.views import app_views -from flask import Flask, make_response, jsonify -from os import getenv -from flask_cors import CORS -from flasgger import Swagger + app = Flask(__name__) -app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True +'''The Flask web application instance.''' +app_host = os.getenv('HBNB_API_HOST', '0.0.0.0') +app_port = int(os.getenv('HBNB_API_PORT', '5000')) +app.url_map.strict_slashes = False app.register_blueprint(app_views) -cors = CORS(app, resources={r"/api/*": {"origins": "0.0.0.0"}}) +CORS(app, resources={'/*': {'origins': app_host}}) @app.teardown_appcontext -def close_db(obj): - """ calls methods close() """ +def teardown_flask(exception): + '''The Flask app/request context end event listener.''' + # print(exception) storage.close() @app.errorhandler(404) -def page_not_foun(error): - """ Loads a custom 404 page not found """ - return make_response(jsonify({"error": "Not found"}), 404) - - -app.config['SWAGGER'] = { - 'title': 'AirBnB clone - RESTful API', - 'description': 'This is the api that was created for the hbnb restful api project,\ - all the documentation will be shown below', - 'uiversion': 3} - -Swagger(app) - -if __name__ == "__main__": - - host = getenv('HBNB_API_HOST', default='0.0.0.0') - port = getenv('HBNB_API_PORT', default=5000) - - app.run(host, int(port), threaded=True) +def error_404(error): + '''Handles the 404 HTTP error code.''' + return jsonify(error='Not found'), 404 + + +@app.errorhandler(400) +def error_400(error): + '''Handles the 400 HTTP error code.''' + msg = 'Bad request' + if isinstance(error, Exception) and hasattr(error, 'description'): + msg = error.description + return jsonify(error=msg), 400 + + +if __name__ == '__main__': + app_host = os.getenv('HBNB_API_HOST', '0.0.0.0') + app_port = int(os.getenv('HBNB_API_PORT', '5000')) + app.run( + host=app_host, + port=app_port, + threaded=True + ) diff --git a/api/v1/views/__init__.py b/api/v1/views/__init__.py index 87a3da99aa7..aaa1fd261f0 100644 --- a/api/v1/views/__init__.py +++ b/api/v1/views/__init__.py @@ -1,17 +1,17 @@ - #!/usr/bin/python3 -"""Init file for views module""" +'''Contains the blueprint for the API.''' from flask import Blueprint app_views = Blueprint('app_views', __name__, url_prefix='/api/v1') +'''The blueprint for the AirBnB clone API.''' -from api.v1.views.index import * -from api.v1.views.states import * -from api.v1.views.cities import * from api.v1.views.amenities import * -from api.v1.views.users import * +from api.v1.views.cities import * +from api.v1.views.index import * +from api.v1.views.places_amenities import * from api.v1.views.places import * from api.v1.views.places_reviews import * -from api.v1.views.places_amenities import * +from api.v1.views.states import * +from api.v1.views.users import * diff --git a/api/v1/views/__pycache__/__init__.cpython-38.pyc b/api/v1/views/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60e84f6229e096dc1a0e1751a6a7d3574ce82165 GIT binary patch literal 577 zcmZvZy-ve06os9?CMhigNL>)9YdR#VSP_D5EG)E3mMb@Qg@v0&b`qfPfOrmGDJv7N z01G!Epr*o6?$JFy`h4RohQmI=^*ULsz6?U%>t=U3*j(YOGc1h6gc;0~#@dWcgK(2s z++sF!UaZ*0ot|{&b)qMGt-7sxt@^F@TRmuXFt2Iu4$ZqGfxkVwNkuNG6k9&d@Ak5!ZG42Bu$+bsHWVr2Pw{cb(>cw#-ZK*%9nDcEiP-v+ z(C<0iHPyhe` literal 0 HcmV?d00001 diff --git a/api/v1/views/__pycache__/index.cpython-38.pyc b/api/v1/views/__pycache__/index.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..27f54f61e2c68a3175a7d6922693d3cf8fb8353b GIT binary patch literal 967 zcmZuv&2H2%5Vjr1$)?+GB{(4tIe~KNszTyWA)u}Jk&pmUddVe(*xRPfCM%D3OIPg) zuDk&UdhDC<47qaZE0hC_y`fqOCi2W=e(afVW`A`xB1pgP?~lMEC08; z>B+S{k__fSRMt{`imvcElF&9df~GDOSw$t0VV>IAGEOr!GyH4lbhax;b2d-3f3 z^Mtj*See5{Lc0b=mxalo%HdE!VQ>6P3>ABJ@xUEqwylz$6GP6h&~t3;jArzVVo`kl zFp7~D@5H*98s!XITA8V?w_>ee($t{hlhPcXN_7t~4CNw1Ta z{^SNIh?`NIS5@46Jc9pWW>H#>ahYkbJyvyTPE)>Xx&OAx3zdp@%J$v*dpK&9@_kS` z5os@X!KH#!6s2);ViO<@w97z;g&Gb16mvk^Wly-~C|bX0rnPYs(JN@s7DEUBf~~tC zn-6zUh1yL2dju*4;i+CA literal 0 HcmV?d00001 diff --git a/api/v1/views/amenities.py b/api/v1/views/amenities.py index 4e8700ac986..6714adeae7a 100644 --- a/api/v1/views/amenities.py +++ b/api/v1/views/amenities.py @@ -1,73 +1,86 @@ #!/usr/bin/python3 -""" -This file contains the Amenity module -""" +'''Contains the amenities view for the API.''' +from flask import jsonify, request +from werkzeug.exceptions import NotFound, MethodNotAllowed, BadRequest + from api.v1.views import app_views -from flask import jsonify, abort, request, make_response from models import storage from models.amenity import Amenity -from flasgger.utils import swag_from -@app_views.route('/amenities', methods=['GET'], strict_slashes=False) -@swag_from('documentation/amenity/get.yml', methods=['GET']) -def get_all_amenities(): - """ get amenities by id """ - all_list = [obj.to_dict() for obj in storage.all(Amenity).values()] - return jsonify(all_list) +ALLOWED_METHODS = ['GET', 'DELETE', 'POST', 'PUT'] +'''Methods allowed for the amenities endpoint.''' + + +@app_views.route('/amenities', methods=ALLOWED_METHODS) +@app_views.route('/amenities/', methods=ALLOWED_METHODS) +def handle_amenities(amenity_id=None): + '''The method handler for the amenities endpoint. + ''' + handlers = { + 'GET': get_amenities, + 'DELETE': remove_amenity, + 'POST': add_amenity, + 'PUT': update_amenity, + } + if request.method in handlers: + return handlers[request.method](amenity_id) + else: + raise MethodNotAllowed(list(handlers.keys())) -@app_views.route('/amenities/', methods=['GET'], - strict_slashes=False) -@swag_from('documentation/amenity/get_id.yml', methods=['GET']) -def get_amenity(amenity_id): - """ get amenity by id""" - amenity = storage.get(Amenity, amenity_id) - if amenity is None: - abort(404) - return jsonify(amenity.to_dict()) +def get_amenities(amenity_id=None): + '''Gets the amenity with the given id or all amenities. + ''' + all_amenities = storage.all(Amenity).values() + if amenity_id: + res = list(filter(lambda x: x.id == amenity_id, all_amenities)) + if res: + return jsonify(res[0].to_dict()) + raise NotFound() + all_amenities = list(map(lambda x: x.to_dict(), all_amenities)) + return jsonify(all_amenities) -@app_views.route('/amenities/', methods=['DELETE'], - strict_slashes=False) -@swag_from('documentation/amenity/delete.yml', methods=['DELETE']) -def del_amenity(amenity_id): - """ delete amenity by id""" - amenity = storage.get(Amenity, amenity_id) - if amenity is None: - abort(404) - amenity.delete() - storage.save() - return jsonify({}) +def remove_amenity(amenity_id=None): + '''Removes a amenity with the given id. + ''' + all_amenities = storage.all(Amenity).values() + res = list(filter(lambda x: x.id == amenity_id, all_amenities)) + if res: + storage.delete(res[0]) + storage.save() + return jsonify({}), 200 + raise NotFound() -@app_views.route('/amenities/', methods=['POST'], - strict_slashes=False) -@swag_from('documentation/amenity/post.yml', methods=['POST']) -def create_obj_amenity(): - """ create new instance """ - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - if 'name' not in request.get_json(): - return make_response(jsonify({"error": "Missing name"}), 400) - js = request.get_json() - obj = Amenity(**js) - obj.save() - return (jsonify(obj.to_dict()), 201) +def add_amenity(amenity_id=None): + '''Adds a new amenity. + ''' + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + if 'name' not in data: + raise BadRequest(description='Missing name') + new_amenity = Amenity(**data) + new_amenity.save() + return jsonify(new_amenity.to_dict()), 201 -@app_views.route('/amenities/', methods=['PUT'], - strict_slashes=False) -@swag_from('documentation/amenity/put.yml', methods=['PUT']) -def post_amenity(amenity_id): - """ """ - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - obj = storage.get(Amenity, amenity_id) - if obj is None: - abort(404) - for key, value in request.get_json().items(): - if key not in ['id', 'created_at', 'updated_at']: - setattr(obj, key, value) - storage.save() - return jsonify(obj.to_dict()) +def update_amenity(amenity_id=None): + '''Updates the amenity with the given id. + ''' + xkeys = ('id', 'created_at', 'updated_at') + all_amenities = storage.all(Amenity).values() + res = list(filter(lambda x: x.id == amenity_id, all_amenities)) + if res: + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + old_amenity = res[0] + for key, value in data.items(): + if key not in xkeys: + setattr(old_amenity, key, value) + old_amenity.save() + return jsonify(old_amenity.to_dict()), 200 + raise NotFound() diff --git a/api/v1/views/cities.py b/api/v1/views/cities.py index 915eb3fe4ac..ff75c32e7e5 100644 --- a/api/v1/views/cities.py +++ b/api/v1/views/cities.py @@ -1,83 +1,98 @@ #!/usr/bin/python3 -""" -This file contains the City module -""" +'''Contains the cities view for the API.''' +from flask import jsonify, request +from werkzeug.exceptions import NotFound, MethodNotAllowed, BadRequest + from api.v1.views import app_views -from flask import jsonify, abort, request, make_response -from models import storage -from models.state import State +from models import storage, storage_t from models.city import City -from flasgger.utils import swag_from +from models.place import Place +from models.review import Review +from models.state import State -@app_views.route('/states//cities', - methods=['GET'], strict_slashes=False) -@swag_from('documentation/city/get.yml', methods=['GET']) -def get_cities(state_id): - """ Gets cities for state_id """ - state = storage.get(State, state_id) - if state is None: - abort(404) - list_cities = [obj.to_dict() for obj in state.cities] - return jsonify(list_cities) +@app_views.route('/states//cities', methods=['GET', 'POST']) +@app_views.route('/cities/', methods=['GET', 'DELETE', 'PUT']) +def handle_cities(state_id=None, city_id=None): + '''The method handler for the cities endpoint. + ''' + handlers = { + 'GET': get_cities, + 'DELETE': remove_city, + 'POST': add_city, + 'PUT': update_city, + } + if request.method in handlers: + return handlers[request.method](state_id, city_id) + else: + raise MethodNotAllowed(list(handlers.keys())) -@app_views.route('/cities/', methods=['GET'], - strict_slashes=False) -@swag_from('documentation/city/get_id.yml', methods=['GET']) -def get_city(city_id): - """ get city by id""" - city = storage.get(City, city_id) - if city is None: - abort(404) - return jsonify(city.to_dict()) +def get_cities(state_id=None, city_id=None): + '''Gets the city with the given id or all cities in + the state with the given id. + ''' + if state_id: + state = storage.get(State, state_id) + if state: + cities = list(map(lambda x: x.to_dict(), state.cities)) + return jsonify(cities) + elif city_id: + city = storage.get(City, city_id) + if city: + return jsonify(city.to_dict()) + raise NotFound() -@app_views.route('/cities/', methods=['DELETE'], - strict_slashes=False) -@swag_from('documentation/city/delete.yml', methods=['DELETE']) -def del_city(city_id): - """ delete city by id""" - city = storage.get(City, city_id) - if city is None: - abort(404) - city.delete() - storage.save() - return jsonify({}) +def remove_city(state_id=None, city_id=None): + '''Removes a city with the given id. + ''' + if city_id: + city = storage.get(City, city_id) + if city: + storage.delete(city) + if storage_t != "db": + for place in storage.all(Place).values(): + if place.city_id == city_id: + for review in storage.all(Review).values(): + if review.place_id == place.id: + storage.delete(review) + storage.delete(place) + storage.save() + return jsonify({}), 200 + raise NotFound() -@app_views.route('/states//cities', methods=['POST'], - strict_slashes=False) -@swag_from('documentation/city/post.yml', methods=['POST']) -def create_obj_city(state_id): - """ create new instance """ +def add_city(state_id=None, city_id=None): + '''Adds a new city. + ''' state = storage.get(State, state_id) - if state is None: - abort(404) - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - if 'name' not in request.get_json(): - return make_response(jsonify({"error": "Missing name"}), 400) - - js = request.get_json() - obj = City(**js) - obj.state_id = state.id - obj.save() - return jsonify(obj.to_dict()), 201 + if not state: + raise NotFound() + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + if 'name' not in data: + raise BadRequest(description='Missing name') + data['state_id'] = state_id + city = City(**data) + city.save() + return jsonify(city.to_dict()), 201 -@app_views.route('/cities/', methods=['PUT'], - strict_slashes=False) -@swag_from('documentation/city/put.yml', methods=['PUT']) -def post_city(city_id): - """ """ - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - obj = storage.get(City, city_id) - if obj is None: - abort(404) - for key, value in request.get_json().items(): - if key not in ['id', 'state_id', 'created_at', 'updated_at']: - setattr(obj, key, value) - storage.save() - return jsonify(obj.to_dict()) +def update_city(state_id=None, city_id=None): + '''Updates the city with the given id. + ''' + xkeys = ('id', 'state_id', 'created_at', 'updated_at') + if city_id: + city = storage.get(City, city_id) + if city: + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + for key, value in data.items(): + if key not in xkeys: + setattr(city, key, value) + city.save() + return jsonify(city.to_dict()), 200 + raise NotFound() diff --git a/api/v1/views/documentation/amenity/delete.yml b/api/v1/views/documentation/amenity/delete.yml deleted file mode 100644 index 4f80783eb53..00000000000 --- a/api/v1/views/documentation/amenity/delete.yml +++ /dev/null @@ -1,20 +0,0 @@ -Removes an amenity by id ---- -tags: - - Amenities -parameters: - - name: place_id - in: path - type: string - required: true - description: the unique id of the place to be delete - - name: amenity_id - in: path - type: string - required: true - description: amenity id to remove -responses: - 404: - description: place not found / amenity not found / amenity not found in place 😳 - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/amenity/get.yml b/api/v1/views/documentation/amenity/get.yml deleted file mode 100644 index 2d09b5cf118..00000000000 --- a/api/v1/views/documentation/amenity/get.yml +++ /dev/null @@ -1,25 +0,0 @@ -GET method, get all amenities of a place ---- -tags: - - Amenities -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - name: - type: string - description: Place name diff --git a/api/v1/views/documentation/amenity/get_id.yml b/api/v1/views/documentation/amenity/get_id.yml deleted file mode 100644 index a399f61a88f..00000000000 --- a/api/v1/views/documentation/amenity/get_id.yml +++ /dev/null @@ -1,34 +0,0 @@ -GET method, retrieve a amenity base on amenity_id ---- -tags: - - Amenities -parameters: - - name: amenity_id - in: path - type: string - required: true - description: amenity id -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - name: - type: string - description: Place name - - 404: - description: amenity not found diff --git a/api/v1/views/documentation/amenity/post.yml b/api/v1/views/documentation/amenity/post.yml deleted file mode 100644 index 6ee7742d023..00000000000 --- a/api/v1/views/documentation/amenity/post.yml +++ /dev/null @@ -1,17 +0,0 @@ -Post a new amenity. ---- -tags: - - Amenities -parameters: - - name: amenity_id - in: body - requires: - - name - properties: - name: - type: string -responses: - 400: - description: Not Valid JSON 😳 - 201: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/amenity/put.yml b/api/v1/views/documentation/amenity/put.yml deleted file mode 100644 index dfc5bbcce0a..00000000000 --- a/api/v1/views/documentation/amenity/put.yml +++ /dev/null @@ -1,20 +0,0 @@ -Update a amenity instance by id ---- -tags: - - Amenities -parameters: - - name: amenity_id - in: path - type: string - required: true - description: the unique id of the amenity to be update - - name: update_request - in: body - required: true -responses: - 404: - description: State not found 😳 - 400: - description: Not a Valid JSON - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/city/delete.yml b/api/v1/views/documentation/city/delete.yml deleted file mode 100644 index 6660688a609..00000000000 --- a/api/v1/views/documentation/city/delete.yml +++ /dev/null @@ -1,15 +0,0 @@ -DELETE method, delete place instance by id ---- -tags: - - Cities -parameters: - - name: city_id - in: path - type: string - required: true - description: the unique id of the city to be delete -responses: - 404: - description: City not found 😳 - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/city/get.yml b/api/v1/views/documentation/city/get.yml deleted file mode 100644 index 08906a8182c..00000000000 --- a/api/v1/views/documentation/city/get.yml +++ /dev/null @@ -1,37 +0,0 @@ -GET method, get cities list on the state_id ---- -tags: - - Cities -parameters: - - name: city_id - in: path - type: string - required: true - description: the unique id of the state to be listed -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - name: - type: string - description: Place name - state_id: - type: string - description: city id - - 404: - description: No state linked to id diff --git a/api/v1/views/documentation/city/get_id.yml b/api/v1/views/documentation/city/get_id.yml deleted file mode 100644 index 72fcb489bed..00000000000 --- a/api/v1/views/documentation/city/get_id.yml +++ /dev/null @@ -1,37 +0,0 @@ -GET method, retrieve a city base on state_id ---- -tags: - - Cities -parameters: - - name: city_id - in: path - type: string - required: true - description: the unique id of the city to be listed -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - name: - type: string - description: Place name - state_id: - type: string - description: city id - - 404: - description: City not found diff --git a/api/v1/views/documentation/city/post.yml b/api/v1/views/documentation/city/post.yml deleted file mode 100644 index f1248409c58..00000000000 --- a/api/v1/views/documentation/city/post.yml +++ /dev/null @@ -1,26 +0,0 @@ - Post a new city. - --- - tags: - - Cities - parameters: - - state_id: - in: path - type: string - required: true - description: city state id - - name: body_request - in: body - required: true - requires: - - name - properties: - name: - type: string - - responses: - 404: - description: State not found!!!! - 400: - description: Missing name or Not Valid JSON 😳 - 201: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/city/put.yml b/api/v1/views/documentation/city/put.yml deleted file mode 100644 index 848b7cc7105..00000000000 --- a/api/v1/views/documentation/city/put.yml +++ /dev/null @@ -1,22 +0,0 @@ -Update a city instance by id ---- -tags: - - Cities -parameters: - - name: city_id - in: path - type: string - required: true - description: the unique id of the city to be update - - name: update_request - in: body - required: true - - -responses: - 404: - description: State not found 😳 - 400: - description: Not a Valid JSON - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/place_amenity/delete.yml b/api/v1/views/documentation/place_amenity/delete.yml deleted file mode 100644 index 09f8e877bb7..00000000000 --- a/api/v1/views/documentation/place_amenity/delete.yml +++ /dev/null @@ -1,20 +0,0 @@ -Removes an amenity by id ---- -tags: - - Place_Amenities -parameters: - - name: place_id - in: path - type: string - required: true - description: the unique id of the place with the amenity to be delete - - name: amenity_id - in: path - type: string - required: true - description: amenity id to remove -responses: - 404: - description: place not found / amenity not found / amenity not found in place 😳 - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/place_amenity/get_id.yml b/api/v1/views/documentation/place_amenity/get_id.yml deleted file mode 100644 index 2fec28b85db..00000000000 --- a/api/v1/views/documentation/place_amenity/get_id.yml +++ /dev/null @@ -1,34 +0,0 @@ -GET method, retrieve a amenities base on place ---- -tags: - - Place_Amenities -parameters: - - name: amenity_id - in: path - type: string - required: true - description: amenity id -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - name: - type: string - description: Place name - - 404: - description: Place not found diff --git a/api/v1/views/documentation/place_amenity/post.yml b/api/v1/views/documentation/place_amenity/post.yml deleted file mode 100644 index 44f70759103..00000000000 --- a/api/v1/views/documentation/place_amenity/post.yml +++ /dev/null @@ -1,22 +0,0 @@ -Links a review to a place. ---- -tags: - - Place_Amenities -parameters: - - name: place_id - in: path - type: string - required: true - description: Amenity id - - name: amenity_id - in: path - type: string - required: true - description: id of the place to be linked -responses: - 404: - description: Not found - 201: - description: Successful request ✔️ - 201: - description: Amenity already linked to a place diff --git a/api/v1/views/documentation/places/delete.yml b/api/v1/views/documentation/places/delete.yml deleted file mode 100644 index def87630cb9..00000000000 --- a/api/v1/views/documentation/places/delete.yml +++ /dev/null @@ -1,15 +0,0 @@ -DELETE method, delete place instance by id ---- -tags: - - Places -parameters: - - name: place_id - in: path - type: string - required: true - description: the unique id of the place to be delete -responses: - 404: - description: Place not found 😳 - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/places/get.yml b/api/v1/views/documentation/places/get.yml deleted file mode 100644 index 619a12a700c..00000000000 --- a/api/v1/views/documentation/places/get.yml +++ /dev/null @@ -1,58 +0,0 @@ -GET method, lists all places of a city ---- -tags: - - Places -parameters: - - name: city_id - in: path - type: string - required: true - description: the unique id of the city to be listed -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - updated_at: - type: string - description: datetime of instance update - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - description: - type: string - description: Place description - latitude: - type: number - description: Place latitude - longitude: - type: number - description: Place longitude - max_guest: - type: integer - description: Max guests - name: - type: string - description: Place name - number_bathrooms: - type: integer - description: Number of bathrooms - number_rooms: - type: integer - description: Number of rooms - price_by_night: - type: number - description: Price by night - user_id: - type: string - description: Owner id - - 404: - description: City not found \ No newline at end of file diff --git a/api/v1/views/documentation/places/get_id.yml b/api/v1/views/documentation/places/get_id.yml deleted file mode 100644 index 61d8c1d01cb..00000000000 --- a/api/v1/views/documentation/places/get_id.yml +++ /dev/null @@ -1,58 +0,0 @@ -GET method, retrieve a place ---- -tags: - - Places -parameters: - - name: place_id - in: path - type: string - required: true - description: the unique id of the place to be listed -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - updated_at: - type: string - description: datetime of instance update - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - description: - type: string - description: Place description - latitude: - type: number - description: Place latitude - longitude: - type: number - description: Place longitude - max_guest: - type: integer - description: Max guests - name: - type: string - description: Place name - number_bathrooms: - type: integer - description: Number of bathrooms - number_rooms: - type: integer - description: Number of rooms - price_by_night: - type: number - description: Price by night - user_id: - type: string - description: Owner id - - 404: - description: City not found diff --git a/api/v1/views/documentation/places/post.yml b/api/v1/views/documentation/places/post.yml deleted file mode 100644 index 57b0c209fc3..00000000000 --- a/api/v1/views/documentation/places/post.yml +++ /dev/null @@ -1,26 +0,0 @@ - Posts a new state. - --- - tags: - - Places - parameters: - - name: city_id - in: path - required: true - description: city id to be linked - - name: user_id and name - in: body - required: true - requires: - - user_id - - name - properties: - user_id: - type: string - name: - type: string - - responses: - 400: - description: Missing name or Not Valid JSON 😳 - 201: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/places/put.yml b/api/v1/views/documentation/places/put.yml deleted file mode 100644 index 0372c7f8d31..00000000000 --- a/api/v1/views/documentation/places/put.yml +++ /dev/null @@ -1,21 +0,0 @@ -Update a state instance by id ---- -tags: - - Places -parameters: - - name: place_id - in: path - type: string - required: true - description: the unique id of the place to be update - - name: request - in: body - required: true - -responses: - 404: - description: State not found 😳 - 400: - description: Not a Valid JSON - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/places/search.yml b/api/v1/views/documentation/places/search.yml deleted file mode 100644 index ce85297e514..00000000000 --- a/api/v1/views/documentation/places/search.yml +++ /dev/null @@ -1,78 +0,0 @@ -Search places ---- -tags: - - Places -parameters: - - name: user_id and name - in: body - required: false - description: required ids - requieres: - - states - - cities - - amenities - properties: - states: - type: array - items: - type: string - cities: - type: array - items: - type: string - amenities: - type: array - items: - type: string - -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - updated_at: - type: string - description: datetime of instance update - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - description: - type: string - description: Place description - latitude: - type: number - description: Place latitude - longitude: - type: number - description: Place longitude - max_guest: - type: integer - description: Max guests - name: - type: string - description: Place name - number_bathrooms: - type: integer - description: Number of bathrooms - number_rooms: - type: integer - description: Number of rooms - price_by_night: - type: number - description: Price by night - user_id: - type: string - description: Owner id - - 404: - description: Resource not found - - 400: - description: Not a valid JSON \ No newline at end of file diff --git a/api/v1/views/documentation/reviews/delete.yml b/api/v1/views/documentation/reviews/delete.yml deleted file mode 100644 index 01772caa135..00000000000 --- a/api/v1/views/documentation/reviews/delete.yml +++ /dev/null @@ -1,15 +0,0 @@ -Removes a review by id ---- -tags: - - Reviews -parameters: - - name: review_id - in: path - type: string - required: true - description: the unique id of the review to be delete -responses: - 404: - description: Review not found in place 😳 - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/reviews/get.yml b/api/v1/views/documentation/reviews/get.yml deleted file mode 100644 index b8879abc6c4..00000000000 --- a/api/v1/views/documentation/reviews/get.yml +++ /dev/null @@ -1,36 +0,0 @@ -GET method, get all reviews of a place ---- -tags: - - Reviews -parameters: - - name: place_id - in: path - type: string - required: true - description: place id -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - text: - type: string - description: Place description - place_id: - type: string - description: Place id - 404: - description: Place not found \ No newline at end of file diff --git a/api/v1/views/documentation/reviews/get_id.yml b/api/v1/views/documentation/reviews/get_id.yml deleted file mode 100644 index bfcf3a7de75..00000000000 --- a/api/v1/views/documentation/reviews/get_id.yml +++ /dev/null @@ -1,36 +0,0 @@ -GET method, retrieve a review ---- -tags: - - Reviews -parameters: - - name: review_id - in: path - type: string - required: true - description: Review id -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - text: - type: string - description: Place description - place_id: - type: string - description: Place id - 404: - description: Place not found diff --git a/api/v1/views/documentation/reviews/post.yml b/api/v1/views/documentation/reviews/post.yml deleted file mode 100644 index 62b04cc9981..00000000000 --- a/api/v1/views/documentation/reviews/post.yml +++ /dev/null @@ -1,29 +0,0 @@ -Post a new review. ---- -tags: - - Reviews -parameters: - - name: review_id - in: path - type: string - required: true - description: review id - - name: user_id and text - in: body - required: true - requires: - - user_id - - text - properties: - user_id: - type: string - text: - type: string - -responses: - 404: - description: review not found 😳 - 400: - description: Not a Valid JSON - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/reviews/put.yml b/api/v1/views/documentation/reviews/put.yml deleted file mode 100644 index bc941f3c63d..00000000000 --- a/api/v1/views/documentation/reviews/put.yml +++ /dev/null @@ -1,25 +0,0 @@ -Update a review instance by id ---- -tags: - - Reviews -parameters: - - name: review_id - in: path - type: string - required: true - description: the unique id of the review to be update - - name: update_request - in: body - required: true - requieres: - - parameters - properties: - parameters: - type: string -responses: - 404: - description: review not found 😳 - 400: - description: Not a Valid JSON - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/state/delete.yml b/api/v1/views/documentation/state/delete.yml deleted file mode 100644 index 49f85f6d25e..00000000000 --- a/api/v1/views/documentation/state/delete.yml +++ /dev/null @@ -1,15 +0,0 @@ -DELETE method, delete instance my id ---- -tags: - - States -parameters: - - name: state_id - in: path - type: string - required: true - description: the unique id of the state to delete -responses: - 404: - description: State not found 😳 - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/state/get.yml b/api/v1/views/documentation/state/get.yml deleted file mode 100644 index 816b171f3c9..00000000000 --- a/api/v1/views/documentation/state/get.yml +++ /dev/null @@ -1,28 +0,0 @@ -GET method, lists all states ---- -tags: - - States -parameters: - - name: no needed - in: path - type: string - required: false - description: lists all states -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - id: - type: string - description: The unique id of the state instance - name: - type: string - description: The State name diff --git a/api/v1/views/documentation/state/get_id.yml b/api/v1/views/documentation/state/get_id.yml deleted file mode 100644 index b4fa3463b7f..00000000000 --- a/api/v1/views/documentation/state/get_id.yml +++ /dev/null @@ -1,31 +0,0 @@ -GET method, lists state by unique id ---- -tags: - - States -parameters: - - name: state_id - in: path - type: string - required: false - description: the unique id of the state -responses: - 404: - description: State not found - 200: - description: Successful request - schema: - properties: - __class__: - type: string - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: datetime of instance update - id: - type: string - description: The unique id of the state instance - name: - type: string - description: State name diff --git a/api/v1/views/documentation/state/post.yml b/api/v1/views/documentation/state/post.yml deleted file mode 100644 index 4ddf490ab39..00000000000 --- a/api/v1/views/documentation/state/post.yml +++ /dev/null @@ -1,19 +0,0 @@ - Posts a new state. - --- - tags: - - States - parameters: - - name: request - in: body - required: true - requires: - - name - properties: - name: - type: string - - responses: - 400: - description: Missing name or Not Valid JSON 😳 - 201: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/state/put.yml b/api/v1/views/documentation/state/put.yml deleted file mode 100644 index 11e11944b3e..00000000000 --- a/api/v1/views/documentation/state/put.yml +++ /dev/null @@ -1,24 +0,0 @@ -Update a state instance by id ---- -tags: - - States -parameters: - - name: state_id - in: path - type: string - required: true - description: the unique id of the state to update - - name: request - in: body - required: true - requires: - - name - properties: - name: - type: string - -responses: - 404: - description: State not found 😳 - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/user/delete.yml b/api/v1/views/documentation/user/delete.yml deleted file mode 100644 index e6111b8c91b..00000000000 --- a/api/v1/views/documentation/user/delete.yml +++ /dev/null @@ -1,15 +0,0 @@ -Removes an user by id ---- -tags: - - Users -parameters: - - name: user_id - in: path - type: string - required: false - description: the unique id of the user -responses: - 404: - description: User not found 😳 - 200: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/user/get.yml b/api/v1/views/documentation/user/get.yml deleted file mode 100644 index 8a249ec8f0b..00000000000 --- a/api/v1/views/documentation/user/get.yml +++ /dev/null @@ -1,34 +0,0 @@ -GET method, get all users ---- -tags: - - Users -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - email: - type: string - description: User email - password: - type: string - description: User password - first_name: - type: string - description: User first name - last_name: - type: string - description: User last name diff --git a/api/v1/views/documentation/user/get_id.yml b/api/v1/views/documentation/user/get_id.yml deleted file mode 100644 index 58a576c16fb..00000000000 --- a/api/v1/views/documentation/user/get_id.yml +++ /dev/null @@ -1,42 +0,0 @@ -GET method, get user by id ---- -tags: - - Users -parameters: - - name: user_id - in: path - type: string - required: true - description: User id to retrieve -responses: - 200: - description: Succsesful resquest - schema: - type: array - items: - properties: - __class__: - type: "string" - created_at: - type: string - description: datetime of instance creation - updated_at: - type: string - description: time of last update of the instance - id: - type: string - description: The unique id of the state instance - email: - type: string - description: User email - password: - type: string - description: User password - first_name: - type: string - description: User first name - last_name: - type: string - description: User last name - 404: - description: User not found! \ No newline at end of file diff --git a/api/v1/views/documentation/user/post.yml b/api/v1/views/documentation/user/post.yml deleted file mode 100644 index 6e95ff2a5f1..00000000000 --- a/api/v1/views/documentation/user/post.yml +++ /dev/null @@ -1,21 +0,0 @@ -Post a new amenity. ---- -tags: - - Users -parameters: - - name: user and pasword - in: body - required: true - requires: - - email: - - password: - properties: - email: - type: string - password: - type: string -responses: - 400: - description: Missing email/password or Not Valid JSON 😳 - 201: - description: Successful request ✔️ diff --git a/api/v1/views/documentation/user/put.yml b/api/v1/views/documentation/user/put.yml deleted file mode 100644 index 2fa8dacd981..00000000000 --- a/api/v1/views/documentation/user/put.yml +++ /dev/null @@ -1,18 +0,0 @@ -Update a user instance by id ---- -tags: - - Users -parameters: - - name: user_id - in: path - type: string - required: true - description: the unique id of the user to be update - - name: update_request - in: body - required: true -responses: - 404: - description: User not found 😳 - 200: - description: Successful request ✔️ diff --git a/api/v1/views/index.py b/api/v1/views/index.py index 6d34db8feb1..ff219605366 100644 --- a/api/v1/views/index.py +++ b/api/v1/views/index.py @@ -1,29 +1,36 @@ #!/usr/bin/python3 -""" -This module contains endpoint(route) status -""" -from models import storage -from flask import Flask -from api.v1.views import app_views +'''Contains the index view for the API.''' from flask import jsonify +from api.v1.views import app_views +from models import storage +from models.amenity import Amenity +from models.city import City +from models.place import Place +from models.review import Review +from models.state import State +from models.user import User + -@app_views.route('/status', strict_slashes=False) -def status(): - """ - Returns a JSON status - """ - return jsonify({"status": "OK"}) +@app_views.route('/status') +def get_status(): + '''Gets the status of the API. + ''' + return jsonify(status='OK') -@app_views.route('/stats', strict_slashes=False) -def count(): - """ - Retrieves the number of each objects by type - """ - return jsonify({"amenities": storage.count("Amenity"), - "cities": storage.count("City"), - "places": storage.count("Place"), - "reviews": storage.count("Review"), - "states": storage.count("State"), - "users": storage.count("User")}) +@app_views.route('/stats') +def get_stats(): + '''Gets the number of objects for each type. + ''' + objects = { + 'amenities': Amenity, + 'cities': City, + 'places': Place, + 'reviews': Review, + 'states': State, + 'users': User + } + for key, value in objects.items(): + objects[key] = storage.count(value) + return jsonify(objects) diff --git a/api/v1/views/places.py b/api/v1/views/places.py index 5e32ea3ecae..71126290566 100644 --- a/api/v1/views/places.py +++ b/api/v1/views/places.py @@ -1,150 +1,199 @@ #!/usr/bin/python3 -""" -This file contains the Place module -""" +'''Contains the places view for the API.''' +from flask import jsonify, request +from werkzeug.exceptions import NotFound, MethodNotAllowed, BadRequest + from api.v1.views import app_views -from flask import jsonify, abort, request, make_response -from models import storage -from models.place import Place -from models.city import City -from models.user import User +from models import storage, storage_t from models.amenity import Amenity +from models.city import City +from models.place import Place from models.state import State -from flasgger.utils import swag_from +from models.user import User -@app_views.route('/cities//places', - methods=['GET'], strict_slashes=False) -@swag_from('documentation/places/get.yml', methods=['GET']) -def get_all_places(city_id): - """ list cities by id """ +@app_views.route('/cities//places', methods=['GET', 'POST']) +@app_views.route('/places/', methods=['GET', 'DELETE', 'PUT']) +def handle_places(city_id=None, place_id=None): + '''The method handler for the places endpoint. + ''' + handlers = { + 'GET': get_places, + 'DELETE': remove_place, + 'POST': add_place, + 'PUT': update_place + } + if request.method in handlers: + return handlers[request.method](city_id, place_id) + else: + raise MethodNotAllowed(list(handlers.keys())) + + +def get_places(city_id=None, place_id=None): + '''Gets the place with the given id or all places in + the city with the given id. + ''' + if city_id: + city = storage.get(City, city_id) + if city: + all_places = [] + if storage_t == 'db': + all_places = list(city.places) + else: + all_places = list(filter( + lambda x: x.city_id == city_id, + storage.all(Place).values() + )) + places = list(map(lambda x: x.to_dict(), all_places)) + return jsonify(places) + elif place_id: + place = storage.get(Place, place_id) + if place: + return jsonify(place.to_dict()) + raise NotFound() + + +def remove_place(city_id=None, place_id=None): + '''Removes a place with the given id. + ''' + if place_id: + place = storage.get(Place, place_id) + if place: + storage.delete(place) + storage.save() + return jsonify({}), 200 + raise NotFound() + + +def add_place(city_id=None, place_id=None): + '''Adds a new place. + ''' city = storage.get(City, city_id) - if city is None: - abort(404) - places = [obj.to_dict() for obj in city.places] - return jsonify(places) - - -@app_views.route('/places/', methods=['GET'], - strict_slashes=False) -@swag_from('documentation/places/get_id.yml', methods=['GET']) -def get_place(place_id): - """ get place by id """ - place = storage.get(Place, place_id) - if place is None: - abort(404) - return jsonify(place.to_dict()) - - -@app_views.route('/places/', methods=['DELETE'], - strict_slashes=False) -@swag_from('documentation/places/delete.yml', methods=['DELETE']) -def del_place(place_id): - """ delete place by id """ + if not city: + raise NotFound() + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + if 'user_id' not in data: + raise BadRequest(description='Missing user_id') + user = storage.get(User, data['user_id']) + if not user: + raise NotFound() + if 'name' not in data: + raise BadRequest(description='Missing name') + data['city_id'] = city_id + new_place = Place(**data) + new_place.save() + return jsonify(new_place.to_dict()), 201 + + +def update_place(city_id=None, place_id=None): + '''Updates the place with the given id. + ''' + xkeys = ('id', 'user_id', 'city_id', 'created_at', 'updated_at') place = storage.get(Place, place_id) - if place is None: - abort(404) - place.delete() - storage.save() - return jsonify({}) - - -@app_views.route('/cities//places', methods=['POST'], - strict_slashes=False) -@swag_from('documentation/places/post.yml', methods=['POST']) -def create_obj_place(city_id): - """ create new instance """ - city = storage.get(City, city_id) - if city is None: - abort(404) - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - if 'user_id' not in request.get_json(): - return make_response(jsonify({"error": "Missing user_id"}), 400) - if 'name' not in request.get_json(): - return make_response(jsonify({"error": "Missing name"}), 400) - kwargs = request.get_json() - kwargs['city_id'] = city_id - user = storage.get(User, kwargs['user_id']) - if user is None: - abort(404) - obj = Place(**kwargs) - obj.save() - return (jsonify(obj.to_dict()), 201) - - -@app_views.route('/places/', methods=['PUT'], - strict_slashes=False) -@swag_from('documentation/places/put.yml', methods=['PUT']) -def post_place(place_id): - """ update by id """ - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - obj = storage.get(Place, place_id) - if obj is None: - abort(404) - for key, value in request.get_json().items(): - if key not in ['id', 'user_id', 'city_id', 'created_at', 'updated']: - setattr(obj, key, value) - storage.save() - return jsonify(obj.to_dict()) - - -@app_views.route('/places_search', methods=['POST'], - strict_slashes=False) -@swag_from('documentation/places/search.yml', methods=['POST']) -def search_places_by_id(): - """ search places by id """ - if request.get_json() is None: - return make_response(jsonify({"error": "Not a JSON"}), 400) - + if place: + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + for key, value in data.items(): + if key not in xkeys: + setattr(place, key, value) + place.save() + return jsonify(place.to_dict()), 200 + raise NotFound() + + +@app_views.route('/places_search', methods=['POST']) +def find_places(): + '''Finds places based on a list of State, City, or Amenity ids. + ''' data = request.get_json() - - if data and len(data): - states = data.get('states', None) - cities = data.get('cities', None) - amenities = data.get('amenities', None) - - if not data or not len(data) or ( - not states and - not cities and - not amenities): - places = storage.all(Place).values() - list_places = [] - for place in places: - list_places.append(place.to_dict()) - return jsonify(list_places) - - list_places = [] - if states: - states_obj = [storage.get(State, s_id) for s_id in states] - for state in states_obj: - if state: - for city in state.cities: - if city: - for place in city.places: - list_places.append(place) - - if cities: - city_obj = [storage.get(City, c_id) for c_id in cities] - for city in city_obj: - if city: - for place in city.places: - if place not in list_places: - list_places.append(place) - - if amenities: - if not list_places: - list_places = storage.all(Place).values() - amenities_obj = [storage.get(Amenity, a_id) for a_id in amenities] - list_places = [place for place in list_places - if all([am in place.amenities - for am in amenities_obj])] - + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + all_places = storage.all(Place).values() places = [] - for p in list_places: - d = p.to_dict() - d.pop('amenities', None) - places.append(d) - - return jsonify(places) + places_id = [] + keys_status = ( + all([ + 'states' in data and type(data['states']) is list, + 'states' in data and len(data['states']) + ]), + all([ + 'cities' in data and type(data['cities']) is list, + 'cities' in data and len(data['cities']) + ]), + all([ + 'amenities' in data and type(data['amenities']) is list, + 'amenities' in data and len(data['amenities']) + ]) + ) + if keys_status[0]: + for state_id in data['states']: + if not state_id: + continue + state = storage.get(State, state_id) + if not state: + continue + for city in state.cities: + new_places = [] + if storage_t == 'db': + new_places = list( + filter(lambda x: x.id not in places_id, city.places) + ) + else: + new_places = [] + for place in all_places: + if place.id in places_id: + continue + if place.city_id == city.id: + new_places.append(place) + places.extend(new_places) + places_id.extend(list(map(lambda x: x.id, new_places))) + if keys_status[1]: + for city_id in data['cities']: + if not city_id: + continue + city = storage.get(City, city_id) + if city: + new_places = [] + if storage_t == 'db': + new_places = list( + filter(lambda x: x.id not in places_id, city.places) + ) + else: + new_places = [] + for place in all_places: + if place.id in places_id: + continue + if place.city_id == city.id: + new_places.append(place) + places.extend(new_places) + del places_id + if all([not keys_status[0], not keys_status[1]]) or not data: + places = all_places + if keys_status[2]: + amenity_ids = [] + for amenity_id in data['amenities']: + if not amenity_id: + continue + amenity = storage.get(Amenity, amenity_id) + if amenity and amenity.id not in amenity_ids: + amenity_ids.append(amenity.id) + del_indices = [] + for place in places: + place_amenities_ids = list(map(lambda x: x.id, place.amenities)) + if not amenity_ids: + continue + for amenity_id in amenity_ids: + if amenity_id not in place_amenities_ids: + del_indices.append(place.id) + break + places = list(filter(lambda x: x.id not in del_indices, places)) + result = [] + for place in places: + obj = place.to_dict() + if 'amenities' in obj: + del obj['amenities'] + result.append(obj) + return jsonify(result) diff --git a/api/v1/views/places_amenities.py b/api/v1/views/places_amenities.py index 2c3dc28c59f..dad1389ad11 100644 --- a/api/v1/views/places_amenities.py +++ b/api/v1/views/places_amenities.py @@ -1,57 +1,106 @@ #!/usr/bin/python3 -"""places_amenities.py""" -import os +'''Contains the places_amenities view for the API.''' +from flask import jsonify, request +from werkzeug.exceptions import NotFound, MethodNotAllowed + from api.v1.views import app_views -from flask import abort, jsonify, make_response, request -from models import storage +from models import storage, storage_t from models.amenity import Amenity from models.place import Place -from flasgger.utils import swag_from - - -@app_views.route('/places//amenities', methods=['GET'], - strict_slashes=False) -@swag_from('documentation/place_amenity/get_id.yml', methods=['GET']) -def get_amenities(place_id): - """ retrieves all amenities from a place """ - place = storage.get(Place, place_id) - if place is None: - abort(404) - amenities = [obj.to_dict() for obj in place.amenities] - return jsonify(amenities) - - -@app_views.route('/places//amenities/', - methods=['DELETE'], strict_slashes=False) -@swag_from('documentation/place_amenity/delete.yml', methods=['DELETE']) -def delete_amenity(place_id, amenity_id): - """ delete amenity from place """ - place = storage.get(Place, place_id) - if place is None: - abort(404) - amenity = storage.get(Amenity, amenity_id) - if amenity is None: - abort(404) - if amenity not in place.amenities: - abort(404) - place.amenities.remove(amenity) - storage.save() - return jsonify({}) - - -@app_views.route('/places//amenities/', - methods=['POST'], strict_slashes=False) -@swag_from('documentation/place_amenity/post.yml', methods=['POST']) -def post_amenity2(place_id, amenity_id): - """ post amenity by id """ - place = storage.get(Place, place_id) - if place is None: - abort(404) - amenity = storage.get(Amenity, amenity_id) - if amenity is None: - abort(404) - if amenity in place.amenities: - return (jsonify(amenity.to_dict()), 200) - place.amenities.append(obj) - storage.save() - return (jsonify(amenity.to_dict(), 201)) + + +@app_views.route('/places//amenities', methods=['GET']) +@app_views.route( + '/places//amenities/', + methods=['DELETE', 'POST'] +) +def handle_places_amenities(place_id=None, amenity_id=None): + '''The method handler for the places endpoint. + ''' + handlers = { + 'GET': get_place_amenities, + 'DELETE': remove_place_amenity, + 'POST': add_place_amenity + } + if request.method in handlers: + return handlers[request.method](place_id, amenity_id) + else: + raise MethodNotAllowed(list(handlers.keys())) + + +def get_place_amenities(place_id=None, amenity_id=None): + '''Gets the amenities of a place with the given id. + ''' + if place_id: + place = storage.get(Place, place_id) + if place: + all_amenities = list(map(lambda x: x.to_dict(), place.amenities)) + return jsonify(all_amenities) + raise NotFound() + + +def remove_place_amenity(place_id=None, amenity_id=None): + '''Removes an amenity with a given id from a place with a given id. + ''' + if place_id and amenity_id: + place = storage.get(Place, place_id) + if not place: + raise NotFound() + amenity = storage.get(Amenity, amenity_id) + if not amenity: + raise NotFound() + place_amenity_link = list( + filter(lambda x: x.id == amenity_id, place.amenities) + ) + if not place_amenity_link: + raise NotFound() + if storage_t == 'db': + amenity_place_link = list( + filter(lambda x: x.id == place_id, amenity.place_amenities) + ) + if not amenity_place_link: + raise NotFound() + place.amenities.remove(amenity) + place.save() + return jsonify({}), 200 + else: + amenity_idx = place.amenity_ids.index(amenity_id) + place.amenity_ids.pop(amenity_idx) + place.save() + return jsonify({}), 200 + raise NotFound() + + +def add_place_amenity(place_id=None, amenity_id=None): + '''Adds an amenity with a given id to a place with a given id. + ''' + if place_id and amenity_id: + place = storage.get(Place, place_id) + if not place: + raise NotFound() + amenity = storage.get(Amenity, amenity_id) + if not amenity: + raise NotFound() + if storage_t == 'db': + place_amenity_link = list( + filter(lambda x: x.id == amenity_id, place.amenities) + ) + amenity_place_link = list( + filter(lambda x: x.id == place_id, amenity.place_amenities) + ) + if amenity_place_link and place_amenity_link: + res = amenity.to_dict() + del res['place_amenities'] + return jsonify(res), 200 + place.amenities.append(amenity) + place.save() + res = amenity.to_dict() + del res['place_amenities'] + return jsonify(res), 201 + else: + if amenity_id in place.amenity_ids: + return jsonify(amenity.to_dict()), 200 + place.amenity_ids.push(amenity_id) + place.save() + return jsonify(amenity.to_dict()), 201 + raise NotFound() diff --git a/api/v1/views/places_reviews.py b/api/v1/views/places_reviews.py index b8af2a7d683..1962ad75b18 100644 --- a/api/v1/views/places_reviews.py +++ b/api/v1/views/places_reviews.py @@ -1,88 +1,96 @@ #!/usr/bin/python3 -""" -This file contains the Review module -""" +'''Contains the places_reviews view for the API.''' +from flask import jsonify, request +from werkzeug.exceptions import NotFound, MethodNotAllowed, BadRequest + from api.v1.views import app_views -from flask import jsonify, abort, request, make_response from models import storage from models.place import Place from models.review import Review from models.user import User -from flasgger.utils import swag_from -@app_views.route('/places//reviews', - methods=['GET'], strict_slashes=False) -@swag_from('documentation/reviews/get.yml', methods=['GET']) -def get_all_reviews(place_id): - """ get reviews from a spcific place """ - place = storage.get(Place, place_id) - if place is None: - abort(404) - reviews = [obj.to_dict() for obj in place.reviews] - return jsonify(reviews) +@app_views.route('/places//reviews', methods=['GET', 'POST']) +@app_views.route('/reviews/', methods=['GET', 'DELETE', 'PUT']) +def handle_reviews(place_id=None, review_id=None): + '''The method handler for the reviews endpoint. + ''' + handlers = { + 'GET': get_reviews, + 'DELETE': remove_review, + 'POST': add_review, + 'PUT': update_review + } + if request.method in handlers: + return handlers[request.method](place_id, review_id) + else: + raise MethodNotAllowed(list(handlers.keys())) -@app_views.route('/reviews/', methods=['GET'], - strict_slashes=False) -@swag_from('documentation/reviews/get_id.yml', methods=['GET']) -def get_review(review_id): - """ get review by id""" - review = storage.get(Review, review_id) - if review is None: - abort(404) - return jsonify(review.to_dict()) +def get_reviews(place_id=None, review_id=None): + '''Gets the review with the given id or all reviews in + the place with the given id. + ''' + if place_id: + place = storage.get(Place, place_id) + if place: + reviews = [] + for review in place.reviews: + reviews.append(review.to_dict()) + return jsonify(reviews) + elif review_id: + review = storage.get(Review, review_id) + if review: + return jsonify(review.to_dict()) + raise NotFound() -@app_views.route('/reviews/', methods=['DELETE'], - strict_slashes=False) -@swag_from('documentation/reviews/delete.yml', methods=['DELETE']) -def del_review(review_id): - """ delete review by id""" +def remove_review(place_id=None, review_id=None): + '''Removes a review with the given id. + ''' review = storage.get(Review, review_id) - if review is None: - abort(404) - review.delete() - storage.save() - return jsonify({}) + if review: + storage.delete(review) + storage.save() + return jsonify({}), 200 + raise NotFound() -@app_views.route('/places//reviews', methods=['POST'], - strict_slashes=False) -@swag_from('documentation/reviews/post.yml', methods=['POST']) -def create_obj_review(place_id): - """ create new instance """ +def add_review(place_id=None, review_id=None): + '''Adds a new review. + ''' place = storage.get(Place, place_id) - if place is None: - abort(404) - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - if 'user_id' not in request.get_json(): - return make_response(jsonify({"error": "Missing user_id"}), 400) - if 'text' not in request.get_json(): - return make_response(jsonify({"error": "Missing text"}), 400) - kwargs = request.get_json() - kwargs['place_id'] = place_id - user = storage.get(User, kwargs['user_id']) - if user is None: - abort(404) - obj = Review(**kwargs) - obj.save() - return (jsonify(obj.to_dict()), 201) + if not place: + raise NotFound() + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + if 'user_id' not in data: + raise BadRequest(description='Missing user_id') + user = storage.get(User, data['user_id']) + if not user: + raise NotFound() + if 'text' not in data: + raise BadRequest(description='Missing text') + data['place_id'] = place_id + new_review = Review(**data) + new_review.save() + return jsonify(new_review.to_dict()), 201 -@app_views.route('/reviews/', methods=['PUT'], - strict_slashes=False) -@swag_from('documentation/reviews/put.yml', methods=['PUT']) -def post_review(review_id): - """ updates by id """ - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - obj = storage.get(Review, review_id) - if obj is None: - abort(404) - for key, value in request.get_json().items(): - if key not in ['id', 'user_id', 'place_id', 'created_at', 'updated']: - setattr(obj, key, value) - storage.save() - return jsonify(obj.to_dict()) +def update_review(place_id=None, review_id=None): + '''Updates the review with the given id. + ''' + xkeys = ('id', 'user_id', 'place_id', 'created_at', 'updated_at') + if review_id: + review = storage.get(Review, review_id) + if review: + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + for key, value in data.items(): + if key not in xkeys: + setattr(review, key, value) + review.save() + return jsonify(review.to_dict()), 200 + raise NotFound() diff --git a/api/v1/views/states.py b/api/v1/views/states.py index fc7e318a3d7..2307ff158d5 100644 --- a/api/v1/views/states.py +++ b/api/v1/views/states.py @@ -1,71 +1,86 @@ #!/usr/bin/python3 -"""State module""" +'''Contains the states view for the API.''' +from flask import jsonify, request +from werkzeug.exceptions import NotFound, MethodNotAllowed, BadRequest + from api.v1.views import app_views -from flask import jsonify, abort, request, make_response from models import storage from models.state import State -from flasgger.utils import swag_from -@app_views.route('/states', methods=['GET'], strict_slashes=False) -@swag_from('documentation/state/get.yml', methods=['GET']) -def get_all(): - """ get all by id """ - all_list = [obj.to_dict() for obj in storage.all(State).values()] - return jsonify(all_list) +ALLOWED_METHODS = ['GET', 'DELETE', 'POST', 'PUT'] +'''Methods allowed for the states endpoint.''' + + +@app_views.route('/states', methods=ALLOWED_METHODS) +@app_views.route('/states/', methods=ALLOWED_METHODS) +def handle_states(state_id=None): + '''The method handler for the states endpoint. + ''' + handlers = { + 'GET': get_states, + 'DELETE': remove_state, + 'POST': add_state, + 'PUT': update_state, + } + if request.method in handlers: + return handlers[request.method](state_id) + else: + raise MethodNotAllowed(list(handlers.keys())) -@app_views.route('/states/', methods=['GET'], - strict_slashes=False) -@swag_from('documentation/state/get_id.yml', methods=['GET']) -def get_method_state(state_id): - """ get state by id""" - state = storage.get(State, state_id) - if state is None: - abort(404) - return jsonify(state.to_dict()) +def get_states(state_id=None): + '''Gets the state with the given id or all states. + ''' + all_states = storage.all(State).values() + if state_id: + res = list(filter(lambda x: x.id == state_id, all_states)) + if res: + return jsonify(res[0].to_dict()) + raise NotFound() + all_states = list(map(lambda x: x.to_dict(), all_states)) + return jsonify(all_states) -@app_views.route('/states/', methods=['DELETE'], - strict_slashes=False) -@swag_from('documentation/state/delete.yml', methods=['DELETE']) -def del_method(state_id): - """ delete state by id""" - state = storage.get(State, state_id) - if state is None: - abort(404) - state.delete() - storage.save() - return jsonify({}) +def remove_state(state_id=None): + '''Removes a state with the given id. + ''' + all_states = storage.all(State).values() + res = list(filter(lambda x: x.id == state_id, all_states)) + if res: + storage.delete(res[0]) + storage.save() + return jsonify({}), 200 + raise NotFound() -@app_views.route('/states/', methods=['POST'], - strict_slashes=False) -@swag_from('documentation/state/post.yml', methods=['POST']) -def create_obj(): - """ create new instance """ - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - if 'name' not in request.get_json(): - return make_response(jsonify({"error": "Missing name"}), 400) - js = request.get_json() - obj = State(**js) - obj.save() - return jsonify(obj.to_dict()), 201 +def add_state(state_id=None): + '''Adds a new state. + ''' + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + if 'name' not in data: + raise BadRequest(description='Missing name') + new_state = State(**data) + new_state.save() + return jsonify(new_state.to_dict()), 201 -@app_views.route('/states/', methods=['PUT'], - strict_slashes=False) -@swag_from('documentation/state/put.yml', methods=['PUT']) -def post_method(state_id): - """ post method """ - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - obj = storage.get(State, state_id) - if obj is None: - abort(404) - for key, value in request.get_json().items(): - if key not in ['id', 'created_at', 'updated']: - setattr(obj, key, value) - storage.save() - return jsonify(obj.to_dict()) +def update_state(state_id=None): + '''Updates the state with the given id. + ''' + xkeys = ('id', 'created_at', 'updated_at') + all_states = storage.all(State).values() + res = list(filter(lambda x: x.id == state_id, all_states)) + if res: + data = request.get_json() + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + old_state = res[0] + for key, value in data.items(): + if key not in xkeys: + setattr(old_state, key, value) + old_state.save() + return jsonify(old_state.to_dict()), 200 + raise NotFound() diff --git a/api/v1/views/users.py b/api/v1/views/users.py index ad0fa1c193c..ec68ce94636 100644 --- a/api/v1/views/users.py +++ b/api/v1/views/users.py @@ -1,75 +1,99 @@ #!/usr/bin/python3 -""" -This file contains the User module -""" +'''Contains the users view for the API.''' +from flask import jsonify, request +from werkzeug.exceptions import NotFound, BadRequest + from api.v1.views import app_views -from flask import jsonify, abort, request, make_response from models import storage from models.user import User -from flasgger.utils import swag_from -@app_views.route('/users', methods=['GET'], strict_slashes=False) -@swag_from('documentation/user/get.yml', methods=['GET']) -def get_all_users(): - """ get users by id""" - all_list = [obj.to_dict() for obj in storage.all(User).values()] - return jsonify(all_list) +@app_views.route('/users', methods=['GET']) +@app_views.route('/users/', methods=['GET']) +def get_users(user_id=None): + '''Gets the user with the given id or all users. + ''' + if user_id: + user = storage.get(User, user_id) + if user: + obj = user.to_dict() + if 'places' in obj: + del obj['places'] + if 'reviews' in obj: + del obj['reviews'] + return jsonify(obj) + raise NotFound() + all_users = storage.all(User).values() + users = [] + for user in all_users: + obj = user.to_dict() + if 'places' in obj: + del obj['places'] + if 'reviews' in obj: + del obj['reviews'] + users.append(obj) + return jsonify(users) -@app_views.route('/users/', methods=['GET'], - strict_slashes=False) -@swag_from('documentation/user/get_id.yml', methods=['GET']) -def get_user(user_id): - """ get user by id""" +@app_views.route('/users/', methods=['DELETE']) +def remove_user(user_id): + '''Removes a user with the given id. + ''' user = storage.get(User, user_id) - if user is None: - abort(404) - return jsonify(user.to_dict()) - + if user: + storage.delete(user) + storage.save() + return jsonify({}), 200 + raise NotFound() -@app_views.route('/users/', methods=['DELETE'], - strict_slashes=False) -@swag_from('documentation/user/delete.yml', methods=['DELETE']) -def del_user(user_id): - """ delete user by id""" - user = storage.get(User, user_id) - if user is None: - abort(404) - user.delete() - storage.save() - return jsonify({}) +@app_views.route('/users', methods=['POST']) +def add_user(): + '''Adds a new user. + ''' + data = {} + try: + data = request.get_json() + except Exception: + data = None + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + if 'email' not in data: + raise BadRequest(description='Missing email') + if 'password' not in data: + raise BadRequest(description='Missing password') + user = User(**data) + user.save() + obj = user.to_dict() + if 'places' in obj: + del obj['places'] + if 'reviews' in obj: + del obj['reviews'] + return jsonify(obj), 201 -@app_views.route('/users/', methods=['POST'], - strict_slashes=False) -@swag_from('documentation/user/post.yml', methods=['POST']) -def create_obj_user(): - """ create new instance """ - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - if 'email' not in request.get_json(): - return make_response(jsonify({"error": "Missing email"}), 400) - if 'password'not in request.get_json(): - return make_response(jsonify({"error": "Missing password"}), 400) - js = request.get_json() - obj = User(**js) - obj.save() - return (jsonify(obj.to_dict()), 201) - -@app_views.route('/users/', methods=['PUT'], - strict_slashes=False) -@swag_from('documentation/user/put.yml', methods=['PUT']) -def post_user(user_id): - """ """ - if not request.get_json(): - return make_response(jsonify({"error": "Not a JSON"}), 400) - obj = storage.get(User, user_id) - if obj is None: - abort(404) - for key, value in request.get_json().items(): - if key not in ['id', 'email', 'created_at', 'updated']: - setattr(obj, key, value) - storage.save() - return jsonify(obj.to_dict()) +@app_views.route('/users/', methods=['PUT']) +def update_user(user_id): + '''Updates the user with the given id. + ''' + xkeys = ('id', 'email', 'created_at', 'updated_at') + user = storage.get(User, user_id) + if user: + data = {} + try: + data = request.get_json() + except Exception: + data = None + if type(data) is not dict: + raise BadRequest(description='Not a JSON') + for key, value in data.items(): + if key not in xkeys: + setattr(user, key, value) + user.save() + obj = user.to_dict() + if 'places' in obj: + del obj['places'] + if 'reviews' in obj: + del obj['reviews'] + return jsonify(obj), 200 + raise NotFound() From c80b3e8a1c8d49829b54130d07512c343524c36f Mon Sep 17 00:00:00 2001 From: Damilola-Nuga <58979551+Damilola-Nuga@users.noreply.github.com> Date: Tue, 18 Feb 2025 03:36:27 +0100 Subject: [PATCH 4/4] 2 yeah --- models/engine/db_storage.py | 11 +++++ models/engine/file_storage.py | 17 +++++++ .../test_engine/test_db_storage.py | 45 ++++++++++++++++--- .../test_engine/test_file_storage.py | 42 +++++++++++++++-- 4 files changed, 107 insertions(+), 8 deletions(-) diff --git a/models/engine/db_storage.py b/models/engine/db_storage.py index b8e7d291e6f..121de953931 100755 --- a/models/engine/db_storage.py +++ b/models/engine/db_storage.py @@ -51,6 +51,17 @@ def all(self, cls=None): new_dict[key] = obj return (new_dict) + def get(self, cls, id): + """retrieves an object of a class with id""" + obj = None + if cls is not None and issubclass(cls, BaseModel): + obj = self.__session.query(cls).filter(cls.id == id).first() + return obj + + def count(self, cls=None): + """retrieves the number of objects of a class or all (if cls==None)""" + return len(self.all(cls)) + def new(self, obj): """add the object to the current database session""" self.__session.add(obj) diff --git a/models/engine/file_storage.py b/models/engine/file_storage.py index d78a9821e5d..e8152c827e8 100755 --- a/models/engine/file_storage.py +++ b/models/engine/file_storage.py @@ -34,6 +34,23 @@ def all(self, cls=None): return new_dict return self.__objects + def get(self, cls, id): + """retrieves an object of a class with id""" + if cls is not None: + res = list( + filter( + lambda x: type(x) is cls and x.id == id, + self.__objects.values() + ) + ) + if res: + return res[0] + return None + + def count(self, cls=None): + """retrieves the number of objects of a class or all (if cls==None)""" + return len(self.all(cls)) + def new(self, obj): """sets in __objects the obj with key .id""" if obj is not None: diff --git a/tests/test_models/test_engine/test_db_storage.py b/tests/test_models/test_engine/test_db_storage.py index 766e625b5af..152aaeb90e3 100755 --- a/tests/test_models/test_engine/test_db_storage.py +++ b/tests/test_models/test_engine/test_db_storage.py @@ -68,21 +68,56 @@ def test_dbs_func_docstrings(self): "{:s} method needs a docstring".format(func[0])) -class TestFileStorage(unittest.TestCase): +@unittest.skipIf(models.storage_t != 'db', "not testing db storage") +class TestDBStorage(unittest.TestCase): """Test the FileStorage class""" - @unittest.skipIf(models.storage_t != 'db', "not testing db storage") def test_all_returns_dict(self): """Test that all returns a dictionaty""" self.assertIs(type(models.storage.all()), dict) - @unittest.skipIf(models.storage_t != 'db', "not testing db storage") def test_all_no_class(self): """Test that all returns all rows when no class is passed""" - @unittest.skipIf(models.storage_t != 'db', "not testing db storage") def test_new(self): """test that new adds an object to the database""" - @unittest.skipIf(models.storage_t != 'db', "not testing db storage") def test_save(self): """Test that save properly saves objects to file.json""" + + def test_get(self): + """test that get returns an object of a given class by id.""" + storage = models.storage + obj = State(name='Michigan') + obj.save() + self.assertEqual(obj.id, storage.get(State, obj.id).id) + self.assertEqual(obj.name, storage.get(State, obj.id).name) + self.assertIsNot(obj, storage.get(State, obj.id + 'op')) + self.assertIsNone(storage.get(State, obj.id + 'op')) + self.assertIsNone(storage.get(State, 45)) + self.assertIsNone(storage.get(None, obj.id)) + self.assertIsNone(storage.get(int, obj.id)) + with self.assertRaises(TypeError): + storage.get(State, obj.id, 'op') + with self.assertRaises(TypeError): + storage.get(State) + with self.assertRaises(TypeError): + storage.get() + + def test_count(self): + """test that count returns the number of objects of a given class.""" + storage = models.storage + self.assertIs(type(storage.count()), int) + self.assertIs(type(storage.count(None)), int) + self.assertIs(type(storage.count(int)), int) + self.assertIs(type(storage.count(State)), int) + self.assertEqual(storage.count(), storage.count(None)) + State(name='Lagos').save() + self.assertGreater(storage.count(State), 0) + self.assertEqual(storage.count(), storage.count(None)) + a = storage.count(State) + State(name='Enugu').save() + self.assertGreater(storage.count(State), a) + Amenity(name='Free WiFi').save() + self.assertGreater(storage.count(), storage.count(State)) + with self.assertRaises(TypeError): + storage.count(State, 'op') diff --git a/tests/test_models/test_engine/test_file_storage.py b/tests/test_models/test_engine/test_file_storage.py index 1474a34fec0..e2df4ff8fc9 100755 --- a/tests/test_models/test_engine/test_file_storage.py +++ b/tests/test_models/test_engine/test_file_storage.py @@ -68,9 +68,9 @@ def test_fs_func_docstrings(self): "{:s} method needs a docstring".format(func[0])) +@unittest.skipIf(models.storage_t == 'db', "not testing file storage") class TestFileStorage(unittest.TestCase): """Test the FileStorage class""" - @unittest.skipIf(models.storage_t == 'db', "not testing file storage") def test_all_returns_dict(self): """Test that all returns the FileStorage.__objects attr""" storage = FileStorage() @@ -78,7 +78,6 @@ def test_all_returns_dict(self): self.assertEqual(type(new_dict), dict) self.assertIs(new_dict, storage._FileStorage__objects) - @unittest.skipIf(models.storage_t == 'db', "not testing file storage") def test_new(self): """test that new adds an object to the FileStorage.__objects attr""" storage = FileStorage() @@ -94,7 +93,6 @@ def test_new(self): self.assertEqual(test_dict, storage._FileStorage__objects) FileStorage._FileStorage__objects = save - @unittest.skipIf(models.storage_t == 'db', "not testing file storage") def test_save(self): """Test that save properly saves objects to file.json""" storage = FileStorage() @@ -113,3 +111,41 @@ def test_save(self): with open("file.json", "r") as f: js = f.read() self.assertEqual(json.loads(string), json.loads(js)) + + def test_get(self): + """test that get returns an object of a given class by id.""" + storage = models.storage + obj = State(name='Michigan') + obj.save() + self.assertEqual(obj.id, storage.get(State, obj.id).id) + self.assertEqual(obj.name, storage.get(State, obj.id).name) + self.assertIsNot(obj, storage.get(State, obj.id + 'op')) + self.assertIsNone(storage.get(State, obj.id + 'op')) + self.assertIsNone(storage.get(State, 45)) + self.assertIsNone(storage.get(None, obj.id)) + self.assertIsNone(storage.get(int, obj.id)) + with self.assertRaises(TypeError): + storage.get(State, obj.id, 'op') + with self.assertRaises(TypeError): + storage.get(State) + with self.assertRaises(TypeError): + storage.get() + + def test_count(self): + """test that count returns the number of objects of a given class.""" + storage = models.storage + self.assertIs(type(storage.count()), int) + self.assertIs(type(storage.count(None)), int) + self.assertIs(type(storage.count(int)), int) + self.assertIs(type(storage.count(State)), int) + self.assertEqual(storage.count(), storage.count(None)) + State(name='Lagos').save() + self.assertGreater(storage.count(State), 0) + self.assertEqual(storage.count(), storage.count(None)) + a = storage.count(State) + State(name='Enugu').save() + self.assertGreater(storage.count(State), a) + Amenity(name='Free WiFi').save() + self.assertGreater(storage.count(), storage.count(State)) + with self.assertRaises(TypeError): + storage.count(State, 'op')