Skip to content

Commit

Permalink
feat: agrego comando para pasar url a noticia; refactor de la view, l…
Browse files Browse the repository at this point in the history
…os mensaje internos los maneja CindyMoon
  • Loading branch information
SBen-IV committed Nov 26, 2023
1 parent 9e69c5e commit b1e0997
Show file tree
Hide file tree
Showing 11 changed files with 105 additions and 26 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ docker compose up --build # hace el build si es necesario y run
## TODOs

- [x] Ver cómo cambiar las noticias automáticas para hacer menos pegadas a la página (método que reciba una fecha y devuelva sólo noticias posteriores).
- [ ] Agregar método para convertir una url de una noticia.
- [x] Agregar método para convertir una url de una noticia.
- [ ] Agregar archivo config para variables como delay, intervalo entre mensajes, etc.
- [x] Agregar script para correr en "dev" y "prod".
- [x] Agregar comando /status, /estado o /info que devuelva el estado del bot
Expand Down
4 changes: 4 additions & 0 deletions src/connectors/fiuba_web.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,7 @@ def obtener_noticias(self, n: int = 1) -> list:
@abstractclassmethod
def obtener_noticias_nuevas(self, ultima_noticia: Noticia) -> list:
pass

@abstractclassmethod
def obtener_noticia(self, url: str) -> Noticia:
pass
17 changes: 14 additions & 3 deletions src/connectors/silk.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from error_handler import logging
from entities.noticia import Noticia
from exceptions.cantidad_noticias_exception import CantidadNoticiasMaximaException, CantidadNoticiasNegativaException
from exceptions.url_incorrecta_exception import URLNoPerteneceADominioException

DOMINIO = "https://fi.uba.ar"
LINK_NOTICIAS = DOMINIO + "/noticias/pagina/1"
Expand All @@ -28,11 +29,15 @@ def obtener_noticias(self, n_noticias: int = 1) -> list:
noticias = []

for uri in uris_noticias[:n_noticias]:
noticias.append(self.obtener_noticia(uri))
noticias.append(self.__obtener_noticia(uri))

return noticias

def obtener_noticia(self, uri: str) -> Noticia:
def obtener_noticia(self, url: str) -> Noticia:
uri = self.__obtener_uri(url)
return self.__obtener_noticia(uri)

def __obtener_noticia(self, uri: str) -> Noticia:
url = DOMINIO + uri
self.logger.info("Obteniendo noticia de {url}".format(url=url))
pagina = requests.get(url)
Expand All @@ -57,7 +62,7 @@ def obtener_noticias_nuevas(self, ultima_noticia: Noticia) -> list:
noticias_nuevas = []

for uri in uris_noticias[:MAX_NOTICIAS]:
noticia = self.obtener_noticia(uri)
noticia = self.__obtener_noticia(uri)

if noticia.fecha > ultima_noticia.fecha:
noticias_nuevas.append(noticia)
Expand All @@ -77,3 +82,9 @@ def __validar_cantidad(self, n_noticias: int) -> None:
raise CantidadNoticiasNegativaException(n_noticias)
elif n_noticias > MAX_NOTICIAS:
raise CantidadNoticiasMaximaException(n_noticias)

def __obtener_uri(self, url: str) -> str:
if url.startswith(DOMINIO) and len(url) > len(DOMINIO):
return url[len(DOMINIO):]

raise URLNoPerteneceADominioException(DOMINIO, url)
25 changes: 12 additions & 13 deletions src/controllers/jjjameson.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from telegram.ext import CallbackContext
from connectors.fiuba_web import FiubaWeb
from view.imprenta import Imprenta
from view.interno import Interno
from repositories.noticias_repository import NoticiasRepository
from repositories.estado_repository import EstadoRepository
from error_handler import logging
Expand All @@ -15,11 +16,12 @@


class JJJameson:
def __init__(self, fiuba_web: FiubaWeb, noticias_repo: NoticiasRepository, estado_repo: EstadoRepository, imprenta: Imprenta, job_queue, bot):
def __init__(self, fiuba_web: FiubaWeb, noticias_repo: NoticiasRepository, estado_repo: EstadoRepository, imprenta: Imprenta, interno: Interno, job_queue, bot):
self.fiuba_web = fiuba_web
self.repo = noticias_repo
self.estado_repo = estado_repo
self.imprenta = imprenta
self.interno = interno
self.noticias_automaticas = self.estado_repo.noticias_automaticas()

