-
Notifications
You must be signed in to change notification settings - Fork 2
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
feat: implement database to store users email #8
Open
R1D3R175
wants to merge
21
commits into
UNICT-DMI:main
Choose a base branch
from
R1D3R175:main
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 17 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
940f241
chore: add `SQLAlchemy` to `requirements.txt`
R1D3R175 fa5248e
feat: initialize ORM components
R1D3R175 cc42bc2
feat: define `User` ORM class
R1D3R175 cc363b4
feat: create mock `/login` command
R1D3R175 f11c8cd
feat: update to `python-telegram-bot` latest version
R1D3R175 f796bda
style: address pylint errors
R1D3R175 09f7993
feat: automatically hash email when constructing object
R1D3R175 4f7d84e
fix: add code to create table
R1D3R175 08d3ace
fix: remove salt
R1D3R175 90c6fde
feat: add login command with db interaction
R1D3R175 51e7170
fix: move command description to `/help`
R1D3R175 572f6dd
feat: add `sessionmaker` for an easier interaction
R1D3R175 3fa095f
style: remove trailing whitespace
R1D3R175 7cb5af9
feat: add missing check for email
R1D3R175 3817cc6
feat: add with block to correctly handle sessions
R1D3R175 a8c7f9d
fix: change data check message
R1D3R175 661108d
fix: change context type hinting
R1D3R175 096ea3f
chore: specify dependencies version
R1D3R175 70f5ba5
feat: make registration procedure a conversation
R1D3R175 96c4d25
refactor: change `Base` class position
R1D3R175 4105280
refactor: change docstrings, move out invalid data handlers
R1D3R175 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
"""Data""" | ||
""" | ||
Data | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
""" | ||
Initialize the database engine + base model | ||
""" | ||
import os | ||
|
||
from sqlalchemy import create_engine | ||
from sqlalchemy.orm import DeclarativeBase, sessionmaker | ||
|
||
db_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "db.sqlite3") | ||
engine = create_engine("sqlite:///" + db_path) | ||
Session = sessionmaker(engine) | ||
|
||
# pylint: disable=too-few-public-methods | ||
class Base(DeclarativeBase): | ||
pass | ||
|
||
# pylint: disable=wrong-import-position,cyclic-import | ||
from .models import User | ||
R1D3R175 marked this conversation as resolved.
Show resolved
Hide resolved
R1D3R175 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Base.metadata.create_all(engine) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
""" | ||
Definition of database tables | ||
""" | ||
import hashlib | ||
|
||
from sqlalchemy.orm import Mapped, mapped_column | ||
from sqlalchemy import String | ||
from . import Base | ||
|
||
# pylint: disable=too-few-public-methods | ||
class User(Base): | ||
""" | ||
User table, maps the following fields: | ||
- id (int): primary key, autoincrement | ||
- email (str): hexdigest of salted user's email hashed with sha256 | ||
- chat_id (int): id of the chat the user is in | ||
""" | ||
__tablename__ = "user" | ||
|
||
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True) | ||
email: Mapped[str] = mapped_column(String(64), unique=True) | ||
chat_id: Mapped[int] = mapped_column(unique=True) | ||
|
||
def __init__(self, email: str, chat_id: int): | ||
self.email = hashlib.sha256(email.encode()).hexdigest() | ||
self.chat_id = chat_id |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,47 +1,59 @@ | ||
"""main module""" | ||
from telegram import BotCommand | ||
from telegram.ext import CommandHandler, MessageHandler, Updater, Dispatcher, Filters | ||
|
||
from module.commands import start, report, help_cmd | ||
""" | ||
main module | ||
""" | ||
from module.commands import start, report, help, login | ||
from module.data import HELP, REPORT | ||
|
||
def add_commands(up: Updater) -> None: | ||
"""Adds list of commands with their description to the boy | ||
from telegram import BotCommand, Update | ||
from telegram.ext import filters, Application, ApplicationBuilder, CommandHandler, MessageHandler, ContextTypes | ||
|
||
async def add_commands(app: Application) -> None: | ||
""" | ||
Adds a list of commands with their description to the bot | ||
|
||
Args: | ||
up(Updater): supplied Updater | ||
Args: | ||
app (Application): the built application | ||
""" | ||
commands = [ | ||
BotCommand("start", "messaggio di benvenuto"), | ||
BotCommand("help", "ricevi aiuto sui comandi"), | ||
BotCommand("report", "segnala un problema") | ||
BotCommand("report", "segnala un problema"), | ||
BotCommand("login", "procedura di autenticazione") | ||
] | ||
up.bot.set_my_commands(commands=commands) | ||
|
||
def add_handlers(dp:Dispatcher) -> None: | ||
"""Adds all the handlers the bot will react to | ||
await app.bot.set_my_commands(commands) | ||
|
||
Args: | ||
dp:suppplied Dispatcher | ||
def add_handlers(app: Application) -> None: | ||
""" | ||
Adds all the handlers to the bot | ||
|
||
dp.add_handler(CommandHandler("start", start, Filters.chat_type.private)) | ||
dp.add_handler(CommandHandler("chatid", lambda u, c: u.message.reply_text(str(u.message.chat_id)))) | ||
dp.add_handler(CommandHandler("help", help_cmd, Filters.chat_type.private)) | ||
dp.add_handler(MessageHandler(Filters.regex(HELP) & Filters.chat_type.private, help_cmd)) | ||
dp.add_handler(CommandHandler("report", report)) | ||
dp.add_handler(MessageHandler(Filters.regex(REPORT) & Filters.chat_type.private, report)) | ||
dp.add_handler(CommandHandler("chatid", lambda u, c: u.message.reply_text(str(u.message.chat_id)))) | ||
Args: | ||
app (Application): the built application | ||
""" | ||
async def chatid(update: Update, context: ContextTypes.DEFAULT_TYPE): | ||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text=str(update.effective_chat.id) | ||
) | ||
|
||
handlers = [ | ||
CommandHandler("start", start, filters.ChatType.PRIVATE), | ||
CommandHandler("chatid", chatid), | ||
CommandHandler("help", help, filters.ChatType.PRIVATE), | ||
MessageHandler(filters.Regex(HELP) & filters.ChatType.PRIVATE, help), | ||
CommandHandler("report", report), | ||
MessageHandler(filters.Regex(REPORT) & filters.ChatType.PRIVATE, report), | ||
CommandHandler("login", login) | ||
] | ||
|
||
def main() -> None: | ||
"""Main function""" | ||
updater = Updater() | ||
add_commands(updater) | ||
add_handlers(updater.dispatcher) | ||
app.add_handlers(handlers) | ||
|
||
updater.start_polling() | ||
updater.idle() | ||
def main(): | ||
app = ApplicationBuilder().token("TOKEN").build() | ||
add_commands(app) | ||
add_handlers(app) | ||
|
||
app.run_polling() | ||
|
||
if __name__ == "__main__": | ||
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,7 @@ | ||
"""Commands""" | ||
""" | ||
Commands | ||
""" | ||
from .start import start | ||
from .help import help | ||
from .report import report | ||
from .login import login |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
"""/help command""" | ||
from telegram import Update | ||
from telegram.ext import ContextTypes | ||
|
||
from module.data.constants import HELP_CMD_TEXT | ||
|
||
async def help(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: | ||
""" | ||
Called by the /help command | ||
Sends a list of the avaible bot's commands | ||
|
||
Args: | ||
update: update event | ||
context: context passed by the handler | ||
""" | ||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text=HELP_CMD_TEXT | ||
) |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
""" | ||
/login command | ||
""" | ||
import hashlib | ||
|
||
from telegram import Update | ||
from telegram.ext import ContextTypes | ||
|
||
from sqlalchemy import select | ||
from data.db import Session | ||
from data.db.models import User | ||
|
||
async def login(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: | ||
R1D3R175 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
""" | ||
Called by the /login command. | ||
|
||
Theoretically, it should send an OTP to the student's email address | ||
that must be validated. | ||
If this check is successfull the user is then logged in and registered | ||
in the database. | ||
|
||
Args: | ||
update: update event | ||
context: context passed by the handler | ||
""" | ||
args = update.message.text.strip().split()[1:] | ||
|
||
if len(args) != 1: | ||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text="Utilizzo sbagliato. /login <email>" | ||
) | ||
|
||
return | ||
|
||
email = args[0] | ||
if not email.endswith("@studium.unict.it"): | ||
R1D3R175 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text=( | ||
"Questo bot e' solo per gli studenti di UNICT.\n" | ||
"Se sei uno studente controlla di aver scritto bene l'email " | ||
"(deve finire con @studium.unict.it)" | ||
) | ||
) | ||
|
||
return | ||
|
||
with Session() as session: | ||
stmt = select(User).where(User.chat_id == update.effective_chat.id) | ||
result = session.scalars(stmt).first() | ||
if result is None: | ||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text="Non sei registrato, procedo alla registrazione.." | ||
) | ||
|
||
session.add(User(email=email, chat_id=update.effective_chat.id)) | ||
session.commit() | ||
|
||
return | ||
|
||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text="Sei gia' registrato! Controllo se i dati corrispondono..." | ||
) | ||
|
||
if result.chat_id != update.effective_chat.id: | ||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text="Il chat_id non corrisponde..." | ||
) | ||
|
||
return | ||
|
||
email_digest = hashlib.sha256(email.encode()).hexdigest() | ||
if result.email != email_digest: | ||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text="L'email non corrisponde..." | ||
) | ||
|
||
return | ||
|
||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text="Bentornato!" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,19 @@ | ||
"""/start command""" | ||
from telegram import Update | ||
from telegram.ext import CallbackContext | ||
from telegram.ext import ContextTypes | ||
|
||
from module.data import START_CMD_TEXT | ||
|
||
def start(update: Update, context: CallbackContext) -> None: | ||
"""Called by the /start command | ||
Sends a welcome message | ||
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: | ||
""" | ||
Called by the /start command | ||
Sends a welcome message | ||
|
||
Args: | ||
update: update event | ||
context: context passed by the handler | ||
Args: | ||
update: update event | ||
context: context passed by the handler | ||
""" | ||
context.bot.sendMessage( | ||
chat_id=update.message.chat_id, text=START_CMD_TEXT | ||
await context.bot.send_message( | ||
chat_id=update.effective_chat.id, | ||
text=START_CMD_TEXT | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,5 +3,5 @@ | |
REPORT, | ||
HELP, | ||
HELP_CMD_TEXT, | ||
START_CMD_TEXT | ||
START_CMD_TEXT, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
python-telegram-bot==13.5 | ||
python-telegram-bot | ||
R1D3R175 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pyyaml | ||
SQLAlchemy |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Evita sempre di mettere direttive a questo livello, in quanto verranno eseguite nel momento in cui il modulo viene importato. Senza saperlo sto provocando un side-effect (creando un file).
Inoltre rendi piu' delicati i test (cosa succede se voglio usare un altro path invece di db.sqlite?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Per cui come dovrei fare?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Essenzialmente l'ideale sarebbe rinchiudere tutto dentro una funzione da chiamare al momento del bisogno, possibilmente anche dal main.
Non c'è bisogno di avere una sessione globale: puoi crearne una nuova ogni volta che ti serve, è praticamente equivalente. Leggi questa risposta da uno degli sviluppatori per approfondire.
Se proprio pensi di aver bisogno di uno stato globale, un Singleton potrebbe fare al caso tuo. Almeno puoi controllare il momento in cui viene inizializzato, piuttosto che fare tutto nel momento il cui il modulo viene importato