Changes most of nemubot modules to packages

This commit is contained in:
Némunaire 2012-06-29 19:20:29 +02:00
parent 7b7bbd99e5
commit 316e6878ba
13 changed files with 420 additions and 1247 deletions

View file

@ -3,7 +3,6 @@
import re import re
import sys import sys
from datetime import timedelta from datetime import timedelta
from datetime import datetime
from datetime import date from datetime import date
import time import time
import threading import threading
@ -12,6 +11,8 @@ from module_state import ModuleState
nemubotversion = 3.0 nemubotversion = 3.0
from . import Manager
def help_tiny (): def help_tiny ():
"""Line inserted in the response to the command !help""" """Line inserted in the response to the command !help"""
return "events manager" return "events manager"
@ -19,63 +20,23 @@ def help_tiny ():
def help_full (): def help_full ():
return "This module store a lot of events: ny, we, vacs, " + (", ".join(DATAS.index.keys())) + "\n!eventslist: gets list of timer\n!start /something/: launch a timer" return "This module store a lot of events: ny, we, vacs, " + (", ".join(DATAS.index.keys())) + "\n!eventslist: gets list of timer\n!start /something/: launch a timer"
class Manager(threading.Thread):
def __init__(self):
self.stop = False
threading.Thread.__init__(self)
def alertEnd(self, evt):
global newStrendEvt, SRVS, DATAS
#Send the message on each matched servers
for server in SRVS.keys():
if not evt.hasAttribute("server") or server == evt["server"]:
if evt["channel"] == SRVS[server].nick:
SRVS[server].send_msg_usr(evt["proprio"], "%s: %s arrivé à échéance." % (evt["proprio"], evt["name"]))
else:
SRVS[server].send_msg(evt["channel"], "%s: %s arrivé à échéance." % (evt["proprio"], evt["name"]))
DATAS.delChild(DATAS.index[evt["name"]])
save()
newStrendEvt.set()
def run(self):
global DATAS
while not self.stop:
newStrendEvt.clear()
closer = None
#Gets the closer event
for evt in DATAS.index.keys():
if DATAS.index[evt].hasAttribute("end") and (closer is None or DATAS.index[evt].getDate("end") < closer.getDate("end")) and DATAS.index[evt].getDate("end") > datetime.now():
closer = DATAS.index[evt]
if closer is not None and closer.hasAttribute("end"):
#print ("Closer: %s à %s"%(closer.name, closer["end"]))
timeleft = (closer.getDate("end") - datetime.now()).seconds
timer = threading.Timer(timeleft, self.alertEnd, (closer,))
timer.start()
#print ("Start timer (%ds)"%timeleft)
newStrendEvt.wait()
if closer is not None and closer.hasAttribute("end") and closer.getDate("end") > datetime.now():
timer.cancel()
self.threadManager = None
threadManager = None threadManager = None
newStrendEvt = threading.Event()
def load(): def load():
global DATAS, threadManager global DATAS, SRVS, threadManager
#Define the index #Define the index
DATAS.setIndex("name") DATAS.setIndex("name")
#Load the manager #Load the manager
threadManager = Manager() Manager.save = save
threadManager = Manager(DATAS, SRVS)
threadManager.start() threadManager.start()
def close(): def close():
global threadManager global threadManager
if threadManager is not None: if threadManager is not None:
threadManager.stop = True threadManager.stop = True
newStrendEvt.set() Manager.newStrendEvt.set()
def parseanswer(msg): def parseanswer(msg):
@ -122,7 +83,7 @@ def parseanswer(msg):
strnd["end"] = datetime.now() + timedelta(days=int(result.group(1))) strnd["end"] = datetime.now() + timedelta(days=int(result.group(1)))
else: else:
strnd["end"] = datetime.now() + timedelta(seconds=int(result.group(1))) strnd["end"] = datetime.now() + timedelta(seconds=int(result.group(1)))
newStrendEvt.set() Manager.newStrendEvt.set()
msg.send_snd ("%s commencé le %s et se terminera le %s."% (msg.cmd[1], datetime.now(), strnd.getDate("end"))) msg.send_snd ("%s commencé le %s et se terminera le %s."% (msg.cmd[1], datetime.now(), strnd.getDate("end")))
except: except:
msg.send_snd ("Impossible de définir la fin de %s."% (msg.cmd[1])) msg.send_snd ("Impossible de définir la fin de %s."% (msg.cmd[1]))
@ -139,7 +100,7 @@ def parseanswer(msg):
msg.send_chn ("%s a duré %s." % (msg.cmd[1], msg.just_countdown(datetime.now () - DATAS.index[msg.cmd[1]].getDate("start")))) msg.send_chn ("%s a duré %s." % (msg.cmd[1], msg.just_countdown(datetime.now () - DATAS.index[msg.cmd[1]].getDate("start"))))
if DATAS.index[msg.cmd[1]]["proprio"] == msg.sender or (msg.cmd[0] == "forceend" and msg.sender == msg.srv.owner): if DATAS.index[msg.cmd[1]]["proprio"] == msg.sender or (msg.cmd[0] == "forceend" and msg.sender == msg.srv.owner):
DATAS.delChild(DATAS.index[msg.cmd[1]]) DATAS.delChild(DATAS.index[msg.cmd[1]])
newStrendEvt.set() Manager.newStrendEvt.set()
save() save()
else: else:
msg.send_snd ("Vous ne pouvez pas terminer le compteur %s, créé par %s."% (msg.cmd[1], DATAS.index[msg.cmd[1]]["proprio"])) msg.send_snd ("Vous ne pouvez pas terminer le compteur %s, créé par %s."% (msg.cmd[1], DATAS.index[msg.cmd[1]]["proprio"]))

View file

