Commit ee385852 authored by Maxime Bombar's avatar Maxime Bombar

Merge branch 'master' of gitlab.crans.org:esum/NinjaBot

parents 1bc199bb b9963534
import irc.bot
import config
class Bot(irc.bot.SingleServerIRCBot):
def __init__(self, nickname, channel="#bot", server="irc.crans.org", port=6667):
irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
self.nick = nickname
self.channel = channel
self.operators = config.operators
def on_nicknameinuse(self, conn, e):
conn.nick(conn.get_nickname() + "_")
self.nick += "_"
def on_welcome(self, conn, e):
conn.join(self.channel)
self.on_welcome_ext(conn, e)
def on_privmsg(self, conn, e):
if e.source.nick in self.operators:
return self.do_command(conn, e.arguments[0].split(' '), self.operators[e.source.nick], e.source.nick)
return self.do_command(conn, e.arguments[0].split(' '), 0, e.source.nick)
def do_command(self, conn, command, level, source):
if command[0].casefold() == "op":
if len(command) == 2:
dst_level = 100
else:
try:
dst_level = int(command[2])
except:
dst_level = 0
if 0 <= dst_level < level:
self.operators[command[1]] = dst_level
elif command[0].casefold() == "join" and level >= 100:
for channel in command[1:]:
conn.join(channel)
elif command[0].casefold() == "leave" and level >= 100:
for channel in command[1:]:
conn.part(channel, "Ce n'est qu'un au revoir")
else:
self.do_command_ext(conn, command, level, source)
import asyncio
import aioimaplib
import asyncio
import email
import irc.bot
import config
from subs import subs
import threading
from enum import Enum
import quopri
import re
import time
import quopri
import threading
from bot import Bot
import config
import secrets
from subs import subs
def write_subs(subs):
with open('subs.py', 'w') as s:
s.write('subs = { ' + ',\n'.join([repr(nick) + ':{' + ',\n'.join([repr(channel) + ': [' + ','.join([repr(patt) for patt in subs[nick][channel]]) + ']' for channel in subs[nick]]) + '}' for nick in subs]) + ' }\n')
s.write('subs={' + ','.join([repr(nick) + ':{' + ','.join([repr(channel) + ':[' + ','.join([repr(patt) for patt in subs[nick][channel]]) + ']' for channel in subs[nick]]) + '}' for nick in subs]) + ' }\n')
class Update:
class Information(Enum):
required = 0
optional = 1
class Update(Enum):
edit = 0
attachment = 1
rename = 2
class Bot(irc.bot.SingleServerIRCBot):
def __init__(self, nickname, channel="#bot", server="irc.crans.org", port=6667):
irc.bot.SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname)
self.nick = nickname
self.channel = channel
self.operators = config.operators
self.started = False
self.active = []
#self.on_command_ext = lambda *args, **kwargs: None
#self.on_pubmsg_ext = lambda conn, e: None
#self.source_file = ""
def on_nicknameinuse(self, conn, e):
conn.nick(conn.get_nickname() + "_")
self.nick += "_"
def on_welcome(self, conn, e):
conn.join(self.channel)
self.on_welcome_ext(conn, e)
def on_privmsg(self, conn, e):
if e.source.nick in self.operators:
return self.do_command(conn, e.arguments[0].split(' '), self.operators[e.source.nick], e.source.nick)
return self.do_command(conn, e.arguments[0].split(' '), 0, e.source.nick)
def do_command(self, conn, command, level, source):
if command[0].casefold() == "op":
if len(command) == 2:
dst_level = 100
else:
try:
dst_level = int(command[2])
except:
dst_level = 0
if 0 <= dst_level < level:
self.operators[command[1]] = dst_level
elif command[0].casefold() == "upgrade" and level >= float("inf"):
pass
#if self.source_file:
# self.do_command_ext, self.on_pubmsg_ext = updgrade(self.source_file)
elif command[0].casefold() == "join" and level >= 100:
for channel in command[1:]:
conn.join(channel)
elif command[0].casefold() == "leave" and level >= 100:
for channel in command[1:]:
conn.part(channel, "Ce n'est qu'un au revoir")
elif command[0].casefold() == "on" and level >= 100:
for channel in command[1:]:
self.active.append(channel)
elif command[0].casefold() == "off" and level >= 100:
for channel in command[1:]:
if channel in self.active:
self.active.remove(channel)
else:
self.do_command_ext(conn, command, level, source)
create = 1
remove = 2
rename = 3
attach = 4
delete_attach = 5
DEFAULT_SENDER = 'wiki@crans.org'
UPDATES = {
'wiki@crans.org' : (
# fonction de pré-traitement du mail
lambda mail: quopri.decodestring(mail.get_payload()).decode('utf-8').replace('\r', ''), {
Update.edit: (
lambda **kwargs: '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99{comment}\x0f \x0315,99(r{rev})'.format(**kwargs) if kwargs['comment']\
else '\x0310,99{page}\x0f \x033,99{user}\x0f \x0315,99(r{rev})\x0f'.format(**kwargs),
'page', [
(Information.required, ['page', 'user'], r'La page « (?P<page>.*) » a été modifiée par (?P<user>.*) :'),
(Information.required, ['rev'], r'\?action=diff&rev1=[0-9]+&rev2=(?P<rev>[0-9]+)\n'),
(Information.optional, ['comment'], r'\s*Commentaire :\s*\n\s*(?P<comment>[^\n]*)\n')
]
),
Update.create: (
lambda **kwargs: '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99{comment}\x0f \x0315,99(r1)'.format(**kwargs) if kwargs['comment']\
else '\x0310,99{page}\x0f \x033,99{user}\x0f \x0315,99(r1)\x0f'.format(**kwargs),
'page', [
(Information.required, ['page', 'user'], r'La page « (?P<page>.*) » a été modifiée par (?P<user>.*) :'),
(Information.required, [], r'\s*Nouvelle page :\n'),
(Information.optional, ['comment'], r'\s*Commentaire :\s*\n\s*(?P<comment>[^\n]*)\n')
]
),
Update.remove: (
lambda **kwargs: '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99{comment}\x0f'.format(**kwargs) if kwargs['comment']\
else '\x0310,99{page}\x0f \x033,99{user}\x0f'.format(**kwargs),
'page', [
(Information.required, ['page', 'user'], r'La page « (?P<page>.*) » a été supprimée par (?P<user>.*) :'),
(Information.optional, ['comment'], r'\s*Commentaire :\s*\n\s*(?P<comment>[^\n]*)\n')
]
),
Update.rename: (
lambda **kwargs: '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99rename -->\x0f \x0310,99{new}\x0f \x0399,99{comment}\x0f'.format(**kwargs) if kwargs['comment']\
else '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99rename -->\x0f \x0310,99{new}\x0f'.format(**kwargs),
'page', [
(Information.required, ['page', 'new', 'user'], r'La page « (?P<page>.*) » a été renommée « (?P<new>.*) » par (?P<user>.*) :'),
(Information.optional, ['comment'], r'\s*Commentaire :\s*\n\s*(?P<comment>[^\n]*)\n')
]
),
Update.attach: (
lambda **kwargs: '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99ajout de la pièce jointe\x0f : \x0310,99{name}\x0f'.format(**kwargs),
'page', [
(Information.required, ['page', 'user'], r'vous vous êtes abonné aux notifications de changements pour la page "(?P<page>.*)"\.Une pièce jointe vient d\'y être ajouté par (?P<user>.*)\. Quelques détails sur la pièce jointe :'),
(Information.required, ['name'], r'Nom\s*:\s*(?P<name>[^\n]*)\n')
]
),
Update.delete_attach:(
lambda **kwargs: '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99suppression de la pièce jointe\x0f : \x0310,99{name}\x0f'.format(**kwargs),
'page', [
(Information.required, ['page', 'user'], r'vous vous êtes abonné aux notifications de changements pour la page "(?P<page>.*)"\.Une pièce jointe de cette page vient d\'être supprimée par (?P<user>.*)\. Quelques détails sur la pièce jointe :'),
(Information.required, ['name'], r'Nom\s*:\s*(?P<name>[^\n]*)\n')
]
)
}
)
}
class Nsa(Bot):
def __init__(self):
......@@ -148,7 +166,7 @@ class Nsa(Bot):
conn.privmsg(source, ' + {i}. {patt}'.format(i=i, patt=patt))
write_subs(subs)
def push_update(self, page, user, revision, comment, type=Update.edit):
def push_update(self, page, message):
global subs
patts = {}
for nick in subs:
......@@ -158,25 +176,26 @@ class Nsa(Bot):
for channel in patts:
if any(re.fullmatch(patt, page) for patt in patts[channel]):
t = time.time()
if type == Update.edit:
if comment:
self.connection.privmsg(channel, '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99{comment}\x0f \x0315,99(r{revision})'.format(page=page, user=user, revision=revision, comment=comment))
else:
self.connection.privmsg(channel, '\x0310,99{page}\x0f \x033,99{user}\x0f \x0315,99(r{revision})\x0f'.format(page=page, user=user, revision=revision))
elif type == Update.attachment:
self.connection.privmsg(channel, '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99{comment}\x0f : \x0310,99{revision}\x0f'.format(page=page, user=user, comment=comment, revision=revision))
elif type == Update.rename:
self.connection.privmsg(channel, '\x0310,99{page}\x0f \x033,99{user}\x0f \x0399,99rename -->\x0f \x0310,99{revision}\x0f \x0399,99{comment}\x0f'.format(page=page, user=user, comment=comment, revision=revision))
self.connection.privmsg(channel, message)
# on attend 5 secondes pour éviter que le serveur nous empêche d'envoyer les messages
# time.sleep n'a pas l'air de trop marcher dans les thread du coup je le combine avec time.time
while t + 5 > time.time():
time.sleep(1)
@asyncio.coroutine
<<<<<<< HEAD:src/nsabot.py
def idle_loop(host, user, password, nsa):
=======
def idle_loop(host, user, password, ninja):
global UPDATES, DEFAULT_SENDER
>>>>>>> b9963534ec17e245f5dc1d5fc9ef5ff488dedd87:src/ninjabot.py
imap_client = aioimaplib.IMAP4_SSL(host=host, timeout=30)
yield from imap_client.wait_hello_from_server()
yield from imap_client.login(user, password)
yield from imap_client.select()
print('Running...')
while True:
idle = yield from imap_client.idle_start(timeout=60)
msgs = yield from imap_client.wait_server_push()
......@@ -186,6 +205,7 @@ def idle_loop(host, user, password, nsa):
if m.endswith(' EXISTS'):
mail = yield from imap_client.uid('fetch', m[:-7], '(RFC822)')
mail = email.message_from_bytes(mail.lines[1])
<<<<<<< HEAD:src/nsabot.py
body = quopri.decodestring(mail.get_payload()).decode('utf-8').replace('\r', '')
page_user = re.search(r'La page « (?P<page>.*) » a été modifiée par (?P<user>.*) :', body)
revision = re.search(r'\?action=diff&rev1=[0-9]+&rev2=(?P<rev>[0-9]+)\n', body)
......@@ -202,6 +222,32 @@ def idle_loop(host, user, password, nsa):
piece = re.search(r'Nom\s*:\s*(?P<name>[^\n]*)\n', body)
if page_user:
nsa.push_update(page_user.group('page'), page_user.group('user'), piece.group('name'), "ajout d'une pièce jointe" if page_user.group('add').startswith('v') else 'suppression de la pièce jointe', type=Update.attachment)
=======
sender = mail['From']
if sender not in UPDATES:
sender = DEFAULT_SENDER
preprocessor, updates = UPDATES[sender]
body = preprocessor(mail)
for update in updates:
next_update = False
message, page, regexps = updates[update]
kwargs = {}
for info, groups, regexp in regexps:
m = re.search(regexp, body)
if info == Information.required and not m:
next_update = True
break
elif m:
for group in groups:
kwargs[group] = m.group(group)
else:
for group in groups:
kwargs[group] = None
if next_update: continue
message = message(**kwargs)
page = kwargs[page]
ninja.push_update(page, message)
>>>>>>> b9963534ec17e245f5dc1d5fc9ef5ff488dedd87:src/ninjabot.py
if __name__ == '__main__':
......@@ -211,6 +257,11 @@ if __name__ == '__main__':
t.start()
while True:
try:
<<<<<<< HEAD:src/nsabot.py
loop.run_until_complete(idle_loop(secrets.host, secrets.user, secrets.password, nsa))
=======
# Des fois ça timeout et je ne sais pas pourquoi, d'où le while True
loop.run_until_complete(idle_loop(secrets.host, secrets.user, secrets.password, ninja))
>>>>>>> b9963534ec17e245f5dc1d5fc9ef5ff488dedd87:src/ninjabot.py
except:
pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment