Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Huge backend refactor for streamlined styling` #210

Merged
merged 13 commits into from
Nov 17, 2023
34 changes: 34 additions & 0 deletions .github/workflows/formatting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Code Formatting Check

on:
push:
branches:
- '*'

jobs:
check_formatting:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.8

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install isort black ruff

- name: Check code formatting with isort
run: isort --profile black --check backend

- name: Check code formatting with black
run: black --check .

- name: Check code formatting with ruff
run: ruff format --check .

1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ iOSInjectionProject/
*.DS_Store

# IDE
*.vscode
*__pycache__*

*egg-info
Expand Down
6 changes: 3 additions & 3 deletions .hooks/check_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
with open(os.path.join(root_dir, "data", "server_locations.json"), "r") as f:
data = json.load(f)
except Exception as e:
print('FAILURE!', e)
print("FAILURE!", e)
sys.exit(1)

try:
with open(os.path.join(root_dir, "data", "all_locations.json"), "r") as f:
data = json.load(f)
except Exception as e:
print(f"Failure with {e}")
sys.exit(1)
print('SUCCESS!')
print("SUCCESS!")
sys.exit(0)

13 changes: 13 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,16 @@ repos:
entry: python .hooks/check_json.py
language: system
files: '\.(json|py)$'
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.1.5
hooks:
# Run the linter.
- id: ruff
# Run the formatter.
- id: ruff-format
- repo: https://github.com/ambv/black
rev: stable
hooks:
- id: black
language_version: python3.8
32 changes: 32 additions & 0 deletions backend/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"editor.rulers": [
88
],
"python.languageServer": "None",
"editor.formatOnSave": true,
"security.workspace.trust.untrustedFiles": "open",
"editor.inlineSuggest.enabled": true,
"security.workspace.trust.enabled": false,
"autoDocstring.docstringFormat": "google-notypes",
"terminal.integrated.enableMultiLinePasteWarning": false,
"jupyter.interactiveWindow.textEditor.executeSelection": true,
"terminal.integrated.inheritEnv": false,
"jupyter.widgetScriptSources": [
"jsdelivr.com",
"unpkg.com"
],
"[python]": {
"editor.formatOnType": true,
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
},
"isort.args": [
"--profile",
"black"
],
"git.openRepositoryInParentFolders": "never",
"editor.fontLigatures": false,
}
126 changes: 20 additions & 106 deletions backend/app.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,22 @@
import json
import os
import time
from datetime import datetime
from typing import Any, Dict

from flask import Flask, jsonify, request
from googlemaps import Client as GoogleMaps
from PIL import Image, ImageOps

from haversine import haversine
from pennyme.locations import COUNTRIES
from pennyme.github_update import push_newmachine_to_github
from slack import WebClient
from slack.errors import SlackApiError
from thefuzz import process as fuzzysearch

from pennyme.github_update import push_newmachine_to_github
from pennyme.locations import COUNTRIES
from pennyme.slack import image_slack, message_slack, process_uploaded_image

app = Flask(__name__)

PATH_COMMENTS = os.path.join("..", "..", "images", "comments")
PATH_IMAGES = os.path.join("..", "..", "images")
PATH_MACHINES = os.path.join("..", "data", "all_locations.json")
PATH_SERVER_LOCATION = os.path.join("..", "..", "images", "server_locations.json")
SLACK_TOKEN = os.environ.get("SLACK_TOKEN")
IMG_PORT = "http://37.120.179.15:8000/"
GM_API_KEY = open("../../gpc_api_key.keypair", "r").read()

client = WebClient(token=os.environ["SLACK_TOKEN"])
gm_client = GoogleMaps(GM_API_KEY)
GM_CLIENT = GoogleMaps(open("../../gpc_api_key.keypair", "r").read())

with open("blocked_ips.json", "r") as infile:
# NOTE: blocking an IP requires restart of app.py via waitress
Expand All @@ -45,22 +35,9 @@
IP_COMMENT_DICT = json.load(f)


def reload_server_data():
# add server location IDs
with open(PATH_SERVER_LOCATION, "r", encoding="latin-1") as infile:
d = json.load(infile)
for elem in d["features"]:
MACHINE_NAMES[
elem["properties"]["id"]
] = f"{elem['properties']['name']} ({elem['properties']['area']})"
return MACHINE_NAMES


@app.route("/add_comment", methods=["GET"])
def add_comment():
"""
Receives a comment and adds it to the json file
"""
"""Receives a comment and adds it to the json file."""

comment = str(request.args.get("comment"))
machine_id = str(request.args.get("id"))
Expand Down Expand Up @@ -90,24 +67,9 @@ def add_comment():
return jsonify({"message": "Success!"}), 200


def process_uploaded_image(image, img_path):
image.save(img_path)

# optimize file size
img = Image.open(img_path)
img = ImageOps.exif_transpose(img)
basewidth = 400
wpercent = basewidth / float(img.size[0])
if wpercent > 1:
return "Image uploaded successfully, no resize necessary"
# resize
hsize = int((float(img.size[1]) * float(wpercent)))
img = img.resize((basewidth, hsize), Image.Resampling.LANCZOS)
img.save(img_path, quality=95)


@app.route("/upload_image", methods=["POST"])
def upload_image():
"""Receives an image and saves it to the server."""
machine_id = str(request.args.get("id"))
ip_address = request.remote_addr
if ip_address in blocked_ips:
Expand All @@ -126,61 +88,15 @@ def upload_image():
return "Image uploaded successfully"


def image_slack(
machine_id: int,
ip: str,
m_name: str = None,
img_slack_text: str = "Image uploaded for machine",
):
if m_name is None:
MACHINE_NAMES = reload_server_data()
m_name = MACHINE_NAMES[int(machine_id)]
text = f"{img_slack_text} {machine_id} - {m_name} (from {ip})"
try:
response = client.chat_postMessage(
channel="#pennyme_uploads", text=text, username="PennyMe"
)
response = client.chat_postMessage(
channel="#pennyme_uploads",
text=text,
username="PennyMe",
blocks=[
{
"type": "image",
"title": {
"type": "plain_text",
"text": "NEW Image!",
"emoji": True,
},
"image_url": f"{IMG_PORT}{machine_id}.jpg",
"alt_text": text,
}
],
)
except SlackApiError as e:
print("Error sending message: ", e)
assert e.response["ok"] is False
assert e.response["error"]
raise e


def message_slack(machine_id, comment_text, ip: str):
MACHINE_NAMES = reload_server_data()
m_name = MACHINE_NAMES[int(machine_id)]
text = (
f"New comment for machine {machine_id} - {m_name}: {comment_text} (from {ip})"
)
try:
response = client.chat_postMessage(
channel="#pennyme_uploads", text=text, username="PennyMe"
)
except SlackApiError as e:
assert e.response["ok"] is False
assert e.response["error"]
raise e


def save_comment(comment: str, ip: str, machine_id: int):
"""
Saves a comment to the json file.

Args:
comment: The comment to save.
ip: The IP address of the user.
machine_id: The ID of the machine.
"""
# Create dict hierarchy if needed
if ip not in IP_COMMENT_DICT.keys():
IP_COMMENT_DICT[ip] = {}
Expand All @@ -197,9 +113,7 @@ def save_comment(comment: str, ip: str, machine_id: int):

@app.route("/create_machine", methods=["POST"])
def create_machine():
"""
Receives a comment and adds it to the json file
"""
"""Receives a comment and adds it to the json file."""
title = str(request.args.get("title")).strip()
address = str(request.args.get("address")).strip()
area = str(request.args.get("area")).strip()
Expand All @@ -223,7 +137,7 @@ def create_machine():
# Verify that address matches coordinates
queries = [address, address + area, address + title]
for query in queries:
coordinates = gm_client.geocode(query)
coordinates = GM_CLIENT.geocode(query)
try:
lat = coordinates[0]["geometry"]["location"]["lat"]
lng = coordinates[0]["geometry"]["location"]["lng"]
Expand All @@ -246,7 +160,7 @@ def create_machine():
400,
)

out = gm_client.reverse_geocode(
out = GM_CLIENT.reverse_geocode(
[location[1], location[0]], result_type="street_address"
)

Expand All @@ -259,13 +173,13 @@ def create_machine():
address = ad
b = False
elif b:
out = gm_client.reverse_geocode(
out = GM_CLIENT.reverse_geocode(
(location[1], location[0]), result_type="point_of_interest"
)
if out != []:
address = out[0]["formatted_address"]
else:
out = gm_client.reverse_geocode(
out = GM_CLIENT.reverse_geocode(
(location[1], location[0]), result_type="postal_code"
)
if out != []:
Expand Down
25 changes: 12 additions & 13 deletions backend/old/assemble_all_locations.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import os
import json
import glob
import json
import os

# Assemble a single json with locations of all machines.
locations = []
with open('../data/all_locations.json', 'a', encoding='utf8') as target_file:

# Loop over all jsons that we have
for country_folder, _, _ in os.walk('../data/countries/'):
for file in glob.glob(country_folder+'/data.json'):
with open(file, 'r') as source_file:
with open("../data/all_locations.json", "a", encoding="utf8") as target_file:
# Loop over all jsons that we have
for country_folder, _, _ in os.walk("../data/countries/"):
for file in glob.glob(country_folder + "/data.json"):
with open(file, "r") as source_file:
print(file)
txt = json.load(source_file, encoding='utf8')
txt = txt['data']
txt = json.load(source_file, encoding="utf8")
txt = txt["data"]
locations.extend(txt)
data = {'data': locations}
json.dump(data, target_file, ensure_ascii=False, indent=4)

data = {"data": locations}
json.dump(data, target_file, ensure_ascii=False, indent=4)
7 changes: 1 addition & 6 deletions backend/old/get_pennycollector_dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,15 @@
2. Searches the location name on a map and saves the geographic coordinates
3. Saves data to .json
"""
#%%
import json
import os
import sys

import requests
from bs4 import BeautifulSoup
import os
from country_mapper import COUNTRY_TO_CODE
from googlemaps import Client as GoogleMaps

sys.path.append(".")
from country_mapper import COUNTRY_TO_CODE


WEB_PREFIX = "http://209.221.138.252/"
API_KEY = open("../../gpc_api_key.keypair", "r").read()
Expand All @@ -29,7 +25,6 @@


for COUNTRY, CODE in COUNTRY_TO_CODE.items():

area = COUNTRY.lower().replace(" ", "_")
url = "http://209.221.138.252/Locations.aspx?area=" + str(CODE)
mhtml = requests.get(url).content
Expand Down
Loading
Loading