@ -1,418 +0,0 @@
# coding=utf-8
from datetime import datetime
import http.client
import hashlib
import re
import random
import socket
import sys
import threading
import time
from urllib.parse import quote
from module_state import ModuleState
import module_states_file as xmlparser
nemubotversion = 3.0
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "MCQ module, working with http://bot.nemunai.re/"
def help_full ():
return "!qcm [/nbQuest/] [/theme/]"
class QuestionFile:
def __init__(self, filename):
self.questions = xmlparser.parse_file(filename)
self.questions.setIndex("xml:id")
def getQuestion(self, ident):
if ident in self.questions.index:
return Question(self.questions.index[ident])
else:
return None
class Course:
def __init__(self, iden):
global COURSES
if iden in COURSES.index:
self.node = COURSES.index[iden]
else:
self.node = { "code":"N/A", "name":"N/A", "branch":"N/A" }
@property
def id(self):
return self.node["xml:id"]
@property
def code(self):
return self.node["code"]
@property
def name(self):
return self.node["name"]
@property
def branch(self):
return self.node["branch"]
@property
def validated(self):
return int(self.node["validated"]) > 0
class User:
def __init__(self, iden):
global USERS
if iden in USERS.index:
self.node = USERS.index[iden]
else:
self.node = { "username":"N/A", "email":"N/A" }
@property
def id(self):
return self.node["xml:id"]
@property
def username(self):
return self.node["username"]
@property
def email(self):
return self.node["email"]
@property
def validated(self):
return int(self.node["validated"]) > 0
class Question:
def __init__(self, node):
self.node = node
@property
def ident(self):
return self.node["xml:id"]
@property
def id(self):
return self.node["xml:id"]
@property
def question(self):
return self.node["question"]
@property
def course(self):
return Course(self.node["course"])
@property
def answers(self):
return self.node.getNodes("answer")
@property
def validator(self):
return User(self.node["validator"])
@property
def writer(self):
return User(self.node["writer"])
@property
def validated(self):
return self.node["validated"]
@property
def addedtime(self):
return datetime.fromtimestamp(float(self.node["addedtime"]))
@property
def author(self):
return User(self.node["writer"])
def report(self, raison="Sans raison"):
conn = http.client.HTTPConnection(CONF.getNode("server")["url"])
try:
conn.request("GET", "report.php?id=" + hashlib.md5(self.id.encode()).hexdigest() + "&raison=" + quote(raison))
except socket.gaierror:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return False
res = conn.getresponse()
conn.close()
return (res.status == http.client.OK)
@property
def tupleInfo(self):
return (self.author.username, self.validator.username, self.addedtime)
@property
def bestAnswer(self):
best = self.answers[0]
for answer in self.answers:
if best.getInt("score") < answer.getInt("score"):
best = answer
return best["answer"]
def isCorrect(self, msg):
msg = msg.lower().replace(" ", "")
for answer in self.answers:
if msg == answer["answer"].lower().replace(" ", ""):
return True
return False
def getScore(self, msg):
msg = msg.lower().replace(" ", "")
for answer in self.answers:
if msg == answer["answer"].lower().replace(" ", ""):
return answer.getInt("score")
return 0
class Session:
def __init__(self, srv, chan, sender):
self.questions = list()
self.current = -1
self.score = 0
self.good = 0
self.bad = 0
self.trys = 0
self.timer = None
self.server = srv
self.channel = chan
self.sender = sender
def addQuestion(self, ident):
if ident not in self.questions:
self.questions.append(ident)
return True
return False
def next_question(self):
self.trys = 0
self.current += 1
return self.question
@property
def question(self):
if self.current >= 0 and self.current < len(self.questions):
global QUESTIONS
return Question(QUESTIONS.index[self.questions[self.current]])
else:
return None
def askNext(self, bfr = ""):
global SESSIONS
self.timer = None
nextQ = self.next_question()
if nextQ is not None:
if self.channel == "nemubot":
self.server.send_msg_final(self.sender, "%s%s" % (bfr, nextQ.question))
elif self.sender != self.channel:
self.server.send_msg_final(self.channel, "%s: %s%s" % (self.sender, bfr, nextQ.question))
else:
self.server.send_msg_final(self.channel, "%s%s" % (bfr, nextQ.question))
else:
if self.good > 1:
goodS = "s"
else:
goodS = ""
if self.channel == "nemubot":
self.server.send_msg_final(self.sender, "%sFini, tu as donné %d bonne%s réponse%s sur %d questions." % (self.sender, bfr, self.good, goodS, goodS, len(self.questions)))
elif self.sender != self.channel:
self.server.send_msg_final(self.channel, "%s: %sFini, tu as donné %d bonne%s réponse%s sur %d questions." % (self.sender, bfr, self.good, goodS, goodS, len(self.questions)))
else:
self.server.send_msg_final(self.channel, "%sFini, vous avez donné %d bonne%s réponse%s sur %d questions." % (bfr, self.good, goodS, goodS, len(self.questions)))
del SESSIONS[self.sender]
def prepareNext(self, lag = 3):
if self.timer is None:
self.timer = threading.Timer(lag, self.askNext)
self.timer.start()
QUESTIONS = None
COURSES = None
USERS = None
SESSIONS = dict()
def load():
CONF.setIndex("name", "file")
def buildSession(msg, categ = None, nbQuest = 10, channel = False):
global QUESTIONS, COURSES, USERS
if QUESTIONS is None:
QUESTIONS = xmlparser.parse_file(CONF.index["main"]["url"])
QUESTIONS.setIndex("xml:id")
COURSES = xmlparser.parse_file(CONF.index["courses"]["url"])
COURSES.setIndex("xml:id")
USERS = xmlparser.parse_file(CONF.index["users"]["url"])
USERS.setIndex("xml:id")
#Remove no validated questions
keys = list()
for k in QUESTIONS.index.keys():
keys.append(k)
for ques in keys:
if QUESTIONS.index[ques]["validated"] != "1" or QUESTIONS.index[ques]["reported"] == "1":
del QUESTIONS.index[ques]
#Apply filter
QS = list()
if categ is not None and len(categ) > 0:
#Find course id corresponding to categ
courses = list()
for c in COURSES.childs:
if c["code"] in categ:
courses.append(c["xml:id"])
#Keep only questions matching course or branch
for q in QUESTIONS.index.keys():
if (QUESTIONS.index[q]["branch"] is not None and QUESTIONS.index[q]["branch"].find(categ)) or QUESTIONS.index[q]["course"] in courses:
QS.append(q)
else:
for q in QUESTIONS.index.keys():
QS.append(q)
nbQuest = min(nbQuest, len(QS))
if channel:
sess = Session(msg.srv, msg.channel, msg.channel)
else:
sess = Session(msg.srv, msg.channel, msg.sender)
maxQuest = len(QS) - 1
for i in range(0, nbQuest):
while True:
q = QS[random.randint(0, maxQuest)]
if sess.addQuestion(q):
break
if channel:
SESSIONS[msg.channel] = sess
else:
SESSIONS[msg.sender] = sess
def askQuestion(msg, bfr = ""):
SESSIONS[msg.sender].askNext(bfr)
def parseanswer(msg):
global DATAS, SESSIONS, COURSES, QUESTIONS, USERS
if msg.cmd[0] == "qcm" or msg.cmd[0] == "qcmchan" or msg.cmd[0] == "simulateqcm":
if msg.sender in SESSIONS:
if len(msg.cmd) > 1:
if msg.cmd[1] == "stop" or msg.cmd[1] == "end":
sess = SESSIONS[msg.sender]
if sess.good > 1: goodS = "s"
else: goodS = ""
msg.send_chn("%s: Fini, tu as donné %d bonne%s réponse%s sur %d questions." % (msg.sender, sess.good, goodS, goodS, sess.current))
del SESSIONS[msg.sender]
return True
elif msg.cmd[1] == "next" or msg.cmd[1] == "suivant" or msg.cmd[1] == "suivante":
askQuestion(msg)
return True
msg.send_chn("%s: tu as déjà une session de QCM en cours, finis-la avant d'en commencer une nouvelle." % msg.sender)
elif msg.channel in SESSIONS:
if len(msg.cmd) > 1:
if msg.cmd[1] == "stop" or msg.cmd[1] == "end":
sess = SESSIONS[msg.channel]
if sess.good > 1: goodS = "s"
else: goodS = ""
msg.send_chn("Fini, vous avez donné %d bonne%s réponse%s sur %d questions." % (sess.good, goodS, goodS, sess.current))
del SESSIONS[msg.channel]
return True
elif msg.cmd[1] == "next" or msg.cmd[1] == "suivant" or msg.cmd[1] == "suivante":
SESSIONS[msg.channel].prepareNext(1)
return True
else:
nbQuest = 10
filtre = list()
if len(msg.cmd) > 1:
for cmd in msg.cmd[1:]:
try:
tmp = int(cmd)
nbQuest = tmp
except ValueError:
filtre.append(cmd.upper())
if len(filtre) == 0:
filtre = None
if msg.channel in SESSIONS:
msg.send_snd("Il y a deja une session de QCM sur ce chan.")
else:
buildSession(msg, filtre, nbQuest, msg.cmd[0] == "qcmchan")
if msg.cmd[0] == "qcm":
askQuestion(msg)
elif msg.cmd[0] == "qcmchan":
SESSIONS[msg.channel].askNext()
else:
msg.send_chn("QCM de %d questions" % len(SESSIONS[msg.sender].questions))
del SESSIONS[msg.sender]
return True
elif msg.sender in SESSIONS:
if msg.cmd[0] == "info" or msg.cmd[0] == "infoquestion":
msg.send_chn("Cette question a été écrite par %s et validée par %s, le %s" % SESSIONS[msg.sender].question.tupleInfo)
return True
elif msg.cmd[0] == "report" or msg.cmd[0] == "reportquestion":
if len(msg.cmd) == 1:
msg.send_chn("Veuillez indiquer une raison de report")
elif SESSIONS[msg.sender].question.report(' '.join(msg.cmd[1:])):
msg.send_chn("Cette question vient d'être signalée.")
SESSIONS[msg.sender].askNext()
else:
msg.send_chn("Une erreur s'est produite lors du signalement de la question, veuillez recommencer plus tard.")
return True
elif msg.channel in SESSIONS:
if msg.cmd[0] == "info" or msg.cmd[0] == "infoquestion":
msg.send_chn("Cette question a été écrite par %s et validée par %s, le %s" % SESSIONS[msg.channel].question.tupleInfo)
return True
elif msg.cmd[0] == "report" or msg.cmd[0] == "reportquestion":
if len(msg.cmd) == 1:
msg.send_chn("Veuillez indiquer une raison de report")
elif SESSIONS[msg.channel].question.report(' '.join(msg.cmd[1:])):
msg.send_chn("Cette question vient d'être signalée.")
SESSIONS[msg.channel].prepareNext()
else:
msg.send_chn("Une erreur s'est produite lors du signalement de la question, veuillez recommencer plus tard.")
return True
else:
if msg.cmd[0] == "listecours":
if COURSES is None:
msg.send_chn("La liste de cours n'est pas encore construite, lancez un QCM pour la construire.")
else:
lst = ""
for cours in COURSES.getNodes("course"):
lst += cours["code"] + " (" + cours["name"] + "), "
msg.send_chn("Liste des cours existants : " + lst[:len(lst)-2])
elif msg.cmd[0] == "refreshqcm":
QUESTIONS = None
COURSES = None
USERS = None
return False
def parseask(msg):
if msg.sender in SESSIONS:
dest = msg.sender
if SESSIONS[dest].question.isCorrect(msg.content):
SESSIONS[dest].good += 1
SESSIONS[dest].score += SESSIONS[dest].question.getScore(msg.content)
askQuestion(msg, "correct ; ")
else:
SESSIONS[dest].bad += 1
if SESSIONS[dest].trys == 0:
SESSIONS[dest].trys = 1
msg.send_chn("%s: non, essaie encore :p" % msg.sender)
else:
askQuestion(msg, "non, la bonne reponse était : %s ; " % SESSIONS[dest].question.bestAnswer)
return True
elif msg.channel in SESSIONS:
dest = msg.channel
if SESSIONS[dest].question.isCorrect(msg.content):
SESSIONS[dest].good += 1
SESSIONS[dest].score += SESSIONS[dest].question.getScore(msg.content)
msg.send_chn("%s: correct :)" % msg.sender)
SESSIONS[dest].prepareNext()
else:
SESSIONS[dest].bad += 1
msg.send_chn("%s: non, essaie encore :p" % msg.sender)
return True
return False

