import os import discord import yaml import requests from datetime import date import urllib.parse # To send discord messages (fucking async functions…) import asyncio from apscheduler.schedulers.background import BackgroundScheduler scheduler = BackgroundScheduler() scheduler.start() from dotenv import load_dotenv load_dotenv() from email.message import EmailMessage import smtplib, ssl # Create a secure SSL context ssl_context = ssl.create_default_context() def load_guilds_data(): with open("guilds.yml", 'r') as stream: try: return yaml.safe_load(stream) except yaml.YAMLError as exc: print(exc) def send_mail(guild, subject, content): msg = EmailMessage() msg['Subject'] = subject msg['From'] = guild['mail_from'] msg['To'] = guild['mailing'] msg.set_content(content) with smtplib.SMTP_SSL(guild['smtp_host'], guild['smtp_port'], context=ssl_context) as server: server.login(guild['smtp_username'], guild['smtp_pass']) server.send_message(msg) def mail_message(message): send_mail(guilds[message.guild.id], f'Nouveau message discord de {message.author.display_name}', f'{message.author.display_name}:\n{message.content}') def req(url, data): x = requests.post(url, headers={'Content-Type': 'application/x-www-form-urlencoded'}, data=data) if x.status_code != 200: print('ERROR', x) print(x.content) raise Exception('Request error ' + str(x.status_code)) # Load some data TOKEN = os.getenv('DISCORD_TOKEN') guilds = load_guilds_data() reminder_channels = [] for i in guilds: if 'reminder_channel' in guilds[i]: reminder_channels.append(guilds[i]['reminder_channel']) from html.parser import HTMLParser class TokenFinder(HTMLParser): def __init__(self, admin_url): self.token = None self.delete_links = [] self.admin_url = admin_url super().__init__() def handle_starttag(self, tag, attrs_tuple): if tag != 'input' and tag != 'a': return attrs = dict(attrs_tuple) if tag == 'input' and 'type' in attrs and attrs['type'] == 'hidden' and 'name' in attrs and attrs['name'] == 'control' and 'value' in attrs : self.token = attrs['value'] elif tag == 'a' and 'href' in attrs and attrs['href'].startswith(self.admin_url + '/action/delete_column/') : self.delete_links.append(attrs['href']) def create_framavote (guild, names): erase_framadate(guild['framavote']) for i in range(len(guild['members'])): create_line_framadate(guild['framavote'], 'AnneONyme'+str(i), names) def erase_framadate (admin_url): req(admin_url, 'remove_all_votes=') req(admin_url, 'confirm_remove_all_votes=') def create_line_framadate (admin_url, voter, names): finder = TokenFinder() finder.feed(requests.get(admin_url).content.decode('UTF-8')) if not finder.token: print('Framavote token not found') data = 'control=' + finder.token + '&name=' + voter + ''.join('&choices%5B'+str(i)+'%5D=+' for i in range(len(names))) + '&save=' print(data) x = req(admin_url, data) @scheduler.scheduled_job('cron', day=25) def cleaner (): for guild_id in guilds: erase_framadate(guilds[guild_id]['framadate_week']) erase_framadate(guilds[guild_id]['framadate_weekend']) # TODO erase calc revenus ? @scheduler.scheduled_job('cron', day=1) def reminder (): for i in guilds: print(f"reminding {i} : {guilds[i]['mailing']}") message = generate_reminder_message(guilds[i]) send_mail(guilds[i], 'La mutunion c’est bientôt !', message) channel = client.get_channel(guilds[i]['reminder_channel']) asyncio.run_coroutine_threadsafe(channel.send(message), client.loop) def generate_reminder_message (guild): # If the 10 is weekend sondage = guild['framadate_week'] if date.today().replace(day=10).weekday() > 4: sondage = guild['framadate_weekend'] return f""" Coucou ! Il est l’heure de déclarer ses revenus : <{guild['link_declaration']}> Et d’annoncer à quelle heure vous souhaitez faire la mutunion : <{sondage}> Bon début de mois :D Le mutubot """ # Discord API intents = discord.Intents.default() intents.message_content = True client = discord.Client(intents=intents) randomvote = None @client.event async def on_ready(): print(f'{client.user} is connected to the following guild:\n') for guild in client.guilds: print(f'{guild.name} (id: {guild.id})') @client.event async def on_message(message): global randomvote if message.author == client.user: return if message.guild.id not in guilds: return if message.content.startswith('!randomvote '): await message.reply('Êtes vous sûr·e ? Répondez « Pamplemousse agrivoltaiste » pour confirmer') randomvote = message.content.split(' ')[1:] return if message.content == 'Pamplemousse agrivoltaiste' and message.type == discord.MessageType.reply : create_framavote(guilds[message.guild.id], ['1', '2', '3', '4', '5', '6']) randomvote = None await message.reply("C’est fait ! Vérifiez bien par vous même parce que je suis un peu fini à l’arache…") return if message.channel.id in guilds[message.guild.id]['mailed_channels']: mail_message(message) # Actually starts the bot client.run(TOKEN)