deprecated db.transaction

This commit is contained in:
Riccardo Berto 2022-03-28 17:40:43 +02:00
parent 654f580fc5
commit 344455e409

128
main.py
View File

@ -7,31 +7,31 @@ from glob import glob
from email.message import Message from email.message import Message
from sqlalchemy import create_engine, text from sqlalchemy import create_engine, text
from sqlalchemy.engine import Connection
import gpxpy import gpxpy
from bs4 import BeautifulSoup
config = configparser.ConfigParser() config = configparser.ConfigParser()
config.read('config.ini') config.read("config.ini")
db = create_engine(f"postgresql://{config['db']['username']}:{config['db']['password']}@{config['db']['host']}/{config['db']['database']}").connect() db = create_engine(
f"postgresql://{config['db']['username']}:{config['db']['password']}@{config['db']['host']}/{config['db']['database']}"
).connect()
mail = IMAP4(host=config['mail']['host']) mail = IMAP4(host=config["mail"]["host"])
fitotrack_msg_filter = 'ALL' fitotrack_msg_filter = "ALL"
def init_database(): def init_database():
with open('init.sql') as f: with open("init.sql") as f:
db.execute('\n'.join(f.readlines())) db.execute("\n".join(f.readlines()))
def _get_sender(msg: Message) -> str: def _get_sender(msg: Message) -> str:
sender: str = msg.get('from') sender: str = msg.get("from")
if ' ' in sender: if " " in sender:
sender = sender.split(' ') sender = sender.split(" ")
for field in sender: for field in sender:
if '@' in field and '<' in field and '>' in field: if "@" in field and "<" in field and ">" in field:
return field[1:-1] return field[1:-1]
return sender return sender
@ -39,87 +39,113 @@ def _get_sender(msg: Message) -> str:
def get_gpx_files_from_mail(): def get_gpx_files_from_mail():
mail.starttls(ssl.create_default_context()) mail.starttls(ssl.create_default_context())
mail.login(config['mail']['username'], config['mail']['password']) mail.login(config["mail"]["username"], config["mail"]["password"])
mail.select() mail.select()
_, ids = mail.search(None, fitotrack_msg_filter) _, ids = mail.search(None, fitotrack_msg_filter)
ids = ids[0].split() ids = ids[0].split()
for i in ids: for i in ids:
_, fetched = mail.fetch(i, '(RFC822)') _, fetched = mail.fetch(i, "(RFC822)")
email_message = email.message_from_bytes(fetched[0][1]) email_message = email.message_from_bytes(fetched[0][1])
sender = _get_sender(email_message) sender = _get_sender(email_message)
for part in email_message.walk(): for part in email_message.walk():
if part.get_content_maintype() == 'multipart' or part.get_content_disposition() is None: if (
part.get_content_maintype() == "multipart"
or part.get_content_disposition() is None
):
continue continue
filename = part.get_filename() filename = part.get_filename()
if filename: if filename:
filename = f'{sender}_{filename}' filename = f"{sender}_{filename}"
if not os.path.exists(f'gpx_files/{filename}'): if not os.path.exists(f"gpx_files/{filename}"):
with open(f'gpx_files/{filename}', 'wb') as f: with open(f"gpx_files/{filename}", "wb") as f:
print(f'creating {filename}') print(f"creating {filename}")
f.write(part.get_payload(decode=True)) f.write(part.get_payload(decode=True))
mail.store(i, '+FLAGS', '\\Deleted') mail.store(i, "+FLAGS", "\\Deleted")
mail.expunge() mail.expunge()
mail.close() mail.close()
mail.logout() mail.logout()
def process_gpx_files(tx: Connection): def process_gpx_files():
for filepath in glob('gpx_files/*.gpx'): for filepath in glob("gpx_files/*.gpx"):
owner = os.path.split(filepath)[-1].split('_workout-')[0] owner = os.path.split(filepath)[-1].split("_workout-")[0]
filename = f'workout-{os.path.split(filepath)[-1].split("_workout-")[1]}' filename = f'workout-{os.path.split(filepath)[-1].split("_workout-")[1]}'
print(f'Processing {filename}') print(f"Processing {filename}")
if list(tx.execute(text('select exists(select from training where owner = :owner and filename = :filename)'), if list(
dict(owner=owner, filename=filename,),),)[0][0]: db.execute(
text(
"select exists(select from training where owner = :owner and filename = :filename)"
),
dict(
owner=owner,
filename=filename,
),
),
)[0][0]:
os.remove(filepath) os.remove(filepath)
continue continue
with open(filepath) as f: with open(filepath) as f:
gpx_file = gpxpy.parse(f) gpx_file = gpxpy.parse(f)
if gpx_file.creator != 'FitoTrack': if gpx_file.creator != "FitoTrack":
raise ValueError('gpx file not generated by the FitoTrack app') raise ValueError("gpx file not generated by the FitoTrack app")
training_id = list(tx.execute( training_id = list(
text(""" db.execute(
text(
"""
insert into training(owner, filename, type, description, moving_time, stopped_time, moving_distance, stopped_distance) values insert into training(owner, filename, type, description, moving_time, stopped_time, moving_distance, stopped_distance) values
(:owner, :filename, :type, :description, :moving_time, :stopped_time, :moving_distance, :stopped_distance) returning id (:owner, :filename, :type, :description, :moving_time, :stopped_time, :moving_distance, :stopped_distance) returning id
"""), """
dict(owner=owner, ),
filename=filename, dict(
type='cycling', # TODO other training types owner=owner,
description=gpx_file.description, filename=filename,
moving_time=gpx_file.get_moving_data().moving_time, type="cycling", # TODO other training types
stopped_time=gpx_file.get_moving_data().stopped_time, description=gpx_file.description,
moving_distance=gpx_file.get_moving_data().moving_distance, moving_time=gpx_file.get_moving_data().moving_time,
stopped_distance=gpx_file.get_moving_data().stopped_distance,), stopped_time=gpx_file.get_moving_data().stopped_time,
))[0][0] moving_distance=gpx_file.get_moving_data().moving_distance,
stopped_distance=gpx_file.get_moving_data().stopped_distance,
),
)
)[0][0]
for track in gpx_file.tracks: for track in gpx_file.tracks:
for segment in track.segments: for segment in track.segments:
for point in segment.points: for point in segment.points:
tx.execute(text(""" db.execute(
text(
"""
insert into training_data(training_id, t, geog, speed, elevation) insert into training_data(training_id, t, geog, speed, elevation)
values (:training_id, :t, :geog, :speed, :elevation) values (:training_id, :t, :geog, :speed, :elevation)
"""), """
dict(training_id=training_id, ),
t=point.time, dict(
geog=f'POINT({point.latitude} {point.longitude})', training_id=training_id,
speed=point.speed, t=point.time,
elevation=point.elevation,),) geog=f"POINT({point.latitude} {point.longitude})",
speed=point.speed,
elevation=point.elevation,
),
)
os.remove(filepath) os.remove(filepath)
def main(): def main():
try: try:
os.mkdir('gpx_files') os.mkdir("gpx_files")
except FileExistsError: except FileExistsError:
pass pass
init_database() init_database()
get_gpx_files_from_mail() get_gpx_files_from_mail()
db.transaction(process_gpx_files)
with db.begin():
process_gpx_files()
if __name__ == '__main__': if __name__ == "__main__":
try: try:
main() main()
except (KeyboardInterrupt, EOFError): except (KeyboardInterrupt, EOFError):