if self.noticias_automaticas:
Expand Down Expand Up @@ -48,7 +50,9 @@ def conseguir_noticias(self, update: Update, context: CallbackContext):
raise CantidadNoticiasNoEsNumeroException(arg=context.args[0])

def convertir_noticia(self, update: Update, context: CallbackContext):
update.effective_chat.send_message("Trabajando en esta feature...")
if len(context.args) > 0:
noticia = self.fiuba_web.obtener_noticia(context.args[0])
self.interno.enviar_noticia(update.effective_chat, noticia)

def __activar_noticias_automaticas(self, job_queue, chat):
self.job = job_queue.run_repeating(self.conseguir_noticias_automatico, INTERVALO_MENSAJES_AUTOMATICOS, context=chat)
Expand All @@ -59,19 +63,19 @@ def activar_noticias_automaticas(self, update: Update, context: CallbackContext)
self.noticias_automaticas = True
self.estado_repo.guardar(self.noticias_automaticas)
self.logger.info("Se activaron las noticias automáticas.")
update.effective_chat.send_message("Se activaron las noticias automáticas.")
self.interno.notificar_noticias_automaticas(update.effective_chat, self.noticias_automaticas)
else:
update.effective_chat.send_message("Las noticias automáticas ya están activadas.")
self.interno.notificar_noticias_automaticas(update.effective_chat, self.noticias_automaticas, self.noticias_automaticas)

def desactivar_noticias_automaticas(self, update: Update, _: CallbackContext):
if self.noticias_automaticas:
self.job.schedule_removal()
self.noticias_automaticas = False
self.estado_repo.guardar(self.noticias_automaticas)
self.logger.info("Se desactivaron las noticias automáticas.")
update.effective_chat.send_message("Se desactivaron las noticias automáticas.")
self.interno.notificar_noticias_automaticas(update.effective_chat, self.noticias_automaticas, True)
else:
update.effective_chat.send_message("Las noticias automáticas no están activadas.")
self.interno.notificar_noticias_automaticas(update.effective_chat)

def conseguir_noticias_automatico(self, context: CallbackContext):
ultima_noticia_guardada = self.repo.ultima_noticia()
Expand All @@ -87,12 +91,7 @@ def conseguir_noticias_automatico(self, context: CallbackContext):
self.logger.info("No hay noticias nuevas.")

def estado(self, update: Update, _: CallbackContext):
update.effective_chat.send_message("Noticias automáticas: {noticias_automaticas}".format(noticias_automaticas=self.noticias_automaticas))
self.interno.notificar_estado(update.effective_chat, self.noticias_automaticas)

def ayuda(self, update: Update, context: CallbackContext):
update.effective_chat.send_message("/noticias <n> - trae las últimas noticias\n"
+ "/convertir_noticia <url> - convierte la noticia\n"
+ "/empezar - \n"
+ "/terminar - \n"
+ "/estado - \n"
+ "/ayuda - imprime este mensaje\n")
self.interno.ayuda(update.effective_chat)
3 changes: 2 additions & 1 deletion src/error_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from telegram import Update, ParseMode
from telegram.ext import CallbackContext
from exceptions.cantidad_noticias_exception import *
from exceptions.url_incorrecta_exception import *