202
modules/qcm/__init__.py Normal file
View file

@ -0,0 +1,202 @@
# coding=utf-8
from datetime import datetime
import http.client
import re
import random
import sys
import time
nemubotversion = 3.0
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "MCQ module, working with http://bot.nemunai.re/"
def help_full ():
return "!qcm [<nbQuest>] [<theme>]"
from . import Question
from . import Course
from . import Session
def load():
CONF.setIndex("name", "file")
def buildSession(msg, categ = None, nbQuest = 10, channel = False):
if Question.QUESTIONS is None:
Question.QUESTIONS = xmlparser.parse_file(CONF.index["main"]["url"])
Question.QUESTIONS.setIndex("xml:id")
Course.COURSES = xmlparser.parse_file(CONF.index["courses"]["url"])
Course.COURSES.setIndex("xml:id")
User.USERS = xmlparser.parse_file(CONF.index["users"]["url"])
User.USERS.setIndex("xml:id")
#Remove no validated questions
keys = list()
for k in Question.QUESTIONS.index.keys():
keys.append(k)
for ques in keys:
if Question.QUESTIONS.index[ques]["validated"] != "1" or Question.QUESTIONS.index[ques]["reported"] == "1":
del Question.QUESTIONS.index[ques]
#Apply filter
QS = list()
if categ is not None and len(categ) > 0:
#Find course id corresponding to categ
courses = list()
for c in Course.COURSES.childs:
if c["code"] in categ:
courses.append(c["xml:id"])
#Keep only questions matching course or branch
for q in Question.QUESTIONS.index.keys():
if (Question.QUESTIONS.index[q]["branch"] is not None and Question.QUESTIONS.index[q]["branch"].find(categ)) or Question.QUESTIONS.index[q]["course"] in courses:
QS.append(q)
else:
for q in Question.QUESTIONS.index.keys():
QS.append(q)
nbQuest = min(nbQuest, len(QS))
if channel:
sess = Session.Session(msg.srv, msg.channel, msg.channel)
else:
sess = Session.Session(msg.srv, msg.channel, msg.sender)
maxQuest = len(QS) - 1
for i in range(0, nbQuest):
while True:
q = QS[random.randint(0, maxQuest)]
if sess.addQuestion(q):
break
if channel:
Session.SESSIONS[msg.channel] = sess
else:
Session.SESSIONS[msg.sender] = sess
def askQuestion(msg, bfr = ""):
Session.SESSIONS[msg.sender].askNext(bfr)
def parseanswer(msg):
global DATAS
if msg.cmd[0] == "qcm" or msg.cmd[0] == "qcmchan" or msg.cmd[0] == "simulateqcm":
if msg.sender in Session.SESSIONS:
if len(msg.cmd) > 1:
if msg.cmd[1] == "stop" or msg.cmd[1] == "end":
sess = Session.SESSIONS[msg.sender]
if sess.good > 1: goodS = "s"
else: goodS = ""
msg.send_chn("%s: Fini, tu as donné %d bonne%s réponse%s sur %d questions." % (msg.sender, sess.good, goodS, goodS, sess.current))
del Session.SESSIONS[msg.sender]
return True
elif msg.cmd[1] == "next" or msg.cmd[1] == "suivant" or msg.cmd[1] == "suivante":
askQuestion(msg)
return True
msg.send_chn("%s: tu as déjà une session de QCM en cours, finis-la avant d'en commencer une nouvelle." % msg.sender)
elif msg.channel in Session.SESSIONS:
if len(msg.cmd) > 1:
if msg.cmd[1] == "stop" or msg.cmd[1] == "end":
sess = Session.SESSIONS[msg.channel]
if sess.good > 1: goodS = "s"
else: goodS = ""
msg.send_chn("Fini, vous avez donné %d bonne%s réponse%s sur %d questions." % (sess.good, goodS, goodS, sess.current))
del Session.SESSIONS[msg.channel]
return True
elif msg.cmd[1] == "next" or msg.cmd[1] == "suivant" or msg.cmd[1] == "suivante":
Session.SESSIONS[msg.channel].prepareNext(1)
return True
else:
nbQuest = 10
filtre = list()
if len(msg.cmd) > 1:
for cmd in msg.cmd[1:]:
try:
tmp = int(cmd)
nbQuest = tmp
except ValueError:
filtre.append(cmd.upper())
if len(filtre) == 0:
filtre = None
if msg.channel in Session.SESSIONS:
msg.send_snd("Il y a deja une session de QCM sur ce chan.")
else:
buildSession(msg, filtre, nbQuest, msg.cmd[0] == "qcmchan")
if msg.cmd[0] == "qcm":
askQuestion(msg)
elif msg.cmd[0] == "qcmchan":
Session.SESSIONS[msg.channel].askNext()
else:
msg.send_chn("QCM de %d questions" % len(Session.SESSIONS[msg.sender].questions))
del Session.SESSIONS[msg.sender]
return True
elif msg.sender in Session.SESSIONS:
if msg.cmd[0] == "info" or msg.cmd[0] == "infoquestion":
msg.send_chn("Cette question a été écrite par %s et validée par %s, le %s" % Session.SESSIONS[msg.sender].question.tupleInfo)
return True
elif msg.cmd[0] == "report" or msg.cmd[0] == "reportquestion":
if len(msg.cmd) == 1:
msg.send_chn("Veuillez indiquer une raison de report")
elif Session.SESSIONS[msg.sender].question.report(' '.join(msg.cmd[1:])):
msg.send_chn("Cette question vient d'être signalée.")
Session.SESSIONS[msg.sender].askNext()
else:
msg.send_chn("Une erreur s'est produite lors du signalement de la question, veuillez recommencer plus tard.")
return True
elif msg.channel in Session.SESSIONS:
if msg.cmd[0] == "info" or msg.cmd[0] == "infoquestion":
msg.send_chn("Cette question a été écrite par %s et validée par %s, le %s" % Session.SESSIONS[msg.channel].question.tupleInfo)
return True
elif msg.cmd[0] == "report" or msg.cmd[0] == "reportquestion":
if len(msg.cmd) == 1:
msg.send_chn("Veuillez indiquer une raison de report")
elif Session.SESSIONS[msg.channel].question.report(' '.join(msg.cmd[1:])):
msg.send_chn("Cette question vient d'être signalée.")
Session.SESSIONS[msg.channel].prepareNext()
else:
msg.send_chn("Une erreur s'est produite lors du signalement de la question, veuillez recommencer plus tard.")
return True
else:
if msg.cmd[0] == "listecours":
if Course.COURSES is None:
msg.send_chn("La liste de cours n'est pas encore construite, lancez un QCM pour la construire.")
else:
lst = ""
for cours in Course.COURSES.getNodes("course"):
lst += cours["code"] + " (" + cours["name"] + "), "
msg.send_chn("Liste des cours existants : " + lst[:len(lst)-2])
elif msg.cmd[0] == "refreshqcm":
Question.QUESTIONS = None
Course.COURSES = None
User.USERS = None
return False
def parseask(msg):
if msg.sender in Session.SESSIONS:
dest = msg.sender
if Session.SESSIONS[dest].question.isCorrect(msg.content):
Session.SESSIONS[dest].good += 1
Session.SESSIONS[dest].score += Session.SESSIONS[dest].question.getScore(msg.content)
askQuestion(msg, "correct ; ")
else:
Session.SESSIONS[dest].bad += 1
if Session.SESSIONS[dest].trys == 0:
Session.SESSIONS[dest].trys = 1
msg.send_chn("%s: non, essaie encore :p" % msg.sender)
else:
askQuestion(msg, "non, la bonne reponse était : %s ; " % Session.SESSIONS[dest].question.bestAnswer)
return True
elif msg.channel in Session.SESSIONS:
dest = msg.channel
if Session.SESSIONS[dest].question.isCorrect(msg.content):
Session.SESSIONS[dest].good += 1
Session.SESSIONS[dest].score += Session.SESSIONS[dest].question.getScore(msg.content)
msg.send_chn("%s: correct :)" % msg.sender)
Session.SESSIONS[dest].prepareNext()
else:
Session.SESSIONS[dest].bad += 1
msg.send_chn("%s: non, essaie encore :p" % msg.sender)
return True
return False

