-
Notifications
You must be signed in to change notification settings - Fork 2
/
bot_routines.py
168 lines (138 loc) · 6.71 KB
/
bot_routines.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# This file contains the routines that will be executed by the bot, such as updating the database with new alerts from INMET, deleting past alerts, and sending alerts to the users.
import arrow
import logging
from alerts import parse_alerts
from models.db import INMETBotDB
from models.Alert import Alert
from utils import viacep, bot_messages
from bot_config import updater
routinesLogger = logging.getLogger(__name__)
routinesLogger.setLevel(logging.DEBUG)
def delete_past_alerts_routine():
"""Delete past alerts published by INMET from the database."""
routinesLogger.info("Starting delete_past_alerts_routine routine.")
alerts = list(INMETBotDB.alertsCollection.find({}))
timeNow = arrow.utcnow().to("Brazil/East")
for alert in alerts:
if timeNow > arrow.get(alert["endDate"]):
routinesLogger.info(
f"alert {alert['alertID']} is past and will be deleted."
)
INMETBotDB.alertsCollection.delete_one({"alertID": alert["alertID"]})
routinesLogger.info("Finished delete_past_alerts_routine routine.")
return True
def parse_alerts_routine(ignoreModerate=False):
"""
Parse alerts published by INMET and insert them into database.
Parameters
--------
ignoreModerate : bool
If set to True, will ignore alerts of moderate severity. Defaults to False.
"""
routinesLogger.info("Starting parse_alerts_routine routine.")
alertsXML = parse_alerts.parse_alerts_xml(ignoreModerate)
if alertsXML:
alerts = parse_alerts.instantiate_alerts_objects(alertsXML, ignoreModerate)
routinesLogger.info(f"New alerts found: {alerts}")
for alert in alerts:
alert.insert_alert()
routinesLogger.info("Finished parse_alerts_routine routine.")
return True
# TODO: Reduce code duplication.
def notify_chats_routine():
"""
Check alerts from the database and notify chats.
For every alert and chat, check if chat has been notified for that alert; if it has not, check if there is any city (obtained by CEPs in the chat's CEP list) that is included in the alert.
If there is, notify chat and mark chat as notified (so it won't get notified again for the same alert).
"""
routinesLogger.info("Starting notify_chats_routine routine.")
# Create a list of all subscribed chats
subscribedChats = list(INMETBotDB.subscribedChatsCollection.find({}))
# Create an empty string to store the alert message
alertMessage = ""
# Create a counter to keep track of the number of alerts
alertCounter = 1
for chat in subscribedChats:
cities = []
if chat["activated"]:
routinesLogger.debug(f"Checking chat {chat['chatID']}")
try:
cities = [viacep.get_cep_city(cep) for cep in chat["CEPs"]]
except Exception as error:
routinesLogger.error(
f"Unknown error when getting CEPs for chat {chat}: {error}"
)
pass
for cep in chat["CEPs"]:
try:
city = viacep.get_cep_city(cep)
routinesLogger.debug(f"- Checking {city}...")
except Exception as error:
routinesLogger.warning(f"Viacep error: {error}")
continue
# Get alerts, by city, that weren't notified to this chat
alerts = list(
INMETBotDB.alertsCollection.find(
{
"$and": [
{"cities": city},
{"notifiedChats": {"$ne": chat["chatID"]}},
]
}
)
)
if alerts:
# Any alerts here are to be sent to the chat,
# since they affect a zip code and the chat hasn't been notified yet
alertMessage = ""
routinesLogger.info(f"-- Existing alert for {city}. --")
for alert in alerts:
if alertCounter >= bot_messages.MAX_ALERTS_PER_MESSAGE:
try:
updater.bot.send_message(
chat_id=chat["chatID"],
text=alertMessage,
parse_mode="markdown",
disable_web_page_preview=True,
)
except Exception as error:
routinesLogger.error(
f"ERRO: unable to send message to {chat['chatID']} ({chat['title']}): {error}.\nRemoving chat from DB......"
)
INMETBotDB.subscribedChatsCollection.delete_one(
{"chatID": chat["chatID"]}
)
alertMessage = ""
alertCounter = 1
alertObj = Alert(alertDict=alert)
affectedCities = [
city for city in cities if city in alertObj.cities
]
alertMessage += alertObj.get_alert_message(affectedCities)
routinesLogger.info(
f"-- Notifying chat {chat['chatID']} about alert {alert['alertID']}... --"
)
INMETBotDB.alertsCollection.update_one(
{"alertID": alert["alertID"]},
{"$addToSet": {"notifiedChats": chat["chatID"]}},
)
alertCounter += 1
# "Footer" message after all alerts
alertMessage += f"\nMais informações em {bot_messages.ALERTAS_URL}."
try:
updater.bot.send_message(
chat_id=chat["chatID"],
text=alertMessage,
parse_mode="markdown",
disable_web_page_preview=True,
)
except Exception as error:
routinesLogger.error(
f"ERRO: unable to send message to {chat['chatID']} ({chat['title']}): {error}.\nRemoving chat from DB......"
)
INMETBotDB.subscribedChatsCollection.delete_one(
{"chatID": chat["chatID"]}
)
routinesLogger.info("Finished notify_chats_routine routine.")
if __name__ == "__main__":
pass