logging.basicConfig(format='[%(asctime)s] [%(levelname)s] [%(name)s] [%(funcName)s] %(message)s', level=logging.INFO,
datefmt="%d/%m/%Y | %H:%M:%S")
Expand All @@ -20,7 +21,7 @@ def error_handler(update: Update, context: CallbackContext) -> None:
"""
logger.error(msg="Exception while handling an update:", exc_info=context.error)

if isinstance(context.error, CantidadNoticiasException):
if isinstance(context.error, CantidadNoticiasException) or isinstance(context.error, URLNoPerteneceADominioException):
update.effective_chat.send_message(context.error.message)
else:

Expand Down
4 changes: 4 additions & 0 deletions src/exceptions/url_incorrecta_exception.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class URLNoPerteneceADominioException(Exception):
def __init__(self, dominio, url) -> None:
self.message = "{url} no pertenece al dominio {dominio}".format(url=url, dominio=dominio)
super().__init__(self.message)
5 changes: 3 additions & 2 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from controllers.jjjameson import JJJameson
from connectors.silk import Silk
from view.threats_and_menaces import ThreatsAndMenaces
from view.cindy_moon import CindyMoon
from repositories.noticias_repository import NoticiasRepository
from repositories.estado_repository import EstadoRepository
from error_handler import error_handler, logging
Expand All @@ -21,11 +22,11 @@ def main():

logger.info("Iniciando {full_name} (@{username}).".format(full_name=bot.full_name, username=bot.username))

jameson = JJJameson(Silk(), NoticiasRepository(), EstadoRepository(), ThreatsAndMenaces(), updater.job_queue, updater.bot)
jameson = JJJameson(Silk(), NoticiasRepository(), EstadoRepository(), ThreatsAndMenaces(), CindyMoon(), updater.job_queue, updater.bot)
filtro = Filters.chat(chat_id=int(os.getenv('ID_GRUPO_NOTICIAS')))

updater.dispatcher.add_handler(CommandHandler('noticias', jameson.conseguir_noticias, filtro))
updater.dispatcher.add_handler(CommandHandler('convertir_noticia', jameson.convertir_noticia, filtro))
updater.dispatcher.add_handler(CommandHandler('convertir', jameson.convertir_noticia, filtro))
updater.dispatcher.add_handler(CommandHandler('empezar', jameson.activar_noticias_automaticas, filtro))
updater.dispatcher.add_handler(CommandHandler('terminar', jameson.desactivar_noticias_automaticas, filtro))
updater.dispatcher.add_handler(CommandHandler('ayuda', jameson.ayuda, filtro))
Expand Down
40 changes: 40 additions & 0 deletions src/view/cindy_moon.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
from view.interno import Interno
from entities.noticia import Noticia
from telegram import ParseMode, Chat
from error_handler import logging
from view.contants import *

class CindyMoon(Interno):
def __init__(self):
self.logger = logging.getLogger(__class__.__name__)

def notificar_noticias_automaticas(self, chat: Chat, estado_actual: bool = False, estado_anterior: bool = False) -> None:
message = "Las noticias automáticas no están activadas."

if estado_actual != estado_anterior:
if estado_actual:
message = "Se activaron las noticias automáticas."
else:
message = "Se desactivaron las noticias automáticas."
elif estado_actual:
message = "Las noticias automáticas ya están activadas."

chat.send_message(message)

def notificar_estado(self, chat: Chat, noticias_automaticas: bool) -> None:
chat.send_message("Noticias automáticas: {noticias_automaticas}".format(noticias_automaticas=noticias_automaticas))

def enviar_noticia(self, chat: Chat, noticia: Noticia) -> None:
chat.send_message(FORMATO_MENSAJE.format(titulo=noticia.titulo,
descripcion=noticia.descripcion,
url=noticia.url,
texto_url=MAS_INFORMACION),
parse_mode=ParseMode.HTML)

def ayuda(self, chat: Chat) -> None:
chat.send_message("/noticias <n> - trae las últimas 'n' noticias\n"
+ "/convertir <url> - convierte la noticia\n"
+ "/empezar - activa las noticias automáticas en el canal de noticias\n"
+ "/terminar - desactiva las noticias automáticas en el canal de noticias\n"
+ "/estado - muestra el estado del bot\n"
+ "/ayuda - imprime este mensaje\n")
4 changes: 4 additions & 0 deletions src/view/contants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from emoji import emojize

MAS_INFORMACION = emojize(":information: Más información")
FORMATO_MENSAJE = "<b>{titulo}</b>\n\n{descripcion}\n\n<a href=\"{url}\">{texto_url}</a>\n"
21 changes: 20 additions & 1 deletion src/view/interno.py
Original file line number Diff line number Diff line change
@@ -1 +1,20 @@
# Cindy Moon
from abc import ABC, abstractclassmethod
from telegram import Chat
from entities.noticia import Noticia

class Interno(ABC):
@abstractclassmethod
def notificar_noticias_automaticas(self, chat: Chat, estado_actual: bool, estado_anterior: bool) -> None:
pass

@abstractclassmethod
def notificar_estado(self, chat: Chat, noticias_automaticas: bool) -> None:
pass

@abstractclassmethod
def enviar_noticia(self, chat: Chat, noticia: Noticia) -> None:
pass

@abstractclassmethod
def ayuda(self, chat: Chat) -> None:
pass
6 changes: 1 addition & 5 deletions src/view/threats_and_menaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,8 @@

from view.imprenta import Imprenta
from telegram import ParseMode, Chat
from emoji import emojize
from error_handler import logging

MAS_INFORMACION = emojize(":information: Más información")
FORMATO_MENSAJE = "<b>{titulo}</b>\n\n{descripcion}\n\n<a href=\"{url}\">{texto_url}</a>\n"

from view.contants import *

class ThreatsAndMenaces(Imprenta):
def __init__(self):
Expand Down

0 comments on commit b1e0997

Please sign in to comment.