From 65ea49e666283ce31a89e0b3f858069ffdf5b92f Mon Sep 17 00:00:00 2001 From: K-dash Date: Tue, 28 May 2024 17:51:17 +0900 Subject: [PATCH 1/4] Unify frontend and backend directory structure - Remove backend/frontend directories and move files under src - Rename frontend directory to static (convention for Flask) - Update import paths and references accordingly - Rename main.py to cli.py to avoid naming conflicts - Allow Flask app to accept requests from all network interfaces(0.0.0.0) --- src/__init__.py | 0 src/{backend => }/api.py | 14 +++++++------ src/{backend => }/art.py | 0 src/{backend/main.py => cli.py} | 27 +++++++++++++------------- src/{backend => }/helper.py | 26 +++++++++++++++---------- src/{backend => }/send_email.py | 0 src/{backend => }/server.py | 9 ++++----- src/{frontend => static}/script.js | 0 src/{backend => }/templates/index.html | 0 9 files changed, 42 insertions(+), 34 deletions(-) create mode 100644 src/__init__.py rename src/{backend => }/api.py (96%) rename src/{backend => }/art.py (100%) rename src/{backend/main.py => cli.py} (75%) rename src/{backend => }/helper.py (95%) rename src/{backend => }/send_email.py (100%) rename src/{backend => }/server.py (89%) rename src/{frontend => static}/script.js (100%) rename src/{backend => }/templates/index.html (100%) diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/api.py b/src/api.py similarity index 96% rename from src/backend/api.py rename to src/api.py index bae46a0..abb9a80 100644 --- a/src/backend/api.py +++ b/src/api.py @@ -160,6 +160,7 @@ def forecast(lat, long, decimal, days=0): daily_data["date"], ] + def gather_data(lat, long, ocean): """ Calls APIs though python files @@ -178,10 +179,11 @@ def gather_data(lat, long, ocean): "Direction": ocean_data[1], "Period": ocean_data[2], "UV Index": uv_index, - "Forecast": json_forecast + "Forecast": json_forecast, } return ocean_data, uv_index, data_dict + def seperate_args_and_get_location(args): """ Gets user's coordinates from either the argument(location=) or, if none, @@ -189,9 +191,9 @@ def seperate_args_and_get_location(args): """ coordinates = get_coordinates(args) location_data = { - "coordinates" : coordinates, - "lat" : coordinates[0], - "long" : coordinates[1], - "city" : coordinates[2] + "coordinates": coordinates, + "lat": coordinates[0], + "long": coordinates[1], + "city": coordinates[2], } - return location_data \ No newline at end of file + return location_data diff --git a/src/backend/art.py b/src/art.py similarity index 100% rename from src/backend/art.py rename to src/art.py diff --git a/src/backend/main.py b/src/cli.py similarity index 75% rename from src/backend/main.py rename to src/cli.py index 4bfb982..41caf6c 100644 --- a/src/backend/main.py +++ b/src/cli.py @@ -3,20 +3,20 @@ """ import sys -import helper -import api -import art import os -import subprocess -from dotenv import load_dotenv -from helper import arguments_dictionary +sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) -def main(lat=0, long=0): +from src import helper +from src import api +from src import art + + +def run(lat=0, long=0): """ Main function """ - #Seperates the cli args into a list + # Seperates the cli args into a list args = helper.seperate_args(sys.argv) # return coordinates, lat, long, city @@ -29,9 +29,9 @@ def main(lat=0, long=0): if lat == 0 and long == 0: lat, long = set_location[2], set_location[3] - #Sets ocean = dictionary with + # Sets ocean = dictionary with arguments = helper.arguments_dictionary(lat, long, city, args) - #Updates the ocean dict with the valeus from the arguments + # Updates the ocean dict with the valeus from the arguments arguments = helper.set_output_values(args, arguments) lat = float(lat) @@ -42,14 +42,15 @@ def main(lat=0, long=0): uv_index = data[1] data_dict = data[2] - #Non-JSON output + # Non-JSON output if arguments["json_output"] == 0: helper.print_outputs(lat, long, coordinates, ocean_data, arguments) return data_dict - #JSON Output + # JSON Output else: json_output = helper.json_output(data_dict) return json_output + if __name__ == "__main__": - main() \ No newline at end of file + run() diff --git a/src/backend/helper.py b/src/helper.py similarity index 95% rename from src/backend/helper.py rename to src/helper.py index 909c10a..fb5b133 100644 --- a/src/backend/helper.py +++ b/src/helper.py @@ -1,13 +1,12 @@ """ General helper functions """ -import subprocess + import json import api import art -import os import pandas as pd -from http.server import SimpleHTTPRequestHandler, HTTPServer + def arguments_dictionary(lat, long, city, args): """ @@ -25,11 +24,11 @@ def arguments_dictionary(lat, long, city, args): "show_period": 1, "show_city": 1, "show_date": 1, - "json_output" : 0, + "json_output": 0, "unit": "imperial", "decimal": extract_decimal(args), "forecast_days": get_forecast_days(args), - "color": get_color(args) + "color": get_color(args), } return arguments @@ -136,6 +135,7 @@ def round_decimal(round_list, decimal): rounded_list.append(round(num, decimal)) return rounded_list + def set_output_values(args, ocean): """ Takes a list of command line arguments(args) and sets the appropritate values @@ -163,14 +163,16 @@ def set_output_values(args, ocean): ocean["json_output"] = 1 return ocean + def json_output(data_dict): """ If JSON=TRUE in .args, we print and return the JSON data - """ + """ json_out = json.dumps(data_dict, indent=4) print(json_out) return data_dict + def print_outputs(lat, long, coordinates, ocean_data, arguments): """ Basically the main printing function, calls all the other printing functions @@ -183,12 +185,15 @@ def print_outputs(lat, long, coordinates, ocean_data, arguments): print("No ocean data at this location.") else: print_location(arguments["city"], arguments["show_city"]) - art.print_wave(arguments["show_wave"], arguments["show_large_wave"], arguments["color"]) + art.print_wave( + arguments["show_wave"], arguments["show_large_wave"], arguments["color"] + ) print_output(arguments) print("\n") forecast = api.forecast(lat, long, arguments["decimal"], arguments["forecast_days"]) print_forecast(arguments, forecast) + def set_location(location): """ Sets locations variables @@ -197,12 +202,13 @@ def set_location(location): lat, long = location["lat"], location["long"] return coordinates, city, lat, long + def forecast_to_json(data, decimal): """ Takes forecast() as input and returns it in JSON format """ surf_height, swell_direction, swell_period, dates = data - + # Formatting into JSON forecasts = [] for i in range(len(dates)): @@ -210,8 +216,8 @@ def forecast_to_json(data, decimal): "date": str(dates[i].date()), "surf height": round(float(surf_height[i]), decimal), "swell direction": round(float(swell_direction[i]), decimal), - "swell period": round(float(swell_period[i]), decimal) + "swell period": round(float(swell_period[i]), decimal), } forecasts.append(forecast) - + return forecasts diff --git a/src/backend/send_email.py b/src/send_email.py similarity index 100% rename from src/backend/send_email.py rename to src/send_email.py diff --git a/src/backend/server.py b/src/server.py similarity index 89% rename from src/backend/server.py rename to src/server.py index 3d788e5..dd19335 100644 --- a/src/backend/server.py +++ b/src/server.py @@ -7,7 +7,6 @@ from dotenv import load_dotenv, dotenv_values import os import subprocess -import json import asyncio import urllib.parse @@ -20,7 +19,7 @@ @app.route("/help") def serve_help(): - return send_from_directory("../../", "help.txt") + return send_from_directory("../", "help.txt") @app.route("/home") @@ -30,7 +29,7 @@ def serve_index(): @app.route("/script.js") def serve_script(): - return send_file("../frontend/script.js") + return send_file("static/script.js") @app.route("/") @@ -52,7 +51,7 @@ def default_route(): async def run_subprocess(): try: result = subprocess.run( - ["python3", "main.py", args], + ["python3", "cli.py", args], capture_output=True, text=True, check=True, @@ -72,4 +71,4 @@ async def run_subprocess(): if __name__ == "__main__": - app.run(port=os.getenv("PORT")) + app.run(host="0.0.0.0", port=os.getenv("PORT")) diff --git a/src/frontend/script.js b/src/static/script.js similarity index 100% rename from src/frontend/script.js rename to src/static/script.js diff --git a/src/backend/templates/index.html b/src/templates/index.html similarity index 100% rename from src/backend/templates/index.html rename to src/templates/index.html From e7acc8fdaed62c5b99673a48395cdec83a3dfad5 Mon Sep 17 00:00:00 2001 From: K-dash Date: Tue, 28 May 2024 17:52:52 +0900 Subject: [PATCH 2/4] Refactor directory structure and update Dockerfile accordingly --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0064e13..31289ad 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,7 +17,8 @@ COPY . . # USER app # Set the working directory for running the application -WORKDIR /app/src/backend +WORKDIR /app/src +EXPOSE 8000 # Command to run the Flask application -CMD ["python3", "server.py"] \ No newline at end of file +CMD ["python3", "server.py"] From 136f2e07f7ca82ab0e79991115e8530a7ad6f637 Mon Sep 17 00:00:00 2001 From: K-dash Date: Tue, 28 May 2024 17:55:29 +0900 Subject: [PATCH 3/4] Update tests and CI configuration for directory structure changes - Modify test directory structure to match the updated source directory - Update import paths and references in test files - Adjust pytest.yaml configuration to reflect the new directory structure --- .github/workflows/pytest.yml | 4 ++-- src/tests/__init__.py | 0 src/tests/test_code.py | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) create mode 100644 src/tests/__init__.py diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 120e0ff..9b5096c 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -20,5 +20,5 @@ jobs: pip install pytest - name: Test with pytest run: | - cd src/tests - pytest \ No newline at end of file + cd src + pytest diff --git a/src/tests/__init__.py b/src/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/tests/test_code.py b/src/tests/test_code.py index 6477ac4..dfc3d36 100644 --- a/src/tests/test_code.py +++ b/src/tests/test_code.py @@ -6,14 +6,14 @@ import sys -sys.path.append("../backend") +sys.path.append("../src") from unittest.mock import patch import io import time -from main import main -from helper import extract_decimal -from api import get_coordinates, get_uv, ocean_information +from src import cli +from src.helper import extract_decimal +from src.api import get_coordinates, get_uv, ocean_information def test_invalid_input(): @@ -56,9 +56,9 @@ def test_main_output(): Main() returns a dictionary of: location, height, period, etc. This functions checks if the dictionary is returned and is populated """ - #Hardcode lat and long for location. If not, when test are ran in Github Actions - #We get an error(because server probably isn't near ocean) - data_dict = main(36.95, -121.97) + # Hardcode lat and long for location. If not, when test are ran in Github Actions + # We get an error(because server probably isn't near ocean) + data_dict = cli.run(36.95, -121.97) print(data_dict) time.sleep(5) assert len(data_dict) >= 5 From 60001d6556e45cd28bdc8781074e9b5de7ea31fe Mon Sep 17 00:00:00 2001 From: K-dash Date: Tue, 28 May 2024 18:00:32 +0900 Subject: [PATCH 4/4] Update README.md to reflect directory structure changes --- README.md | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 38ebb2b..3c7281f 100644 --- a/README.md +++ b/README.md @@ -83,7 +83,7 @@ To run locally on your machine, I recommend either: 4. `python3 -m venv venv` 5. `source venv/bin/activate` 6. `pip install -r requirements.txt` -7. `cd src/backend` +7. `cd src` 8. `python3 server.py` **Or running Docker (install [Docker](https://docs.docker.com/engine/install/))** @@ -102,6 +102,8 @@ Change `.env.example` to `.env` | Variable | Description| | -------- | ------- | +| `PORT` | The port you want to open to run the application. Default = `8000` | +| `IP_ADDRESS` | The ip your server is running on. Default = `localhost` | | `SMTP_SERVER` | The email server you are using. Default = smtp.gmail.com | | `EMAIL` | The email you will send the report from. | | `EMAIL_PW` | The sending email's password | @@ -109,13 +111,6 @@ Change `.env.example` to `.env` | `COMMAND` | The command that will be ran and shown in the email. Default = `localhost:8000` | | `SUBJECT` | The email's subject. Default = Surf Report | -**config.json** - -| Variable | Description| -| -------- | ------- | -| `port` | The port you want to open to run the application. Default = `8000` | -| `ip_address` | The ip your server is running on. Default = `localhost` | - **Email Server** @@ -135,7 +130,7 @@ Although this application was made with the cli in mind, there is a frontend. `http://localhost:8000/home` **or** `:/home` if the application is running on a different host or you have changed the default port. -You may need to change `ip_address` in `config.json` to match the ip of the host running the machine. +You may need to change `IP_ADDRESS` in `.env` to match the ip of the host running the machine. Now, running `python3 server.py` will launch the website! @@ -153,4 +148,4 @@ Questions? Comments? * [GitHub](https://github.com/ryansurf) ## License -[![License](https://img.shields.io/:license-mit-blue.svg?style=flat-square)](https://badges.mit-license.org) \ No newline at end of file +[![License](https://img.shields.io/:license-mit-blue.svg?style=flat-square)](https://badges.mit-license.org)