Soutenance module: convert to V3.2

This commit is contained in:
Némunaire 2012-10-15 01:52:32 +02:00
commit 28dee24b5a
3 changed files with 196 additions and 201 deletions

View file

@ -1,4 +1,5 @@
<?xml version="1.0" ?> <?xml version="1.0" ?>
<nemubotmodule name="soutenance"> <nemubotmodule name="soutenance">
<server ip="intra.acu.epita.fr" url="/intra/sout_liste.html" /> <server ip="www.acu.epita.fr" url="/intra/sout_liste.html" />
</nemubotmodule> <message type="cmd" name="soutenance" call="ask_soutenance" />
</nemubotmodule>

View file

@ -2,87 +2,178 @@
from datetime import datetime from datetime import datetime
from datetime import timedelta from datetime import timedelta
import http.client
import re import re
import threading
import time import time
from response import Response
from .Soutenance import Soutenance from .Soutenance import Soutenance
class SiteSoutenances: class SiteSoutenances(threading.Thread):
def __init__(self, page): def __init__(self, datas):
save = False self.souts = list()
self.souts = list() self.updated = datetime.now()
self.updated = datetime.now() self.datas = datas
last = None threading.Thread.__init__(self)
for line in page.split("\n"):
if re.match("</tr>", line) is not None: def getPage(self):
conn = http.client.HTTPSConnection(CONF.getNode("server")["ip"], timeout=10)
try:
conn.request("GET", CONF.getNode("server")["url"])
res = conn.getresponse()
page = res.read()
except:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return ""
conn.close()
return page
def parsePage(self, page):
save = False save = False
elif re.match("<tr.*>", line) is not None: for line in page.split("\n"):
save = True if re.match("</tr>", line) is not None:
last = Soutenance() save = False
self.souts.append(last) elif re.match("<tr.*>", line) is not None:
elif save: save = True
result = re.match("<td[^>]+>(.*)</td>", line) last = Soutenance()
if last.hour is None: self.souts.append(last)
try: elif save:
last.hour = datetime.fromtimestamp(time.mktime(time.strptime(result.group(1), "%Y-%m-%d %H:%M"))) result = re.match("<td[^>]+>(.*)</td>", line)
except ValueError: if last.hour is None:
continue try:
elif last.rank == 0: last.hour = datetime.fromtimestamp(time.mktime(time.strptime(result.group(1), "%Y-%m-%d %H:%M")))
last.rank = int (result.group(1)) except ValueError:
elif last.login == None: continue
last.login = result.group(1) elif last.rank == 0:
elif last.state == None: last.rank = int (result.group(1))
last.state = result.group(1) elif last.login == None:
elif last.assistant == None: last.login = result.group(1)
last.assistant = result.group(1) elif last.state == None:
elif last.start == None: last.state = result.group(1)
try: elif last.assistant == None:
last.start = datetime.fromtimestamp(time.mktime(time.strptime(result.group(1), "%Y-%m-%d %H:%M"))) last.assistant = result.group(1)
except ValueError: elif last.start == None:
last.start = None try:
elif last.end == None: last.start = datetime.fromtimestamp(time.mktime(time.strptime(result.group(1), "%Y-%m-%d %H:%M")))
try: except ValueError:
last.end = datetime.fromtimestamp(time.mktime(time.strptime(result.group(1), "%Y-%m-%d %H:%M"))) last.start = None
except ValueError: elif last.end == None:
last.end = None try:
last.end = datetime.fromtimestamp(time.mktime(time.strptime(result.group(1), "%Y-%m-%d %H:%M")))
def update(self): except ValueError:
if self.findLast() is not None and datetime.now () - self.updated > timedelta(minutes=2): last.end = None
return None
elif datetime.now () - self.updated < timedelta(hours=1):
return self
else:
return None
def findAssistants(self): def gen_response(self, req, msg):
h = {} """Generate a text response on right server and channel"""
for s in self.souts: return Response(req["sender"], msg, req["channel"], server=req["server"])
if s.assistant is not None and s.assistant != "":
h[s.assistant] = (s.start, s.end)
return h
def findLast(self): def res_next(self, req):
close = None soutenance = self.findLast()
for s in self.souts: if soutenance is None:
if (s.state != "En attente" and s.start is not None and (close is None or close.rank < s.rank or close.hour.day > s.hour.day)) and (close is None or s.hour - close.hour < timedelta(seconds=2499)): return self.gen_response(req, "Il ne semble pas y avoir de soutenance pour le moment.")
close = s else:
return close if soutenance.start > soutenance.hour:
avre = "%s de *retard*"%msg.just_countdown(soutenance.start - soutenance.hour, 4)
else:
avre = "%s *d'avance*"%msg.just_countdown(soutenance.hour - soutenance.start, 4)
self.gen_response(req, "Actuellement à la soutenance numéro %d, commencée il y a %s avec %s."%(soutenance.rank, msg.just_countdown(datetime.now () - soutenance.start, 4), avre))
def findAll(self, login): def res_assistants(self, req):
ss = list() assistants = self.findAssistants()
for s in self.souts: if len(assistants) > 0:
if s.login == login: return self.gen_response(req, "Les %d assistants faisant passer les soutenances sont : %s." % (len(assistants), ', '.join(assistants.keys())))
ss.append(s) else:
return ss return self.gen_response(req, "Il ne semble pas y avoir de soutenance pour le moment.")
def findClose(self, login): def res_soutenance(self, req):
ss = self.findAll(login) name = req["user"]
close = None
for s in ss: if name == "acu" or name == "yaka" or name == "acus" or name == "yakas" or name == "assistant" or name == "assistants":
if close is not None: return self.res_assistants(req)
print (close.hour) elif name == "next":
print (s.hour) return self.res_next(req)
if close is None or (close.hour < s.hour and close.hour.day >= datetime.datetime().day):
close = s soutenance = self.findClose(name)
return close if soutenance is None:
return self.gen_response(req, "Pas d'horaire de soutenance pour %s."%name)
else:
if soutenance.state == "En cours":
return self.gen_response(req, "%s est actuellement en soutenance avec %s. Elle était prévue à %s, position %d."%(name, soutenance.assistant, soutenance.hour, soutenance.rank))
elif soutenance.state == "Effectue":
return self.gen_response(req, "%s a passé sa soutenance avec %s. Elle a duré %s."%(name, soutenance.assistant, msg.just_countdown(soutenance.end - soutenance.start, 4)))
elif soutenance.state == "Retard":
return self.gen_response(req, "%s était en retard à sa soutenance de %s."%(name, soutenance.hour))
else:
last = self.findLast()
if last is not None:
if soutenance.hour + (last.start - last.hour) > datetime.now ():
return self.gen_response(req, "Soutenance de %s : %s, position %d ; estimation du passage : dans %s."%(name, soutenance.hour, soutenance.rank, msg.just_countdown((soutenance.hour - datetime.now ()) + (last.start - last.hour))))
else:
return self.gen_response(req, "Soutenance de %s : %s, position %d ; passage imminent."%(name, soutenance.hour, soutenance.rank))
else:
return self.gen_response(req, "Soutenance de %s : %s, position %d."%(name, soutenance.hour, soutenance.rank))
def res_list(self, req):
name = req["user"]
souts = self.findAll(name)
if souts is None:
self.gen_response(req, "Pas de soutenance prévues pour %s."%name)
else:
first = True
for s in souts:
if first:
self.gen_response(req, "Soutenance(s) de %s : - %s (position %d) ;"%(name, s.hour, s.rank))
first = False
else:
self.gen_response(req, " %s - %s (position %d) ;"%(len(name)*' ', s.hour, s.rank))
def run(self):
self.parsePage(self.getPage().decode())
res = list()
for u in self.datas.getNodes("request"):
res.append(self.res_soutenance(u))
return res
def needUpdate(self):
if self.findLast() is not None and datetime.now () - self.updated > timedelta(minutes=2):
return True
elif datetime.now () - self.updated < timedelta(hours=1):
return False
else:
return True
def findAssistants(self):
h = dict()
for s in self.souts:
if s.assistant is not None and s.assistant != "":
h[s.assistant] = (s.start, s.end)
return h
def findLast(self):
close = None
for s in self.souts:
if (s.state != "En attente" and s.start is not None and (close is None or close.rank < s.rank or close.hour.day > s.hour.day)) and (close is None or s.hour - close.hour < timedelta(seconds=2499)):
close = s
return close
def findAll(self, login):
ss = list()
for s in self.souts:
if s.login == login:
ss.append(s)
return ss
def findClose(self, login):
ss = self.findAll(login)
close = None
for s in ss:
if close is not None:
print (close.hour)
print (s.hour)
if close is None or (close.hour < s.hour and close.hour.day >= datetime.datetime().day):
close = s
return close