View file

@ -1,19 +1,12 @@
# coding=utf-8 # coding=utf-8
import re import re
import time
import random
import sys
import threading
from datetime import timedelta
from datetime import datetime from datetime import datetime
from datetime import date
from module_state import ModuleState
from wrapper import Wrapper
nemubotversion = 3.0 nemubotversion = 3.0
from . import GameUpdater
channels = "#nemutest #42sh #ykar #epitagueule" channels = "#nemutest #42sh #ykar #epitagueule"
LASTSEEN = dict () LASTSEEN = dict ()
temps = dict () temps = dict ()
@ -21,9 +14,14 @@ temps = dict ()
SCORES = None SCORES = None
def load(): def load():
global DATAS, SCORES global DATAS, SCORES, CONF
DATAS.setIndex("name", "player") DATAS.setIndex("name", "player")
SCORES = QDWrapper() SCORES = QDWrapper(DATAS)
GameUpdater.SCORES = SCORES
GameUpdater.CONF = CONF
GameUpdater.save = save
GameUpdater.getUser = getUser
def help_tiny (): def help_tiny ():
"""Line inserted in the response to the command !help""" """Line inserted in the response to the command !help"""
@ -33,150 +31,6 @@ def help_full ():
return "!42: display scores\n!42 help: display the performed calculate\n!42 manche: display information about current round\n!42 /who/: show the /who/'s scores" return "!42: display scores\n!42 help: display the performed calculate\n!42 manche: display information about current round\n!42 /who/: show the /who/'s scores"
class QDWrapper(Wrapper):
def __init__(self):
global DATAS
Wrapper.__init__(self)
self.DATAS = DATAS
self.stateName = "player"
self.attName = "name"
def __getitem__(self, i):
if i in self.cache:
return self.cache[i]
else:
sc = Score()
sc.parse(Wrapper.__getitem__(self, i))
self.cache[i] = sc
return sc
class Score:
"""Manage the user's scores"""
def __init__(self):
#FourtyTwo
self.ftt = 0
#TwentyThree
self.twt = 0
self.pi = 0
self.notfound = 0
self.tententen = 0
self.leet = 0
self.great = 0
self.bad = 0
self.triche = 0
self.last = None
self.changed = False
def parse(self, item):
self.ftt = item.getInt("fourtytwo")
self.twt = item.getInt("twentythree")
self.pi = item.getInt("pi")
self.notfound = item.getInt("notfound")
self.tententen = item.getInt("tententen")
self.leet = item.getInt("leet")
self.great = item.getInt("great")
self.bad = item.getInt("bad")
self.triche = item.getInt("triche")
def save(self, state):
state.setAttribute("fourtytwo", self.ftt)
state.setAttribute("twentythree", self.twt)
state.setAttribute("pi", self.pi)
state.setAttribute("notfound", self.notfound)
state.setAttribute("tententen", self.tententen)
state.setAttribute("leet", self.leet)
state.setAttribute("great", self.great)
state.setAttribute("bad", self.bad)
state.setAttribute("triche", self.triche)
def merge(self, other):
self.ftt += other.ftt
self.twt += other.twt
self.pi += other.pi
self.notfound += other.notfound
self.tententen += other.tententen
self.leet += other.leet
self.great += other.great
self.bad += other.bad
self.triche += other.triche
def newWinner(self):
self.ftt = 0
self.twt = 0
self.pi = 1
self.notfound = 1
self.tententen = 0
self.leet = 1
self.great = -1
self.bad = -4
self.triche = 0
def isWinner(self):
return self.great >= 42
def playFtt(self):
if self.canPlay():
self.ftt += 1
def playTwt(self):
if self.canPlay():
self.twt += 1
def playSuite(self):
self.canPlay()
self.twt += 1
self.great += 1
def playPi(self):
if self.canPlay():
self.pi += 1
def playNotfound(self):
if self.canPlay():
self.notfound += 1
def playTen(self):
if self.canPlay():
self.tententen += 1
def playLeet(self):
if self.canPlay():
self.leet += 1
def playGreat(self):
if self.canPlay():
self.great += 1
def playBad(self):
if self.canPlay():
self.bad += 1
self.great += 1
def playTriche(self):
self.triche += 1
def oupsTriche(self):
self.triche -= 1
def bonusQuestion(self):
return
def toTuple(self):
return (self.ftt, self.twt, self.pi, self.notfound, self.tententen, self.leet, self.great, self.bad, self.triche)
def canPlay(self):
ret = self.last == None or self.last.minute != datetime.now().minute or self.last.hour != datetime.now().hour or self.last.day != datetime.now().day
self.changed = self.changed or ret
return ret
def hasChanged(self):
if self.changed:
self.changed = False
self.last = datetime.now()
return True
else:
return False
def score(self):
return (self.ftt * 2 + self.great * 5 + self.leet * 13.37 + (self.pi + 1) * 3.1415 * (self.notfound + 1) + self.tententen * 10 + self.twt - (self.bad + 1) * 10 * (self.triche * 5 + 1) + 7)
def details(self):
return "42: %d, 23: %d, leet: %d, pi: %d, 404: %d, 10: %d, great: %d, bad: %d, triche: %d = %d."%(self.ftt, self.twt, self.leet, self.pi, self.notfound, self.tententen, self.great, self.bad, self.triche, self.score())
def rev (tupl):
(k, v) = tupl
return (v.score(), k)
def parseanswer (msg): def parseanswer (msg):
if msg.cmd[0] == "42" or msg.cmd[0] == "score" or msg.cmd[0] == "scores": if msg.cmd[0] == "42" or msg.cmd[0] == "score" or msg.cmd[0] == "scores":
global SCORES global SCORES
@ -261,14 +115,20 @@ def win(msg):
def parseask (msg): def parseask (msg):
if len(DELAYED) > 0: if len(GameUpdater.DELAYED) > 0:
if msg.sender in DELAYED: if msg.sender in GameUpdater.DELAYED:
DELAYED[msg.sender].msg = msg.content GameUpdater.DELAYED[msg.sender].msg = msg.content
DELAYED[msg.sender].delayEvnt.set() GameUpdater.DELAYED[msg.sender].delayEvnt.set()
return True return True
return False return False
def rev (tupl):
(k, v) = tupl
return (v.score(), k)
def getUser(name): def getUser(name):
global SCORES global SCORES
if name not in SCORES: if name not in SCORES:
@ -277,7 +137,7 @@ def getUser(name):
def parselisten (msg): def parselisten (msg):
if len(DELAYED) > 0 and msg.sender in DELAYED and DELAYED[msg.sender].good(msg.content): if len(GameUpdater.DELAYED) > 0 and msg.sender in GameUpdater.DELAYED and GameUpdater.DELAYED[msg.sender].good(msg.content):
msg.send_chn("%s: n'oublie pas le nemubot: devant ta réponse pour qu'elle soit prise en compte !" % msg.sender) msg.send_chn("%s: n'oublie pas le nemubot: devant ta réponse pour qu'elle soit prise en compte !" % msg.sender)
bfrseen = None bfrseen = None
@ -285,8 +145,8 @@ def parselisten (msg):
bfrseen = LASTSEEN[msg.realname] bfrseen = LASTSEEN[msg.realname]
LASTSEEN[msg.realname] = datetime.now() LASTSEEN[msg.realname] = datetime.now()
# if msg.channel == "#nemutest" and msg.sender not in DELAYED: # if msg.channel == "#nemutest" and msg.sender not in GameUpdater.DELAYED:
if msg.channel != "#nemutest" and msg.sender not in DELAYED: if msg.channel != "#nemutest" and msg.sender not in GameUpdater.DELAYED:
if re.match("^(42|quarante[- ]?deux).{,2}$", msg.content.strip().lower()): if re.match("^(42|quarante[- ]?deux).{,2}$", msg.content.strip().lower()):
if msg.time.minute == 10 and msg.time.second == 10 and msg.time.hour == 10: if msg.time.minute == 10 and msg.time.second == 10 and msg.time.hour == 10:
@ -355,77 +215,3 @@ def parselisten (msg):
return True return True
return False return False
DELAYED = dict()
class DelayedTuple:
def __init__(self, regexp, great):
self.delayEvnt = threading.Event()
self.msg = None
self.regexp = regexp
self.great = great
def triche(self, res):
if res is not None:
return re.match(".*" + self.regexp + ".*", res.lower() + " ") is None
else:
return True
def perfect(self, res):
if res is not None:
return re.match(".*" + self.great + ".*", res.lower() + " ") is not None
else:
return False
def wait(self, timeout):
self.delayEvnt.wait(timeout)
LASTQUESTION = 99999
class GameUpdater(threading.Thread):
def __init__(self, msg, bfrseen):
self.msg = msg
self.bfrseen = bfrseen
threading.Thread.__init__(self)
def run(self):
global DELAYED, LASTQUESTION
if self.bfrseen is not None:
seen = datetime.now() - self.bfrseen
rnd = random.randint(0, int(seen.seconds/90))
else:
rnd = 1
if rnd != 0:
QUESTIONS = CONF.getNodes("question")
if self.msg.channel == "#nemutest":
quest = 9
else:
if LASTQUESTION >= len(QUESTIONS):
random.shuffle(QUESTIONS)
LASTQUESTION = 0
quest = LASTQUESTION
LASTQUESTION += 1
question = QUESTIONS[quest]["question"]
regexp = QUESTIONS[quest]["regexp"]
great = QUESTIONS[quest]["great"]
self.msg.send_chn("%s: %s" % (self.msg.sender, question))
DELAYED[self.msg.sender] = DelayedTuple(regexp, great)
DELAYED[self.msg.sender].wait(20)
if DELAYED[self.msg.sender].triche(DELAYED[self.msg.sender].msg):
getUser(self.msg.sender).playTriche()
self.msg.send_chn("%s: Tricheur !" % self.msg.sender)
elif DELAYED[self.msg.sender].perfect(DELAYED[self.msg.sender].msg):
if random.randint(0, 10) == 1:
getUser(self.msg.sender).bonusQuestion()
self.msg.send_chn("%s: Correct !" % self.msg.sender)
else:
self.msg.send_chn("%s: J'accepte" % self.msg.sender)
del DELAYED[self.msg.sender]
SCORES.save(self.msg.sender)
save()

