2024-05-10 07:54:20 +00:00
|
|
|
|
import os
|
|
|
|
|
import discord
|
|
|
|
|
import yaml
|
|
|
|
|
import requests
|
|
|
|
|
from datetime import date
|
2024-11-07 18:37:12 +00:00
|
|
|
|
import urllib.parse
|
2024-05-10 07:54:20 +00:00
|
|
|
|
|
2024-05-10 11:24:06 +00:00
|
|
|
|
# To send discord messages (fucking async functions…)
|
|
|
|
|
import asyncio
|
|
|
|
|
|
2024-05-10 07:54:20 +00:00
|
|
|
|
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}')
|
|
|
|
|
|
2024-11-07 18:37:12 +00:00
|
|
|
|
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))
|
2024-05-10 07:54:20 +00:00
|
|
|
|
|
|
|
|
|
# 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'])
|
|
|
|
|
|
|
|
|
|
|
2024-11-07 18:37:12 +00:00
|
|
|
|
from html.parser import HTMLParser
|
|
|
|
|
|
|
|
|
|
class TokenFinder(HTMLParser):
|
2024-11-07 18:48:17 +00:00
|
|
|
|
def __init__(self, admin_url):
|
|
|
|
|
self.token = None
|
2024-11-07 19:29:41 +00:00
|
|
|
|
self.public_link = None
|
2024-11-07 18:48:17 +00:00
|
|
|
|
self.delete_links = []
|
|
|
|
|
self.admin_url = admin_url
|
2024-11-07 18:37:12 +00:00
|
|
|
|
super().__init__()
|
|
|
|
|
|
|
|
|
|
def handle_starttag(self, tag, attrs_tuple):
|
2024-11-07 18:48:17 +00:00
|
|
|
|
if tag != 'input' and tag != 'a':
|
2024-11-07 18:37:12 +00:00
|
|
|
|
return
|
|
|
|
|
attrs = dict(attrs_tuple)
|
2024-11-07 18:48:17 +00:00
|
|
|
|
if tag == 'input' and 'type' in attrs and attrs['type'] == 'hidden' and 'name' in attrs and attrs['name'] == 'control' and 'value' in attrs :
|
2024-11-07 18:37:12 +00:00
|
|
|
|
self.token = attrs['value']
|
2024-11-07 19:29:41 +00:00
|
|
|
|
elif tag == 'input' and 'id' in attrs and attrs['id'] == 'public-link' and 'value' in attrs :
|
|
|
|
|
self.public_link = attrs['value']
|
2024-11-07 18:48:17 +00:00
|
|
|
|
elif tag == 'a' and 'href' in attrs and attrs['href'].startswith(self.admin_url + '/action/delete_column/') :
|
|
|
|
|
self.delete_links.append(attrs['href'])
|
2024-11-07 18:37:12 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def create_framavote (guild, names):
|
2024-11-07 19:29:41 +00:00
|
|
|
|
# Parse html to find data
|
|
|
|
|
finder = TokenFinder(guild['framavote'])
|
|
|
|
|
finder.feed(requests.get(guild['framavote']).content.decode('UTF-8'))
|
|
|
|
|
if not finder.token:
|
|
|
|
|
print('Framavote token not found')
|
|
|
|
|
|
|
|
|
|
# Remove everything
|
|
|
|
|
erase_framadate(guild['framavote'], finder.delete_links)
|
|
|
|
|
|
|
|
|
|
# Add columns
|
|
|
|
|
for name in names:
|
|
|
|
|
req(guild['framavote'], 'choice='+name+'&confirm_add_column=')
|
|
|
|
|
|
|
|
|
|
# Update control sum
|
|
|
|
|
finder.feed(requests.get(guild['framavote']).content.decode('UTF-8'))
|
|
|
|
|
|
|
|
|
|
# Add lines
|
2024-11-07 18:37:12 +00:00
|
|
|
|
for i in range(len(guild['members'])):
|
2024-11-07 19:29:41 +00:00
|
|
|
|
create_line_framadate(finder.token, guild['framavote'], 'AnneONyme'+str(i), names)
|
2024-11-07 18:37:12 +00:00
|
|
|
|
|
2024-11-07 19:29:41 +00:00
|
|
|
|
return finder.public_link
|
2024-11-07 18:37:12 +00:00
|
|
|
|
|
2024-11-07 19:29:41 +00:00
|
|
|
|
def erase_framadate (admin_url, delete_links=[]):
|
2024-11-07 18:37:12 +00:00
|
|
|
|
req(admin_url, 'remove_all_votes=')
|
|
|
|
|
req(admin_url, 'confirm_remove_all_votes=')
|
2024-11-07 19:29:41 +00:00
|
|
|
|
for link in delete_links:
|
|
|
|
|
requests.get(link)
|
2024-11-07 18:37:12 +00:00
|
|
|
|
|
|
|
|
|
|
2024-11-07 19:29:41 +00:00
|
|
|
|
def create_line_framadate (token, admin_url, voter, names):
|
|
|
|
|
data = 'control=' + token + '&name=' + voter + ''.join('&choices%5B'+str(i)+'%5D=+' for i in range(len(names))) + '&save='
|
2024-11-07 18:37:12 +00:00
|
|
|
|
x = req(admin_url, data)
|
2024-05-10 07:54:20 +00:00
|
|
|
|
|
|
|
|
|
@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 ?
|
|
|
|
|
|
2024-09-10 16:33:50 +00:00
|
|
|
|
@scheduler.scheduled_job('cron', day=1)
|
2024-05-10 11:24:06 +00:00
|
|
|
|
def reminder ():
|
2024-05-10 07:54:20 +00:00
|
|
|
|
for i in guilds:
|
2024-05-10 11:24:06 +00:00
|
|
|
|
print(f"reminding {i} : {guilds[i]['mailing']}")
|
2024-05-10 07:54:20 +00:00
|
|
|
|
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'])
|
2024-05-10 11:24:06 +00:00
|
|
|
|
asyncio.run_coroutine_threadsafe(channel.send(message), client.loop)
|
2024-05-10 07:54:20 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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']}>
|
|
|
|
|
|
2024-05-10 11:24:06 +00:00
|
|
|
|
Et d’annoncer à quelle heure vous souhaitez faire la mutunion :
|
2024-05-10 07:54:20 +00:00
|
|
|
|
<{sondage}>
|
|
|
|
|
|
|
|
|
|
Bon début de mois :D
|
|
|
|
|
Le mutubot
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Discord API
|
|
|
|
|
|
|
|
|
|
intents = discord.Intents.default()
|
|
|
|
|
intents.message_content = True
|
|
|
|
|
client = discord.Client(intents=intents)
|
2024-11-07 18:37:12 +00:00
|
|
|
|
randomvote = None
|
2024-05-10 07:54:20 +00:00
|
|
|
|
|
|
|
|
|
@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):
|
2024-11-07 18:37:12 +00:00
|
|
|
|
global randomvote
|
2024-05-10 07:54:20 +00:00
|
|
|
|
if message.author == client.user:
|
|
|
|
|
return
|
|
|
|
|
if message.guild.id not in guilds:
|
|
|
|
|
return
|
2024-11-07 18:37:12 +00:00
|
|
|
|
if message.content.startswith('!randomvote '):
|
2024-11-07 19:29:41 +00:00
|
|
|
|
await message.reply('Cela va détruire le framavote actuel. Êtes vous sûr·e ? Répondez « Pamplemousse agrivoltaiste » pour confirmer')
|
2024-11-07 18:37:12 +00:00
|
|
|
|
randomvote = message.content.split(' ')[1:]
|
|
|
|
|
return
|
2024-11-07 19:29:41 +00:00
|
|
|
|
elif message.content == 'Pamplemousse agrivoltaiste' and message.type == discord.MessageType.reply :
|
|
|
|
|
public_link = create_framavote(guilds[message.guild.id], randomvote)
|
2024-11-07 18:37:12 +00:00
|
|
|
|
randomvote = None
|
2024-11-07 19:29:41 +00:00
|
|
|
|
await message.reply("C’est fait ! Vérifiez bien par vous même parce que je suis un peu fini à l’arache… " + public_link)
|
2024-11-07 18:37:12 +00:00
|
|
|
|
return
|
2024-11-07 19:29:41 +00:00
|
|
|
|
elif message.channel.id in guilds[message.guild.id]['mailed_channels']:
|
2024-05-10 07:54:20 +00:00
|
|
|
|
mail_message(message)
|
|
|
|
|
|
|
|
|
|
# Actually starts the bot
|
|
|
|
|
client.run(TOKEN)
|