View file

@ -1,21 +1,15 @@
# coding=utf-8 # coding=utf-8
import http.client
import time import time
import re import re
import _thread
import threading import threading
from datetime import date from datetime import date
from datetime import datetime from datetime import datetime
from module_state import ModuleState from . import SiteSoutenances
from .SiteSoutenances import SiteSoutenances
from .Delayed import Delayed from .Delayed import Delayed
nemubotversion = 3.0 nemubotversion = 3.2
DELAYED = dict()
def help_tiny(): def help_tiny():
"""Line inserted in the response to the command !help""" """Line inserted in the response to the command !help"""
@ -24,123 +18,32 @@ def help_tiny():
def help_full(): def help_full():
return "!soutenance: gives information about current defenses state\n!soutenance <who>: gives the date of the next defense of /who/.\n!soutenances <who>: gives all defense dates of /who/" return "!soutenance: gives information about current defenses state\n!soutenance <who>: gives the date of the next defense of /who/.\n!soutenances <who>: gives all defense dates of /who/"
datas = None def load(context):
THREAD = None global CONF
wait = list() SiteSoutenances.CONF = CONF
def parseanswer(msg): def ask_soutenance(msg):
global THREAD, wait req = ModuleState("request")
if msg.cmd[0] == "soutenance" or msg.cmd[0] == "soutenances": if len(msg.cmd) > 1:
if THREAD is None: req.setAttribute("user", msg.cmd[1])
THREAD = _thread.start_new_thread (startSoutenance, (msg,))
else: else:
wait.append(msg) req.setAttribute("user", "next")
return True req.setAttribute("server", msg.srv.id)
return False req.setAttribute("channel", msg.channel)
req.setAttribute("sender", msg.sender)
#An instance of this module is already running?
if not DATAS.hasAttribute("_running") or DATAS["_running"].needUpdate():
DATAS.addChild(req)
site = SiteSoutenances.SiteSoutenances(DATAS)
DATAS.setAttribute("_running", site)
def parseask(msg): res = site.run()
if len(DELAYED) > 0 and msg.nick == msg.srv.partner:
treat = False
for part in msg.content.split(';'):
if part is None:
continue
for d in DELAYED.keys():
if DELAYED[d].res is None and part.find(DELAYED[d].name) >= 0:
result = re.match(".* est (.*[^.])\.?", part)
if result is not None:
DELAYED[d].res = result.group(1)
DELAYED[d].evt.set()
return treat
return False
for n in DATAS.getNodes("request"):
DATAS.delChild(n)
def startSoutenance (msg): return res
global datas, THREAD, wait
#Starts by updating datas
if datas is not None:
datas = datas.update ()
if datas is None:
datas = SiteSoutenances(getPage().decode())
if len(msg.cmd) == 1 or msg.cmd[1] == "next":
soutenance = datas.findLast()
if soutenance is None:
msg.send_chn ("Il ne semble pas y avoir de soutenance pour le moment.")
else: else:
if soutenance.start > soutenance.hour: site = DATAS["_running"]
avre = "%s de *retard*"%msg.just_countdown(soutenance.start - soutenance.hour, 4) return site.res_soutenance(req)
else:
avre = "%s *d'avance*"%msg.just_countdown(soutenance.hour - soutenance.start, 4)
msg.send_chn ("Actuellement à la soutenance numéro %d, commencée il y a %s avec %s."%(soutenance.rank, msg.just_countdown(datetime.now () - soutenance.start, 4), avre))
elif msg.cmd[1] == "assistants" or msg.cmd[1] == "assistant" or msg.cmd[1] == "yaka" or msg.cmd[1] == "yakas" or msg.cmd[1] == "acu" or msg.cmd[1] == "acus":
assistants = datas.findAssistants()
if len(assistants) > 0:
msg.send_chn ("Les %d assistants faisant passer les soutenances sont : %s." % (len(assistants), ', '.join(assistants.keys())))
else:
msg.send_chn ("Il ne semble pas y avoir de soutenance pour le moment.")
else:
name = msg.cmd[1]
if msg.cmd[0] == "soutenance":
soutenance = datas.findClose(name)
if soutenance is None:
global DELAYED
DELAYED[msg] = Delayed(name)
msg.srv.send_msg_prtn ("~whois %s" % name)
DELAYED[msg].wait(5)
if DELAYED[msg].res is not None:
name = DELAYED[msg].res
soutenance = datas.findClose(name)
if soutenance is None:
msg.send_chn ("Pas d'horaire de soutenance pour %s."%name)
else:
if soutenance.state == "En cours":
msg.send_chn ("%s est actuellement en soutenance avec %s. Elle était prévue à %s, position %d."%(name, soutenance.assistant, soutenance.hour, soutenance.rank))
elif soutenance.state == "Effectue":
msg.send_chn ("%s a passé sa soutenance avec %s. Elle a duré %s."%(name, soutenance.assistant, msg.just_countdown(soutenance.end - soutenance.start, 4)))
elif soutenance.state == "Retard":
msg.send_chn ("%s était en retard à sa soutenance de %s."%(name, soutenance.hour))
else:
last = datas.findLast()
if last is not None:
if soutenance.hour + (last.start - last.hour) > datetime.now ():
msg.send_chn ("Soutenance de %s : %s, position %d ; estimation du passage : dans %s."%(name, soutenance.hour, soutenance.rank, msg.just_countdown((soutenance.hour - datetime.now ()) + (last.start - last.hour))))
else:
msg.send_chn ("Soutenance de %s : %s, position %d ; passage imminent."%(name, soutenance.hour, soutenance.rank))
else:
msg.send_chn ("Soutenance de %s : %s, position %d."%(name, soutenance.hour, soutenance.rank))
elif msg.cmd[0] == "soutenances":
souts = datas.findAll(name)
if souts is None:
msg.send_snd ("Pas de soutenance prévues pour %s."%name)
else:
first = True
for s in souts:
if first:
msg.send_snd ("Soutenance(s) de %s : - %s (position %d) ;"%(name, s.hour, s.rank))
first = False
else:
msg.send_snd (" %s - %s (position %d) ;"%(len(name)*' ', s.hour, s.rank))
THREAD = None
if len(wait) > 0:
startSoutenance(wait.pop())
def getPage():
conn = http.client.HTTPConnection(CONF.getNode("server")["ip"], timeout=10)
try:
conn.request("GET", CONF.getNode("server")["url"])
res = conn.getresponse()
data = res.read()
except:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return ""
conn.close()
return data