View file

@ -7,137 +7,28 @@ import _thread
import threading import threading
from datetime import date from datetime import date
from datetime import datetime from datetime import datetime
from datetime import timedelta
from module_state import ModuleState from module_state import ModuleState
from .SiteSoutenances import SiteSoutenances
from .Delayed import Delayed
nemubotversion = 3.0 nemubotversion = 3.0
def getPage ():
conn = http.client.HTTPSConnection(CONF.getNode("server")["ip"])
conn.request("GET", CONF.getNode("server")["url"])
res = conn.getresponse()
data = res.read()
conn.close()
return data
class Soutenance:
def __init__(self):
self.hour = None
self.rank = 0
self.login = None
self.state = None
self.assistant = None
self.start = None
self.end = None
DELAYED = dict() DELAYED = dict()
class Delayed: def help_tiny():
def __init__(self, name):
self.name = name
self.res = None
self.evt = threading.Event()
def wait(self, timeout):
self.evt.clear()
self.evt.wait(timeout)
class SiteSoutenances:
def __init__(self, page):
save = False
self.souts = list()
self.updated = datetime.now ()
last = None
for line in page.split("\n"):
if re.match("</tr>", line) is not None:
save = False
elif re.match("<tr.*>", line) is not None:
save = True
last = Soutenance()
self.souts.append(last)
elif save:
result = re.match("<td[^>]+>(.*)</td>", line)
if last.hour is None:
try:
last.hour = datetime.fromtimestamp (time.mktime (time.strptime (result.group(1), "%Y-%m-%d %H:%M")))
except ValueError:
continue
elif last.rank == 0:
last.rank = int (result.group(1))
elif last.login == None:
last.login = result.group(1)
elif last.state == None:
last.state = result.group(1)
elif last.assistant == None:
last.assistant = result.group(1)
elif last.start == None:
try:
last.start = datetime.fromtimestamp (time.mktime (time.strptime (result.group(1), "%Y-%m-%d %H:%M")))
except ValueError:
last.start = None
elif last.end == None:
try:
last.end = datetime.fromtimestamp (time.mktime (time.strptime (result.group(1), "%Y-%m-%d %H:%M")))
except ValueError:
last.end = None
def update(self):
if self.findLast() is not None and datetime.now () - self.updated > timedelta(minutes=2):
return None
elif datetime.now () - self.updated < timedelta(hours=1):
return self
else:
return None
def findAssistants(self):
h = {}
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
def help_tiny ():
"""Line inserted in the response to the command !help""" """Line inserted in the response to the command !help"""
return "EPITA ING1 defenses module" return "EPITA ING1 defenses module"
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 datas = None
THREAD = None THREAD = None
wait = list() wait = list()
def parseanswer (msg): def parseanswer(msg):
global THREAD, wait global THREAD, wait
if msg.cmd[0] == "soutenance" or msg.cmd[0] == "soutenances": if msg.cmd[0] == "soutenance" or msg.cmd[0] == "soutenances":
if THREAD is None: if THREAD is None:
@ -148,6 +39,22 @@ def parseanswer (msg):
return False return False
def parseask(msg):
if len(DELAYED) > 0 and msg.sender == 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
def startSoutenance (msg): def startSoutenance (msg):
global datas, THREAD, wait global datas, THREAD, wait
@ -224,17 +131,16 @@ def startSoutenance (msg):
startSoutenance(wait.pop()) startSoutenance(wait.pop())
def parseask (msg): def getPage():
if len(DELAYED) > 0 and msg.sender == msg.srv.partner: conn = http.client.HTTPConnection(CONF.getNode("server")["ip"])
treat = False try:
for part in msg.content.split(';'): conn.request("GET", CONF.getNode("server")["url"])
if part is None:
continue res = conn.getresponse()
for d in DELAYED.keys(): data = res.read()
if DELAYED[d].res is None and part.find(DELAYED[d].name) >= 0: except:
result = re.match(".* est (.*[^.])\.?", part) print ("[%s] impossible de récupérer la page %s."%(s, p))
if result is not None: return ""
DELAYED[d].res = result.group(1)
DELAYED[d].evt.set() conn.close()
return treat return data
return False

