forked from DGNum/infrastructure
Tom Hubrecht
88d9b8c3e3
Signed-off-by: Tom Hubrecht <tom.hubrecht@dgnum.eu> Acked-by: Ryan Lahfa <ryan.lahfa@dgnum.eu> Acked-by: Maurice Debray <maurice.debray@dgnum.eu> Acked-by: Lubin Bailly <lubin.bailly@dgnum.eu> Acked-by: Jean-Marc Gailis <jean-marc.gailis@dgnum.eu> as the legal authority, at the time of writing, in DGNum. Acked-by: Elias Coppens <elias.coppens@dgnum.eu> as a member, at the time of writing, of the DGNum executive counsel.
126 lines
4.7 KiB
Python
126 lines
4.7 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# SPDX-FileCopyrightText: 2024 Ryan Lahfa <ryan.lahfa@dgnum.eu>
|
|
#
|
|
# SPDX-License-Identifier: EUPL-1.2
|
|
|
|
import asyncio
|
|
|
|
from irctokens.line import build, Line
|
|
from ircrobots.bot import Bot as BaseBot
|
|
from ircrobots.server import Server as BaseServer
|
|
from ircrobots.params import ConnectionParams
|
|
|
|
import aiohttp
|
|
|
|
BRIDGE_NICKNAME = "hermes"
|
|
|
|
SERVERS = [
|
|
("dgnum", "irc.dgnum.eu")
|
|
]
|
|
|
|
TEAMS = {
|
|
"fai": ("tomate", "elias", "JeMaGius", "Luj", "catvayor", "Raito"),
|
|
"marketing": ("cst1", "elias"),
|
|
"bureau": ("Raito", "JeMaGius", "Luj", "gdd")
|
|
}
|
|
|
|
# times format is 0700-29092024
|
|
TRIGGER = '!'
|
|
async def create_meet(title: str, times: list[str], timezone: str = "UTC") -> str:
|
|
async with aiohttp.ClientSession() as session:
|
|
payload = {
|
|
'name': title,
|
|
'times': times,
|
|
'timezone': timezone
|
|
}
|
|
async with session.post('https://api.meet.dgnum.eu/event', json=payload) as response:
|
|
response.raise_for_status()
|
|
id = (await response.json()).get('id')
|
|
if not id:
|
|
raise RuntimeError('No ID attributed to a meet')
|
|
return f'https://meet.dgnum.eu/{id}'
|
|
|
|
def expand_times(times: list[str]) -> list[str]:
|
|
expanded = []
|
|
# TODO: verify the date exist in the calendar
|
|
# TODO: verify that we don't write any duplicates.
|
|
for time in times:
|
|
if '-' not in time:
|
|
for i in range(7, 20):
|
|
expanded.append(f'{i:02}00-{time}')
|
|
else:
|
|
expanded.append(time)
|
|
return expanded
|
|
|
|
def bridge_stripped(possible_command: str, origin_nick: str) -> str | None:
|
|
if origin_nick.lower() == BRIDGE_NICKNAME:
|
|
stripped_user = possible_command.split(':')[1].lstrip()
|
|
return stripped_user if stripped_user.startswith(TRIGGER) else None
|
|
else:
|
|
return possible_command if possible_command.startswith(TRIGGER) else None
|
|
|
|
class Server(BaseServer):
|
|
def extract_valid_command(self, line: Line) -> str | None:
|
|
me = self.nickname_lower
|
|
if line.command == "PRIVMSG" and \
|
|
self.has_channel(line.params[0]) and \
|
|
line.hostmask is not None and \
|
|
self.casefold(line.hostmask.nickname) != me and \
|
|
self.has_user(line.hostmask.nickname):
|
|
return bridge_stripped(line.params[1], line.hostmask.nickname)
|
|
|
|
|
|
async def line_read(self, line: Line):
|
|
print(f"{self.name} < {line.format()}")
|
|
if line.command == "001":
|
|
print(f"connected to {self.isupport.network}")
|
|
await self.send(build("JOIN", ["#dgnum-bridge-test"]))
|
|
|
|
# In case `!probe_meet <title> <team> <time_1> <time_2> … <time_N> [<timezone>]`
|
|
if (command := self.extract_valid_command(line)) is not None:
|
|
text = command.lstrip(TRIGGER)
|
|
if text.startswith('probe_meet') or text.startswith('pm'):
|
|
args = text.split(' ')
|
|
if len(args) < 4:
|
|
await self.send(build("PRIVMSG", [line.params[0], "usage is !probe_meet <title> <team> <time_1> [<time_2> <time_3> … <time_N>] ; time is in [00-hour-]DDMMYYYY format."]))
|
|
return
|
|
|
|
title, team = args[1], args[2]
|
|
print(f"creating meet '{title}' for team '{team}'")
|
|
try:
|
|
times = expand_times(args[3:])
|
|
link = await create_meet(title, times)
|
|
if team not in TEAMS:
|
|
await self.send(build("PRIVMSG", [line.params[0], f"team {team} does not exist"]))
|
|
return
|
|
|
|
targets = TEAMS[team]
|
|
ping_mentions = ', '.join(targets)
|
|
await self.send(build("PRIVMSG", [line.params[0], f'{ping_mentions} {link}']))
|
|
except ValueError as e:
|
|
print(e)
|
|
await self.send(build("PRIVMSG", [line.params[0], "time format is [00-hour-]DDMMYYYY, hour is optional, by default it's 07:00 to 19:00 in Europe/Paris timezone"]))
|
|
except aiohttp.ClientError as e:
|
|
print(e)
|
|
await self.send(build("PRIVMSG", [line.params[0], "failed to create the meet on meet.dgnum.eu, API error, check the logs"]))
|
|
|
|
|
|
async def line_send(self, line: Line):
|
|
print(f"{self.name} > {line.format()}")
|
|
|
|
class Bot(BaseBot):
|
|
def create_server(self, name: str):
|
|
return Server(self, name)
|
|
|
|
async def main():
|
|
bot = Bot()
|
|
for name, host in SERVERS:
|
|
# For IPv4-only connections.
|
|
params = ConnectionParams("Takumi", host, 6698)
|
|
await bot.add_server(name, params)
|
|
|
|
await bot.run()
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|