commit c66fcd5939dcaf9be98b04ce5f96b148d2090b13 Author: Stefano Pigozzi Date: Wed Aug 30 20:47:15 2017 +0200 Import from Steffo99/pizzabot diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b83542a --- /dev/null +++ b/.gitignore @@ -0,0 +1,103 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +.idea \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5de2cdb --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# pizzabot +Un bot di Telegram per ordinazioni di una pizzeria + +## Variabili di ambiente richieste +- `telegram_api_key`: l'API key del bot pizzeria \ No newline at end of file diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..551eafd --- /dev/null +++ b/bot.py @@ -0,0 +1,10 @@ +from telegram.ext import Updater +import logging +import os + +logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') + +if __name__ == "__main__": + bot = Updater(os.environ("telegram_api_key")) + bot.start_polling() + bot.idle() \ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 0000000..6673de9 --- /dev/null +++ b/database.py @@ -0,0 +1,94 @@ +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker, relationship, composite +from sqlalchemy import Column, BigInteger, Integer, String, Numeric, DateTime, ForeignKey, Float, create_engine +from dbcomposites import Coordinates + +# Init the sqlalchemy engine +engine = create_engine("postgres://steffo:HIDDENPASSWORD@royal.steffo.eu:5432/pizzadev") +Base = declarative_base(bind=engine) +Session = sessionmaker(bind=engine) + +# Create a new default session +session = Session() + + +class TelegramUser(Base): + """Basic Telegram user data""" + __tablename__ = "tusers" + + tid = Column(BigInteger, primary_key=True) + tusername = Column(String) + tfirstname = Column(String, nullable=False) + tlastname = Column(String) + + def __str__(self): + if self.tusername is not None: + return f"@{self.tusername}" + elif self.tlastname is not None: + return f"{self.tfirstname} {self.tlastname}" + else: + return f"{self.tfirstname}" + + def __repr__(self): + return f"" + + +class Pizza(Base): + """Data for a pizza type""" + __tablename__ = "pizza" + + id = Column(Integer, primary_key=True) + name = Column(String, nullable=False, unique=True) + details = Column(String) + price = Column(Numeric, scale=2, nullable=False) + + def __str__(self, full=False): + if full: + return f"{self.name} [{self.price}]\n{self.details}" + return f"{self.name} [{self.price}]" + + def __repr__(self): + return f"" + + +class PizzaSelection(Base): + """Data for a single pizza placed in a order""" + __tablename__ = "pizzaselection" + + order_id = Column(Integer, ForeignKey("orders.id"), primary_key=True) + pizza_id = Column(Integer, ForeignKey("pizza.id"), primary_key=True) + pizza = relationship("Pizza") + + notes = Column(String) + + def __repr__(self): + return "" + + +class Order(Base): + """Data for a pizza order""" + __tablename__ = "orders" + + id = Column(Integer, primary_key=True) + creation_time = Column(DateTime, nullable=False) + requested_time = Column(DateTime) + delivery_time = Column(DateTime) + completed_time = Column(DateTime) + notes = Column(String) + + delivery_long = Column(Float, nullable=False) + delivery_lat = Column(Float, nullable=False) + delivery_location = composite(Coordinates, delivery_long, delivery_lat) + + user_id = Column(Integer, ForeignKey("tusers.id")) + user = relationship("TelegramUser") + + pizzas = relationship("PizzaSelection") + + def __repr__(self): + return f"" + + +# If run as script, create all the tables in the db +if __name__ == "__main__": + Base.metadata.create_all(bind=engine) \ No newline at end of file diff --git a/dbcomposites.py b/dbcomposites.py new file mode 100644 index 0000000..125968b --- /dev/null +++ b/dbcomposites.py @@ -0,0 +1,19 @@ +# Custom composite types +# All types must contain the __composite_values__ method + +class Coordinates(object): + """Geographic coordinates""" + def __init__(self, longitude, latitude): + self.longitude = longitude + self.latitude = latitude + + def __repr__(self): + return f"Coordinates(longitude={self.longitude}, latitude={self.latitude})" + + def __eq__(self, other): + return isinstance(other, Coordinates) \ + and self.longitude == other.longitude \ + and self.latitude == other.latitude + + def __composite_values__(self): + return self.longitude, self.latitude \ No newline at end of file