View file

@ -1,206 +0,0 @@
# coding=utf-8
from datetime import timedelta
from datetime import datetime
from datetime import date
import http.client
import hashlib
import sys
import traceback
import socket
import time
import base64
import threading
from urllib.parse import unquote
from module_state import ModuleState
nemubotversion = 3.0
import atom
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "Alert on changes on websites"
def help_full ():
return "This module is autonomous you can't interract with it."
WATCHER = None
def load():
global WATCHER, DATAS
#Load the watcher
WATCHER = Watcher()
for site in DATAS.getNodes("watch"):
s = Site(site)
WATCHER.addServer(s)
WATCHER.start()
def close():
global WATCHER
if WATCHER is not None:
WATCHER.stop = True
WATCHER.newSrv.set()
class Watcher(threading.Thread):
def __init__(self):
self.servers = list()
self.stop = False
self.newSrv = threading.Event()
threading.Thread.__init__(self)
def addServer(self, server):
self.servers.append(server)
self.newSrv.set()
def check(self, closer):
closer.check()
self.newSrv.set()
def run(self):
while not self.stop:
self.newSrv.clear()
closer = None
#Gets the closer server update
for server in self.servers:
if server.update < datetime.now():
#print ("Closer now: %s à %s"%(server.url, server.update))
self.check(server)
elif closer is None or server.update < closer.update:
closer = server
if closer is not None:
#print ("Closer: %s à %s"%(closer.url, closer.update))
timeleft = (closer.update - datetime.now()).seconds
timer = threading.Timer(timeleft, self.check, (closer,))
timer.start()
#print ("Start timer (%ds)"%timeleft)
self.newSrv.wait()
if closer is not None and closer.update is not None and closer.update > datetime.now():
timer.cancel()
def stop(self):
self.stop = True
self.newSrv.set()
class Site:
def __init__(self, item):
self.server = item.getAttribute("server")
self.page = item.getAttribute("page")
if len(self.page) <= 0 or self.page[0] != "/":
self.page = "/" + self.page
if item.hasAttribute("type"):
self.type = item.getAttribute("type")
else:
self.type = "hash"
self.message = item.getAttribute("message")
if item.hasAttribute("time"):
self.updateTime = item.getInt("time")
else:
self.updateTime = 60
self.lastChange = datetime.now()
self.lastpage = None
self.channels = list()
for channel in item.getNodes('channel'):
self.channels.append(channel.getAttribute("name"))
self.categories = dict()
for category in item.getNodes('category'):
self.categories[category.getAttribute("term")] = category.getAttribute("part")
@property
def update(self):
if self.lastpage is None:
return self.lastChange
else:
return self.lastChange + timedelta(seconds=self.updateTime)
@property
def url(self):
return self.server + self.page
def send_message (self, msg):
global SRVS
if len(self.channels) > 0:
for server in SRVS.keys():
for chan in self.channels:
SRVS[server].send_msg (chan, msg)
else:
for server in SRVS.keys():
SRVS[server].send_global (msg)
def treat_atom (self, content):
change=False
f = atom.Atom (content)
if self.lastpage is not None:
diff = self.lastpage.diff (f)
if len(diff) > 0:
print ("[%s] Page differ!"%self.server)
diff.reverse()
for d in diff:
if self.message.count("%s") == 2 and len(self.categories) > 0:
if d.category is None or d.category not in self.categories:
messageI = self.message % (self.categories[""], "%s")
else:
messageI = self.message % (self.categories[d.category], "%s")
self.send_message (messageI % unquote (d.link))
elif self.message.count("%s") == 2:
if f.id == youtube.idAtom:
youtube.send_global (d.link2, self.message % (d.title, unquote (d.link)))
else:
self.send_message (self.message % (d.title, unquote (d.link)))
elif self.message.count("%s") == 1:
self.send_message(self.message % unquote (d.title))
else:
self.send_message(self.message)
change=True
return (f, change)
def check (self):
try:
#print ("Check %s"%(self.url))
(status, content) = getPage(self.server, self.page)
if content is None:
return
if self.type == "atom":
(self.lastpage, change) = self.treat_atom (content)
else:
hash = hashlib.sha224(content).hexdigest()
if hash != self.lastpage:
if self.lastpage is not None:
self.send_message (self.message)
self.lastpage = hash
self.lastChange = datetime.now()
# if self.updateTime < 10:
# self.updateTime = 10
# if self.updateTime > 400:
# self.updateTime = 400
except:
print ("Une erreur est survenue lors de la récupération de la page " + self.server + "/" + self.page)
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
self.updateTime *= 2
def getPage(s, p):
conn = http.client.HTTPConnection(s)
try:
conn.request("GET", p)
res = conn.getresponse()
data = res.read()
except socket.gaierror:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return (None, None)
conn.close()
return (res.status, data)

