diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3b22887 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore virtual environment folder +.venv/* \ No newline at end of file diff --git a/app.py b/app.py index 065415c..3603be3 100644 --- a/app.py +++ b/app.py @@ -1,8 +1,14 @@ # BEGIN CODE HERE -from flask import Flask +from flask import Flask, request, jsonify from flask_pymongo import PyMongo from flask_cors import CORS from pymongo import TEXT +from numpy import dot +from numpy.linalg import norm +from selenium import webdriver +from selenium.webdriver.chrome.options import Options +from selenium.webdriver.common.by import By + # END CODE HERE app = Flask(__name__) @@ -15,26 +21,117 @@ @app.route("/search", methods=["GET"]) def search(): # BEGIN CODE HERE - return "" + query = request.args.get("name") + if not query: + return jsonify({"error": "No query provided"}), 400 + result = list(mongo.db.products.find({"name": query}).sort("price", -1)) + + if not result: + return jsonify({"error": "Product not found"}), 404 + + for product in result: + product["_id"] = str(product["_id"]) + + return jsonify(result) + # END CODE HERE @app.route("/add-product", methods=["POST"]) def add_product(): # BEGIN CODE HERE - return "" + data = request.json + + def check_price(price): + parts = price.split(".") + if len(parts) != 2: + return False + return parts[0].isnumeric() and parts[1].isnumeric() + + if ( + not data + or not data["name"].strip() + or not data.get("production_year").isdigit() + or not check_price(data.get("price")) + ): + return jsonify({"error": "Wrong JSON data provided"}), 400 + + # Check valid values for color and size + valid_colors = ["1", "2", "3"] + valid_sizes = ["1", "2", "3", "4"] + if data["color"] not in valid_colors or data["size"] not in valid_sizes: + return jsonify({"error": "Invalid color or size provided"}), 400 + + existing_product = mongo.db.products.find_one({"name": data["name"]}) + if existing_product: + # Ενημέρωση των πεδίων του υπάρχοντος προϊόντος + mongo.db.products.update_one( + {"_id": existing_product["_id"]}, + {"$set": data}, + ) + return jsonify({"message": "Product updated successfully"}), 200 + + # Προσθήκη νέου προϊόντος στη βάση + mongo.db.products.insert_one(data) + + return jsonify({"message": "Product added successfully"}), 201 + # END CODE HERE @app.route("/content-based-filtering", methods=["POST"]) def content_based_filtering(): # BEGIN CODE HERE - return "" + def calculate_similarity(product1, product2): + cosine_similarity = dot(product1, product2) / (norm(product1) * norm(product2)) + return cosine_similarity + + given_product = request.get_json() + given_product_features = [ + given_product.get("production_year"), + given_product.get("price"), + given_product.get("color"), + given_product.get("size"), + ] + similar_products = [] + all_products = mongo.db.products.find( + {}, + {"name": 1, "production_year": 1, "price": 1, "color": 1, "size": 1}, + ) + for product in all_products: + product_features = [ + product["production_year"], + product["price"], + product["color"], + product["size"], + ] + similarity = calculate_similarity(given_product_features, product_features) + if similarity > 0.7: + similar_products.append(product["name"]) + + return jsonify(similar_products) # END CODE HERE @app.route("/crawler", methods=["GET"]) def crawler(): # BEGIN CODE HERE - return "" + url = "https:qa.auth.gr/el/x/studyguide/600000438/current" + options = Options() + options.headless = True + driver = webdriver.Chrome(options=options) + semester = request.args.get("semester") + driver.get(url) + print(semester) + section = driver.find_element(By.ID, "exam" + semester) + elements = section.find_elements(By.TAG_NAME, "a") + res = [] + for element in elements: + res.append(element.text) + driver.quit() + return jsonify(res) # END CODE HERE + + +if __name__ == "__main__": + app.run(debug=True) diff --git a/homepage.html b/homepage.html index 5cfa39a..53a84ef 100644 --- a/homepage.html +++ b/homepage.html @@ -9,6 +9,104 @@ + + +
+
+
+ Logo +
+
+ +
+
+
+ + +
+ + +
+
+
+

Heading

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

+
+
+ Image 1 +
+
+
+ + + +
+
+
+

• Lorem ipsum

+

• Lorem ipsum

+

• Lorem ipsum

+

• Lorem ipsum

+

• Lorem ipsum

+

• Lorem ipsum

+
+
+

Heading

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed

+
+
+ image-2 + image-3 +
+
+
+

Lorem ipsum dolor

+
+
+

Lorem ipsum dolor

+
+
+
+
+ + + +
+
+ +
+
+ +
+ + + diff --git a/products.css b/products.css index 4d40fdc..65dfe51 100644 --- a/products.css +++ b/products.css @@ -1,3 +1,13 @@ /* BEGIN CODE HERE */ +header.container-fluid img { + width: 250px; + height: 58px; +} -/* END CODE HERE */ \ No newline at end of file +label.form-label { + display: inline-block; + width: 100px; + text-align: left; +} + +/* END CODE HERE */ diff --git a/products.html b/products.html index d5596c4..77722f9 100644 --- a/products.html +++ b/products.html @@ -1,17 +1,182 @@ - + - - + + WIS Project - Products - - + + + +
+
+
+ Logo +
+
+ +
+
+
+ +
+ +
+
+
+

