diff --git a/PCP/server/data/data.sql b/PCP/server/data/data.sql index 60f9817..054e451 100644 --- a/PCP/server/data/data.sql +++ b/PCP/server/data/data.sql @@ -7,6 +7,7 @@ DROP TABLE IF EXISTS Retailers CASCADE; DROP TABLE IF EXISTS ProductCategories CASCADE; DROP TABLE IF EXISTS user_authentication CASCADE; DROP TABLE IF EXISTS Currency CASCADE; +DROP TABLE IF EXISTS Cart CASCADE; -- Create Product User Authentication Table @@ -93,3 +94,13 @@ CREATE TABLE PriceAlerts ( FOREIGN KEY (user_id) REFERENCES user_authentication(user_id) ON DELETE CASCADE, FOREIGN KEY (ProductID) REFERENCES Products(ProductID) ON DELETE CASCADE ); + +-- Create Cart table +CREATE TABLE Cart ( + CartID SERIAL PRIMARY KEY, + UserID INT NOT NULL, + ProductID INT NOT NULL, + Quantity INT NOT NULL DEFAULT 1, + FOREIGN KEY (UserID) REFERENCES user_authentication(user_id) ON DELETE CASCADE, + FOREIGN KEY (ProductID) REFERENCES Products(ProductID) ON DELETE CASCADE +); diff --git a/PCP/server/src/api/cart_api.py b/PCP/server/src/api/cart_api.py new file mode 100644 index 0000000..0187a47 --- /dev/null +++ b/PCP/server/src/api/cart_api.py @@ -0,0 +1,62 @@ +from flask import jsonify, make_response, request +from flask_restful import Resource + +try: + from src.db.cart import get_cart_contents, add_item_to_cart, remove_item_from_cart + from src.utilities.swen_344_db_utils import exec_get_all +except ImportError: + from db.cart import get_cart_contents, add_item_to_cart, remove_item_from_cart + from utilities.swen_344_db_utils import exec_get_all + + +def verify_session_key(session_key): + """Check the session key and return the user ID if valid.""" + query = "SELECT user_id FROM user_authentication WHERE session_key = %s;" + result = exec_get_all(query, (session_key,)) + return result[0][0] if result else None + + +class Cart(Resource): + def get(self, user_id): + print(f"Fetching cart for user ID: {user_id}") + try: + cart_items = get_cart_contents(user_id) + print(f"Cart items: {cart_items}") + if not cart_items: + return jsonify({"error": "No items found in the cart"}), 404 + return jsonify({"cart_items": cart_items}) + except Exception as e: + print(f"Error: {e}") + return jsonify({"error": str(e)}), 500 + + +class AddToCart(Resource): + def post(self, user_id, product_id, quantity): + """Adds a new item to the shopping cart or updates the quantity if it already exists.""" + try: + result = add_item_to_cart(user_id, product_id, quantity) + if result: + return jsonify({'message': 'Item added to cart successfully'}), 200 + else: + return jsonify({'error': 'Failed to add item to cart'}), 500 + except Exception as e: + return jsonify({"error": str(e)}), 500 + +class RemoveFromCart(Resource): + def delete(self, product_id): + # Retrieve session key from the request headers + session_key = request.headers.get('X-Session-Key') + if not session_key: + return make_response(jsonify({"message": "No session key provided."}), 401) + + # Verify the session key and get the associated user ID + user_id = verify_session_key(session_key) + if not user_id: + return make_response(jsonify({"message": "Invalid session key."}), 401) + + # Proceed with deleting the item from the cart + try: + remove_item_from_cart(user_id, product_id) + return make_response(jsonify({'message': 'Item removed from cart successfully'}), 204) + except Exception as e: + return make_response(jsonify({"error": str(e)}), 500) diff --git a/PCP/server/src/db/cart.py b/PCP/server/src/db/cart.py new file mode 100644 index 0000000..f6e28f7 --- /dev/null +++ b/PCP/server/src/db/cart.py @@ -0,0 +1,34 @@ +try: + from src.utilities.swen_344_db_utils import exec_get_all, exec_commit +except ImportError: + from utilities.swen_344_db_utils import exec_get_all, exec_commit + + +def get_cart_contents(user_id): + """Fetches all items in the user's cart.""" + sql = """ + SELECT p.ProductID, p.ProductName, p.ProductDescription, p.ImageURL, c.Quantity, pr.Price + FROM Cart c + JOIN Products p ON c.ProductID = p.ProductID + JOIN Prices pr ON p.ProductID = pr.ProductID + WHERE c.UserID = %s; + """ + result = exec_get_all(sql, (user_id,)) + return result + + +def add_item_to_cart(user_id, product_id, quantity): + """Adds a new item or updates the quantity of an existing item in the cart.""" + sql = """ + INSERT INTO Cart (UserID, ProductID, Quantity) + VALUES (%s, %s, %s) + ON DUPLICATE KEY UPDATE Quantity = Quantity + VALUES(Quantity); + """ + result = exec_commit(sql, (user_id, product_id, quantity)) + return result + + +def remove_item_from_cart(user_id, product_id): + """Removes an item from the cart.""" + sql = "DELETE FROM Cart WHERE UserID = %s AND ProductID = %s;" + exec_commit(sql, (user_id, product_id)) diff --git a/PCP/server/src/server.py b/PCP/server/src/server.py index f9bd085..4678dc5 100644 --- a/PCP/server/src/server.py +++ b/PCP/server/src/server.py @@ -1,6 +1,6 @@ from flask import Flask -from flask_restful import Api from flask_cors import CORS +from flask_restful import Api try: from utilities.swen_344_db_utils import * @@ -14,7 +14,8 @@ from api.retailer_api import * from api.prices_api import * from api.user_favorites_api import * -except: + from api.cart_api import Cart, AddToCart, RemoveFromCart +except ImportError: from .utilities.swen_344_db_utils import * from .api.login_api import * from .api.signup_api import * @@ -26,7 +27,8 @@ from .api.retailer_api import * from .api.prices_api import * from .api.user_favorites_api import * - + from .api.cart_api import Cart, AddToCart, RemoveFromCart + app = Flask(__name__) # create Flask instance CORS(app) # Enable CORS on Flask server to work with Nodejs pages api = Api(app) # api router @@ -47,6 +49,9 @@ api.add_resource(Prices, '/prices') api.add_resource(UserFavorites, '/user_favorites') api.add_resource(UserFavoritesById, '/user_favorites/') +api.add_resource(Cart, '/cart/') +api.add_resource(AddToCart, '/addtocart///') +api.add_resource(RemoveFromCart, '/removefromcart//') def setup_database(): diff --git a/PCP/server/tests/1_api/test_3_logout_api.py b/PCP/server/tests/1_api/test_3_logout_api.py index 02d6b50..aa82827 100644 --- a/PCP/server/tests/1_api/test_3_logout_api.py +++ b/PCP/server/tests/1_api/test_3_logout_api.py @@ -40,7 +40,7 @@ def test_1_successful_logout(self, mock_post): self.assertEqual(response.status_code, 200) # Simulating extracting session key from login response - session_key = response.json().get('sessionKey') + session_key = response.get('sessionKey') self.assertIsNotNone(session_key, "Session key should not be None") # Simulating logout with the session key