View file

@ -0,0 +1,32 @@
# coding=utf-8
nemubotversion = 3.0
from .Watcher import Watcher
from .Site import Site
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "Alert on changes on websites"
def help_full ():
return "This module is autonomous you can't interract with it."
WATCHER = None
def load():
global WATCHER, DATAS
#Load the watcher
WATCHER = Watcher()
for site in DATAS.getNodes("watch"):
s = Site(site)
WATCHER.addServer(s)
WATCHER.start()
def close():
global WATCHER
if WATCHER is not None:
WATCHER.stop = True
WATCHER.newSrv.set()

View file

@ -13,102 +13,25 @@ from urllib.parse import unquote
from module_state import ModuleState from module_state import ModuleState
from . import User
from .UpdatedStorage import UpdatedStorage
from .Delayed import Delayed
nemubotversion = 3.0 nemubotversion = 3.0
THREAD = None THREAD = None
search = list() search = list()
class UpdatedStorage:
def __init__(self):
sock = connect_to_ns(CONF.getNode("server")["url"],
CONF.getNode("server").getInt("port"))
self.users = dict()
if sock != None:
users = list_users(sock)
if users is not None:
for l in users:
u = User(l)
if u.login not in self.users:
self.users[u.login] = list()
self.users[u.login].append(u)
self.lastUpdate = datetime.now ()
else:
self.users = None
sock.close()
else:
self.users = None
def update(self):
if datetime.now () - self.lastUpdate < timedelta(minutes=10):
return self
else:
return None
class User(object):
def __init__(self, line):
fields = line.split()
self.login = fields[1]
self.ip = fields[2]
self.location = fields[8]
self.promo = fields[9]
@property
def sm(self):
for sm in CONF.getNodes("sm"):
if self.ip.startswith(sm["ip"]):
return sm["name"]
return None
@property
def poste(self):
if self.sm is None:
if self.ip.startswith('10.'):
return 'quelque part sur le PIE (%s)'%self.ip
else:
return "chez lui"
else:
if self.ip.startswith('10.247') or self.ip.startswith('10.248') or self.ip.startswith('10.249') or self.ip.startswith('10.250'):
return "en " + self.sm + " rangée " + self.ip.split('.')[2] + " poste " + self.ip.split('.')[3]
else:
return "en " + self.sm
def __cmp__(self, other):
return cmp(self.login, other.login)
def __hash__(self):
return hash(self.login)
def connect_to_ns(server, port):
try:
s = socket.socket()
s.settimeout(3)
s.connect((server, port))
except socket.error:
return None
s.recv(8192)
return s
def list_users(sock):
try:
sock.send('list_users\n'.encode())
buf = ''
while True:
tmp = sock.recv(8192).decode()
buf += tmp
if '\nrep 002' in tmp or tmp == '':
break
return buf.split('\n')[:-2]
except socket.error:
return None
def help_tiny (): def help_tiny ():
"""Line inserted in the response to the command !help""" """Line inserted in the response to the command !help"""
return "Find a user on the PIE" return "Find a user on the PIE"
def help_full (): def help_full ():
return "!whereis /who/: gives the position of /who/.\n!whereare /who/ [/other who/ ...]: gives the position of /who/." return "!whereis <who>: gives the position of /who/.\n!whereare <who> [<other who> ...]: gives the position of these <who>.\n!peoplein <sm>: gives the number of people in this /sm/.\n!ip <who>: gets the IP adress of /who/.\n!whoison <location>: gives the name or the number (if > 15) of people at this /location/.\n!whoisin <sm>: gives the name or the number of people in this /sm/"
def load():
global CONF
User.CONF = CONF
datas = None datas = None
@ -117,7 +40,7 @@ def startWhereis(msg):
if datas is not None: if datas is not None:
datas = datas.update () datas = datas.update ()
if datas is None: if datas is None:
datas = UpdatedStorage() datas = UpdatedStorage(CONF.getNode("server")["url"], CONF.getNode("server").getInt("port"))
if datas is None or datas.users is None: if datas is None or datas.users is None:
msg.send_chn("Hmm c'est embarassant, serait-ce la fin du monde ou juste netsoul qui est mort ?") msg.send_chn("Hmm c'est embarassant, serait-ce la fin du monde ou juste netsoul qui est mort ?")
return return
@ -178,10 +101,6 @@ def whoison(msg):
DELAYED = dict() DELAYED = dict()
delayEvnt = threading.Event() delayEvnt = threading.Event()
class Delayed:
def __init__(self):
self.names = dict()
def whereis_msg(msg): def whereis_msg(msg):
names = list() names = list()
for name in msg.cmd: for name in msg.cmd:

View file

@ -1,2 +0,0 @@
<?xml version="1.0" ?>
<nemubotmodule name="ycc" />

View file

@ -3,7 +3,8 @@
import http.client import http.client
import re import re
import sys import sys
import threading
from .Tinyfier import Tinyfier
nemubotversion = 3.0 nemubotversion = 3.0
@ -15,24 +16,6 @@ def help_full ():
return "TODO" return "TODO"
class Tinyfier(threading.Thread):
def __init__(self, url, msg):
self.url = url
self.msg = msg
threading.Thread.__init__(self)
def run(self):
(status, page) = getPage("ycc.fr", "/redirection/create/" + self.url)
if status == http.client.OK and len(page) < 100:
srv = re.match(".*((ht|f)tps?://|www.)([^/ ]+).*", self.url)
if srv is None:
self.msg.send_chn("Mauvaise URL : %s" % (self.url))
else:
self.msg.send_chn("URL pour %s : %s" % (srv.group(3), page.decode()))
else:
print ("ERROR: ycc.fr seem down?")
self.msg.send_chn("La situation est embarassante, il semblerait que YCC soit down :(")
def parseanswer(msg): def parseanswer(msg):
global LAST_URLS global LAST_URLS
if msg.cmd[0] == "ycc": if msg.cmd[0] == "ycc":
@ -42,7 +25,7 @@ def parseanswer(msg):
t = Tinyfier(url, msg) t = Tinyfier(url, msg)
t.start() t.start()
else: else:
msg.send_chn("%s: je n'ai pas d'autre URL a reduire" % msg.sender) msg.send_chn("%s: je n'ai pas d'autre URL reduire" % msg.sender)
else: else:
if len(msg.cmd) < 6: if len(msg.cmd) < 6:
for url in msg.cmd[1:]: for url in msg.cmd[1:]:
@ -66,17 +49,3 @@ def parselisten (msg):
LAST_URLS[msg.channel] = list(res.group(1)) LAST_URLS[msg.channel] = list(res.group(1))
return True return True
return False return False
def getPage(s, p):
conn = http.client.HTTPConnection(s)
try:
conn.request("GET", p)
except socket.gaierror:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return None
res = conn.getresponse()
data = res.read()
conn.close()
return (res.status, data)

View file

