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 )
2024-11-07 19:54:08 +00:00
def send_mass_mail ( guild , subject , content ) :
send_mail ( guild , guild [ ' mailing ' ] , subject , content )
def send_mail ( guild , to , subject , content ) :
2024-05-10 07:54:20 +00:00
msg = EmailMessage ( )
msg [ ' Subject ' ] = subject
msg [ ' From ' ] = guild [ ' mail_from ' ]
2024-11-07 19:54:08 +00:00
msg [ ' To ' ] = to
2024-05-10 07:54:20 +00:00
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 ) :
2024-11-07 19:54:08 +00:00
send_mass_mail ( guilds [ message . guild . id ] , f ' [Mutubot] Nouveau message discord de { message . author . display_name } ' , f ' { message . author . display_name } : \n { message . content } ' )
2024-05-10 07:54:20 +00:00
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 = [ ]
2024-11-07 19:54:08 +00:00
self . public_links = [ ]
2024-11-07 18:48:17 +00:00
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 19:54:08 +00:00
elif tag == ' a ' and ' href ' in attrs and self . public_link and attrs [ ' href ' ] . startswith ( self . public_link + ' /vote/ ' ) :
self . public_links . append ( attrs [ ' href ' ] )
2024-11-07 18:37:12 +00:00
2024-11-07 19:54:08 +00:00
def scrap_framavote ( admin_url ) :
# Parse html to find data
finder = TokenFinder ( admin_url )
finder . feed ( requests . get ( admin_url ) . content . decode ( ' UTF-8 ' ) )
return finder
2024-11-07 18:37:12 +00:00
def create_framavote ( guild , names ) :
2024-11-07 19:54:08 +00:00
finder = scrap_framavote ( guild [ ' framavote ' ] )
2024-11-07 19:29:41 +00:00
# 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
2024-11-07 19:54:08 +00:00
finder = scrap_framavote ( guild [ ' framavote ' ] )
2024-11-07 19:29:41 +00:00
# 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:54:08 +00:00
# Update links
finder = scrap_framavote ( guild [ ' framavote ' ] )
# Send links
for mail , link in zip ( guild [ ' members ' ] , finder . public_links ) :
content = f """
Ce mail remplace tous les précédents !
Voici votre lien de vote anonyme :
{ { link } }
"""
send_mail ( guild , mail , ' [Mutubot] Votre lien de vote anonyme ' , content )
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 ] )
2024-11-07 19:54:08 +00:00
send_mass_mail ( guilds [ i ] , ' [Mutubot] La mutunion c’ est bientôt ! ' , message )
2024-05-10 07:54:20 +00:00
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 )