Search a product

+
+
+
+ + +
+
+
+ +
+
+

Results

+ + + + + + + + + + + + + + +
IDNameProduction yearPriceColorSize
+
+
+
+ + + +
+

Add a product

+ +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+ + + + + - + - \ No newline at end of file + diff --git a/products.js b/products.js index 40fe8f5..0e6118d 100644 --- a/products.js +++ b/products.js @@ -1,19 +1,81 @@ const api = "http://127.0.0.1:5000"; window.onload = () => { - // BEGIN CODE HERE - - // END CODE HERE -} + // BEGIN CODE HERE + document + .querySelector(".btn-primary") + .addEventListener("click", searchButtonOnClick); + document + .querySelector("form") + .addEventListener("submit", productFormOnSubmit); + // END CODE HERE +}; searchButtonOnClick = () => { - // BEGIN CODE HERE + // BEGIN CODE HERE + const searchInput = document.querySelector(".input-group input").value; + const tbody = document.querySelector("table tbody"); + tbody.innerHTML = ""; + if (!searchInput) return; - // END CODE HERE -} + fetch(`${api}/search?name=${encodeURIComponent(searchInput)}`) + .then((response) => { + if (!response.ok) { + throw new Error("Error fetching product data: " + response.statusText); + } + return response.json(); + }) + .then((product) => { + console.log(product[0]); + const row = document.createElement("tr"); + row.innerHTML = ` + ${product[0]._id} + ${product[0].name} + ${product[0].production_year} + ${product[0].price} + ${product[0].color} + ${product[0].size} + `; + tbody.appendChild(row); + }) + .catch((error) => { + console.error(error); + }); + // END CODE HERE +}; productFormOnSubmit = (event) => { - // BEGIN CODE HERE + // BEGIN CODE HERE + event.preventDefault(); + + const productData = { + name: document.getElementById("productName").value, + production_year: document.getElementById("productionYear").value, + price: document.getElementById("price").value, + color: document.getElementById("color").value, + size: document.getElementById("size").value, + }; - // END CODE HERE -} + fetch(`${api}/add-product`, { + method: "POST", + headers: { + "Content-Type": "application/json;charset=UTF-8", + }, + body: JSON.stringify(productData), + }) + .then((response) => { + if (response.status === 200) { + document.querySelector("form").reset(); + console.log("Product updated successfully"); + } else if (response.status === 201) { + document.querySelector("form").reset(); + console.log("Product added successfully"); + } else { + throw new Error("Error adding product: " + response.statusText); + } + }) + .catch((error) => { + console.error(error); + }); + // END CODE HERE +};