-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbot.py
More file actions
212 lines (178 loc) Β· 7.02 KB
/
bot.py
File metadata and controls
212 lines (178 loc) Β· 7.02 KB
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
"""
Grillo Telegram Bot - Main bot file with command handlers.
This bot allows interaction with the WEEE-Open/grillo API via Telegram.
"""
import logging
from datetime import datetime
from telegram import Update
from telegram.ext import Application, CommandHandler, MessageHandler, ContextTypes, filters
from config import config
from grillo_client import GrilloClient, get_user_client_by_telegram
from user_mapper import user_mapper
# Enable logging
logging.basicConfig(
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
level=logging.INFO
)
logger = logging.getLogger(__name__)
handlers = []
async def help(update: Update, context: ContextTypes.DEFAULT_TYPE, pre: str = "") -> None:
"""Send a message when the command /help is issued."""
await update.effective_message.reply_html(
pre +
"<b>Available commands:</b>\n"
"/help - Show this help message\n"
"/status - Check current lab status\n"
"/clockin - Clock in to the lab\n"
"/clockout - Clock out from the lab\n"
)
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Send a message when the command /start is issued."""
user = update.effective_user
telegram_id = user.id
# Check if user is mapped
is_mapped = user_mapper.is_user_mapped(telegram_id)
print(is_mapped)
mapping_status = ""
if not is_mapped:
res = user_mapper.map_user(telegram_id)
if res:
mapping_status = "\n\n<b>Successfully linked your account to {ldap_user}!</b>"
else:
mapping_status = (
"\n\n<b>Not authenticated</b>\n"
)
await help(update, context, f"π¦ <b>Welcome to Grillo Bot, {user.mention_html()}!</b>\n{mapping_status}\n\n")
async def status(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None: # TODO check, function is as from Copilot
"""Check the status of the default lab location."""
try:
grillo = get_user_client_by_telegram(update.effective_user.id)
location_id = " ".join(context.args) if context.args else "default"
location = grillo.get_location(location_id)
response = f"π <b>Status for {location['name']}</b>\n\n"
# People in the lab
people = location.get("people", [])
if people:
response += "π₯ <b>People in lab:</b>\n"
for person in people:
response += f" β’ {person.get('name', 'Unknown')}\n"
else:
response += "π₯ No one is currently in the lab.\n"
# Upcoming bookings
bookings = location.get("bookings", [])
if bookings:
response += "\nπ
<b>Upcoming bookings:</b>\n"
for booking in bookings[:5]: # Show max 5
start = datetime.fromtimestamp(booking['startTime'])
response += f" β’ {start.strftime('%a %H:%M')} - {booking.get('userName', 'Unknown')}\n"
await update.effective_message.reply_html(response)
except Exception as e:
logger.error(f"Error fetching status: {e}")
await update.effective_message.reply_text(f"β Error fetching status: {str(e)}")
async def clockin(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Clock in to the lab."""
try:
grillo = get_user_client_by_telegram(update.effective_user.id)
if context.args:
admin = grillo.is_admin()
if admin:
grillo = GrilloClient(user_id=context.args[0], api_token=config.GRILLO_API_TOKEN)
location = context.args[1] if len(context.args) > 1 else None
else:
location= context.args[0]
else:
location = None
result = grillo.clockin(location)
loc_name = result.get("location", "the lab")
await update.effective_message.reply_text(f"β
Clocked in to {loc_name}!")
except Exception as e:
logger.error(f"Error clocking in: {e}")
await update.effective_message.reply_text(f"β Error clocking in: {str(e)}")
async def clockout(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Clock out from the lab."""
if not context.args:
await update.effective_message.reply_text(
"β Please provide a summary of your work.\n"
"Usage: /clockout <summary>"
)
return
try:
grillo = get_user_client_by_telegram(update.effective_user.id)
summary = " ".join(context.args)
res = grillo.clockout(summary)
endTime = int(res.get("endTime", 0))
startTime = int(res.get("startTime", 0))
duration = endTime - startTime
hours = duration // 3600
minutes = (duration % 3600) // 60
time_str = "Spent "
if hours > 0:
time_str += f"{hours}h "
time_str += f"{minutes}m in the lab."
await update.effective_message.reply_text(f"β
Clocked out successfully!\n{time_str}")
except Exception as e:
logger.error(f"Error clocking out: {e}")
await update.effective_message.reply_text(f"β Error clocking out: {str(e)}")
async def unknown_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Handle unknown commands."""
await update.effective_message.reply_text(
"β Command not recognized.\n\n"
"Use /help to see available commands."
)
def error_handler(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
"""Log errors caused by updates."""
logger.error(f"Update {update} caused error {context.error}")
def main() -> None:
"""Start the bot."""
# Validate configuration
try:
config.validate()
except ValueError as e:
logger.error(f"Configuration error: {e}")
return
# Create the Application
application = Application.builder().token(config.TELEGRAM_BOT_TOKEN).build()
# Register command handlers
handlers = [
start,
help,
status,
clockin,
clockout,
]
aliases = {
"info": help,
"login": clockin,
"logout": clockout,
"inlab": status,
}
for handler in handlers:
application.add_handler(
CommandHandler(
handler.__name__,
handler,
filters=filters.UpdateType.MESSAGE | filters.UpdateType.EDITED_MESSAGE
)
)
for handler in aliases.keys():
application.add_handler(
CommandHandler(
handler,
aliases[handler],
filters=filters.UpdateType.MESSAGE | filters.UpdateType.EDITED_MESSAGE
)
)
# must be last
application.add_handler(
MessageHandler(
filters.COMMAND & (filters.UpdateType.MESSAGE | filters.UpdateType.EDITED_MESSAGE),
unknown_command
)
)
# Register error handler
application.add_error_handler(error_handler)
# Start the bot
logger.info("Starting Grillo Telegram Bot...")
application.run_polling(allowed_updates=Update.ALL_TYPES)
if __name__ == "__main__":
main()