@ -10,9 +10,19 @@ servers = dict()
prompt = __import__ ("prompt") prompt = __import__ ("prompt")
#Add modules dir path
if os.path.isdir("./modules/"):
modules_path = os.path.realpath(os.path.abspath("./modules/"))
if modules_path not in sys.path:
sys.path.insert(0, modules_path)
#Load given files
if len(sys.argv) >= 2: if len(sys.argv) >= 2:
for arg in sys.argv[1:]: for arg in sys.argv[1:]:
prompt.load_file(arg, servers) if os.path.isfile(arg):
prompt.load_file(arg, servers)
elif os.path.isdir(arg):
sys.path.insert(1, arg)
print ("Nemubot ready, my PID is %i!" % (os.getpid())) print ("Nemubot ready, my PID is %i!" % (os.getpid()))
while prompt.launch(servers): while prompt.launch(servers):

178
prompt.py
View file

@ -1,4 +1,5 @@
import imp import imp
import os
import shlex import shlex
import sys import sys
import traceback import traceback
@ -92,12 +93,12 @@ def launch(servers):
# # # #
########################## ##########################
def mod_save(mod, datas_path, config): def mod_save(mod, datas_path):
mod.DATAS.save(datas_path + "/" + config["name"] + ".xml") mod.DATAS.save(datas_path + "/" + mod.name + ".xml")
mod.print ("Saving!") mod.print ("Saving!")
def mod_has_access(mod, config, msg): def mod_has_access(mod, config, msg):
if config.hasNode("channel"): if config is not None and config.hasNode("channel"):
for chan in config.getChilds("channel"): for chan in config.getChilds("channel"):
if (chan["server"] is None or chan["server"] == msg.srv.id) and (chan["channel"] is None or chan["channel"] == msg.channel): if (chan["server"] is None or chan["server"] == msg.srv.id) and (chan["channel"] is None or chan["channel"] == msg.channel):
return True return True
@ -111,93 +112,106 @@ def mod_has_access(mod, config, msg):
# # # #
########################## ##########################
def load_module_from_name(name, servers, config=None):
try:
#Import the module code
mod = __import__(name)
try:
if mod.nemubotversion < 3.0:
print (" Module `%s' is not compatible with this version." % name)
return
#Set module common functions and datas
mod.name = name
mod.print = lambda msg: print("[%s] %s"%(mod.name, msg))
mod.DATAS = xmlparser.parse_file(datas_path + "/" + name + ".xml")
mod.CONF = config
mod.SRVS = servers
mod.has_access = lambda msg: mod_has_access(mod, config, msg)
mod.save = lambda: mod_save(mod, datas_path)
#Load dependancies
if mod.CONF is not None and mod.CONF.hasNode("dependson"):
mod.MODS = dict()
for depend in mod.CONF.getNodes("dependson"):
for md in MODS:
if md.name == depend["name"]:
mod.MODS[md.name] = md
break
if depend["name"] not in mod.MODS:
print ("\033[1;31mERROR:\033[0m in module `%s', module `%s' require by this module but is not loaded." % (mod.name,depend["name"]))
return
try:
test = mod.parseask
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parseask defined." % mod.name)
mod.parseask = lambda x: False
try:
test = mod.parseanswer
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parseanswer defined." % mod.name)
mod.parseanswer = lambda x: False
try:
test = mod.parselisten
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parselisten defined." % mod.name)
mod.parselisten = lambda x: False
try:
mod.load()
print (" Module `%s' successfully loaded." % name)
except AttributeError:
print (" Module `%s' successfully added." % name)
#TODO: don't append already running modules
MODS.append(mod)
except AttributeError:
print (" Module `%s' is not a nemubot module." % name)
for srv in servers:
servers[srv].update_mods(MODS)
except IOError:
print (" Module `%s' not loaded: unable to find module implementation." % name)
except ImportError:
print ("\033[1;31mERROR:\033[0m Module attached to the file `%s' not loaded. Is this file existing?" % name)
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
def load_module(config, servers): def load_module(config, servers):
global MODS global MODS
if config.hasAttribute("name"): if config.hasAttribute("name"):
try: load_module_from_name(config["name"], servers, config)
#Import the module code
mod = imp.load_source(config["name"], modules_path + "/" + config["name"] + ".py")
try:
if mod.nemubotversion < 3.0:
print (" Module `%s' is not compatible with this version." % config["name"])
return
#Set module common functions and datas
mod.name = config["name"]
mod.print = lambda msg: print("[%s] %s"%(mod.name, msg))
mod.DATAS = xmlparser.parse_file(datas_path + "/" + config["name"] + ".xml")
mod.CONF = config
mod.SRVS = servers
mod.has_access = lambda msg: mod_has_access(mod, config, msg)
mod.save = lambda: mod_save(mod, datas_path, config)
#Load dependancies
if mod.CONF.hasNode("dependson"):
mod.MODS = dict()
for depend in mod.CONF.getNodes("dependson"):
for md in MODS:
if md.name == depend["name"]:
mod.MODS[md.name] = md
break
if depend["name"] not in mod.MODS:
print ("\033[1;35mERROR:\033[0m in module `%s', module `%s' require by this module but is not loaded." % (mod.name,depend["name"]))
return
try:
test = mod.parseask
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parseask defined." % mod.name)
mod.parseask = lambda x: False
try:
test = mod.parseanswer
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parseanswer defined." % mod.name)
mod.parseanswer = lambda x: False
try:
test = mod.parselisten
except AttributeError:
print ("\033[1;35mWarning:\033[0m in module `%s', no function parselisten defined." % mod.name)
mod.parselisten = lambda x: False
try:
mod.load()
print (" Module `%s' successfully loaded." % config["name"])
except AttributeError:
print (" Module `%s' successfully added." % config["name"])
#TODO: don't append already running modules
MODS.append(mod)
except AttributeError:
print (" Module `%s' is not a nemubot module." % config["name"])
for srv in servers:
servers[srv].update_mods(MODS)
except IOError:
print (" Module `%s' not loaded: unable to find module implementation." % config["name"])
def load_file(filename, servers): def load_file(filename, servers):
"""Realy load a file""" """Realy load a file"""
global MODS global MODS
config = xmlparser.parse_file(filename) if os.path.isfile(filename):
if config.getName() == "nemubotconfig" or config.getName() == "config": config = xmlparser.parse_file(filename)
#Preset each server in this file if config.getName() == "nemubotconfig" or config.getName() == "config":
for serveur in config.getNodes("server"): #Preset each server in this file
srv = server.Server(serveur, config["nick"], config["owner"], config["realname"]) for serveur in config.getNodes("server"):
if srv.id not in servers: srv = server.Server(serveur, config["nick"], config["owner"], config["realname"])
servers[srv.id] = srv if srv.id not in servers:
print (" Server `%s' successfully added." % srv.id) servers[srv.id] = srv
else: print (" Server `%s' successfully added." % srv.id)
print (" Server `%s' already added, skiped." % srv.id) else:
if srv.autoconnect: print (" Server `%s' already added, skiped." % srv.id)
srv.launch(MODS) if srv.autoconnect:
#Load files asked by the configuration file srv.launch(MODS)
for load in config.getNodes("load"): #Load files asked by the configuration file
load_file(load["path"], servers) for load in config.getNodes("load"):
elif config.getName() == "nemubotmodule": load_file(load["path"], servers)
load_module(config, servers) elif config.getName() == "nemubotmodule":
load_module(config, servers)
else:
print (" Can't load `%s'; this is not a valid nemubot configuration file." % filename)
elif os.path.isfile(filename + ".xml"):
load_file(filename + ".xml", servers)
elif os.path.isfile("./modules/" + filename + ".xml"):
load_file("./modules/" + filename + ".xml", servers)
else: else:
print (" Can't load `%s'; this is not a valid nemubot configuration file." % filename) load_module_from_name(filename, servers)
def load(cmds, servers): def load(cmds, servers):