From f5c9954e43af58def29f4ea21719afd0c1d337ce Mon Sep 17 00:00:00 2001 From: Stratos Thivaios Date: Sun, 21 Apr 2024 20:13:40 +0300 Subject: [PATCH] Created docker image --- Docker/Dockerfile | 15 ++ Docker/api.py | 216 +++++++++----------- Docker/docker-compose.yaml | 18 +- Docker/dockerfile | 11 - Docker/requirements.txt | 2 +- Docker/static/templates/air_quality.xml | 11 + Docker/static/templates/cisco.xml | 20 ++ Docker/static/templates/environmental.xml | 12 ++ Docker/static/templates/games.xml | 8 + Docker/static/templates/geocode_aqi.xml | 10 + Docker/static/templates/geocode_weather.xml | 10 + Docker/static/templates/get_stock.xml | 10 + Docker/static/templates/info.xml | 34 +++ Docker/static/templates/no_results.xml | 7 + Docker/static/templates/rps.xml | 25 +++ Docker/static/templates/rps_out.xml | 13 ++ Docker/static/templates/scr-off.xml | 4 + Docker/static/templates/stock_value.xml | 9 + Docker/static/templates/weather.xml | 14 ++ backend/api.py | 1 - 20 files changed, 306 insertions(+), 144 deletions(-) create mode 100644 Docker/Dockerfile delete mode 100644 Docker/dockerfile create mode 100644 Docker/static/templates/air_quality.xml create mode 100644 Docker/static/templates/cisco.xml create mode 100644 Docker/static/templates/environmental.xml create mode 100644 Docker/static/templates/games.xml create mode 100644 Docker/static/templates/geocode_aqi.xml create mode 100644 Docker/static/templates/geocode_weather.xml create mode 100644 Docker/static/templates/get_stock.xml create mode 100644 Docker/static/templates/info.xml create mode 100644 Docker/static/templates/no_results.xml create mode 100644 Docker/static/templates/rps.xml create mode 100644 Docker/static/templates/rps_out.xml create mode 100644 Docker/static/templates/scr-off.xml create mode 100644 Docker/static/templates/stock_value.xml create mode 100644 Docker/static/templates/weather.xml diff --git a/Docker/Dockerfile b/Docker/Dockerfile new file mode 100644 index 0000000..8015371 --- /dev/null +++ b/Docker/Dockerfile @@ -0,0 +1,15 @@ +FROM python:latest + +WORKDIR /ciscapps/ + +ARG fullHostname +ARG hostname +ARG alphavantageKey +ARG serverPort + +COPY requirements.txt requirements.txt +RUN pip3 install -r requirements.txt + +COPY . . + +CMD python3 api.py \ No newline at end of file diff --git a/Docker/api.py b/Docker/api.py index 74ea69d..df8e127 100644 --- a/Docker/api.py +++ b/Docker/api.py @@ -1,53 +1,89 @@ -from flask import Flask, request, jsonify, Response +from datetime import datetime +from flask import Flask, request, Response, render_template import requests import random -# import ast import openmeteo_requests import requests_cache -import pandas as pd -import time from retry_requests import retry from unidecode import unidecode import os -app = Flask(__name__) - -apisrv = 236 -stock_apikey = os.environ.get("stocks_api_key") -api_hostname = os.environ.get("api_hostname") +app = Flask(__name__, template_folder="./static/templates/") + +import logging +log = logging.getLogger('werkzeug') +log.setLevel(logging.ERROR) + +stock_apikey = os.environ['alphavantageKey'] +api_hostname = os.environ['hostname'] +pfHostname = os.environ['fullHostname'] +serverPort = os.environ['serverPort'] +fullHostname = f'{pfHostname}:{serverPort}' + +@app.route("/homepage/") +def homepage(): + code = render_template("cisco.xml", hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/scrOff/") +def scrOff(): + code = render_template("scr-off.xml") + return Response(code, mimetype='text/xml') + +@app.route("/getStock/") +def getStock(): + code = render_template("get_stock.xml", hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/getWeather/") +def getWeather(): + code = render_template("geocode_weather.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/info/") +def getInfo(): + code = render_template("info.xml") + return Response(code, mimetype='text/xml') + +@app.route("/playRps/") +def playRps(): + code = render_template("rps.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/getAqi/") +def getAqi(): + code = render_template("geocode_aqi.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/getGamesList/") +def getGamesList(): + code = render_template("games.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +@app.route("/getEnvApps/") +def getEnvApps(): + code = render_template("environmental.xml",hostname=fullHostname) + return Response(code, mimetype='text/xml') + +# backend calls @app.route("/stock-price/") def get_stock(): nsymb = request.args.get("symbol") out = requests.get(f"https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol={nsymb}&apikey={stock_apikey}") out = out.json() - # out = "{'Global Quote': {'01. symbol': 'MSFT', '02. open': '371.0400', '03. high': '371.9500', '04. low': '367.3454', '05. price': '370.2700', '06. volume': '26816841', '07. latest trading day': '2023-11-14', '08. previous close': '366.6800', '09. change': '-3.5900', '10. change percent': '0.9791%'}}" - # out = ast.literal_eval(out) - # print(out) - price = round(float(out['Global Quote']['05. price']),2) - change = round(float(out['Global Quote']['09. change']),2) + price = round(float(out['Global Quote']['05. price']), 2) + change = round(float(out['Global Quote']['09. change']), 2) change_percent = out['Global Quote']['10. change percent'] - # print(type(price)) - - # print(price) if change > 0: up_or_down = "UP ^" else: up_or_down = "DOWN" - output = f"\n" - output += f"Stock value for {nsymb.upper()}\n" - output += f"\n" - output += f"Symbol : {nsymb.upper()}\n" - output += f"Value : {price}$\n" - output += f"Change : {change}$ ({up_or_down})\n" - output += f"Change (%) : {change_percent}\n" - output += f"\n" - output += f"" - - return Response(output, mimetype='text/xml') - + sResp = render_template("stock_value.xml", symbol=nsymb.upper(), price=price, + change=change, up_or_down=up_or_down, change_percent=change_percent) + return Response(sResp, mimetype='text/xml') @app.route("/geocode-aqi/") def geocode_aqi(): @@ -55,16 +91,9 @@ def geocode_aqi(): name = request.args.get("name").upper() out = requests.get(f"https://geocoding-api.open-meteo.com/v1/search?name={name}&count=10&language=en&format=json") out = out.json() - print(out) cities_data = out['results'] city_info_list = [{'name': city['name'], 'admin1': city.get('admin1', ''), 'latitude': city['latitude'], - 'longitude': city['longitude'], 'country_code': city['country_code']} for city in cities_data] - - - # Print the result - for city_info in city_info_list: - print( - f"{city_info['name']}, {city_info['admin1']}, {city_info['latitude']}, {city_info['longitude']}, {city_info['country_code']}") + 'longitude': city['longitude'], 'country_code': city['country_code']} for city in cities_data] output = f"\n" output += f"Results for your search\n" @@ -76,37 +105,25 @@ def geocode_aqi(): output += f" {city_name}, {city_info['admin1']}, {city_info['country_code']}" city_name = city_name.replace(" ", "_") city_region = city_region.replace(" ", "_") - output += f" http://{api_hostname}/air-quality/?latitude={city_info['latitude']}&longtitude={city_info['longitude']}&name={city_name}&region={city_region}&country={city_info['country_code']}" + output += f" {fullHostname}/air-quality/?latitude={city_info['latitude']}&longtitude={city_info['longitude']}&name={city_name}&region={city_region}&country={city_info['country_code']}" output += f"" output += f"" return Response(output, mimetype='text/xml') except: - output = f"\n" - output += f"No results were found\n" - output += f"\n" - output += f"No results could be returned for your search.\nPerhaps you made a typo?\n" - output += f"\n" - return Response(output, mimetype='text/xml') + return Response(render_template("no_results.xml"), mimetype='text/xml') # return out, 200 - @app.route("/geocode-weather/") def geocode_weather(): try: name = request.args.get("name").upper() out = requests.get(f"https://geocoding-api.open-meteo.com/v1/search?name={name}&count=10&language=en&format=json") out = out.json() - print(out) cities_data = out['results'] city_info_list = [{'name': city['name'], 'admin1': city.get('admin1', ''), 'latitude': city['latitude'], 'longitude': city['longitude'], 'country_code': city['country_code']} for city in cities_data] - # Print the result - for city_info in city_info_list: - print( - f"{city_info['name']}, {city_info['admin1']}, {city_info['latitude']}, {city_info['longitude']}, {city_info['country_code']}") - output = f"\n" output += f"Results for your search\n" for city_info in city_info_list: @@ -117,21 +134,15 @@ def geocode_weather(): output += f" {city_name}, {city_info['admin1']}, {city_info['country_code']}" city_name = city_name.replace(" ", "_") city_region = city_region.replace(" ", "_") - output += f" http://{api_hostname}/weather/?latitude={city_info['latitude']}&longtitude={city_info['longitude']}&name={city_name}&region={city_region}&country={city_info['country_code']}" + output += f" {fullHostname}/weather/?latitude={city_info['latitude']}&longtitude={city_info['longitude']}&name={city_name}&region={city_region}&country={city_info['country_code']}" output += f"" output += f"" return Response(output, mimetype='text/xml') except: - output = f"\n" - output += f"No results were found\n" - output += f"\n" - output += f"No results could be returned for your search.\nPerhaps you made a typo?\n" - output += f"\n" - return Response(output, mimetype='text/xml') + return Response(render_template("no_results.xml"), mimetype='text/xml') # return out, 200 - @app.route("/air-quality/") def get_air_quality(): latitude = float(request.args.get("latitude")) @@ -141,29 +152,18 @@ def get_air_quality(): country = request.args.get("country") out = requests.get(f"https://air-quality-api.open-meteo.com/v1/air-quality?latitude={latitude}&longitude={longtitude}¤t=us_aqi,dust") out = out.json() - print(out) current = out['current'] - dust = current['dust'] air_quality = current['us_aqi'] + date = (f'{datetime.now().year}-{datetime.now().month}-{datetime.now().day} ' + + f'{datetime.now().hour}:{datetime.now().minute}:{datetime.now().second}') - print(dust) - print(air_quality) - - output = f"\n" - output += f"Air Quality\n" - output += f"\n" - output += f"{name}, {region}, {country}\n\n" - output += f"Dust : {dust}\n" - output += f"Air Quality (US AQI) : {air_quality}" - output += f"\n" - output += f"" - + aqResp = render_template("air_quality.xml", city=name, region=region, country=country, + dust=dust, air_quality=air_quality, last_update=date) - return Response(output, mimetype='text/xml') + return Response(aqResp, mimetype='text/xml') # return out, 200 - @app.route("/weather/") def weather(): latitude = float(request.args.get("latitude")) @@ -171,13 +171,11 @@ def weather(): name = request.args.get("name").replace("_", " ") region = request.args.get("region").replace("_", " ") country = request.args.get("country") - # Setup the Open-Meteo backend client with cache and retry on error cache_session = requests_cache.CachedSession('.cache', expire_after = 3600) retry_session = retry(cache_session, retries = 5, backoff_factor = 0.2) openmeteo = openmeteo_requests.Client(session = retry_session) - - # Make sure all required weather variables are listed here + # Make sure all required weather variables are listed here # The order of variables in hourly or daily is important to assign them correctly below url = "https://api.open-meteo.com/v1/forecast" params = { @@ -197,71 +195,45 @@ def weather(): current_wind_speed_10m = current.Variables(2).Value() current_wind_gusts_10m = current.Variables(3).Value() current_relative_humidity_2m = current.Variables(4).Value() + date = (f'{datetime.now().year}-{datetime.now().month}-{datetime.now().day} '+ + f'{datetime.now().hour}:{datetime.now().minute}:{datetime.now().second}') + wResp = render_template("weather.xml", city=name, region=region, country=country, + temperature=round(current_temperature_2m, 2), precipitation=current_precipitation, + w_speed=round(current_wind_speed_10m, 2), wg_speed=round(current_wind_gusts_10m, 2), + humidity=round(current_relative_humidity_2m, 2), last_update=date) - xml = f"\n" - xml += "Current Weather\n" - xml += "\n" - xml += f"{name}, {region}, {country}\n\n" - xml += f"Temperature : {round(current_temperature_2m, 2)}C\n" - xml += f"Precipitation : {current_precipitation}mm\n" - xml += f"Wind speed : {round(current_wind_speed_10m, 2)}m/s\n" - xml += f"Wind gusts : {round(current_wind_gusts_10m, 2)}m/s\n" - xml += f"Humidity : {round(current_relative_humidity_2m, 2)}%" - xml += f"\n" - xml += f"" - - return Response(xml, mimetype='text/xml') - + return Response(wResp, mimetype='text/xml') @app.route("/rps/") def rock_paper_scissors(): user_input = request.args.get("user_input") global computer - possible = ['rock','paper','scissors'] computer = random.choice(possible) - print(computer) if user_input == 'rock' and computer == 'paper': - output = f"{computer}\n" - output += "You loose!" - return output, 200 + lWin = "You loose!" elif user_input == 'rock' and computer == 'scissors': - output = f"{computer}\n" - output += "You win!" - return output, 200 + lWin = "You win!" elif user_input == 'rock' and computer == 'rock': - output = f"{computer}\n" - output += "Tie" - return output, 200 + lWin = "Tie" elif user_input == 'paper' and computer == 'rock': - output = f"{computer}\n" - output += "You win!" - return output, 200 + lWin = "You win!" elif user_input == 'paper' and computer == 'scissors': - output = f"{computer}\n" - output += "You loose!" - return output, 200 + lWin = "You loose!" elif user_input == 'paper' and computer == 'paper': - output = f"{computer}\n" - output += "Tie" - return output, 200 + lWin = "Tie" elif user_input == 'scissors' and computer == 'rock': - output = f"{computer}\n" - output += "You loose!" - return output, 200 + lWin = "You loose!" elif user_input == 'scissors' and computer == 'paper': - output = f"{computer}\n" - output += "You win" - return output, 200 + lWin = "You win" if user_input == 'scissors' and computer == 'scissors': - output = f"{computer}\n" - output += "Tie" - return output, 200 + lWin = "Tie" - return 'knag', 200 + rpsResp = render_template("rps_out.xml", computer=computer.capitalize(), result=lWin, hostname=fullHostname) + return Response(rpsResp, mimetype='text/xml') if __name__ == "__main__": diff --git a/Docker/docker-compose.yaml b/Docker/docker-compose.yaml index 5219926..4d81110 100644 --- a/Docker/docker-compose.yaml +++ b/Docker/docker-compose.yaml @@ -1,11 +1,11 @@ -version: "3" - +version: '3' services: - api: - build: . - ports: - - "80:80" + ciscapps: + image: sthivaios/ciscapps:latest environment: - - stocks_api_key="YOUR_ALPHAVANTAGE_API_KEY_HERE" - - api_hostname="YOUR_IP_OR_DOMAIN_THAT_THE_API_IS_HOSTED_ON" - # the variable above can either be an IP or a domain. it CANNOT be changed later. Keep in mind that the backend listens on port 80. \ No newline at end of file + fullHostname: "" # full hostname with http/https here. eg. : https://ciscapps.com or http://192.168.1.150 + hostname: "" # the ip or domain of the server + alphavantageKey: "XXXXXXXXXX" # your AlphaVantage API key + serverPort: "80" + ports: + - 80:80 \ No newline at end of file diff --git a/Docker/dockerfile b/Docker/dockerfile deleted file mode 100644 index 8c1a2bb..0000000 --- a/Docker/dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:latest - -WORKDIR /api - -COPY . /api/ - -RUN pip install -r requirements.txt - -EXPOSE 80 - -CMD python ./api.py \ No newline at end of file diff --git a/Docker/requirements.txt b/Docker/requirements.txt index ef4548a..a5f32b6 100644 --- a/Docker/requirements.txt +++ b/Docker/requirements.txt @@ -1,7 +1,7 @@ flask +datetime requests openmeteo_requests requests_cache -pandas retry_requests unidecode \ No newline at end of file diff --git a/Docker/static/templates/air_quality.xml b/Docker/static/templates/air_quality.xml new file mode 100644 index 0000000..963a9ae --- /dev/null +++ b/Docker/static/templates/air_quality.xml @@ -0,0 +1,11 @@ + +Current Air Quality + +{{city}}, {{region}}, {{country}} + +Dust : {{dust}} +Air Quality (US AQI) : {{air_quality}} + +Last Updated : {{last_update}} + + \ No newline at end of file diff --git a/Docker/static/templates/cisco.xml b/Docker/static/templates/cisco.xml new file mode 100644 index 0000000..5c51820 --- /dev/null +++ b/Docker/static/templates/cisco.xml @@ -0,0 +1,20 @@ + + CISCAPPS Suite + Welcome! Select an application : + + Environmental + {{hostname}}/getEnvApps/ + + + Stock + {{hostname}}/getStock/ + + + Games + {{hostname}}/getGamesList/ + + + Turn screen off + {{hostname}}/scrOff/ + + \ No newline at end of file diff --git a/Docker/static/templates/environmental.xml b/Docker/static/templates/environmental.xml new file mode 100644 index 0000000..6b93302 --- /dev/null +++ b/Docker/static/templates/environmental.xml @@ -0,0 +1,12 @@ + + CISCAPPS Weather Apps + Select an app : + + Weather + {{hostname}}/getWeather/ + + + Air Quality + {{hostname}}/getAqi/ + + \ No newline at end of file diff --git a/Docker/static/templates/games.xml b/Docker/static/templates/games.xml new file mode 100644 index 0000000..0831b71 --- /dev/null +++ b/Docker/static/templates/games.xml @@ -0,0 +1,8 @@ + + CISCAPPS Games + Select a game : + + Rock, Paper, Scissors + {{hostname}}/playRps/ + + \ No newline at end of file diff --git a/Docker/static/templates/geocode_aqi.xml b/Docker/static/templates/geocode_aqi.xml new file mode 100644 index 0000000..c5495fb --- /dev/null +++ b/Docker/static/templates/geocode_aqi.xml @@ -0,0 +1,10 @@ + + CISCAPPS Air Quality + Search for a city/area : + {{hostname}}/geocode-aqi/ + + Search + name + A + + \ No newline at end of file diff --git a/Docker/static/templates/geocode_weather.xml b/Docker/static/templates/geocode_weather.xml new file mode 100644 index 0000000..5b84fb1 --- /dev/null +++ b/Docker/static/templates/geocode_weather.xml @@ -0,0 +1,10 @@ + + CISCAPPS Weather + Search for a city/area : + {{hostname}}/geocode-weather/ + + Search + name + A + + \ No newline at end of file diff --git a/Docker/static/templates/get_stock.xml b/Docker/static/templates/get_stock.xml new file mode 100644 index 0000000..32f9f4f --- /dev/null +++ b/Docker/static/templates/get_stock.xml @@ -0,0 +1,10 @@ + + Get stock value + Enter the stock symbol : + {{hostname}}/stock-price/ + + Symbol (eg. MSFT) + symbol + A + + \ No newline at end of file diff --git a/Docker/static/templates/info.xml b/Docker/static/templates/info.xml new file mode 100644 index 0000000..6ca5b03 --- /dev/null +++ b/Docker/static/templates/info.xml @@ -0,0 +1,34 @@ + + Cisco Help - KIOYDIOLABS.ORG + +Service Help +---------------- +The "School Schedule" service allows users to view the school schedule for the next day. + +The "CCTV" service allows users to view the latest frame of all CCTV cameras. + +The "Phonebooks" service provides multiple phonebooks each helpful for something specific. + + +For technical support with your Cisco IP Phone please dial the internal Cisco Support Hotline at 2075 or press "Support" below. + + +Press "Exit" to get to your home screen. + + + + Update + SoftKey:Update + 4 + + + Exit + SoftKey:Exit + 3 + + + Support + Dial:2075 + 1 + + \ No newline at end of file diff --git a/Docker/static/templates/no_results.xml b/Docker/static/templates/no_results.xml new file mode 100644 index 0000000..27b60f2 --- /dev/null +++ b/Docker/static/templates/no_results.xml @@ -0,0 +1,7 @@ + +No results were found + +No results could be returned for your search. +Perhaps you made a typo? + + \ No newline at end of file diff --git a/Docker/static/templates/rps.xml b/Docker/static/templates/rps.xml new file mode 100644 index 0000000..bb604bc --- /dev/null +++ b/Docker/static/templates/rps.xml @@ -0,0 +1,25 @@ + +Rock Paper Scissors +Rock, paper, scissors, shoot! + + + Rock + {{hostname}}/rps/?user_input=rock + 1 + + + Paper + {{hostname}}/rps/?user_input=paper + 2 + + + Scissors + {{hostname}}/rps/?user_input=scissors + 3 + + + Exit :( + Init:Services + 4 + + \ No newline at end of file diff --git a/Docker/static/templates/rps_out.xml b/Docker/static/templates/rps_out.xml new file mode 100644 index 0000000..854a3c3 --- /dev/null +++ b/Docker/static/templates/rps_out.xml @@ -0,0 +1,13 @@ + +Rock, Paper, Scissors + +Phone's Choice : {{computer}} + +{{result}} + + + Play again + {{hostname}}/playRps/ + 1 + + \ No newline at end of file diff --git a/Docker/static/templates/scr-off.xml b/Docker/static/templates/scr-off.xml new file mode 100644 index 0000000..c506f31 --- /dev/null +++ b/Docker/static/templates/scr-off.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Docker/static/templates/stock_value.xml b/Docker/static/templates/stock_value.xml new file mode 100644 index 0000000..35e6bb2 --- /dev/null +++ b/Docker/static/templates/stock_value.xml @@ -0,0 +1,9 @@ + +Stock value for {{symbol}} + +Symbol : {{symbol}} +Value : {{price}}$ +Change : {{change}}$ ({{up_or_down}}) +Change (%) : {{change_percent}} + + \ No newline at end of file diff --git a/Docker/static/templates/weather.xml b/Docker/static/templates/weather.xml new file mode 100644 index 0000000..e857140 --- /dev/null +++ b/Docker/static/templates/weather.xml @@ -0,0 +1,14 @@ + +Current Weather + +{{city}}, {{region}}, {{country}} + +Temperature : {{temperature}}C +Precipitation : {{precipitation}}mm +Wind speed : {{w_speed}}m/s +Wind gusts : {{wg_speed}}m/s +Humidity : {{humidity}}% + +Last Updated : {{last_update}} + + \ No newline at end of file diff --git a/backend/api.py b/backend/api.py index 81aabe9..237df94 100644 --- a/backend/api.py +++ b/backend/api.py @@ -242,6 +242,5 @@ def rock_paper_scissors(): return Response(rpsResp, mimetype='text/xml') - if __name__ == "__main__": app.run(host='0.0.0.0', port=80)