From b7e93aa61fec5a4aff238dbd9c477b71beb24a62 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 14 Dec 2022 10:45:36 -0800 Subject: [PATCH 01/48] added class file --- app/planets.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/planets.py diff --git a/app/planets.py b/app/planets.py new file mode 100644 index 000000000..e69de29bb From 5a60c6d008a9a5cbd89fe15fb79082d695de50a4 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 14 Dec 2022 10:49:15 -0800 Subject: [PATCH 02/48] Add moon file --- app/moon.py | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 app/moon.py diff --git a/app/moon.py b/app/moon.py new file mode 100644 index 000000000..01ccfb9b0 --- /dev/null +++ b/app/moon.py @@ -0,0 +1,3 @@ +class Moon: + def __init__(self): + pass \ No newline at end of file From 27cbb176f6c71655aa7a200587a9bd855e9eb7fd Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 14 Dec 2022 10:50:49 -0800 Subject: [PATCH 03/48] simple planet with constructor --- app/planets.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/planets.py b/app/planets.py index e69de29bb..fd079e8f5 100644 --- a/app/planets.py +++ b/app/planets.py @@ -0,0 +1,7 @@ +class Planet: + def __init__(self, id, name, description, has_rings=False, moons=None): + self.id=id + self.name=name + self.description=description + self.has_rings=has_rings + self.moons = moons if moons else [] From a3b70bbb59f9ba4bf0090671a50a2f747678847f Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 14 Dec 2022 10:58:04 -0800 Subject: [PATCH 04/48] Add and register planets route --- app/__init__.py | 2 ++ app/routes.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/__init__.py b/app/__init__.py index 70b4cabfe..3675c9309 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,4 +4,6 @@ def create_app(test_config=None): app = Flask(__name__) + from .routes import planets_bp + app.register_blueprint(planets_bp) return app diff --git a/app/routes.py b/app/routes.py index 8e9dfe684..656c1cb88 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,2 +1,4 @@ from flask import Blueprint +planets_bp = Blueprint("planets", __name__, url_prefix="/planets") + From f93a7e438267546f996fbd18e37b653ff7570560 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 14 Dec 2022 10:59:36 -0800 Subject: [PATCH 05/48] updated classes --- app/planets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/app/planets.py b/app/planets.py index fd079e8f5..0c0435691 100644 --- a/app/planets.py +++ b/app/planets.py @@ -1,3 +1,4 @@ +from .moon import Moon class Planet: def __init__(self, id, name, description, has_rings=False, moons=None): self.id=id From dcfc1ec04d37fd808bc0f0fadaa345ae5cd01dd3 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 14 Dec 2022 11:00:57 -0800 Subject: [PATCH 06/48] updated moon --- app/moon.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/moon.py b/app/moon.py index 01ccfb9b0..07da93d0e 100644 --- a/app/moon.py +++ b/app/moon.py @@ -1,3 +1,7 @@ class Moon: - def __init__(self): - pass \ No newline at end of file + def __init__(self, id, name, description): + self.id=id + self.name=name + self.id=id + self.description=description + \ No newline at end of file From 1f920e13439cbc93e63e9fe8adc2e3218c9bd53b Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 14 Dec 2022 11:10:29 -0800 Subject: [PATCH 07/48] Add planets test route --- app/routes.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/app/routes.py b/app/routes.py index 656c1cb88..0ddd5a922 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,4 +1,10 @@ -from flask import Blueprint - +from flask import Blueprint, jsonify planets_bp = Blueprint("planets", __name__, url_prefix="/planets") +@planets_bp.route("", methods=["GET"]) +def display_planets(): + return "Test Planets" + + + + From 23512bfc9b6444e9cbc8f81d82de6fde5a275ac8 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 14 Dec 2022 11:15:01 -0800 Subject: [PATCH 08/48] moons updated --- app/moon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/moon.py b/app/moon.py index 07da93d0e..78c46b4d6 100644 --- a/app/moon.py +++ b/app/moon.py @@ -2,6 +2,6 @@ class Moon: def __init__(self, id, name, description): self.id=id self.name=name - self.id=id self.description=description - \ No newline at end of file + +moons_list = [Moon(1, "Moon", "Earths Moon")] \ No newline at end of file From 21321af9b5ed0c42859b9eaccf2176af0089bb4f Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 14 Dec 2022 11:19:05 -0800 Subject: [PATCH 09/48] small changes to moons and planets --- app/moon.py | 5 ++++- app/planets.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/moon.py b/app/moon.py index 78c46b4d6..116a25148 100644 --- a/app/moon.py +++ b/app/moon.py @@ -4,4 +4,7 @@ def __init__(self, id, name, description): self.name=name self.description=description -moons_list = [Moon(1, "Moon", "Earths Moon")] \ No newline at end of file + +moons_list = [] +first_mon = Moon(1, "Moon", "Earths Moon") +moons_list.append(first_mon) \ No newline at end of file diff --git a/app/planets.py b/app/planets.py index 0c0435691..712c89db8 100644 --- a/app/planets.py +++ b/app/planets.py @@ -1,4 +1,4 @@ -from .moon import Moon +from .moon import Moon, moons_list class Planet: def __init__(self, id, name, description, has_rings=False, moons=None): self.id=id From fcdb77de90fae6778b00199c390eb9f82dfa6b60 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 14 Dec 2022 11:33:27 -0800 Subject: [PATCH 10/48] planets done --- app/planets.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/planets.py b/app/planets.py index 712c89db8..47be15e26 100644 --- a/app/planets.py +++ b/app/planets.py @@ -6,3 +6,20 @@ def __init__(self, id, name, description, has_rings=False, moons=None): self.description=description self.has_rings=has_rings self.moons = moons if moons else [] + + +solar_system=[] +mercurey = Planet(1, "Mercury", "First Planet near the Sun") +solar_system.append(mercurey) +venus = Planet(2, "Venus", "Second Planet from the sun") +solar_system.append(venus) +earth = Planet(3, "Earth", "Has Humans", False, [moons_list[0]]) +solar_system.append(earth) +mars= Planet(4, "Mars", "Being explored by robots, considered for space colony") +solar_system.append(mars) +jupiter = Planet(5, "Jupiter", "Largest Gas Giant", has_rings=True) +solar_system.append(jupiter) +saturn = Planet(6, "Saturn", "Gas Giant", has_rings=True) +solar_system.append(saturn) +uranus = Planet(7, "Uranus", "Smells bad", has_rings=True) +neptune = Planet(8, "Neptue", "Named for the god of the sea because it is blue", has_rings=True) \ No newline at end of file From 6c7b3aa257b1e5352611f4f6291eeae12a7fd8c3 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 14 Dec 2022 11:37:23 -0800 Subject: [PATCH 11/48] Add and register moons route --- app/__init__.py | 3 ++- app/routes.py | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/app/__init__.py b/app/__init__.py index 3675c9309..d769a6364 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,6 +4,7 @@ def create_app(test_config=None): app = Flask(__name__) - from .routes import planets_bp + from .routes import planets_bp, moons_bp app.register_blueprint(planets_bp) + app.register_blueprint(moons_bp) return app diff --git a/app/routes.py b/app/routes.py index 0ddd5a922..aa737cd5b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,9 +1,33 @@ from flask import Blueprint, jsonify +from .moon import moons_list planets_bp = Blueprint("planets", __name__, url_prefix="/planets") +moons_bp = Blueprint("moons", __name__, url_prefix="/moons") @planets_bp.route("", methods=["GET"]) def display_planets(): return "Test Planets" + + +@planets_bp.route("/", methods=["GET"]) +def display_planet(planet_id): + pass + +@moons_bp.route("", methods=["GET"]) +def get_all_moons(): + moons_response = [] + for moon in moons_list: + moons_response.append({ + "id":moon.id, + "name": moon.name, + "description": moon.description + }) + return jsonify(moons_response) + + + + + + From 091c4cb76c07153e789ec1ddb85617d08aa8c6ad Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 14 Dec 2022 11:50:52 -0800 Subject: [PATCH 12/48] display all planet --- app/routes.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index aa737cd5b..809d2812a 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,11 +1,22 @@ from flask import Blueprint, jsonify from .moon import moons_list +from .planets import Planet, solar_system planets_bp = Blueprint("planets", __name__, url_prefix="/planets") moons_bp = Blueprint("moons", __name__, url_prefix="/moons") @planets_bp.route("", methods=["GET"]) def display_planets(): - return "Test Planets" + planets_response = [] + for planet in solar_system: + planets_response.append({ + "id": planet.id, + "name": planet.name, + "description": planet.description, + "Has Rings": planet.has_rings, + "Moons" : [moon.name for moon in planet.moons] + }) + return jsonify(planets_response) + @planets_bp.route("/", methods=["GET"]) From 3079e6bf580aa71eb62fa25f771cf9a7960ab37b Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 14 Dec 2022 14:25:48 -0800 Subject: [PATCH 13/48] Update display_planet method --- app/routes.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/routes.py b/app/routes.py index 809d2812a..7630ae631 100644 --- a/app/routes.py +++ b/app/routes.py @@ -21,7 +21,17 @@ def display_planets(): @planets_bp.route("/", methods=["GET"]) def display_planet(planet_id): - pass + planet_id = int(planet_id) + for planet in solar_system: + if planet.id == planet_id: + return { + "id": planet.id, + "name": planet.name, + "description": planet.description, + "Has Rings": planet.has_rings, + "Moons" : [moon.name for moon in planet.moons] + } + return {"message":f"{planet_id} not found"}, 404 @moons_bp.route("", methods=["GET"]) def get_all_moons(): From 5fdf06f43a44cad4a9dbb2593739491cfa84eaa8 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Thu, 15 Dec 2022 10:58:56 -0800 Subject: [PATCH 14/48] Add error handling for routes.py and methods for planets.py and moons.py --- app/moon.py | 29 +++++++++++++++++++++++--- app/planets.py | 10 +++++++++ app/routes.py | 55 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/app/moon.py b/app/moon.py index 116a25148..151fd341c 100644 --- a/app/moon.py +++ b/app/moon.py @@ -1,10 +1,33 @@ class Moon: - def __init__(self, id, name, description): + def __init__(self, id, name, description, planet_id): self.id=id self.name=name self.description=description + self.planet_id = planet_id + + def get_siblings_moons(self): + siblings_moons = [] + for moon in moons_list: + if moon.planet_id == self.planet_id: + siblings_moons.append(moon) + return siblings_moons + moons_list = [] -first_mon = Moon(1, "Moon", "Earths Moon") -moons_list.append(first_mon) \ No newline at end of file +first_mon = Moon(1, "Luna", "Earths Moon", 3) +moons_list.append(first_mon) +second_moon = Moon(2,"Phobos", "Moon of mars discovered in 1877", 4) +third_moon = Moon(3, "Deimos", "Second moon of mars discovered in 1877", 4) +forth_moon = Moon(4, "Io", "discovered in 1610", 5) +fifth_moon = Moon(5, "Europa", "discovered 1610", 5) +sixth_moon = Moon(6, "Ganymede", "discovered 1610", 6) +seventh_moon = Moon(7, "Callisto", "Discovered 1610", 5) +eigth_moon = Moon(8, "Amalthea", "Discovered in 1982", 5) +moons_list.append(second_moon) +moons_list.append(third_moon) +moons_list.append(forth_moon) +moons_list.append(fifth_moon) +moons_list.append(sixth_moon) +moons_list.append(seventh_moon) +moons_list.append(eigth_moon) diff --git a/app/planets.py b/app/planets.py index 47be15e26..a09aaced5 100644 --- a/app/planets.py +++ b/app/planets.py @@ -6,6 +6,16 @@ def __init__(self, id, name, description, has_rings=False, moons=None): self.description=description self.has_rings=has_rings self.moons = moons if moons else [] + + def add_moon(self, moon): + # validate if is a moon object + if moon.__class__.__name__ != "Moon": + raise ValueError(f"{moon} is not a moon.") + # validate if the planet_id of the moon is the same as self.id + if moon.planet_id != self.id: + raise ValueError(f"{moon} is not the moon of {self.name}") + self.moons.append(moon) + solar_system=[] diff --git a/app/routes.py b/app/routes.py index 7630ae631..936142306 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,4 +1,4 @@ -from flask import Blueprint, jsonify +from flask import Blueprint, jsonify, abort, make_response from .moon import moons_list from .planets import Planet, solar_system planets_bp = Blueprint("planets", __name__, url_prefix="/planets") @@ -17,21 +17,28 @@ def display_planets(): }) return jsonify(planets_response) - +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"message":f"{planet_id} invalid"}, 400)) + + for planet in solar_system: + if planet.id == planet_id: + return planet + abort(make_response({"message":f"Planet with {planet_id} not found"}, 404)) @planets_bp.route("/", methods=["GET"]) def display_planet(planet_id): - planet_id = int(planet_id) - for planet in solar_system: - if planet.id == planet_id: - return { - "id": planet.id, - "name": planet.name, - "description": planet.description, - "Has Rings": planet.has_rings, - "Moons" : [moon.name for moon in planet.moons] - } - return {"message":f"{planet_id} not found"}, 404 + planet = validate_planet(planet_id) + return { + "id": planet.id, + "name": planet.name, + "description": planet.description, + "Has Rings": planet.has_rings, + "Moons" : [moon.name for moon in planet.moons] + } + @moons_bp.route("", methods=["GET"]) def get_all_moons(): @@ -44,12 +51,24 @@ def get_all_moons(): }) return jsonify(moons_response) - - +def validate_moon(moon_id): + try: + moon_id=int(moon_id) + except: + abort(make_response({"message":f"moon {moon_id} invalid"})) - - + for moon in moons_list: + if moon.id==moon_id: + return moon + abort(make_response({"message": f"moon {moon_id} not found"})) +@moons_bp.route("/", methods=["GET"]) +def get_moon_by_id(moon_id): + moon=validate_moon(moon_id) - + return { + "id": moon.id, + "name": moon.name, + "description": moon.description + } \ No newline at end of file From 531d19c7d27e6caa24035e34ade7f357bb9e819f Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Sat, 17 Dec 2022 15:04:58 -0800 Subject: [PATCH 15/48] Updated data info for planets. --- app/planets.py | 38 +++++++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/app/planets.py b/app/planets.py index 47be15e26..f8fc58bcf 100644 --- a/app/planets.py +++ b/app/planets.py @@ -1,25 +1,45 @@ from .moon import Moon, moons_list class Planet: - def __init__(self, id, name, description, has_rings=False, moons=None): + def __init__(self, id, name, description, mass, diameter, density, gravity, escape_velocity, + rotation_period, day_length, distance_from_sun, orbital_period, orbital_velocity, orbital_inclination, orbital_eccentricity, + obliquity_to_orbit, mean_tempurature_c, surface_pressure, global_magnetic_feild,img,has_rings=False, moons=None): self.id=id self.name=name self.description=description + self.mass=mass + self.diameter=diameter + self.density=density + self.gravity=gravity + self.escape_velocity=escape_velocity + self.rotation_period=rotation_period + self.day_length=day_length + self.distance_from_sun=distance_from_sun + self.orbital_period=orbital_period + self.orbital_velocity=orbital_velocity + self.orbital_inclination=orbital_inclination + self.orbital_eccentricity=orbital_eccentricity + self.obliquity_to_orbit=obliquity_to_orbit + self.mean_tempurature_c=mean_tempurature_c + self.surface_pressure=surface_pressure + self.global_magnetic_feild=global_magnetic_feild + self.img=img self.has_rings=has_rings self.moons = moons if moons else [] solar_system=[] -mercurey = Planet(1, "Mercury", "First Planet near the Sun") +mercurey = Planet(1, "Mercury", "First Planet near the Sun", .330, 4878, 5429, 3.7, 4.3, 1407.6, 4222.6, +57.9, 88.0, 47.4, 7.0, .206, .034, 167, 0, False, 'https://photojournal.jpl.nasa.gov/jpegMod/PIA16853_modest.jpg') solar_system.append(mercurey) -venus = Planet(2, "Venus", "Second Planet from the sun") +venus = Planet(2, "Venus", "Second Planet from the sun", 4.87, 12104, 5243, 8.9, 10.4, -5832.5, 2802.0, 108.2, 224.7, 35.0, 3.4, .0007, 177.4, 464, 92, False, 'https://solarsystem.nasa.gov/resources/2524/newly-processed-views-of-venus-from-mariner-10/?category=planets_venus') solar_system.append(venus) -earth = Planet(3, "Earth", "Has Humans", False, [moons_list[0]]) +earth = Planet(3, "Earth", "Has Humans", 5.97, 12756, 5514, 9.8, 11.2, 23.9, 24.0, 149.6, 365.2, 29.8, 0.0, .017, 23.4, 15, 1, True, 'https://solarsystem.nasa.gov/resources/786/blue-marble-2002/?category=planets_earth', False, [moons_list[0]]) solar_system.append(earth) -mars= Planet(4, "Mars", "Being explored by robots, considered for space colony") +mars= Planet(4, "Mars", "Being explored by robots, considered for space colony", .642, 6792, 3934, 3.7, 5, 24.6, 24.7, 228, 687, 24.1, 1.8, .094, 25.2, -65, .01, False, 'https://solarsystem.nasa.gov/resources/948/hubbles-close-up-view-of-mars-dust-storm/?category=planets_mars') solar_system.append(mars) -jupiter = Planet(5, "Jupiter", "Largest Gas Giant", has_rings=True) +jupiter = Planet(5, "Jupiter", "Largest Gas Giant", 1898, 142984, 1326, 23.1, 59.5, 9.9, 9.9, 778.5, 4331,13.1, 1.3, .049, 3.1, -110, None, True, 'https://solarsystem.nasa.gov/resources/2486/hubbles-new-portrait-of-jupiter/?category=planets_jupiter', has_rings=True) solar_system.append(jupiter) -saturn = Planet(6, "Saturn", "Gas Giant", has_rings=True) +saturn = Planet(6, "Saturn", "Gas Giant", 568, 120536, 687, 9, 35.5, 10.7, 10.7, 1432.0, 10747, 9.7, 2.5, .052, 26.7, -140, None, True, 'https://solarsystem.nasa.gov/resources/2490/saturns-rings-shine-in-hubble-portrait/?category=planets_saturn', has_rings=True) solar_system.append(saturn) -uranus = Planet(7, "Uranus", "Smells bad", has_rings=True) -neptune = Planet(8, "Neptue", "Named for the god of the sea because it is blue", has_rings=True) \ No newline at end of file +uranus = Planet(7, "Uranus", "Smells bad",86.8, 51118, 1270, 8.7, 21.3, -17.2, 17.2, 2867, 30589, 6.8, .8, .047, 97.8, -195, None, True, 'https://solarsystem.nasa.gov/resources/605/keck-telescope-views-of-uranus/?category=planets_uranus', has_rings=True) +neptune = Planet(8, "Neptue", "Named for the god of the sea because it is blue", 102, 49528, 1638, 11.0, 23.5, 16.1, 16.1, 4515, 59800, 5.4, 1.8, .010, 28.3, -200, None, True, 'https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune', has_rings=True) \ No newline at end of file From cb0761cf2034e0a3f5fba09ceac600e80951889b Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Sun, 18 Dec 2022 19:10:32 -0800 Subject: [PATCH 16/48] Update planets routes and add serialize funtion to return all attributes --- app/planets.py | 8 +++++++- app/routes.py | 31 +++++++++++++++++-------------- 2 files changed, 24 insertions(+), 15 deletions(-) diff --git a/app/planets.py b/app/planets.py index eadac4789..3c0de00d3 100644 --- a/app/planets.py +++ b/app/planets.py @@ -35,7 +35,13 @@ def add_moon(self, moon): raise ValueError(f"{moon} is not the moon of {self.name}") self.moons.append(moon) - + def serialize(self): + filtered_attributes = self.__dict__.copy() + new_value = [] + for moon_object in filtered_attributes["moons"]: + new_value.append(moon_object.name) + filtered_attributes["moons"] = new_value + return filtered_attributes solar_system=[] mercurey = Planet(1, "Mercury", "First Planet near the Sun", .330, 4878, 5429, 3.7, 4.3, 1407.6, 4222.6, diff --git a/app/routes.py b/app/routes.py index 936142306..bfe936916 100644 --- a/app/routes.py +++ b/app/routes.py @@ -8,13 +8,14 @@ def display_planets(): planets_response = [] for planet in solar_system: - planets_response.append({ - "id": planet.id, - "name": planet.name, - "description": planet.description, - "Has Rings": planet.has_rings, - "Moons" : [moon.name for moon in planet.moons] - }) + # planets_response.append({ + # "id": planet.id, + # "name": planet.name, + # "description": planet.description, + # "Has Rings": planet.has_rings, + # "Moons" : [moon.name for moon in planet.moons] + # }) + planets_response.append(planet.serialize()) return jsonify(planets_response) def validate_planet(planet_id): @@ -31,13 +32,15 @@ def validate_planet(planet_id): @planets_bp.route("/", methods=["GET"]) def display_planet(planet_id): planet = validate_planet(planet_id) - return { - "id": planet.id, - "name": planet.name, - "description": planet.description, - "Has Rings": planet.has_rings, - "Moons" : [moon.name for moon in planet.moons] - } + # return { + # "id": planet.id, + # "name": planet.name, + # "description": planet.description, + # "Has Rings": planet.has_rings, + # "Moons" : [moon.name for moon in planet.moons] + # } + # Use __dict__ to access all the attributes from planet + return planet.serialize() @moons_bp.route("", methods=["GET"]) From 16a9048704402a8978276f91b38671c9159bf44c Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Tue, 20 Dec 2022 12:28:48 -0800 Subject: [PATCH 17/48] Added modules, created new routes, init database. Co-authored-by: Ya-Juan Ruan --- app/__init__.py | 16 ++ app/models/celestial_body.py | 7 + app/models/moon.py | 56 +++++++ app/models/planet.py | 126 +++++++++++++++ app/moon.py | 33 ---- app/planets.py | 61 ------- app/routes.py | 153 +++++++++++++----- migrations/README | 1 + migrations/alembic.ini | 45 ++++++ migrations/env.py | 96 +++++++++++ migrations/script.py.mako | 24 +++ ...34596_add_moon_planet_and_bodies_models.py | 69 ++++++++ 12 files changed, 550 insertions(+), 137 deletions(-) create mode 100644 app/models/celestial_body.py create mode 100644 app/models/moon.py create mode 100644 app/models/planet.py delete mode 100644 app/moon.py delete mode 100644 app/planets.py create mode 100644 migrations/README create mode 100644 migrations/alembic.ini create mode 100644 migrations/env.py create mode 100644 migrations/script.py.mako create mode 100644 migrations/versions/6015f9934596_add_moon_planet_and_bodies_models.py diff --git a/app/__init__.py b/app/__init__.py index d769a6364..3a2cc797f 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,9 +1,25 @@ from flask import Flask +from flask_sqlalchemy import SQLAlchemy +from flask_migrate import Migrate + +db = SQLAlchemy() +migrate = Migrate() def create_app(test_config=None): app = Flask(__name__) + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://postgres:postgres@localhost:5432/solar_system' + + db.init_app(app) + migrate.init_app(app,db) + from app.models.celestial_body import CelestialBody + from app.models.planet import Planet + from app.models.moon import Moon + + #from app.models.planet import Planet + #from app.models.moon import Moon from .routes import planets_bp, moons_bp app.register_blueprint(planets_bp) app.register_blueprint(moons_bp) diff --git a/app/models/celestial_body.py b/app/models/celestial_body.py new file mode 100644 index 000000000..99d4a79ac --- /dev/null +++ b/app/models/celestial_body.py @@ -0,0 +1,7 @@ +from app import db +class CelestialBody(db.Model): + __tablename__ = 'celestial_bodies' + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + name=db.Column(db.String) + description = db.Column(db.String) + image=db.Column(db.String) diff --git a/app/models/moon.py b/app/models/moon.py new file mode 100644 index 000000000..411b20203 --- /dev/null +++ b/app/models/moon.py @@ -0,0 +1,56 @@ +from app import db + +class Moon(db.Model): + __tablename__='moons' + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + name = db.Column(db.String) + description = db.Column(db.String) + image = db.Column(db.String) + planet_id = db.Column(db.Integer, db.ForeignKey('planets.id')) + planet = db.relationship("Planet", back_populates="moons") + + + def to_dict(self): + moons_as_dict = {} + moons_as_dict["id"] = self.id + moons_as_dict["name"] = self.name + moons_as_dict["description"] = self.description + + return moons_as_dict + + @classmethod + def from_dict(cls, moon_data): + new_moon = Moon(name=moon_data["name"], description=moon_data["desciption"]) + return new_moon +# def __init__(self, id, name, description, planet_id): +# self.id=id +# self.name=name +# self.description=description +# self.planet_id = planet_id + + +# def get_siblings_moons(self): +# siblings_moons = [] +# for moon in moons_list: +# if moon.planet_id == self.planet_id: +# siblings_moons.append(moon) +# return siblings_moons + + +# moons_list = [] +# first_mon = Moon(1, "Luna", "Earths Moon", 3) +# moons_list.append(first_mon) +# second_moon = Moon(2,"Phobos", "Moon of mars discovered in 1877", 4) +# third_moon = Moon(3, "Deimos", "Second moon of mars discovered in 1877", 4) +# forth_moon = Moon(4, "Io", "discovered in 1610", 5) +# fifth_moon = Moon(5, "Europa", "discovered 1610", 5) +# sixth_moon = Moon(6, "Ganymede", "discovered 1610", 6) +# seventh_moon = Moon(7, "Callisto", "Discovered 1610", 5) +# eigth_moon = Moon(8, "Amalthea", "Discovered in 1982", 5) +# moons_list.append(second_moon) +# moons_list.append(third_moon) +# moons_list.append(forth_moon) +# moons_list.append(fifth_moon) +# moons_list.append(sixth_moon) +# moons_list.append(seventh_moon) +# moons_list.append(eigth_moon) diff --git a/app/models/planet.py b/app/models/planet.py new file mode 100644 index 000000000..0b3087254 --- /dev/null +++ b/app/models/planet.py @@ -0,0 +1,126 @@ +#from .moon import Moon, moons_list +from app import db +class Planet(db.Model): + __tablename__='planets' + id = db.Column(db.Integer, primary_key=True, autoincrement=True) + name=db.Column(db.String) + description=db.Column(db.String) + mass=db.Column(db.Float) + diameter=db.Column(db.Float) + density=db.Column(db.Float) + gravity=db.Column(db.Float) + escape_velocity=db.Column(db.Float) + rotation_period=db.Column(db.Float) + day_length=db.Column(db.Float) + distance_from_sun=db.Column(db.Float) + orbital_period=db.Column(db.Float) + orbital_velocity=db.Column(db.Float) + orbital_inclination=db.Column(db.Float) + orbital_eccentricity=db.Column(db.Float) + obliquity_to_orbit=db.Column(db.Float) + mean_tempurature_c=db.Column(db.Float) + surface_pressure=db.Column(db.Float) + global_magnetic_feild=db.Column(db.Boolean) + img=db.Column(db.String) + has_rings=db.Column(db.Boolean) + moons = db.relationship("Moon", back_populates="planet") +# def __init__(self, id, name, description, mass, diameter, density, gravity, escape_velocity, +# rotation_period, day_length, distance_from_sun, orbital_period, orbital_velocity, orbital_inclination, orbital_eccentricity, +# obliquity_to_orbit, mean_tempurature_c, surface_pressure, global_magnetic_feild,img,has_rings=False, moons=None): +# self.id=id +# self.name=name +# self.description=description +# self.mass=mass +# self.diameter=diameter +# self.density=density +# self.gravity=gravity +# self.escape_velocity=escape_velocity +# self.rotation_period=rotation_period +# self.day_length=day_length +# self.distance_from_sun=distance_from_sun +# self.orbital_period=orbital_period +# self.orbital_velocity=orbital_velocity +# self.orbital_inclination=orbital_inclination +# self.orbital_eccentricity=orbital_eccentricity +# self.obliquity_to_orbit=obliquity_to_orbit +# self.mean_tempurature_c=mean_tempurature_c +# self.surface_pressure=surface_pressure +# self.global_magnetic_feild=global_magnetic_feild +# self.img=img +# self.has_rings=has_rings +# self.moons = moons if moons else [] + +# def add_moon(self, moon): +# # validate if is a moon object +# if moon.__class__.__name__ != "Moon": +# raise ValueError(f"{moon} is not a moon.") +# # validate if the planet_id of the moon is the same as self.id +# if moon.planet_id != self.id: +# raise ValueError(f"{moon} is not the moon of {self.name}") +# self.moons.append(moon) + +# def serialize(self): +# filtered_attributes = self.__dict__.copy() +# new_value = [] +# for moon_object in filtered_attributes["moons"]: +# new_value.append(moon_object.name) +# filtered_attributes["moons"] = new_value +# return filtered_attributes + +# solar_system=[]{ + # "name": "Mercury", + # "description": First Planet near the Sun", + # "mass": 0.330, + # "diameter":4878, + # "density": 5429, + # "gravity": 3.7, + # "escape_velocity": 4.3, + # "rotation_period": 1407.6, + # "day_length": 57.9, + # "distance_from_sun":36.04, + # "orbital_period": 88.0, + # "orbital_velocity" : 47.4, + # "orbital_inclination": 7.0, + # "orbital_eccentricity":0.206, + # "obliquity_to_orbit":0.034, + # "mean_tempurature_c":167, + # "surface_pressure":0, + # "global_magnetic_feild":False, + # "img":https://photojournal.jpl.nasa.gov/jpegMod/PIA16853_modest.jpg, + # "has_Rings": False} +# mercurey = +# Planet(1, "Mercury", "First Planet near the Sun", .330, 4878, 5429, 3.7, 4.3, 1407.6, 4222.6, +# 57.9, 88.0, 47.4, 7.0, .206, .034, 167, 0, False, 'https://photojournal.jpl.nasa.gov/jpegMod/PIA16853_modest.jpg') +# solar_system.append(mercurey){ + # "name": "Mercury", + # "description": First Planet near the Sun", + # "mass": 0.330, + # "diameter":4878, + # "density": 5429, + # "gravity": 3.7, + # "escape_velocity": 4.3, + # "rotation_period": 1407.6, + # "day_length": 57.9, + # "distance_from_sun":36.04, + # "orbital_period": 88.0, + # "orbital_velocity" : 47.4, + # "orbital_inclination": 7.0, + # "orbital_eccentricity":0.206, + # "obliquity_to_orbit":0.034, + # "mean_tempurature_c":167, + # "surface_pressure":0, + # "global_magnetic_feild":False, + # "img":https://photojournal.jpl.nasa.gov/jpegMod/PIA16853_modest.jpg, + # "has_Rings": False} +# venus = Planet(2, "Venus", "Second Planet from the sun", 4.87, 12104, 5243, 8.9, 10.4, -5832.5, 2802.0, 108.2, 224.7, 35.0, 3.4, .0007, 177.4, 464, 92, False, 'https://solarsystem.nasa.gov/resources/2524/newly-processed-views-of-venus-from-mariner-10/?category=planets_venus') +# solar_system.append(venus) +# earth = Planet(3, "Earth", "Has Humans", 5.97, 12756, 5514, 9.8, 11.2, 23.9, 24.0, 149.6, 365.2, 29.8, 0.0, .017, 23.4, 15, 1, True, 'https://solarsystem.nasa.gov/resources/786/blue-marble-2002/?category=planets_earth', False, [moons_list[0]]) +# solar_system.append(earth) +# mars= Planet(4, "Mars", "Being explored by robots, considered for space colony", .642, 6792, 3934, 3.7, 5, 24.6, 24.7, 228, 687, 24.1, 1.8, .094, 25.2, -65, .01, False, 'https://solarsystem.nasa.gov/resources/948/hubbles-close-up-view-of-mars-dust-storm/?category=planets_mars') +# solar_system.append(mars) +# jupiter = Planet(5, "Jupiter", "Largest Gas Giant", 1898, 142984, 1326, 23.1, 59.5, 9.9, 9.9, 778.5, 4331,13.1, 1.3, .049, 3.1, -110, None, True, 'https://solarsystem.nasa.gov/resources/2486/hubbles-new-portrait-of-jupiter/?category=planets_jupiter', has_rings=True) +# solar_system.append(jupiter) +# saturn = Planet(6, "Saturn", "Gas Giant", 568, 120536, 687, 9, 35.5, 10.7, 10.7, 1432.0, 10747, 9.7, 2.5, .052, 26.7, -140, None, True, 'https://solarsystem.nasa.gov/resources/2490/saturns-rings-shine-in-hubble-portrait/?category=planets_saturn', has_rings=True) +# solar_system.append(saturn) +# uranus = Planet(7, "Uranus", "Smells bad",86.8, 51118, 1270, 8.7, 21.3, -17.2, 17.2, 2867, 30589, 6.8, .8, .047, 97.8, -195, None, True, 'https://solarsystem.nasa.gov/resources/605/keck-telescope-views-of-uranus/?category=planets_uranus', has_rings=True) +# neptune = Planet(8, "Neptue", "Named for the god of the sea because it is blue", 102, 49528, 1638, 11.0, 23.5, 16.1, 16.1, 4515, 59800, 5.4, 1.8, .010, 28.3, -200, None, True, 'https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune', has_rings=True) \ No newline at end of file diff --git a/app/moon.py b/app/moon.py deleted file mode 100644 index 151fd341c..000000000 --- a/app/moon.py +++ /dev/null @@ -1,33 +0,0 @@ -class Moon: - def __init__(self, id, name, description, planet_id): - self.id=id - self.name=name - self.description=description - self.planet_id = planet_id - - - def get_siblings_moons(self): - siblings_moons = [] - for moon in moons_list: - if moon.planet_id == self.planet_id: - siblings_moons.append(moon) - return siblings_moons - - -moons_list = [] -first_mon = Moon(1, "Luna", "Earths Moon", 3) -moons_list.append(first_mon) -second_moon = Moon(2,"Phobos", "Moon of mars discovered in 1877", 4) -third_moon = Moon(3, "Deimos", "Second moon of mars discovered in 1877", 4) -forth_moon = Moon(4, "Io", "discovered in 1610", 5) -fifth_moon = Moon(5, "Europa", "discovered 1610", 5) -sixth_moon = Moon(6, "Ganymede", "discovered 1610", 6) -seventh_moon = Moon(7, "Callisto", "Discovered 1610", 5) -eigth_moon = Moon(8, "Amalthea", "Discovered in 1982", 5) -moons_list.append(second_moon) -moons_list.append(third_moon) -moons_list.append(forth_moon) -moons_list.append(fifth_moon) -moons_list.append(sixth_moon) -moons_list.append(seventh_moon) -moons_list.append(eigth_moon) diff --git a/app/planets.py b/app/planets.py deleted file mode 100644 index 3c0de00d3..000000000 --- a/app/planets.py +++ /dev/null @@ -1,61 +0,0 @@ -from .moon import Moon, moons_list -class Planet: - def __init__(self, id, name, description, mass, diameter, density, gravity, escape_velocity, - rotation_period, day_length, distance_from_sun, orbital_period, orbital_velocity, orbital_inclination, orbital_eccentricity, - obliquity_to_orbit, mean_tempurature_c, surface_pressure, global_magnetic_feild,img,has_rings=False, moons=None): - self.id=id - self.name=name - self.description=description - self.mass=mass - self.diameter=diameter - self.density=density - self.gravity=gravity - self.escape_velocity=escape_velocity - self.rotation_period=rotation_period - self.day_length=day_length - self.distance_from_sun=distance_from_sun - self.orbital_period=orbital_period - self.orbital_velocity=orbital_velocity - self.orbital_inclination=orbital_inclination - self.orbital_eccentricity=orbital_eccentricity - self.obliquity_to_orbit=obliquity_to_orbit - self.mean_tempurature_c=mean_tempurature_c - self.surface_pressure=surface_pressure - self.global_magnetic_feild=global_magnetic_feild - self.img=img - self.has_rings=has_rings - self.moons = moons if moons else [] - - def add_moon(self, moon): - # validate if is a moon object - if moon.__class__.__name__ != "Moon": - raise ValueError(f"{moon} is not a moon.") - # validate if the planet_id of the moon is the same as self.id - if moon.planet_id != self.id: - raise ValueError(f"{moon} is not the moon of {self.name}") - self.moons.append(moon) - - def serialize(self): - filtered_attributes = self.__dict__.copy() - new_value = [] - for moon_object in filtered_attributes["moons"]: - new_value.append(moon_object.name) - filtered_attributes["moons"] = new_value - return filtered_attributes - -solar_system=[] -mercurey = Planet(1, "Mercury", "First Planet near the Sun", .330, 4878, 5429, 3.7, 4.3, 1407.6, 4222.6, -57.9, 88.0, 47.4, 7.0, .206, .034, 167, 0, False, 'https://photojournal.jpl.nasa.gov/jpegMod/PIA16853_modest.jpg') -solar_system.append(mercurey) -venus = Planet(2, "Venus", "Second Planet from the sun", 4.87, 12104, 5243, 8.9, 10.4, -5832.5, 2802.0, 108.2, 224.7, 35.0, 3.4, .0007, 177.4, 464, 92, False, 'https://solarsystem.nasa.gov/resources/2524/newly-processed-views-of-venus-from-mariner-10/?category=planets_venus') -solar_system.append(venus) -earth = Planet(3, "Earth", "Has Humans", 5.97, 12756, 5514, 9.8, 11.2, 23.9, 24.0, 149.6, 365.2, 29.8, 0.0, .017, 23.4, 15, 1, True, 'https://solarsystem.nasa.gov/resources/786/blue-marble-2002/?category=planets_earth', False, [moons_list[0]]) -solar_system.append(earth) -mars= Planet(4, "Mars", "Being explored by robots, considered for space colony", .642, 6792, 3934, 3.7, 5, 24.6, 24.7, 228, 687, 24.1, 1.8, .094, 25.2, -65, .01, False, 'https://solarsystem.nasa.gov/resources/948/hubbles-close-up-view-of-mars-dust-storm/?category=planets_mars') -solar_system.append(mars) -jupiter = Planet(5, "Jupiter", "Largest Gas Giant", 1898, 142984, 1326, 23.1, 59.5, 9.9, 9.9, 778.5, 4331,13.1, 1.3, .049, 3.1, -110, None, True, 'https://solarsystem.nasa.gov/resources/2486/hubbles-new-portrait-of-jupiter/?category=planets_jupiter', has_rings=True) -solar_system.append(jupiter) -saturn = Planet(6, "Saturn", "Gas Giant", 568, 120536, 687, 9, 35.5, 10.7, 10.7, 1432.0, 10747, 9.7, 2.5, .052, 26.7, -140, None, True, 'https://solarsystem.nasa.gov/resources/2490/saturns-rings-shine-in-hubble-portrait/?category=planets_saturn', has_rings=True) -solar_system.append(saturn) -uranus = Planet(7, "Uranus", "Smells bad",86.8, 51118, 1270, 8.7, 21.3, -17.2, 17.2, 2867, 30589, 6.8, .8, .047, 97.8, -195, None, True, 'https://solarsystem.nasa.gov/resources/605/keck-telescope-views-of-uranus/?category=planets_uranus', has_rings=True) -neptune = Planet(8, "Neptue", "Named for the god of the sea because it is blue", 102, 49528, 1638, 11.0, 23.5, 16.1, 16.1, 4515, 59800, 5.4, 1.8, .010, 28.3, -200, None, True, 'https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune', has_rings=True) \ No newline at end of file diff --git a/app/routes.py b/app/routes.py index bfe936916..74652cd33 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,21 +1,40 @@ -from flask import Blueprint, jsonify, abort, make_response -from .moon import moons_list -from .planets import Planet, solar_system +from flask import Blueprint, jsonify, abort, make_response, request +from app.models.moon import Moon +from app.models.planet import Planet +from app import db planets_bp = Blueprint("planets", __name__, url_prefix="/planets") moons_bp = Blueprint("moons", __name__, url_prefix="/moons") + @planets_bp.route("", methods=["GET"]) def display_planets(): planets_response = [] + solar_system = Planet.query.all() for planet in solar_system: - # planets_response.append({ - # "id": planet.id, - # "name": planet.name, - # "description": planet.description, - # "Has Rings": planet.has_rings, - # "Moons" : [moon.name for moon in planet.moons] - # }) - planets_response.append(planet.serialize()) + planets_response.append({ + "id": planet.id, + "name": planet.name, + "description": planet.description, + "mass": planet.mass, + "diameter":planet.diameter, + "density": planet.density, + "gravity": planet.gravity, + "escape_velocity": planet.escape_velocity, + "rotation_period": planet.rotation_period, + "day_length": planet.day_length, + "distance_from_sun":planet.distance_from_sun, + "orbital_period": planet.orbital_period, + "orbital_velocity" : planet.orbital_velocity, + "orbital_inclination": planet.orbital_inclination, + "orbital_eccentricity":planet.orbital_eccentricity, + "obliquity_to_orbit":planet.obliquity_to_orbit, + "mean_tempurature":planet.mean_tempurature_c, + "surface_pressure":planet.surface_pressure, + "global_magnetic_feild":planet.global_magnetic_feild, + "img":planet.img, + "Has Rings": planet.has_rings, + #"moons":planet.moons + }) return jsonify(planets_response) def validate_planet(planet_id): @@ -23,55 +42,103 @@ def validate_planet(planet_id): planet_id = int(planet_id) except: abort(make_response({"message":f"{planet_id} invalid"}, 400)) - + solar_system = Planet.query.all() for planet in solar_system: if planet.id == planet_id: return planet abort(make_response({"message":f"Planet with {planet_id} not found"}, 404)) -@planets_bp.route("/", methods=["GET"]) -def display_planet(planet_id): - planet = validate_planet(planet_id) - # return { - # "id": planet.id, - # "name": planet.name, - # "description": planet.description, - # "Has Rings": planet.has_rings, - # "Moons" : [moon.name for moon in planet.moons] - # } - # Use __dict__ to access all the attributes from planet - return planet.serialize() +@planets_bp.route("", methods=["POST"]) +def create_planets(): + request_body=request.get_json() + new_planet = Planet( + name=request_body["name"], + description=request_body["description"], + mass=request_body["mass"], + diameter=request_body["diameter"], + density=request_body["density"], + gravity=request_body["gravity"], + escape_velocity=request_body["escape_velocity"], + rotation_period=request_body["rotation_period"], + day_length=request_body["day_length"], + distance_from_sun=request_body["distance_from_sun"], + orbital_period=request_body["orbital_period"], + orbital_velocity=request_body["orbital_velocity"], + orbital_inclination=request_body["orbital_inclination"], + orbital_eccentricity=request_body["orbital_eccentricity"], + obliquity_to_orbit=request_body["obliquity_to_orbit"], + mean_tempurature_c=request_body["mean_tempurature_c"], + surface_pressure=request_body["surface_pressure"], + global_magnetic_feild=request_body["global_magnetic_feild"], + img=request_body["img"], + has_rings=request_body["has_rings"] + ) + db.session.add(new_planet) + db.session.commit() + return make_response(f"New Planet {new_planet.name} created!", 201) + +# @planets_bp.route("/", methods=["GET"]) +# def display_planet(planet_id): +# planet = validate_planet(planet_id) +# # return { +# # "id": planet.id, +# # "name": planet.name, +# # "description": planet.description, +# # "Has Rings": planet.has_rings, +# # "Moons" : [moon.name for moon in planet.moons] +# # } +# # Use __dict__ to access all the attributes from planet +# return planet.serialize() + +@planets_bp.route("//moons", methods=["POST"]) +def create_moon(planet_id): + planet = validate_planet(planet_id) + request_body = request.get_json() + new_moon = Moon( + name=request_body["name"], + description = request_body["description"], + image = request_body["img"], + planet=planet + ) + db.session.add(new_moon) + db.session.commit() + return make_response(f"New Moon {new_moon.name} creative", 201) + @moons_bp.route("", methods=["GET"]) def get_all_moons(): moons_response = [] + moons_list = Moon.query.all() for moon in moons_list: moons_response.append({ "id":moon.id, - "name": moon.name, - "description": moon.description + "title": moon.title, + "description": moon.description, + "image":moon.image, + "planet_id":moon.planet_id, + "planet":moon.planet }) return jsonify(moons_response) -def validate_moon(moon_id): - try: - moon_id=int(moon_id) - except: - abort(make_response({"message":f"moon {moon_id} invalid"})) +# def validate_moon(moon_id): +# try: +# moon_id=int(moon_id) +# except: +# abort(make_response({"message":f"moon {moon_id} invalid"})) - for moon in moons_list: - if moon.id==moon_id: - return moon +# for moon in moons_list: +# if moon.id==moon_id: +# return moon - abort(make_response({"message": f"moon {moon_id} not found"})) +# abort(make_response({"message": f"moon {moon_id} not found"})) -@moons_bp.route("/", methods=["GET"]) -def get_moon_by_id(moon_id): - moon=validate_moon(moon_id) +# @moons_bp.route("/", methods=["GET"]) +# def get_moon_by_id(moon_id): +# moon=validate_moon(moon_id) - return { - "id": moon.id, - "name": moon.name, - "description": moon.description - } \ No newline at end of file +# return { +# "id": moon.id, +# "name": moon.name, +# "description": moon.description +# } \ No newline at end of file diff --git a/migrations/README b/migrations/README new file mode 100644 index 000000000..98e4f9c44 --- /dev/null +++ b/migrations/README @@ -0,0 +1 @@ +Generic single-database configuration. \ No newline at end of file diff --git a/migrations/alembic.ini b/migrations/alembic.ini new file mode 100644 index 000000000..f8ed4801f --- /dev/null +++ b/migrations/alembic.ini @@ -0,0 +1,45 @@ +# A generic, single database configuration. + +[alembic] +# template used to generate migration files +# file_template = %%(rev)s_%%(slug)s + +# set to 'true' to run the environment during +# the 'revision' command, regardless of autogenerate +# revision_environment = false + + +# Logging configuration +[loggers] +keys = root,sqlalchemy,alembic + +[handlers] +keys = console + +[formatters] +keys = generic + +[logger_root] +level = WARN +handlers = console +qualname = + +[logger_sqlalchemy] +level = WARN +handlers = +qualname = sqlalchemy.engine + +[logger_alembic] +level = INFO +handlers = +qualname = alembic + +[handler_console] +class = StreamHandler +args = (sys.stderr,) +level = NOTSET +formatter = generic + +[formatter_generic] +format = %(levelname)-5.5s [%(name)s] %(message)s +datefmt = %H:%M:%S diff --git a/migrations/env.py b/migrations/env.py new file mode 100644 index 000000000..8b3fb3353 --- /dev/null +++ b/migrations/env.py @@ -0,0 +1,96 @@ +from __future__ import with_statement + +import logging +from logging.config import fileConfig + +from sqlalchemy import engine_from_config +from sqlalchemy import pool +from flask import current_app + +from alembic import context + +# this is the Alembic Config object, which provides +# access to the values within the .ini file in use. +config = context.config + +# Interpret the config file for Python logging. +# This line sets up loggers basically. +fileConfig(config.config_file_name) +logger = logging.getLogger('alembic.env') + +# add your model's MetaData object here +# for 'autogenerate' support +# from myapp import mymodel +# target_metadata = mymodel.Base.metadata +config.set_main_option( + 'sqlalchemy.url', + str(current_app.extensions['migrate'].db.engine.url).replace('%', '%%')) +target_metadata = current_app.extensions['migrate'].db.metadata + +# other values from the config, defined by the needs of env.py, +# can be acquired: +# my_important_option = config.get_main_option("my_important_option") +# ... etc. + + +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + url = config.get_main_option("sqlalchemy.url") + context.configure( + url=url, target_metadata=target_metadata, literal_binds=True + ) + + with context.begin_transaction(): + context.run_migrations() + + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # this callback is used to prevent an auto-migration from being generated + # when there are no changes to the schema + # reference: http://alembic.zzzcomputing.com/en/latest/cookbook.html + def process_revision_directives(context, revision, directives): + if getattr(config.cmd_opts, 'autogenerate', False): + script = directives[0] + if script.upgrade_ops.is_empty(): + directives[:] = [] + logger.info('No changes in schema detected.') + + connectable = engine_from_config( + config.get_section(config.config_ini_section), + prefix='sqlalchemy.', + poolclass=pool.NullPool, + ) + + with connectable.connect() as connection: + context.configure( + connection=connection, + target_metadata=target_metadata, + process_revision_directives=process_revision_directives, + **current_app.extensions['migrate'].configure_args + ) + + with context.begin_transaction(): + context.run_migrations() + + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/migrations/script.py.mako b/migrations/script.py.mako new file mode 100644 index 000000000..2c0156303 --- /dev/null +++ b/migrations/script.py.mako @@ -0,0 +1,24 @@ +"""${message} + +Revision ID: ${up_revision} +Revises: ${down_revision | comma,n} +Create Date: ${create_date} + +""" +from alembic import op +import sqlalchemy as sa +${imports if imports else ""} + +# revision identifiers, used by Alembic. +revision = ${repr(up_revision)} +down_revision = ${repr(down_revision)} +branch_labels = ${repr(branch_labels)} +depends_on = ${repr(depends_on)} + + +def upgrade(): + ${upgrades if upgrades else "pass"} + + +def downgrade(): + ${downgrades if downgrades else "pass"} diff --git a/migrations/versions/6015f9934596_add_moon_planet_and_bodies_models.py b/migrations/versions/6015f9934596_add_moon_planet_and_bodies_models.py new file mode 100644 index 000000000..5e250222a --- /dev/null +++ b/migrations/versions/6015f9934596_add_moon_planet_and_bodies_models.py @@ -0,0 +1,69 @@ +"""add moon, planet and bodies models + +Revision ID: 6015f9934596 +Revises: +Create Date: 2022-12-20 11:05:53.575534 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '6015f9934596' +down_revision = None +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_table('celestial_bodies', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('image', sa.String(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('planets', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('name', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('mass', sa.Float(), nullable=True), + sa.Column('diameter', sa.Float(), nullable=True), + sa.Column('density', sa.Float(), nullable=True), + sa.Column('gravity', sa.Float(), nullable=True), + sa.Column('escape_velocity', sa.Float(), nullable=True), + sa.Column('rotation_period', sa.Float(), nullable=True), + sa.Column('day_length', sa.Float(), nullable=True), + sa.Column('distance_from_sun', sa.Float(), nullable=True), + sa.Column('orbital_period', sa.Float(), nullable=True), + sa.Column('orbital_velocity', sa.Float(), nullable=True), + sa.Column('orbital_inclination', sa.Float(), nullable=True), + sa.Column('orbital_eccentricity', sa.Float(), nullable=True), + sa.Column('obliquity_to_orbit', sa.Float(), nullable=True), + sa.Column('mean_tempurature_c', sa.Float(), nullable=True), + sa.Column('surface_pressure', sa.Float(), nullable=True), + sa.Column('global_magnetic_feild', sa.Boolean(), nullable=True), + sa.Column('img', sa.String(), nullable=True), + sa.Column('has_rings', sa.Boolean(), nullable=True), + sa.PrimaryKeyConstraint('id') + ) + op.create_table('moons', + sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), + sa.Column('title', sa.String(), nullable=True), + sa.Column('description', sa.String(), nullable=True), + sa.Column('image', sa.String(), nullable=True), + sa.Column('planet_id', sa.Integer(), nullable=True), + sa.ForeignKeyConstraint(['planet_id'], ['planets.id'], ), + sa.PrimaryKeyConstraint('id') + ) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_table('moons') + op.drop_table('planets') + op.drop_table('celestial_bodies') + # ### end Alembic commands ### From 0d78e7beecdfb88db70251966515d6ba88223278 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Tue, 20 Dec 2022 14:17:09 -0800 Subject: [PATCH 18/48] Create a json file to store all the planets data --- app/planets_data.jsonc | 194 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 app/planets_data.jsonc diff --git a/app/planets_data.jsonc b/app/planets_data.jsonc new file mode 100644 index 000000000..298ceaaf7 --- /dev/null +++ b/app/planets_data.jsonc @@ -0,0 +1,194 @@ +[ + // Mercury + { + "name": "Mercury", + "description": "First Planet near the Sun", + "mass": 0.330, + "diameter": 4878, + "density": 5429, + "gravity": 3.7, + "escape_velocity": 4.3, + "rotation_period": 1407.6, + "day_length": 57.9, + "distance_from_sun": 36.04, + "orbital_period": 88.0, + "orbital_velocity": 47.4, + "orbital_inclination": 7.0, + "orbital_eccentricity": 0.206, + "obliquity_to_orbit": 0.034, + "mean_tempurature_c": 167, + "surface_pressure": 0, + "global_magnetic_feild": false, + "img": "https://photojournal.jpl.nasa.gov/jpegMod/PIA16853_modest.jpg", + "has_rings": false, + "moons": [] + }, + // Venus + { + "name": "Venus", + "description": "Second Planet from the sun", + "mass": 4.87, + "diameter": 12104, + "density": 5243, + "gravity": 8.9, + "escape_velocity": 10.4, + "rotation_period": -5832.5, + "day_length": 2802.0, + "distance_from_sun": 108.2, + "orbital_period": 224.7, + "orbital_velocity": 35.0, + "orbital_inclination": 3.4, + "orbital_eccentricity": 0.0007, + "obliquity_to_orbit": 177.4, + "mean_tempurature_c": 464, + "surface_pressure": 92, + "global_magnetic_feild": false, + "img": "https://solarsystem.nasa.gov/resources/2524/newly-processed-views-of-venus-from-mariner-10/?category=planets_venus", + "has_rings": false, + "moons": [] + }, + // Earth + { + "name": "Earth", + "description": "Has Humans", + "mass": 5.97, + "diameter": 12756, + "density": 5514, + "gravity": 9.8, + "escape_velocity": 11.2, + "rotation_period": 23.9, + "day_length": 24.0, + "distance_from_sun": 149.6, + "orbital_period": 365.2, + "orbital_velocity": 29.8, + "orbital_inclination": 0.0, + "orbital_eccentricity": 0.017, + "obliquity_to_orbit": 23.4, + "mean_tempurature_c": 15, + "surface_pressure": 1, + "global_magnetic_feild": true, + "img": "https://solarsystem.nasa.gov/resources/786/blue-marble-2002/?category=planets_earth", + "has_rings": false, + "moons": [] + }, + // Mars + { + "name": "Mars", + "description": "Being explored by robots, considered for space colony", + "mass": 0.642, + "diameter": 6792, + "density": 3934, + "gravity": 3.7, + "escape_velocity": 5, + "rotation_period": 24.6, + "day_length": 24.7, + "distance_from_sun": 228, + "orbital_period": 687, + "orbital_velocity": 24.1, + "orbital_inclination": 1.8, + "orbital_eccentricity": 0.094, + "obliquity_to_orbit": 25.2, + "mean_tempurature_c": -65, + "surface_pressure": 0.01, + "global_magnetic_feild": false, + "img": "https://solarsystem.nasa.gov/resources/948/hubbles-close-up-view-of-mars-dust-storm/?category=planets_mars", + "has_rings": false, + "moons": [] + }, + // Jupiter + { + "name": "Jupiter", + "description": "Largest Gas Giant", + "mass": 1898, + "diameter": 142984, + "density": 1326, + "gravity": 23.1, + "escape_velocity": 59.5, + "rotation_period": 9.9, + "day_length": 9.9, + "distance_from_sun": 778.5, + "orbital_period": 4331, + "orbital_velocity": 13.1, + "orbital_inclination": 1.3, + "orbital_eccentricity": 0.049, + "obliquity_to_orbit": 3.1, + "mean_tempurature_c": -110, + "surface_pressure": null, + "global_magnetic_feild": true, + "img": "https://solarsystem.nasa.gov/resources/2486/hubbles-new-portrait-of-jupiter/?category=planets_jupiter", + "has_rings": true, + "moons": [] + }, + // Saturn + { + "name": "Saturn", + "description": "Gas Giant", + "mass": 568, + "diameter": 120536, + "density": 687, + "gravity": 9, + "escape_velocity": 35.5, + "rotation_period": 10.7, + "day_length": 10.7, + "distance_from_sun": 1432.0, + "orbital_period": 10747, + "orbital_velocity": 9.7, + "orbital_inclination": 2.5, + "orbital_eccentricity": 0.052, + "obliquity_to_orbit": 26.7, + "mean_tempurature_c": -140, + "surface_pressure": null, + "global_magnetic_feild": true, + "img": "https://solarsystem.nasa.gov/resources/2490/saturns-rings-shine-in-hubble-portrait/?category=planets_saturn", + "has_rings": true, + "moons": [] + }, + // Uranus + { + "name": "Uranus", + "description": "Smells bad", + "mass": 86.8, + "diameter": 51118, + "density": 1270, + "gravity": 8.7, + "escape_velocity": 21.3, + "rotation_period": -17.2, + "day_length": 17.2, + "distance_from_sun": 2867, + "orbital_period": 30589, + "orbital_velocity": 6.8, + "orbital_inclination": 0.8, + "orbital_eccentricity": 0.047, + "obliquity_to_orbit": 97.8, + "mean_tempurature_c": -195, + "surface_pressure": null, + "global_magnetic_feild": true, + "img": "https://solarsystem.nasa.gov/resources/605/keck-telescope-views-of-uranus/?category=planets_uranus", + "has_rings": true, + "moons": [] + }, + // Neptune + { + "name": "Neptue", + "description": "Named for the god of the sea because it is blue", + "mass": 102, + "diameter": 49528, + "density": 1638, + "gravity": 11.0, + "escape_velocity": 23.5, + "rotation_period": 16.1, + "day_length": 16.1, + "distance_from_sun": 4515, + "orbital_period": 59800, + "orbital_velocity": 5.4, + "orbital_inclination": 1.8, + "orbital_eccentricity": 0.01, + "obliquity_to_orbit": 28.3, + "mean_tempurature_c": -200, + "surface_pressure": null, + "global_magnetic_feild": true, + "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", + "has_rings": true, + "moons": [] + } +] \ No newline at end of file From 172bbc032b66454f0034891707184ae5daec5407 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 21 Dec 2022 11:11:36 -0800 Subject: [PATCH 19/48] working on rest of CRUD through DB Co-authored-by: Ya-Juan Ruan --- app/planets_data.jsonc | 2 +- app/routes.py | 182 ++++++++++++++++++++++++++++++----------- 2 files changed, 137 insertions(+), 47 deletions(-) diff --git a/app/planets_data.jsonc b/app/planets_data.jsonc index 298ceaaf7..6bc740f6c 100644 --- a/app/planets_data.jsonc +++ b/app/planets_data.jsonc @@ -169,7 +169,7 @@ }, // Neptune { - "name": "Neptue", + "name": "Neptune", "description": "Named for the god of the sea because it is blue", "mass": 102, "diameter": 49528, diff --git a/app/routes.py b/app/routes.py index 74652cd33..f99aa94ee 100644 --- a/app/routes.py +++ b/app/routes.py @@ -5,6 +5,27 @@ planets_bp = Blueprint("planets", __name__, url_prefix="/planets") moons_bp = Blueprint("moons", __name__, url_prefix="/moons") +def validate_planet(planet_id): + try: + planet_id = int(planet_id) + except: + abort(make_response({"message":f"{planet_id} invalid"}, 400)) + planet = Planet.query.get(planet_id) + if planet: + return planet + abort(make_response({"message":f"Planet with {planet_id} not found"}, 404)) + +def validate_moon(moon_id): + try: + moon_id=int(moon_id) + except: + abort(make_response({"message":f"moon {moon_id} invalid"})) + + moon = Moon.query.get(moon_id) + if moon: + return moon + + abort(make_response({"message": f"moon {moon_id} not found"})) @planets_bp.route("", methods=["GET"]) def display_planets(): @@ -37,17 +58,6 @@ def display_planets(): }) return jsonify(planets_response) -def validate_planet(planet_id): - try: - planet_id = int(planet_id) - except: - abort(make_response({"message":f"{planet_id} invalid"}, 400)) - solar_system = Planet.query.all() - for planet in solar_system: - if planet.id == planet_id: - return planet - abort(make_response({"message":f"Planet with {planet_id} not found"}, 404)) - @planets_bp.route("", methods=["POST"]) def create_planets(): request_body=request.get_json() @@ -77,22 +87,75 @@ def create_planets(): db.session.commit() return make_response(f"New Planet {new_planet.name} created!", 201) -# @planets_bp.route("/", methods=["GET"]) -# def display_planet(planet_id): -# planet = validate_planet(planet_id) -# # return { -# # "id": planet.id, -# # "name": planet.name, -# # "description": planet.description, -# # "Has Rings": planet.has_rings, -# # "Moons" : [moon.name for moon in planet.moons] -# # } -# # Use __dict__ to access all the attributes from planet -# return planet.serialize() +@planets_bp.route("/", methods=["GET"]) +def display_planet(planet_id): + planet = validate_planet(planet_id) + planet_response = [] + planet_response.append({ + "id": planet.id, + "name": planet.name, + "description": planet.description, + "mass": planet.mass, + "diameter":planet.diameter, + "density": planet.density, + "gravity": planet.gravity, + "escape_velocity": planet.escape_velocity, + "rotation_period": planet.rotation_period, + "day_length": planet.day_length, + "distance_from_sun":planet.distance_from_sun, + "orbital_period": planet.orbital_period, + "orbital_velocity" : planet.orbital_velocity, + "orbital_inclination": planet.orbital_inclination, + "orbital_eccentricity":planet.orbital_eccentricity, + "obliquity_to_orbit":planet.obliquity_to_orbit, + "mean_tempurature_c":planet.mean_tempurature_c, + "surface_pressure":planet.surface_pressure, + "global_magnetic_feild":planet.global_magnetic_feild, + "img":planet.img, + "Has Rings": planet.has_rings, + #"moons":planet.moons + }) + return jsonify(planet_response) +@planets_bp.route("/", methods=["PUT"]) +def update_a_planet(planet_id): + planet = validate_planet(planet_id) + request_body = request.get_json() + planet.name=request_body["name"], + planet.description=request_body["description"], + planet.mass=request_body["mass"], + planet.diameter=request_body["diameter"], + planet.density=request_body["density"], + planet.gravity=request_body["gravity"], + planet.escape_velocity=request_body["escape_velocity"], + planet.rotation_period=request_body["rotation_period"], + planet.day_length=request_body["day_length"], + planet.distance_from_sun=request_body["distance_from_sun"], + planet.orbital_period=request_body["orbital_period"], + planet.orbital_velocity=request_body["orbital_velocity"], + planet.orbital_inclination=request_body["orbital_inclination"], + planet.orbital_eccentricity=request_body["orbital_eccentricity"], + planet.obliquity_to_orbit=request_body["obliquity_to_orbit"], + planet.mean_tempurature_c=request_body["mean_tempurature_c"], + planet.surface_pressure=request_body["surface_pressure"], + planet.global_magnetic_feild=request_body["global_magnetic_feild"], + planet.img=request_body["img"], + planet.has_rings=request_body["has_rings"] + db.session.commit() + return make_response(f"Planet {planet.id} successfully updated") + +@planets_bp.route("/", methods=["DELETE"]) +def delete_a_planet(planet_id): + planet = validate_planet(planet_id) -@planets_bp.route("//moons", methods=["POST"]) + db.session.delete(planet) + db.session.commit() + + return make_response(f"Planet {planet.id} successfully deleted") + + +@planets_bp.route("planets//moons", methods=["POST"]) def create_moon(planet_id): planet = validate_planet(planet_id) request_body = request.get_json() @@ -106,39 +169,66 @@ def create_moon(planet_id): db.session.commit() return make_response(f"New Moon {new_moon.name} creative", 201) +@planets_bp.route("//moons", methods=["GET"]) +def get_all_moons_by_planet(planet_id): + planet = validate_planet(planet_id) + moons_response = [] + for moon in planet.moons: + moons_response.append({ + "id":moon.id, + "title": moon.title, + "description": moon.description, + "image":moon.image, + + }) + return jsonify(moons_response) + @moons_bp.route("", methods=["GET"]) def get_all_moons(): + moons = Moon.query.all() moons_response = [] - moons_list = Moon.query.all() - for moon in moons_list: + for moon in moons: moons_response.append({ "id":moon.id, "title": moon.title, "description": moon.description, "image":moon.image, - "planet_id":moon.planet_id, - "planet":moon.planet }) return jsonify(moons_response) -# def validate_moon(moon_id): -# try: -# moon_id=int(moon_id) -# except: -# abort(make_response({"message":f"moon {moon_id} invalid"})) - -# for moon in moons_list: -# if moon.id==moon_id: -# return moon + +@moons_bp.route("/", methods=["GET"]) +def get_moon_by_id(moon_id): + moon=validate_moon(moon_id) -# abort(make_response({"message": f"moon {moon_id} not found"})) + return { + "id": moon.id, + "name": moon.name, + "description": moon.description, + "image": moon.image + } + +@moons_bp.route("/", methods=["PUT"]) +def update_moon(moon_id): + moon=validate_moon(moon_id) + request_body = request.get_json() + moon.name = request_body["name"] + moon.description=request_body["description"] + moon.image=request_body["img"] + moon.planet_id=request_body["planet_id"] + + db.session.commit() + return make_response(f"Moon {moon.name} has been update", 204) + + -# @moons_bp.route("/", methods=["GET"]) -# def get_moon_by_id(moon_id): -# moon=validate_moon(moon_id) + + +@moons_bp.route("/", methods=["DELETE"]) +def delete_moon(moon_id): + moon=validate_moon(moon_id) -# return { -# "id": moon.id, -# "name": moon.name, -# "description": moon.description -# } \ No newline at end of file + db.session.delete(moon) + db.session.commit() + + return make_response(f"moon {moon.id} successfully deleted") \ No newline at end of file From 06bd9e9ff1b300a7964a08a1535cc3811b79e3f8 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 21 Dec 2022 11:38:40 -0800 Subject: [PATCH 20/48] debugging migration for boolean val --- app/models/planet.py | 4 ++-- migrations/versions/0663be054953_.py | 30 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 migrations/versions/0663be054953_.py diff --git a/app/models/planet.py b/app/models/planet.py index 0b3087254..81e83f05a 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -20,9 +20,9 @@ class Planet(db.Model): obliquity_to_orbit=db.Column(db.Float) mean_tempurature_c=db.Column(db.Float) surface_pressure=db.Column(db.Float) - global_magnetic_feild=db.Column(db.Boolean) + global_magnetic_feild=db.Column(db.Boolean, default=False, server_default="false") img=db.Column(db.String) - has_rings=db.Column(db.Boolean) + has_rings=db.Column(db.Boolean, default=False, server_default="false") moons = db.relationship("Moon", back_populates="planet") # def __init__(self, id, name, description, mass, diameter, density, gravity, escape_velocity, # rotation_period, day_length, distance_from_sun, orbital_period, orbital_velocity, orbital_inclination, orbital_eccentricity, diff --git a/migrations/versions/0663be054953_.py b/migrations/versions/0663be054953_.py new file mode 100644 index 000000000..109ddc4ac --- /dev/null +++ b/migrations/versions/0663be054953_.py @@ -0,0 +1,30 @@ +"""empty message + +Revision ID: 0663be054953 +Revises: 6015f9934596 +Create Date: 2022-12-21 11:30:54.155918 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = '0663be054953' +down_revision = '6015f9934596' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('moons', sa.Column('name', sa.String(), nullable=True)) + op.drop_column('moons', 'title') + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('moons', sa.Column('title', sa.VARCHAR(), autoincrement=False, nullable=True)) + op.drop_column('moons', 'name') + # ### end Alembic commands ### From dc30a5cba276ac84f32dc6bb22b9090e3979c23f Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 21 Dec 2022 11:47:15 -0800 Subject: [PATCH 21/48] Finished debugging put. Co-authored-by: Ya-Juan Ruan --- app/routes.py | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/app/routes.py b/app/routes.py index f99aa94ee..2525f2501 100644 --- a/app/routes.py +++ b/app/routes.py @@ -121,25 +121,26 @@ def display_planet(planet_id): def update_a_planet(planet_id): planet = validate_planet(planet_id) request_body = request.get_json() - planet.name=request_body["name"], - planet.description=request_body["description"], - planet.mass=request_body["mass"], - planet.diameter=request_body["diameter"], - planet.density=request_body["density"], - planet.gravity=request_body["gravity"], - planet.escape_velocity=request_body["escape_velocity"], - planet.rotation_period=request_body["rotation_period"], - planet.day_length=request_body["day_length"], - planet.distance_from_sun=request_body["distance_from_sun"], - planet.orbital_period=request_body["orbital_period"], - planet.orbital_velocity=request_body["orbital_velocity"], - planet.orbital_inclination=request_body["orbital_inclination"], - planet.orbital_eccentricity=request_body["orbital_eccentricity"], - planet.obliquity_to_orbit=request_body["obliquity_to_orbit"], - planet.mean_tempurature_c=request_body["mean_tempurature_c"], - planet.surface_pressure=request_body["surface_pressure"], - planet.global_magnetic_feild=request_body["global_magnetic_feild"], - planet.img=request_body["img"], + + planet.name=request_body["name"] + planet.description=request_body["description"] + planet.mass=request_body["mass"] + planet.diameter=request_body["diameter"] + planet.density=request_body["density"] + planet.gravity=request_body["gravity"] + planet.escape_velocity=request_body["escape_velocity"] + planet.rotation_period=request_body["rotation_period"] + planet.day_length=request_body["day_length"] + planet.distance_from_sun=request_body["distance_from_sun"] + planet.orbital_period=request_body["orbital_period"] + planet.orbital_velocity=request_body["orbital_velocity"] + planet.orbital_inclination=request_body["orbital_inclination"] + planet.orbital_eccentricity=request_body["orbital_eccentricity"] + planet.obliquity_to_orbit=request_body["obliquity_to_orbit"] + planet.mean_tempurature_c=request_body["mean_tempurature_c"] + planet.surface_pressure=request_body["surface_pressure"] + planet.global_magnetic_feild=request_body["global_magnetic_feild"] + planet.img=request_body["img"] planet.has_rings=request_body["has_rings"] db.session.commit() From 8bfe97949a9f72558759bd47fedaa741d7391879 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Thu, 22 Dec 2022 11:01:43 -0800 Subject: [PATCH 22/48] Seeing up queries. Co-authored-by: Ya-Juan Ruan --- app/routes.py | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/app/routes.py b/app/routes.py index 2525f2501..30bc09d3b 100644 --- a/app/routes.py +++ b/app/routes.py @@ -27,11 +27,41 @@ def validate_moon(moon_id): abort(make_response({"message": f"moon {moon_id} not found"})) + +def filter_planet(planet_query): + + order_by_asc = request.args.get("order_by_asc") + order_by_desc = request.args.get("order_by_desc") + max = request.args.get("max") + min = request.args.get("min") + #greater_than_ave = request.args.get("greater_than_ave") + global_magnetic_feild= request.args.get("global_magnetic_feild") + has_rings = request.args.get("has_rings") + if order_by_asc: + planet_query = planet_query.query.order_by(getattr(Planet, order_by_asc)) + elif order_by_desc: + planet_query = planet_query.query.order_by(getattr(Planet, order_by_desc).desc()) + elif max: + planet_query = planet_query.query.order_by(getattr(Planet, order_by_desc).desc()).limit(1) + elif min: + planet_query = planet_query.query.order_by(getattr(Planet, order_by_desc)).limit(1) + #elif greater_than_ave: + # planet_query = planet_query.query.filter(getattr(Planet, greater_than_ave).func.avg()) + + elif has_rings or global_magnetic_feild: + required_parameters = {"global_magnetic_feild":global_magnetic_feild, "has_rings":has_rings} + planet_query = planet_query.query.filter_by(**required_parameters) + + return planet_query + + + @planets_bp.route("", methods=["GET"]) def display_planets(): planets_response = [] - solar_system = Planet.query.all() - for planet in solar_system: + planet_query = Planet.query + planet_query = filter_planet(planet_query).all() + for planet in planet_query: planets_response.append({ "id": planet.id, "name": planet.name, From 147a9f060fb2cb644a102ca1eadf1b8635b03ced Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Thu, 22 Dec 2022 18:27:12 -0800 Subject: [PATCH 23/48] Update query filter in planet route --- app/routes.py | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/app/routes.py b/app/routes.py index 30bc09d3b..0a1d8cfc5 100644 --- a/app/routes.py +++ b/app/routes.py @@ -28,39 +28,48 @@ def validate_moon(moon_id): abort(make_response({"message": f"moon {moon_id} not found"})) -def filter_planet(planet_query): +def apply_filter(planet_query): + FILTERABLE_ATTRIBUTES = ['global_magnetic_feild', 'has_rings'] + required_parameters = {} + for attribute in FILTERABLE_ATTRIBUTES: + value = request.args.get(attribute) + if value is not None: + required_parameters[attribute] = value + if required_parameters: + print(required_parameters) + planet_query = planet_query.filter_by(**required_parameters) + print(planet_query) order_by_asc = request.args.get("order_by_asc") order_by_desc = request.args.get("order_by_desc") - max = request.args.get("max") - min = request.args.get("min") + max_query = request.args.get("max") + min_query = request.args.get("min") + + # Validate that only one option at a time is specified + options = [order_by_asc, order_by_desc, max_query, min_query] + num_options = sum(1 if option is not None else 0 for option in options) + if num_options > 1: + abort(make_response("Bad request: Too many options", 400)) + #greater_than_ave = request.args.get("greater_than_ave") - global_magnetic_feild= request.args.get("global_magnetic_feild") - has_rings = request.args.get("has_rings") - if order_by_asc: - planet_query = planet_query.query.order_by(getattr(Planet, order_by_asc)) - elif order_by_desc: - planet_query = planet_query.query.order_by(getattr(Planet, order_by_desc).desc()) - elif max: - planet_query = planet_query.query.order_by(getattr(Planet, order_by_desc).desc()).limit(1) - elif min: - planet_query = planet_query.query.order_by(getattr(Planet, order_by_desc)).limit(1) - #elif greater_than_ave: + if order_by_asc is not None: + planet_query = planet_query.order_by(getattr(Planet, order_by_asc)) + elif order_by_desc is not None: + planet_query = planet_query.order_by(getattr(Planet, order_by_desc).desc()) + elif max_query is not None: + planet_query = planet_query.order_by(getattr(Planet, max_query).desc()).limit(1) + elif min_query is not None: + planet_query = planet_query.order_by(getattr(Planet, min_query)).limit(1) + #elif greater_than_ave is not None: # planet_query = planet_query.query.filter(getattr(Planet, greater_than_ave).func.avg()) - - elif has_rings or global_magnetic_feild: - required_parameters = {"global_magnetic_feild":global_magnetic_feild, "has_rings":has_rings} - planet_query = planet_query.query.filter_by(**required_parameters) return planet_query - - @planets_bp.route("", methods=["GET"]) def display_planets(): planets_response = [] planet_query = Planet.query - planet_query = filter_planet(planet_query).all() + planet_query = apply_filter(planet_query).all() for planet in planet_query: planets_response.append({ "id": planet.id, From 5f7d0239383436c77f6c8a8d1bef665da96c5bf1 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Thu, 22 Dec 2022 18:50:55 -0800 Subject: [PATCH 24/48] Remove debug prints --- app/routes.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/routes.py b/app/routes.py index 0a1d8cfc5..eacd469f4 100644 --- a/app/routes.py +++ b/app/routes.py @@ -36,9 +36,7 @@ def apply_filter(planet_query): if value is not None: required_parameters[attribute] = value if required_parameters: - print(required_parameters) planet_query = planet_query.filter_by(**required_parameters) - print(planet_query) order_by_asc = request.args.get("order_by_asc") order_by_desc = request.args.get("order_by_desc") From 1cf96b665bd52eea7129cd680d82b3309270742a Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Mon, 2 Jan 2023 23:42:08 -0800 Subject: [PATCH 25/48] Add test configuration --- app/__init__.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 3a2cc797f..2000c398e 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,19 +1,33 @@ from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate +from dotenv import load_dotenv +import os db = SQLAlchemy() migrate = Migrate() +load_dotenv() def create_app(test_config=None): app = Flask(__name__) - app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False - app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql+psycopg2://postgres:postgres@localhost:5432/solar_system' + + if not test_config: + app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get( + "SQLALCHEMY_DATABASE_URI") + else: + app.config["TESTING"] = True + app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False + app.config["SQLALCHEMY_DATABASE_URI"] = os.environ.get( + "SQLALCHEMY_TEST_DATABASE_URI") + db.init_app(app) migrate.init_app(app,db) + + from app.models.celestial_body import CelestialBody from app.models.planet import Planet from app.models.moon import Moon From 440728ad7e9a68560dab830eaba07877b0f68b71 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Mon, 2 Jan 2023 23:45:06 -0800 Subject: [PATCH 26/48] Add attribute validation to update and create planet routes --- app/filter_attributes.py | 4 ++++ app/routes.py | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 app/filter_attributes.py diff --git a/app/filter_attributes.py b/app/filter_attributes.py new file mode 100644 index 000000000..8f61ad60a --- /dev/null +++ b/app/filter_attributes.py @@ -0,0 +1,4 @@ +PLANET_ATTRIBUTES = ["name", "description", "mass", "diameter", "density", "gravity", "escape_velocity", + "rotation_period", "day_length", "distance_from_sun", "orbital_period", "orbital_velocity", "orbital_inclination", "orbital_eccentricity", + "obliquity_to_orbit", "mean_tempurature_c", "surface_pressure", "global_magnetic_feild", "has_rings"] +MOON_ATTRIBUTES = ["name", "description"] diff --git a/app/routes.py b/app/routes.py index eacd469f4..c46d002d8 100644 --- a/app/routes.py +++ b/app/routes.py @@ -1,4 +1,5 @@ from flask import Blueprint, jsonify, abort, make_response, request +from app.filter_attributes import PLANET_ATTRIBUTES from app.models.moon import Moon from app.models.planet import Planet from app import db @@ -98,6 +99,9 @@ def display_planets(): @planets_bp.route("", methods=["POST"]) def create_planets(): request_body=request.get_json() + for key in PLANET_ATTRIBUTES: + if not key in request_body: + abort(make_response({"message": f"Bad request: {key} attribute is missing"}, 400)) new_planet = Planet( name=request_body["name"], description=request_body["description"], @@ -118,8 +122,7 @@ def create_planets(): surface_pressure=request_body["surface_pressure"], global_magnetic_feild=request_body["global_magnetic_feild"], img=request_body["img"], - has_rings=request_body["has_rings"] - ) + has_rings=request_body["has_rings"]) db.session.add(new_planet) db.session.commit() return make_response(f"New Planet {new_planet.name} created!", 201) @@ -158,7 +161,9 @@ def display_planet(planet_id): def update_a_planet(planet_id): planet = validate_planet(planet_id) request_body = request.get_json() - + for key in PLANET_ATTRIBUTES: + if not key in request_body: + abort(make_response({"message": f"Bad request: {key} attribute is missing"}, 400)) planet.name=request_body["name"] planet.description=request_body["description"] planet.mass=request_body["mass"] From 15d909ceaffe6efc93e67d261ab2f8010abf0b11 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Mon, 2 Jan 2023 23:46:49 -0800 Subject: [PATCH 27/48] Return planet as a single object instead of array and fix attribute name --- app/routes.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/routes.py b/app/routes.py index c46d002d8..7f28d8fd9 100644 --- a/app/routes.py +++ b/app/routes.py @@ -130,8 +130,7 @@ def create_planets(): @planets_bp.route("/", methods=["GET"]) def display_planet(planet_id): planet = validate_planet(planet_id) - planet_response = [] - planet_response.append({ + planet_response = { "id": planet.id, "name": planet.name, "description": planet.description, @@ -152,9 +151,9 @@ def display_planet(planet_id): "surface_pressure":planet.surface_pressure, "global_magnetic_feild":planet.global_magnetic_feild, "img":planet.img, - "Has Rings": planet.has_rings, + "has_rings": planet.has_rings, #"moons":planet.moons - }) + } return jsonify(planet_response) @planets_bp.route("/", methods=["PUT"]) From 978b8bc690e83c9ae3a74d76d132c6f174b5e8dc Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Mon, 2 Jan 2023 23:47:01 -0800 Subject: [PATCH 28/48] Return responses as JSON --- app/routes.py | 86 +++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/app/routes.py b/app/routes.py index 7f28d8fd9..0c07a70dd 100644 --- a/app/routes.py +++ b/app/routes.py @@ -103,56 +103,56 @@ def create_planets(): if not key in request_body: abort(make_response({"message": f"Bad request: {key} attribute is missing"}, 400)) new_planet = Planet( - name=request_body["name"], - description=request_body["description"], - mass=request_body["mass"], - diameter=request_body["diameter"], - density=request_body["density"], - gravity=request_body["gravity"], - escape_velocity=request_body["escape_velocity"], - rotation_period=request_body["rotation_period"], - day_length=request_body["day_length"], - distance_from_sun=request_body["distance_from_sun"], - orbital_period=request_body["orbital_period"], - orbital_velocity=request_body["orbital_velocity"], - orbital_inclination=request_body["orbital_inclination"], - orbital_eccentricity=request_body["orbital_eccentricity"], - obliquity_to_orbit=request_body["obliquity_to_orbit"], - mean_tempurature_c=request_body["mean_tempurature_c"], - surface_pressure=request_body["surface_pressure"], - global_magnetic_feild=request_body["global_magnetic_feild"], - img=request_body["img"], + name=request_body["name"], + description=request_body["description"], + mass=request_body["mass"], + diameter=request_body["diameter"], + density=request_body["density"], + gravity=request_body["gravity"], + escape_velocity=request_body["escape_velocity"], + rotation_period=request_body["rotation_period"], + day_length=request_body["day_length"], + distance_from_sun=request_body["distance_from_sun"], + orbital_period=request_body["orbital_period"], + orbital_velocity=request_body["orbital_velocity"], + orbital_inclination=request_body["orbital_inclination"], + orbital_eccentricity=request_body["orbital_eccentricity"], + obliquity_to_orbit=request_body["obliquity_to_orbit"], + mean_tempurature_c=request_body["mean_tempurature_c"], + surface_pressure=request_body["surface_pressure"], + global_magnetic_feild=request_body["global_magnetic_feild"], + img=request_body["img"], has_rings=request_body["has_rings"]) db.session.add(new_planet) db.session.commit() - return make_response(f"New Planet {new_planet.name} created!", 201) + return make_response(jsonify(f"New Planet {new_planet.name} created!"), 201) @planets_bp.route("/", methods=["GET"]) def display_planet(planet_id): planet = validate_planet(planet_id) planet_response = { - "id": planet.id, - "name": planet.name, - "description": planet.description, - "mass": planet.mass, - "diameter":planet.diameter, - "density": planet.density, - "gravity": planet.gravity, - "escape_velocity": planet.escape_velocity, - "rotation_period": planet.rotation_period, - "day_length": planet.day_length, - "distance_from_sun":planet.distance_from_sun, - "orbital_period": planet.orbital_period, - "orbital_velocity" : planet.orbital_velocity, - "orbital_inclination": planet.orbital_inclination, - "orbital_eccentricity":planet.orbital_eccentricity, - "obliquity_to_orbit":planet.obliquity_to_orbit, - "mean_tempurature_c":planet.mean_tempurature_c, - "surface_pressure":planet.surface_pressure, - "global_magnetic_feild":planet.global_magnetic_feild, - "img":planet.img, + "id": planet.id, + "name": planet.name, + "description": planet.description, + "mass": planet.mass, + "diameter":planet.diameter, + "density": planet.density, + "gravity": planet.gravity, + "escape_velocity": planet.escape_velocity, + "rotation_period": planet.rotation_period, + "day_length": planet.day_length, + "distance_from_sun":planet.distance_from_sun, + "orbital_period": planet.orbital_period, + "orbital_velocity" : planet.orbital_velocity, + "orbital_inclination": planet.orbital_inclination, + "orbital_eccentricity":planet.orbital_eccentricity, + "obliquity_to_orbit":planet.obliquity_to_orbit, + "mean_tempurature_c":planet.mean_tempurature_c, + "surface_pressure":planet.surface_pressure, + "global_magnetic_feild":planet.global_magnetic_feild, + "img":planet.img, "has_rings": planet.has_rings, - #"moons":planet.moons + #"moons":planet.moons } return jsonify(planet_response) @@ -185,7 +185,7 @@ def update_a_planet(planet_id): planet.has_rings=request_body["has_rings"] db.session.commit() - return make_response(f"Planet {planet.id} successfully updated") + return make_response(jsonify(f"Planet {planet.id} successfully updated")) @planets_bp.route("/", methods=["DELETE"]) def delete_a_planet(planet_id): @@ -194,7 +194,7 @@ def delete_a_planet(planet_id): db.session.delete(planet) db.session.commit() - return make_response(f"Planet {planet.id} successfully deleted") + return make_response(jsonify(f"Planet {planet.id} successfully deleted")) @planets_bp.route("planets//moons", methods=["POST"]) From 4cf6ffc7218b0190075a6f21b5eb42d49b78fad6 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Mon, 2 Jan 2023 23:47:22 -0800 Subject: [PATCH 29/48] Add tests --- tests/__init__.py | 0 tests/conftest.py | 56 +++++++++++++++ tests/test_routes.py | 158 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 tests/__init__.py create mode 100644 tests/conftest.py create mode 100644 tests/test_routes.py diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000..0d479baf0 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,56 @@ +import pytest +from app import create_app +from app import db +from flask.signals import request_finished +from app.models.planet import Planet + + +@pytest.fixture +def app(): + app = create_app({"TESTING": True}) + + @request_finished.connect_via(app) + def expire_session(sender, response, **extra): + db.session.remove() + + with app.app_context(): + db.create_all() + yield app + + with app.app_context(): + db.drop_all() + + +@pytest.fixture +def client(app): + return app.test_client() + +@pytest.fixture +def two_saved_planets(app): + test_one = Planet( + name="Neptune", + description="Named for the god of the sea because it is blue", + mass=102, + diameter=49528, + density=1638, + gravity=11.0, + escape_velocity=23.5, + rotation_period=16.1, + day_length=16.1, + distance_from_sun=4515, + orbital_period=59800, + orbital_velocity=5.4, + orbital_inclination=1.8, + orbital_eccentricity=0.01, + obliquity_to_orbit=28.3, + mean_tempurature_c=-200, + surface_pressure=None, + global_magnetic_feild=True, + img="https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", + has_rings=True, + ) + test_two = Planet(name="number two") + + db.session.add_all([test_one, test_two]) + + db.session.commit() \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py new file mode 100644 index 000000000..5879ba66f --- /dev/null +++ b/tests/test_routes.py @@ -0,0 +1,158 @@ + +def test_get_all_planets_with_no_records(client): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == [] + +def test_get_one_planet(client, two_saved_planets): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + "id":1, + "name": "Neptune", + "description": "Named for the god of the sea because it is blue", + "mass": 102, + "diameter": 49528, + "density": 1638, + "gravity": 11.0, + "escape_velocity": 23.5, + "rotation_period": 16.1, + "day_length": 16.1, + "distance_from_sun": 4515, + "orbital_period": 59800, + "orbital_velocity": 5.4, + "orbital_inclination": 1.8, + "orbital_eccentricity": 0.01, + "obliquity_to_orbit": 28.3, + "mean_tempurature_c": -200, + "surface_pressure": None, + "global_magnetic_feild": True, + "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", + "has_rings": True, + } + +def test_create_one_planet(client): + # Act + response = client.post("/planets", json={ + "name": "Uranus", + "description": "Smells bad", + "mass": 86.8, + "diameter": 51118, + "density": 1270, + "gravity": 8.7, + "escape_velocity": 21.3, + "rotation_period": -17.2, + "day_length": 17.2, + "distance_from_sun": 2867, + "orbital_period": 30589, + "orbital_velocity": 6.8, + "orbital_inclination": 0.8, + "orbital_eccentricity": 0.047, + "obliquity_to_orbit": 97.8, + "mean_tempurature_c": -195, + "surface_pressure": None, + "global_magnetic_feild": True, + "img": "https://solarsystem.nasa.gov/resources/605/keck-telescope-views-of-uranus/?category=planets_uranus", + "has_rings": True, +}) + response_body = response.get_json() + + # Assert + assert response.status_code == 201 + assert response_body == "New Planet Uranus created!" + +def test_update_one_planet(client, two_saved_planets): + # Act + response = client.put("/planets/2", json={ + "name": "Uranus", + "description": "Smells bad", + "mass": 86.8, + "diameter": 51118, + "density": 1270, + "gravity": 8.7, + "escape_velocity": 21.3, + "rotation_period": -17.2, + "day_length": 17.2, + "distance_from_sun": 2867, + "orbital_period": 30589, + "orbital_velocity": 6.8, + "orbital_inclination": 0.8, + "orbital_eccentricity": 0.047, + "obliquity_to_orbit": 97.8, + "mean_tempurature_c": -195, + "surface_pressure": None, + "global_magnetic_feild": True, + "img": "https://solarsystem.nasa.gov/resources/605/keck-telescope-views-of-uranus/?category=planets_uranus", + "has_rings": True, +}) + #Arrange + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == "Planet 2 successfully updated" + +def test_delete_one_planet(client, two_saved_planets): + #Arrange + response = client.delete("/planets/2") + response_body = response.get_json() + + #Assert + assert response.status_code == 200 + assert response_body == "Planet 2 successfully deleted" + +def test_get_one_nonexistent_planet(client, two_saved_planets): + #Arrange + response = client.get("/planets/3") + response_body = response.get_json() + + #Assert + assert response.status_code == 404 + assert response_body == {"message": "Planet with 3 not found"} + +def test_incorrect_id_format(client, two_saved_planets): + #Arrange + response = client.get("/planets/a") + response_body = response.get_json() + + #Assert + assert response.status_code == 400 + assert response_body == {"message": "a invalid"} + +def test_create_incomplete_planet(client): + #Arrange + response = client.post("/planets", json={ + "name": "Uranus"}) + response_body = response.get_json() + + #Assert + assert response.status_code == 400 + assert response_body == {"message": "Bad request: description attribute is missing"} + +def test_update_incomplete_planet(client, two_saved_planets): + #Arrange + response = client.put("/planets/2", json={ + "name": "Uranus"}) + response_body = response.get_json() + + #Assert + assert response.status_code == 400 + assert response_body == {"message": "Bad request: description attribute is missing"} + + +def test_delete_one_nonexistent_planet(client, two_saved_planets): + #Arrange + response = client.get("/planets/3") + response_body = response.get_json() + + #Assert + assert response.status_code == 404 + assert response_body == {"message": "Planet with 3 not found"} \ No newline at end of file From b880e4eb4a5601e456edb0388e58f2d91d789df5 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Tue, 3 Jan 2023 12:44:18 -0800 Subject: [PATCH 30/48] started refactoring and improving test coverage Co-authored-by: Ya-Juan Ruan --- app/routes.py | 4 ++-- tests/conftest.py | 10 ++++++++++ tests/test_routes.py | 25 ++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/app/routes.py b/app/routes.py index 0c07a70dd..f0e0fcfcd 100644 --- a/app/routes.py +++ b/app/routes.py @@ -243,12 +243,12 @@ def get_all_moons(): def get_moon_by_id(moon_id): moon=validate_moon(moon_id) - return { + return jsonify({ "id": moon.id, "name": moon.name, "description": moon.description, "image": moon.image - } + }) @moons_bp.route("/", methods=["PUT"]) def update_moon(moon_id): diff --git a/tests/conftest.py b/tests/conftest.py index 0d479baf0..a822db172 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,6 +3,7 @@ from app import db from flask.signals import request_finished from app.models.planet import Planet +from app.models.moon import Moon @pytest.fixture @@ -53,4 +54,13 @@ def two_saved_planets(app): db.session.add_all([test_one, test_two]) + db.session.commit() + + +@pytest.fixture +def two_saved_moons(app, two_saved_planets): + moon_one=Moon(name="Test Moon", description="First Moon for Neptune", image="pretty_moon.jpg", planet_id=1) + moon_two=Moon(name="2 Test Moon", description="Second Neptune", image="prettiestMoon.jpg", planet_id=1) + + db.session.add_all([moon_one,moon_two]) db.session.commit() \ No newline at end of file diff --git a/tests/test_routes.py b/tests/test_routes.py index 5879ba66f..aa6bd0ee7 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -155,4 +155,27 @@ def test_delete_one_nonexistent_planet(client, two_saved_planets): #Assert assert response.status_code == 404 - assert response_body == {"message": "Planet with 3 not found"} \ No newline at end of file + assert response_body == {"message": "Planet with 3 not found"} + +#tests for moon here to refactor and increase code coverage. + +def test_all_moon_no_records(client): + response = client.get("/moons") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == [] + + + +def test_get_one_moon(client, two_saved_moons): + response=client.get("/moons/1") + response_body=response.get_json() + + assert response_body == { + "id":1, + "name":"Test Moon", + "description":"First Moon for Neptune", + "image":"pretty_moon.jpg" + } \ No newline at end of file From 56ac9ce8ed53a7cfd78e74c513b0e6ee51a2c0a2 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Tue, 3 Jan 2023 15:55:03 -0800 Subject: [PATCH 31/48] Split moon and planet routes --- app/__init__.py | 3 +- app/routes/moon.py | 83 +++++++++++++++++++++++++ app/{routes.py => routes/planet.py} | 95 +---------------------------- 3 files changed, 87 insertions(+), 94 deletions(-) create mode 100644 app/routes/moon.py rename app/{routes.py => routes/planet.py} (75%) diff --git a/app/__init__.py b/app/__init__.py index 2000c398e..07840c1aa 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -34,7 +34,8 @@ def create_app(test_config=None): #from app.models.planet import Planet #from app.models.moon import Moon - from .routes import planets_bp, moons_bp + from .routes.planet import planets_bp + from .routes.moon import moons_bp app.register_blueprint(planets_bp) app.register_blueprint(moons_bp) return app diff --git a/app/routes/moon.py b/app/routes/moon.py new file mode 100644 index 000000000..6ac1acfc8 --- /dev/null +++ b/app/routes/moon.py @@ -0,0 +1,83 @@ +from app.models.moon import Moon +from flask import Blueprint, jsonify, abort, make_response, request +from app import db +from app.routes.planet import planets_bp, validate_planet +moons_bp = Blueprint("moons", __name__, url_prefix="/moons") + +def validate_moon(moon_id): + try: + moon_id=int(moon_id) + except: + abort(make_response({"message":f"moon {moon_id} invalid"})) + + moon = Moon.query.get(moon_id) + if moon: + return moon + + abort(make_response({"message": f"moon {moon_id} not found"})) + + +@planets_bp.route("planets//moons", methods=["POST"]) +def create_moon(planet_id): + planet = validate_planet(planet_id) + request_body = request.get_json() + new_moon = Moon( + name=request_body["name"], + description = request_body["description"], + image = request_body["img"], + planet=planet + ) + db.session.add(new_moon) + db.session.commit() + return make_response(f"New Moon {new_moon.name} creative", 201) + +@planets_bp.route("//moons", methods=["GET"]) +def get_all_moons_by_planet(planet_id): + planet = validate_planet(planet_id) + moons_response = [] + for moon in planet.moons: + moons_response.append({ + "id":moon.id, + "title": moon.title, + "description": moon.description, + "image":moon.image, + + }) + return jsonify(moons_response) + +@moons_bp.route("", methods=["GET"]) +def get_all_moons(): + moons = Moon.query.all() + moons_response = [] + for moon in moons: + moons_response.append({ + "id":moon.id, + "title": moon.title, + "description": moon.description, + "image":moon.image, + }) + return jsonify(moons_response) + + +@moons_bp.route("/", methods=["GET"]) +def get_moon_by_id(moon_id): + moon=validate_moon(moon_id) + + return jsonify({ + "id": moon.id, + "name": moon.name, + "description": moon.description, + "image": moon.image + }) + +@moons_bp.route("/", methods=["PUT"]) +def update_moon(moon_id): + moon=validate_moon(moon_id) + request_body = request.get_json() + moon.name = request_body["name"] + moon.description=request_body["description"] + moon.image=request_body["img"] + moon.planet_id=request_body["planet_id"] + + db.session.commit() + return make_response(f"Moon {moon.name} has been update", 204) \ No newline at end of file diff --git a/app/routes.py b/app/routes/planet.py similarity index 75% rename from app/routes.py rename to app/routes/planet.py index f0e0fcfcd..aaff47114 100644 --- a/app/routes.py +++ b/app/routes/planet.py @@ -1,10 +1,9 @@ from flask import Blueprint, jsonify, abort, make_response, request from app.filter_attributes import PLANET_ATTRIBUTES -from app.models.moon import Moon from app.models.planet import Planet from app import db planets_bp = Blueprint("planets", __name__, url_prefix="/planets") -moons_bp = Blueprint("moons", __name__, url_prefix="/moons") + def validate_planet(planet_id): try: @@ -16,17 +15,6 @@ def validate_planet(planet_id): return planet abort(make_response({"message":f"Planet with {planet_id} not found"}, 404)) -def validate_moon(moon_id): - try: - moon_id=int(moon_id) - except: - abort(make_response({"message":f"moon {moon_id} invalid"})) - - moon = Moon.query.get(moon_id) - if moon: - return moon - - abort(make_response({"message": f"moon {moon_id} not found"})) def apply_filter(planet_query): @@ -194,83 +182,4 @@ def delete_a_planet(planet_id): db.session.delete(planet) db.session.commit() - return make_response(jsonify(f"Planet {planet.id} successfully deleted")) - - -@planets_bp.route("planets//moons", methods=["POST"]) -def create_moon(planet_id): - planet = validate_planet(planet_id) - request_body = request.get_json() - new_moon = Moon( - name=request_body["name"], - description = request_body["description"], - image = request_body["img"], - planet=planet - ) - db.session.add(new_moon) - db.session.commit() - return make_response(f"New Moon {new_moon.name} creative", 201) - -@planets_bp.route("//moons", methods=["GET"]) -def get_all_moons_by_planet(planet_id): - planet = validate_planet(planet_id) - moons_response = [] - for moon in planet.moons: - moons_response.append({ - "id":moon.id, - "title": moon.title, - "description": moon.description, - "image":moon.image, - - }) - return jsonify(moons_response) - -@moons_bp.route("", methods=["GET"]) -def get_all_moons(): - moons = Moon.query.all() - moons_response = [] - for moon in moons: - moons_response.append({ - "id":moon.id, - "title": moon.title, - "description": moon.description, - "image":moon.image, - }) - return jsonify(moons_response) - - -@moons_bp.route("/", methods=["GET"]) -def get_moon_by_id(moon_id): - moon=validate_moon(moon_id) - - return jsonify({ - "id": moon.id, - "name": moon.name, - "description": moon.description, - "image": moon.image - }) - -@moons_bp.route("/", methods=["PUT"]) -def update_moon(moon_id): - moon=validate_moon(moon_id) - request_body = request.get_json() - moon.name = request_body["name"] - moon.description=request_body["description"] - moon.image=request_body["img"] - moon.planet_id=request_body["planet_id"] - - db.session.commit() - return make_response(f"Moon {moon.name} has been update", 204) - - - - - -@moons_bp.route("/", methods=["DELETE"]) -def delete_moon(moon_id): - moon=validate_moon(moon_id) - - db.session.delete(moon) - db.session.commit() - - return make_response(f"moon {moon.id} successfully deleted") \ No newline at end of file + return make_response(jsonify(f"Planet {planet.id} successfully deleted")) \ No newline at end of file From 0bceb5d22ecd394502dc1d5620dec28eb4c4a458 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Tue, 3 Jan 2023 16:17:13 -0800 Subject: [PATCH 32/48] Add test_get_all_planets_with_two_records and make attribute display more consistent --- app/routes/planet.py | 4 ++-- tests/test_routes.py | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/app/routes/planet.py b/app/routes/planet.py index aaff47114..3f04be27d 100644 --- a/app/routes/planet.py +++ b/app/routes/planet.py @@ -75,11 +75,11 @@ def display_planets(): "orbital_inclination": planet.orbital_inclination, "orbital_eccentricity":planet.orbital_eccentricity, "obliquity_to_orbit":planet.obliquity_to_orbit, - "mean_tempurature":planet.mean_tempurature_c, + "mean_tempurature_c":planet.mean_tempurature_c, "surface_pressure":planet.surface_pressure, "global_magnetic_feild":planet.global_magnetic_feild, "img":planet.img, - "Has Rings": planet.has_rings, + "has_rings": planet.has_rings, #"moons":planet.moons }) return jsonify(planets_response) diff --git a/tests/test_routes.py b/tests/test_routes.py index aa6bd0ee7..f81b21867 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -8,6 +8,40 @@ def test_get_all_planets_with_no_records(client): assert response.status_code == 200 assert response_body == [] +def test_get_all_planets_with_two_records(client, two_saved_planets): + #Act + response = client.get("/planets") + response_body = response.get_json() + + #Assert + assert response.status_code == 200 + assert response_body[0] == { + "id":1, + "name": "Neptune", + "description": "Named for the god of the sea because it is blue", + "mass": 102, + "diameter": 49528, + "density": 1638, + "gravity": 11.0, + "escape_velocity": 23.5, + "rotation_period": 16.1, + "day_length": 16.1, + "distance_from_sun": 4515, + "orbital_period": 59800, + "orbital_velocity": 5.4, + "orbital_inclination": 1.8, + "orbital_eccentricity": 0.01, + "obliquity_to_orbit": 28.3, + "mean_tempurature_c": -200, + "surface_pressure": None, + "global_magnetic_feild": True, + "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", + "has_rings": True, + } + assert response_body[1]["name"] == "number two" + + + def test_get_one_planet(client, two_saved_planets): # Act response = client.get("/planets/1") From baa9b8ff5d58bdd686979ae0d0c8c5f2dacaad28 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Tue, 3 Jan 2023 17:40:21 -0800 Subject: [PATCH 33/48] Add to_dict function and tests --- app/models/planet.py | 27 ++++++++++++ tests/test_models.py | 100 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 tests/test_models.py diff --git a/app/models/planet.py b/app/models/planet.py index 81e83f05a..96d9ec65a 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -24,6 +24,33 @@ class Planet(db.Model): img=db.Column(db.String) has_rings=db.Column(db.Boolean, default=False, server_default="false") moons = db.relationship("Moon", back_populates="planet") + + def to_dict(self): + planet_as_dict = {} + planet_as_dict["id"] = self.id + planet_as_dict["name"] = self.name + planet_as_dict["description"] = self.description + planet_as_dict["mass"] = self.mass + planet_as_dict["diameter"]=self.diameter + planet_as_dict["density"] = self.density + planet_as_dict["gravity"] = self.gravity + planet_as_dict["escape_velocity"] = self.escape_velocity + planet_as_dict["rotation_period"] = self.rotation_period + planet_as_dict["day_length"] = self.day_length + planet_as_dict["distance_from_sun"] = self.distance_from_sun + planet_as_dict["orbital_period"] = self.orbital_period + planet_as_dict["orbital_velocity"] = self.orbital_velocity + planet_as_dict["orbital_inclination"] = self.orbital_inclination + planet_as_dict["orbital_eccentricity"] = self.orbital_eccentricity + planet_as_dict["obliquity_to_orbit"] = self.obliquity_to_orbit + planet_as_dict["mean_tempurature_c"] = self.mean_tempurature_c + planet_as_dict["surface_pressure"] = self.surface_pressure + planet_as_dict["global_magnetic_feild"] = self.global_magnetic_feild + planet_as_dict["img"] = self.img + planet_as_dict["has_rings"] = self.has_rings + planet_as_dict["moons"] = list(map(lambda moon: moon.to_dict(), self.moons)) + return planet_as_dict + # def __init__(self, id, name, description, mass, diameter, density, gravity, escape_velocity, # rotation_period, day_length, distance_from_sun, orbital_period, orbital_velocity, orbital_inclination, orbital_eccentricity, # obliquity_to_orbit, mean_tempurature_c, surface_pressure, global_magnetic_feild,img,has_rings=False, moons=None): diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 000000000..fe4f09d26 --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,100 @@ +from app.models.planet import Planet + +def test_to_dict_no_missing_data(): + #Arrange + test_planet = Planet( + id = 1, + name="Neptune", + description="Named for the god of the sea because it is blue", + mass=102, + diameter=49528, + density=1638, + gravity=11.0, + escape_velocity=23.5, + rotation_period=16.1, + day_length=16.1, + distance_from_sun=4515, + orbital_period=59800, + orbital_velocity=5.4, + orbital_inclination=1.8, + orbital_eccentricity=0.01, + obliquity_to_orbit=28.3, + mean_tempurature_c=-200, + surface_pressure=None, + global_magnetic_feild=True, + img="https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", + has_rings=True, + ) + #Act + result = test_planet.to_dict() + + #assert + assert result == { + "id":1, + "name": "Neptune", + "description": "Named for the god of the sea because it is blue", + "mass": 102, + "diameter": 49528, + "density": 1638, + "gravity": 11.0, + "escape_velocity": 23.5, + "rotation_period": 16.1, + "day_length": 16.1, + "distance_from_sun": 4515, + "orbital_period": 59800, + "orbital_velocity": 5.4, + "orbital_inclination": 1.8, + "orbital_eccentricity": 0.01, + "obliquity_to_orbit": 28.3, + "mean_tempurature_c": -200, + "surface_pressure": None, + "global_magnetic_feild": True, + "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", + "has_rings": True, + "moons": [] + } + +def test_to_dict_missing_attributes(): + #Arrange + complete_attributes = { + "id":1, + "name": "Neptune", + "description": "Named for the god of the sea because it is blue", + "mass": 102, + "diameter": 49528, + "density": 1638, + "gravity": 11.0, + "escape_velocity": 23.5, + "rotation_period": 16.1, + "day_length": 16.1, + "distance_from_sun": 4515, + "orbital_period": 59800, + "orbital_velocity": 5.4, + "orbital_inclination": 1.8, + "orbital_eccentricity": 0.01, + "obliquity_to_orbit": 28.3, + "mean_tempurature_c": -200, + "surface_pressure": None, + "global_magnetic_feild": True, + "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", + "has_rings": True, + "moons": [] + } + + for attribute in complete_attributes.keys(): + incomplete_attributes = complete_attributes.copy() + del incomplete_attributes[attribute] + test_planet = Planet(**incomplete_attributes) + + expected = complete_attributes.copy() + if attribute == "moons": + expected[attribute] = [] + else: + expected[attribute] = None + + #Act + result = test_planet.to_dict() + + #Assert + assert result == expected + \ No newline at end of file From 6965b906eaf744da8c6abba85d75a62e328d8d30 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Tue, 3 Jan 2023 17:46:02 -0800 Subject: [PATCH 34/48] Use to_dict function in display_planets and display_planet methods and add missing moons attribute to test function --- app/routes/planet.py | 54 ++++---------------------------------------- tests/test_routes.py | 2 ++ 2 files changed, 7 insertions(+), 49 deletions(-) diff --git a/app/routes/planet.py b/app/routes/planet.py index 3f04be27d..c3865f261 100644 --- a/app/routes/planet.py +++ b/app/routes/planet.py @@ -58,30 +58,7 @@ def display_planets(): planet_query = Planet.query planet_query = apply_filter(planet_query).all() for planet in planet_query: - planets_response.append({ - "id": planet.id, - "name": planet.name, - "description": planet.description, - "mass": planet.mass, - "diameter":planet.diameter, - "density": planet.density, - "gravity": planet.gravity, - "escape_velocity": planet.escape_velocity, - "rotation_period": planet.rotation_period, - "day_length": planet.day_length, - "distance_from_sun":planet.distance_from_sun, - "orbital_period": planet.orbital_period, - "orbital_velocity" : planet.orbital_velocity, - "orbital_inclination": planet.orbital_inclination, - "orbital_eccentricity":planet.orbital_eccentricity, - "obliquity_to_orbit":planet.obliquity_to_orbit, - "mean_tempurature_c":planet.mean_tempurature_c, - "surface_pressure":planet.surface_pressure, - "global_magnetic_feild":planet.global_magnetic_feild, - "img":planet.img, - "has_rings": planet.has_rings, - #"moons":planet.moons - }) + planets_response.append(planet.to_dict()) return jsonify(planets_response) @planets_bp.route("", methods=["POST"]) @@ -118,31 +95,10 @@ def create_planets(): @planets_bp.route("/", methods=["GET"]) def display_planet(planet_id): planet = validate_planet(planet_id) - planet_response = { - "id": planet.id, - "name": planet.name, - "description": planet.description, - "mass": planet.mass, - "diameter":planet.diameter, - "density": planet.density, - "gravity": planet.gravity, - "escape_velocity": planet.escape_velocity, - "rotation_period": planet.rotation_period, - "day_length": planet.day_length, - "distance_from_sun":planet.distance_from_sun, - "orbital_period": planet.orbital_period, - "orbital_velocity" : planet.orbital_velocity, - "orbital_inclination": planet.orbital_inclination, - "orbital_eccentricity":planet.orbital_eccentricity, - "obliquity_to_orbit":planet.obliquity_to_orbit, - "mean_tempurature_c":planet.mean_tempurature_c, - "surface_pressure":planet.surface_pressure, - "global_magnetic_feild":planet.global_magnetic_feild, - "img":planet.img, - "has_rings": planet.has_rings, - #"moons":planet.moons - } - return jsonify(planet_response) + return planet.to_dict() + + + @planets_bp.route("/", methods=["PUT"]) def update_a_planet(planet_id): diff --git a/tests/test_routes.py b/tests/test_routes.py index f81b21867..cdcb7fccd 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -37,6 +37,7 @@ def test_get_all_planets_with_two_records(client, two_saved_planets): "global_magnetic_feild": True, "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", "has_rings": True, + "moons": [] } assert response_body[1]["name"] == "number two" @@ -71,6 +72,7 @@ def test_get_one_planet(client, two_saved_planets): "global_magnetic_feild": True, "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", "has_rings": True, + "moons": [] } def test_create_one_planet(client): From 69205a229aed9a2c1958e44017ef58c854bdc6df Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Tue, 3 Jan 2023 18:22:41 -0800 Subject: [PATCH 35/48] Add from_dict method to planet model and tests for from_dict method --- app/models/planet.py | 31 +++++++++++++++++++ tests/test_models.py | 73 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/app/models/planet.py b/app/models/planet.py index 96d9ec65a..6bec28f92 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -51,6 +51,37 @@ def to_dict(self): planet_as_dict["moons"] = list(map(lambda moon: moon.to_dict(), self.moons)) return planet_as_dict + @classmethod + def from_dict(cls, planets_data): + # Moons are optional + moons = [] + if "moons" in planets_data: + moons = planets_data["moons"] + + new_planet = Planet( + id=planets_data["id"], + name=planets_data["name"], + description=planets_data["description"], + mass=planets_data["mass"], + diameter=planets_data["diameter"], + density=planets_data["density"], + gravity=planets_data["gravity"], + escape_velocity=planets_data["escape_velocity"], + rotation_period=planets_data["rotation_period"], + day_length=planets_data["day_length"], + distance_from_sun=planets_data["distance_from_sun"], + orbital_period=planets_data["orbital_period"], + orbital_velocity=planets_data["orbital_velocity"], + orbital_inclination=planets_data["orbital_inclination"], + orbital_eccentricity=planets_data["orbital_eccentricity"], + obliquity_to_orbit=planets_data["obliquity_to_orbit"], + mean_tempurature_c=planets_data["mean_tempurature_c"], + surface_pressure=planets_data["surface_pressure"], + global_magnetic_feild=planets_data["global_magnetic_feild"], + img=planets_data["img"], + has_rings=planets_data["has_rings"], + moons=moons) + return new_planet # def __init__(self, id, name, description, mass, diameter, density, gravity, escape_velocity, # rotation_period, day_length, distance_from_sun, orbital_period, orbital_velocity, orbital_inclination, orbital_eccentricity, # obliquity_to_orbit, mean_tempurature_c, surface_pressure, global_magnetic_feild,img,has_rings=False, moons=None): diff --git a/tests/test_models.py b/tests/test_models.py index fe4f09d26..542695bc4 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,4 +1,5 @@ from app.models.planet import Planet +import pytest def test_to_dict_no_missing_data(): #Arrange @@ -24,6 +25,7 @@ def test_to_dict_no_missing_data(): global_magnetic_feild=True, img="https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", has_rings=True, + moons = [] ) #Act result = test_planet.to_dict() @@ -97,4 +99,73 @@ def test_to_dict_missing_attributes(): #Assert assert result == expected - \ No newline at end of file + +def test_from_dict_returns_planet(): + #Arrange + test_planet = { + "id":1, + "name": "Neptune", + "description": "Named for the god of the sea because it is blue", + "mass": 102, + "diameter": 49528, + "density": 1638, + "gravity": 11.0, + "escape_velocity": 23.5, + "rotation_period": 16.1, + "day_length": 16.1, + "distance_from_sun": 4515, + "orbital_period": 59800, + "orbital_velocity": 5.4, + "orbital_inclination": 1.8, + "orbital_eccentricity": 0.01, + "obliquity_to_orbit": 28.3, + "mean_tempurature_c": -200, + "surface_pressure": None, + "global_magnetic_feild": True, + "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", + "has_rings": True, + "moons": [] + } + + #Act + new_planet = Planet.from_dict(test_planet) + + #Assert + for key, value in test_planet.items(): + assert getattr(new_planet, key) == value + + + +def test_from_dict_with_missing_attributes(): + #Arrange + complete_attributes = { + "id":1, + "name": "Neptune", + "description": "Named for the god of the sea because it is blue", + "mass": 102, + "diameter": 49528, + "density": 1638, + "gravity": 11.0, + "escape_velocity": 23.5, + "rotation_period": 16.1, + "day_length": 16.1, + "distance_from_sun": 4515, + "orbital_period": 59800, + "orbital_velocity": 5.4, + "orbital_inclination": 1.8, + "orbital_eccentricity": 0.01, + "obliquity_to_orbit": 28.3, + "mean_tempurature_c": -200, + "surface_pressure": None, + "global_magnetic_feild": True, + "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", + "has_rings": True + } + + for attribute in complete_attributes.keys(): + incomplete_attributes = complete_attributes.copy() + del incomplete_attributes[attribute] + + #Act/Assert + with pytest.raises(KeyError, match = attribute): + new_planet = Planet.from_dict(incomplete_attributes) \ No newline at end of file From 091396a12b3e47676c5d729a6fdd4d6061a1cf1b Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Tue, 3 Jan 2023 18:35:22 -0800 Subject: [PATCH 36/48] Make id optional for Planet.from_dict --- app/models/planet.py | 1 - tests/test_models.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/app/models/planet.py b/app/models/planet.py index 6bec28f92..e5b33c9d6 100644 --- a/app/models/planet.py +++ b/app/models/planet.py @@ -59,7 +59,6 @@ def from_dict(cls, planets_data): moons = planets_data["moons"] new_planet = Planet( - id=planets_data["id"], name=planets_data["name"], description=planets_data["description"], mass=planets_data["mass"], diff --git a/tests/test_models.py b/tests/test_models.py index 542695bc4..c82ff1208 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -103,7 +103,6 @@ def test_to_dict_missing_attributes(): def test_from_dict_returns_planet(): #Arrange test_planet = { - "id":1, "name": "Neptune", "description": "Named for the god of the sea because it is blue", "mass": 102, @@ -139,7 +138,6 @@ def test_from_dict_returns_planet(): def test_from_dict_with_missing_attributes(): #Arrange complete_attributes = { - "id":1, "name": "Neptune", "description": "Named for the god of the sea because it is blue", "mass": 102, From 1624900f3739b44f4efeb4dc11f2250eadc95888 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Tue, 3 Jan 2023 18:37:07 -0800 Subject: [PATCH 37/48] Update test to be more robust: Order of attributes should not matter --- tests/test_routes.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/test_routes.py b/tests/test_routes.py index cdcb7fccd..de247bb8c 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -166,7 +166,26 @@ def test_incorrect_id_format(client, two_saved_planets): def test_create_incomplete_planet(client): #Arrange response = client.post("/planets", json={ - "name": "Uranus"}) + "name": "Uranus", + "mass": 86.8, + "diameter": 51118, + "density": 1270, + "gravity": 8.7, + "escape_velocity": 21.3, + "rotation_period": -17.2, + "day_length": 17.2, + "distance_from_sun": 2867, + "orbital_period": 30589, + "orbital_velocity": 6.8, + "orbital_inclination": 0.8, + "orbital_eccentricity": 0.047, + "obliquity_to_orbit": 97.8, + "mean_tempurature_c": -195, + "surface_pressure": None, + "global_magnetic_feild": True, + "img": "https://solarsystem.nasa.gov/resources/605/keck-telescope-views-of-uranus/?category=planets_uranus", + "has_rings": True + }) response_body = response.get_json() #Assert From 0a643156c9192365401819115865f0e575d53357 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Tue, 3 Jan 2023 18:39:32 -0800 Subject: [PATCH 38/48] Use from_dict function in create_planets method --- app/routes/planet.py | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/app/routes/planet.py b/app/routes/planet.py index c3865f261..3a2e3c427 100644 --- a/app/routes/planet.py +++ b/app/routes/planet.py @@ -64,30 +64,10 @@ def display_planets(): @planets_bp.route("", methods=["POST"]) def create_planets(): request_body=request.get_json() - for key in PLANET_ATTRIBUTES: - if not key in request_body: - abort(make_response({"message": f"Bad request: {key} attribute is missing"}, 400)) - new_planet = Planet( - name=request_body["name"], - description=request_body["description"], - mass=request_body["mass"], - diameter=request_body["diameter"], - density=request_body["density"], - gravity=request_body["gravity"], - escape_velocity=request_body["escape_velocity"], - rotation_period=request_body["rotation_period"], - day_length=request_body["day_length"], - distance_from_sun=request_body["distance_from_sun"], - orbital_period=request_body["orbital_period"], - orbital_velocity=request_body["orbital_velocity"], - orbital_inclination=request_body["orbital_inclination"], - orbital_eccentricity=request_body["orbital_eccentricity"], - obliquity_to_orbit=request_body["obliquity_to_orbit"], - mean_tempurature_c=request_body["mean_tempurature_c"], - surface_pressure=request_body["surface_pressure"], - global_magnetic_feild=request_body["global_magnetic_feild"], - img=request_body["img"], - has_rings=request_body["has_rings"]) + try: + new_planet = Planet.from_dict(request_body) + except KeyError as key_error: + abort(make_response({"message": f"Bad request: {key_error.args[0]} attribute is missing"}, 400)) db.session.add(new_planet) db.session.commit() return make_response(jsonify(f"New Planet {new_planet.name} created!"), 201) From 5d18775cba1ab11f0525caa45300151f6948fa4d Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 4 Jan 2023 08:49:14 -0800 Subject: [PATCH 39/48] format --- tests/conftest.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/conftest.py b/tests/conftest.py index a822db172..66c3ab13f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -63,4 +63,4 @@ def two_saved_moons(app, two_saved_planets): moon_two=Moon(name="2 Test Moon", description="Second Neptune", image="prettiestMoon.jpg", planet_id=1) db.session.add_all([moon_one,moon_two]) - db.session.commit() \ No newline at end of file + db.session.commit() From 05281adb826f65e0e69d7d4d4159af12902d289c Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Wed, 4 Jan 2023 11:17:36 -0800 Subject: [PATCH 40/48] Moon tests. Co-authored-by: Ya-Juan Ruan --- app/models/moon.py | 4 ++- app/routes/moon.py | 36 +++++++++++-------- tests/conftest.py | 7 ++-- tests/test_routes.py | 85 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 114 insertions(+), 18 deletions(-) diff --git a/app/models/moon.py b/app/models/moon.py index 411b20203..6f25720d6 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -15,12 +15,14 @@ def to_dict(self): moons_as_dict["id"] = self.id moons_as_dict["name"] = self.name moons_as_dict["description"] = self.description + moons_as_dict["image"] = self.image return moons_as_dict @classmethod def from_dict(cls, moon_data): - new_moon = Moon(name=moon_data["name"], description=moon_data["desciption"]) + new_moon = Moon( + name=moon_data["name"], description=moon_data["description"], image=moon_data["image"]) return new_moon # def __init__(self, id, name, description, planet_id): # self.id=id diff --git a/app/routes/moon.py b/app/routes/moon.py index 6ac1acfc8..aabca6fa7 100644 --- a/app/routes/moon.py +++ b/app/routes/moon.py @@ -17,19 +17,23 @@ def validate_moon(moon_id): abort(make_response({"message": f"moon {moon_id} not found"})) -@planets_bp.route("planets//moons", methods=["POST"]) +@planets_bp.route("//moons", methods=["POST"]) def create_moon(planet_id): planet = validate_planet(planet_id) request_body = request.get_json() - new_moon = Moon( + try: + new_moon = Moon( name=request_body["name"], description = request_body["description"], - image = request_body["img"], + image = request_body["image"], planet=planet ) + except KeyError as key_error: + abort(make_response({"message": f"Bad request: {key_error.args[0]} attribute is missing"}, 400)) + db.session.add(new_moon) db.session.commit() - return make_response(f"New Moon {new_moon.name} creative", 201) + return make_response(jsonify(f"New Moon {new_moon.name} created!"), 201) @planets_bp.route("//moons", methods=["GET"]) def get_all_moons_by_planet(planet_id): @@ -38,7 +42,7 @@ def get_all_moons_by_planet(planet_id): for moon in planet.moons: moons_response.append({ "id":moon.id, - "title": moon.title, + "name": moon.name, "description": moon.description, "image":moon.image, @@ -50,12 +54,7 @@ def get_all_moons(): moons = Moon.query.all() moons_response = [] for moon in moons: - moons_response.append({ - "id":moon.id, - "title": moon.title, - "description": moon.description, - "image":moon.image, - }) + moons_response.append(moon.to_dict()) return jsonify(moons_response) @@ -76,8 +75,17 @@ def update_moon(moon_id): request_body = request.get_json() moon.name = request_body["name"] moon.description=request_body["description"] - moon.image=request_body["img"] - moon.planet_id=request_body["planet_id"] + moon.image=request_body["image"] + + db.session.commit() + return make_response(jsonify(f"Moon {moon.name} has been updated")) +@moons_bp.route("/", methods=["DELETE"]) +def delete_a_planet(moon_id): + moon = validate_planet(moon_id) + + db.session.delete(moon) db.session.commit() - return make_response(f"Moon {moon.name} has been update", 204) \ No newline at end of file + + return make_response(jsonify(f"Moon {moon.id} successfully deleted")) + diff --git a/tests/conftest.py b/tests/conftest.py index 66c3ab13f..412ad51e2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,6 +4,7 @@ from flask.signals import request_finished from app.models.planet import Planet from app.models.moon import Moon +from app.routes.planet import validate_planet @pytest.fixture @@ -29,7 +30,7 @@ def client(app): @pytest.fixture def two_saved_planets(app): test_one = Planet( - name="Neptune", + name="Neptune", description="Named for the god of the sea because it is blue", mass=102, diameter=49528, @@ -59,8 +60,10 @@ def two_saved_planets(app): @pytest.fixture def two_saved_moons(app, two_saved_planets): + planet_one = validate_planet(1) moon_one=Moon(name="Test Moon", description="First Moon for Neptune", image="pretty_moon.jpg", planet_id=1) - moon_two=Moon(name="2 Test Moon", description="Second Neptune", image="prettiestMoon.jpg", planet_id=1) + moon_two=Moon(name="2 Test Moon", description="Second Neptune", image="prettiestMoon.jpg", planet_id = 1) db.session.add_all([moon_one,moon_two]) db.session.commit() + diff --git a/tests/test_routes.py b/tests/test_routes.py index de247bb8c..ce9120042 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -233,4 +233,87 @@ def test_get_one_moon(client, two_saved_moons): "name":"Test Moon", "description":"First Moon for Neptune", "image":"pretty_moon.jpg" - } \ No newline at end of file + } + + +def test_get_all_moons_with_two_records(client, two_saved_moons): + #Act + response = client.get("/moons") + response_body = response.get_json() + + #Assert + assert response.status_code == 200 + assert response_body[0] == { + "id":1, + "name": "Test Moon", + "description": "First Moon for Neptune", + "image":"pretty_moon.jpg" + } + assert response_body[1]["name"] == "2 Test Moon" + assert len(response_body) == 2 + + + +def test_get_one_moon(client, two_saved_moons): + # Act + response = client.get("/moons/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == { + + "id":1, + "name": "Test Moon", + "description": "First Moon for Neptune", + "image":"pretty_moon.jpg" + } + + + +def test_create_one_moon(client,two_saved_planets, two_saved_moons): + # Act + response = client.post("planets/1/moons", json={ + "name": "three moon", + "description": "for testing", + "image": "best_moon.jpb", +}) + + response_body = response.get_json() + + # Assert + assert response.status_code == 201 + assert response_body == "New Moon three moon created!" + +def test_update_one_moon(client, two_saved_moons): + # Act + response = client.put("/moons/2", json={ + "name": "moon", + "description": "Smells bad", + "image": "images.img" +}) + #Arrange + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == "Moon moon has been updated" + +def test_delete_one_planet(client, two_saved_moons): + #Arrange + response = client.delete("/moons/2") + response_body = response.get_json() + + #Assert + assert response.status_code == 200 + assert response_body == "Planet 2 successfully deleted" + + + +def test_all_moons_by_planet(client, two_saved_planets, two_saved_moons): + response = client.get("/planets/1/moons") + response_body = response.get_json() + + # Assert + assert len(response_body) == 2 + From 5e00c1e4f6fea40776ca14c11b05c2ae7da692f2 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 4 Jan 2023 11:57:35 -0800 Subject: [PATCH 41/48] Update test_delete_one_moon to pass test --- tests/test_routes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_routes.py b/tests/test_routes.py index ce9120042..6ddd305ca 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -299,14 +299,14 @@ def test_update_one_moon(client, two_saved_moons): assert response.status_code == 200 assert response_body == "Moon moon has been updated" -def test_delete_one_planet(client, two_saved_moons): +def test_delete_one_moon(client, two_saved_moons): #Arrange response = client.delete("/moons/2") response_body = response.get_json() #Assert assert response.status_code == 200 - assert response_body == "Planet 2 successfully deleted" + assert response_body == "Moon 2 successfully deleted" From d68420b623a30882f78be0546845c3fb40e20a2d Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 4 Jan 2023 12:18:26 -0800 Subject: [PATCH 42/48] Create two global variables to reduce code duplication --- tests/test_routes.py | 128 +++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 78 deletions(-) diff --git a/tests/test_routes.py b/tests/test_routes.py index 6ddd305ca..6238b6bae 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,56 +1,6 @@ +from app.routes.planet import validate_planet -def test_get_all_planets_with_no_records(client): - # Act - response = client.get("/planets") - response_body = response.get_json() - - # Assert - assert response.status_code == 200 - assert response_body == [] - -def test_get_all_planets_with_two_records(client, two_saved_planets): - #Act - response = client.get("/planets") - response_body = response.get_json() - - #Assert - assert response.status_code == 200 - assert response_body[0] == { - "id":1, - "name": "Neptune", - "description": "Named for the god of the sea because it is blue", - "mass": 102, - "diameter": 49528, - "density": 1638, - "gravity": 11.0, - "escape_velocity": 23.5, - "rotation_period": 16.1, - "day_length": 16.1, - "distance_from_sun": 4515, - "orbital_period": 59800, - "orbital_velocity": 5.4, - "orbital_inclination": 1.8, - "orbital_eccentricity": 0.01, - "obliquity_to_orbit": 28.3, - "mean_tempurature_c": -200, - "surface_pressure": None, - "global_magnetic_feild": True, - "img": "https://solarsystem.nasa.gov/resources/611/neptune-full-disk-view/?category=planets_neptune", - "has_rings": True, - "moons": [] - } - assert response_body[1]["name"] == "number two" - - - -def test_get_one_planet(client, two_saved_planets): - # Act - response = client.get("/planets/1") - response_body = response.get_json() - - # Assert - assert response.status_code == 200 - assert response_body == { +NEPTUNE_PLANET = { "id":1, "name": "Neptune", "description": "Named for the god of the sea because it is blue", @@ -75,9 +25,7 @@ def test_get_one_planet(client, two_saved_planets): "moons": [] } -def test_create_one_planet(client): - # Act - response = client.post("/planets", json={ +URANUS_PLANET = { "name": "Uranus", "description": "Smells bad", "mass": 86.8, @@ -98,7 +46,41 @@ def test_create_one_planet(client): "global_magnetic_feild": True, "img": "https://solarsystem.nasa.gov/resources/605/keck-telescope-views-of-uranus/?category=planets_uranus", "has_rings": True, -}) +} + +def test_get_all_planets_with_no_records(client): + # Act + response = client.get("/planets") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == [] + +def test_get_all_planets_with_two_records(client, two_saved_planets): + #Act + response = client.get("/planets") + response_body = response.get_json() + + #Assert + assert response.status_code == 200 + assert response_body[0] == NEPTUNE_PLANET + assert response_body[1]["name"] == "number two" + + + +def test_get_one_planet(client, two_saved_planets): + # Act + response = client.get("/planets/1") + response_body = response.get_json() + + # Assert + assert response.status_code == 200 + assert response_body == NEPTUNE_PLANET + +def test_create_one_planet(client): + # Act + response = client.post("/planets", json=URANUS_PLANET) response_body = response.get_json() # Assert @@ -107,28 +89,7 @@ def test_create_one_planet(client): def test_update_one_planet(client, two_saved_planets): # Act - response = client.put("/planets/2", json={ - "name": "Uranus", - "description": "Smells bad", - "mass": 86.8, - "diameter": 51118, - "density": 1270, - "gravity": 8.7, - "escape_velocity": 21.3, - "rotation_period": -17.2, - "day_length": 17.2, - "distance_from_sun": 2867, - "orbital_period": 30589, - "orbital_velocity": 6.8, - "orbital_inclination": 0.8, - "orbital_eccentricity": 0.047, - "obliquity_to_orbit": 97.8, - "mean_tempurature_c": -195, - "surface_pressure": None, - "global_magnetic_feild": True, - "img": "https://solarsystem.nasa.gov/resources/605/keck-telescope-views-of-uranus/?category=planets_uranus", - "has_rings": True, -}) + response = client.put("/planets/2", json=URANUS_PLANET) #Arrange response_body = response.get_json() @@ -317,3 +278,14 @@ def test_all_moons_by_planet(client, two_saved_planets, two_saved_moons): # Assert assert len(response_body) == 2 + +def test_validate_planet(two_saved_planets): + #Act + result_planet = validate_planet(1) + + #Assert + for key, value in NEPTUNE_PLANET.items(): + assert getattr(result_planet, key) == value + + + From d1b272703adeeda8d1360f5482c3f0b5437cdcaa Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 4 Jan 2023 12:33:47 -0800 Subject: [PATCH 43/48] Update incorrect route name and validate function --- app/routes/moon.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/routes/moon.py b/app/routes/moon.py index aabca6fa7..61081d617 100644 --- a/app/routes/moon.py +++ b/app/routes/moon.py @@ -81,8 +81,8 @@ def update_moon(moon_id): return make_response(jsonify(f"Moon {moon.name} has been updated")) @moons_bp.route("/", methods=["DELETE"]) -def delete_a_planet(moon_id): - moon = validate_planet(moon_id) +def delete_a_moon(moon_id): + moon = validate_moon(moon_id) db.session.delete(moon) db.session.commit() From 8f00da41434b3cca073c7361e81543e4c7b43a95 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 4 Jan 2023 12:39:41 -0800 Subject: [PATCH 44/48] Refactor validate_planet to validate_model and Update all the dependenies --- app/routes/moon.py | 7 ++++--- app/routes/planet.py | 20 ++++++++++---------- tests/conftest.py | 4 ++-- tests/test_routes.py | 10 ++++------ 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/app/routes/moon.py b/app/routes/moon.py index 61081d617..fca0e8ea6 100644 --- a/app/routes/moon.py +++ b/app/routes/moon.py @@ -1,7 +1,8 @@ from app.models.moon import Moon +from app.models.planet import Planet from flask import Blueprint, jsonify, abort, make_response, request from app import db -from app.routes.planet import planets_bp, validate_planet +from app.routes.planet import planets_bp, validate_model moons_bp = Blueprint("moons", __name__, url_prefix="/moons") def validate_moon(moon_id): @@ -19,7 +20,7 @@ def validate_moon(moon_id): @planets_bp.route("//moons", methods=["POST"]) def create_moon(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) request_body = request.get_json() try: new_moon = Moon( @@ -37,7 +38,7 @@ def create_moon(planet_id): @planets_bp.route("//moons", methods=["GET"]) def get_all_moons_by_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) moons_response = [] for moon in planet.moons: moons_response.append({ diff --git a/app/routes/planet.py b/app/routes/planet.py index 3a2e3c427..432f2f319 100644 --- a/app/routes/planet.py +++ b/app/routes/planet.py @@ -5,15 +5,15 @@ planets_bp = Blueprint("planets", __name__, url_prefix="/planets") -def validate_planet(planet_id): +def validate_model(cls, model_id): try: - planet_id = int(planet_id) + model_id = int(model_id) except: - abort(make_response({"message":f"{planet_id} invalid"}, 400)) - planet = Planet.query.get(planet_id) - if planet: - return planet - abort(make_response({"message":f"Planet with {planet_id} not found"}, 404)) + abort(make_response({"message":f"{model_id} invalid"}, 400)) + model = cls.query.get(model_id) + if model: + return model + abort(make_response({"message":f"{cls.__name__} with {model_id} not found"}, 404)) @@ -74,7 +74,7 @@ def create_planets(): @planets_bp.route("/", methods=["GET"]) def display_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) return planet.to_dict() @@ -82,7 +82,7 @@ def display_planet(planet_id): @planets_bp.route("/", methods=["PUT"]) def update_a_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) request_body = request.get_json() for key in PLANET_ATTRIBUTES: if not key in request_body: @@ -113,7 +113,7 @@ def update_a_planet(planet_id): @planets_bp.route("/", methods=["DELETE"]) def delete_a_planet(planet_id): - planet = validate_planet(planet_id) + planet = validate_model(Planet, planet_id) db.session.delete(planet) db.session.commit() diff --git a/tests/conftest.py b/tests/conftest.py index 412ad51e2..42e49268e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,7 +4,7 @@ from flask.signals import request_finished from app.models.planet import Planet from app.models.moon import Moon -from app.routes.planet import validate_planet +from app.routes.planet import validate_model @pytest.fixture @@ -60,7 +60,7 @@ def two_saved_planets(app): @pytest.fixture def two_saved_moons(app, two_saved_planets): - planet_one = validate_planet(1) + planet_one = validate_model(Planet ,1) moon_one=Moon(name="Test Moon", description="First Moon for Neptune", image="pretty_moon.jpg", planet_id=1) moon_two=Moon(name="2 Test Moon", description="Second Neptune", image="prettiestMoon.jpg", planet_id = 1) diff --git a/tests/test_routes.py b/tests/test_routes.py index 6238b6bae..a71c48ef8 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -1,4 +1,5 @@ -from app.routes.planet import validate_planet +from app.routes.planet import validate_model +from app.models.planet import Planet NEPTUNE_PLANET = { "id":1, @@ -277,15 +278,12 @@ def test_all_moons_by_planet(client, two_saved_planets, two_saved_moons): # Assert assert len(response_body) == 2 - - + def test_validate_planet(two_saved_planets): #Act - result_planet = validate_planet(1) + result_planet = validate_model(Planet, 1) #Assert for key, value in NEPTUNE_PLANET.items(): assert getattr(result_planet, key) == value - - From ed06a4475ca475abf74a26e2ce1a3adff5bd6440 Mon Sep 17 00:00:00 2001 From: Ya-Juan Ruan Date: Wed, 4 Jan 2023 12:45:43 -0800 Subject: [PATCH 45/48] Refactor validate_model to validate_model and Update all the dependenies --- app/routes/moon.py | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/app/routes/moon.py b/app/routes/moon.py index fca0e8ea6..77858ea86 100644 --- a/app/routes/moon.py +++ b/app/routes/moon.py @@ -5,18 +5,6 @@ from app.routes.planet import planets_bp, validate_model moons_bp = Blueprint("moons", __name__, url_prefix="/moons") -def validate_moon(moon_id): - try: - moon_id=int(moon_id) - except: - abort(make_response({"message":f"moon {moon_id} invalid"})) - - moon = Moon.query.get(moon_id) - if moon: - return moon - - abort(make_response({"message": f"moon {moon_id} not found"})) - @planets_bp.route("//moons", methods=["POST"]) def create_moon(planet_id): @@ -61,7 +49,7 @@ def get_all_moons(): @moons_bp.route("/", methods=["GET"]) def get_moon_by_id(moon_id): - moon=validate_moon(moon_id) + moon=validate_model(Moon, moon_id) return jsonify({ "id": moon.id, @@ -72,7 +60,7 @@ def get_moon_by_id(moon_id): @moons_bp.route("/", methods=["PUT"]) def update_moon(moon_id): - moon=validate_moon(moon_id) + moon=validate_model(Moon, moon_id) request_body = request.get_json() moon.name = request_body["name"] moon.description=request_body["description"] @@ -83,7 +71,7 @@ def update_moon(moon_id): @moons_bp.route("/", methods=["DELETE"]) def delete_a_moon(moon_id): - moon = validate_moon(moon_id) + moon = validate_model(Moon, moon_id) db.session.delete(moon) db.session.commit() From ccca0ff093862e8347c103a9d1720a9a1bba2759 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Thu, 5 Jan 2023 10:33:44 -0800 Subject: [PATCH 46/48] Add size attribute. --- app/models/moon.py | 1 + migrations/versions/d663f3f6838e_.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 migrations/versions/d663f3f6838e_.py diff --git a/app/models/moon.py b/app/models/moon.py index 6f25720d6..6535b2215 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -4,6 +4,7 @@ class Moon(db.Model): __tablename__='moons' id = db.Column(db.Integer, primary_key=True, autoincrement=True) name = db.Column(db.String) + size = db.Column(db.Float) description = db.Column(db.String) image = db.Column(db.String) planet_id = db.Column(db.Integer, db.ForeignKey('planets.id')) diff --git a/migrations/versions/d663f3f6838e_.py b/migrations/versions/d663f3f6838e_.py new file mode 100644 index 000000000..076d0f835 --- /dev/null +++ b/migrations/versions/d663f3f6838e_.py @@ -0,0 +1,28 @@ +"""empty message + +Revision ID: d663f3f6838e +Revises: 0663be054953 +Create Date: 2023-01-05 10:33:17.544793 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'd663f3f6838e' +down_revision = '0663be054953' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('moons', sa.Column('size', sa.Float(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('moons', 'size') + # ### end Alembic commands ### From ed0abe1e61f4edad7f28944ef2de0fcdd4a6e092 Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Thu, 5 Jan 2023 10:43:05 -0800 Subject: [PATCH 47/48] Co-authored-by: Ya-Juan Ruan --- app/models/moon.py | 3 ++- app/routes/moon.py | 4 ++++ tests/conftest.py | 4 ++-- tests/test_routes.py | 7 ++++++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/app/models/moon.py b/app/models/moon.py index 6535b2215..cdaf6c9e1 100644 --- a/app/models/moon.py +++ b/app/models/moon.py @@ -15,6 +15,7 @@ def to_dict(self): moons_as_dict = {} moons_as_dict["id"] = self.id moons_as_dict["name"] = self.name + moons_as_dict["size"] = self.size moons_as_dict["description"] = self.description moons_as_dict["image"] = self.image @@ -23,7 +24,7 @@ def to_dict(self): @classmethod def from_dict(cls, moon_data): new_moon = Moon( - name=moon_data["name"], description=moon_data["description"], image=moon_data["image"]) + name=moon_data["name"],size=moon_data["size"], description=moon_data["description"], image=moon_data["image"]) return new_moon # def __init__(self, id, name, description, planet_id): # self.id=id diff --git a/app/routes/moon.py b/app/routes/moon.py index 77858ea86..58cafdff5 100644 --- a/app/routes/moon.py +++ b/app/routes/moon.py @@ -13,6 +13,7 @@ def create_moon(planet_id): try: new_moon = Moon( name=request_body["name"], + size = request_body["size"], description = request_body["description"], image = request_body["image"], planet=planet @@ -32,6 +33,7 @@ def get_all_moons_by_planet(planet_id): moons_response.append({ "id":moon.id, "name": moon.name, + "size": moon.size, "description": moon.description, "image":moon.image, @@ -54,6 +56,7 @@ def get_moon_by_id(moon_id): return jsonify({ "id": moon.id, "name": moon.name, + "size": moon.size, "description": moon.description, "image": moon.image }) @@ -63,6 +66,7 @@ def update_moon(moon_id): moon=validate_model(Moon, moon_id) request_body = request.get_json() moon.name = request_body["name"] + moon.size = request_body["size"] moon.description=request_body["description"] moon.image=request_body["image"] diff --git a/tests/conftest.py b/tests/conftest.py index 42e49268e..a07b36eaa 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -61,8 +61,8 @@ def two_saved_planets(app): @pytest.fixture def two_saved_moons(app, two_saved_planets): planet_one = validate_model(Planet ,1) - moon_one=Moon(name="Test Moon", description="First Moon for Neptune", image="pretty_moon.jpg", planet_id=1) - moon_two=Moon(name="2 Test Moon", description="Second Neptune", image="prettiestMoon.jpg", planet_id = 1) + moon_one=Moon(name="Test Moon", size=200.5, description="First Moon for Neptune", image="pretty_moon.jpg", planet_id=1) + moon_two=Moon(name="2 Test Moon", size=100.6, description="Second Neptune", image="prettiestMoon.jpg", planet_id = 1) db.session.add_all([moon_one,moon_two]) db.session.commit() diff --git a/tests/test_routes.py b/tests/test_routes.py index a71c48ef8..d78b42967 100644 --- a/tests/test_routes.py +++ b/tests/test_routes.py @@ -192,7 +192,8 @@ def test_get_one_moon(client, two_saved_moons): assert response_body == { "id":1, - "name":"Test Moon", + "name":"Test Moon", + "size": 200.5, "description":"First Moon for Neptune", "image":"pretty_moon.jpg" } @@ -208,6 +209,7 @@ def test_get_all_moons_with_two_records(client, two_saved_moons): assert response_body[0] == { "id":1, "name": "Test Moon", + "size": 200.5, "description": "First Moon for Neptune", "image":"pretty_moon.jpg" } @@ -227,6 +229,7 @@ def test_get_one_moon(client, two_saved_moons): "id":1, "name": "Test Moon", + "size": 200.5, "description": "First Moon for Neptune", "image":"pretty_moon.jpg" } @@ -237,6 +240,7 @@ def test_create_one_moon(client,two_saved_planets, two_saved_moons): # Act response = client.post("planets/1/moons", json={ "name": "three moon", + "size": 200.5, "description": "for testing", "image": "best_moon.jpb", }) @@ -251,6 +255,7 @@ def test_update_one_moon(client, two_saved_moons): # Act response = client.put("/moons/2", json={ "name": "moon", + "size": 100.6, "description": "Smells bad", "image": "images.img" }) From 033288f8ae97339a95c93e2ecbdb85c3edfe398d Mon Sep 17 00:00:00 2001 From: maple-megan333 Date: Fri, 6 Jan 2023 11:24:47 -0800 Subject: [PATCH 48/48] setting up for deployment --- Procfile | 1 + requirements.txt | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 Procfile diff --git a/Procfile b/Procfile new file mode 100644 index 000000000..066ed31d9 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: gunicorn 'app:create_app()' diff --git a/requirements.txt b/requirements.txt index fba2b3e38..f1c31b3f2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,18 +1,25 @@ alembic==1.5.4 +attrs==22.1.0 autopep8==1.5.5 blinker==1.4 certifi==2020.12.5 chardet==4.0.0 click==7.1.2 +coverage==6.5.0 Flask==1.1.2 Flask-Migrate==2.6.0 Flask-SQLAlchemy==2.4.4 +gunicorn==20.1.0 idna==2.10 +iniconfig==1.1.1 itsdangerous==1.1.0 Jinja2==2.11.3 Mako==1.1.4 MarkupSafe==1.1.1 +packaging==22.0 +pluggy==1.0.0 psycopg2-binary==2.9.4 +py==1.11.0 pycodestyle==2.6.0 pytest==7.1.1 pytest-cov==2.12.1 @@ -23,5 +30,6 @@ requests==2.25.1 six==1.15.0 SQLAlchemy==1.3.23 toml==0.10.2 +tomli==2.0.1 urllib3==1.26.4 Werkzeug==1.0.1