Compare commits
9 commits
flask_and_
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
529bcbb003 | ||
![]() |
bf661d9577 | ||
![]() |
96e6da2752 | ||
![]() |
2125b2d739 | ||
![]() |
924fad4320 | ||
![]() |
6292af08e6 | ||
![]() |
0a6a0c4e6f | ||
![]() |
233519ac3a | ||
![]() |
63a2a7af31 |
8 changed files with 178 additions and 99 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1 +1,4 @@
|
||||||
*.pyc
|
*.pyc
|
||||||
|
irc.db
|
||||||
|
seen_prs
|
||||||
|
|
||||||
|
|
15
Db.py
15
Db.py
|
@ -23,11 +23,16 @@ class LogMessage(BaseModel):
|
||||||
message_type = CharField()
|
message_type = CharField()
|
||||||
message = CharField()
|
message = CharField()
|
||||||
|
|
||||||
|
class Quote(BaseModel):
|
||||||
|
datetime = DateTimeField()
|
||||||
|
author = CharField()
|
||||||
|
message = CharField()
|
||||||
|
|
||||||
|
|
||||||
def create_tables():
|
def create_tables():
|
||||||
database.connect()
|
database.connect()
|
||||||
try:
|
try:
|
||||||
database.create_tables([LogMessage, Day, Channel])
|
database.create_tables([Quote, LogMessage, Day, Channel])
|
||||||
except OperationalError:
|
except OperationalError:
|
||||||
pass # Database already exists
|
pass # Database already exists
|
||||||
|
|
||||||
|
@ -55,6 +60,12 @@ def add_log_message(channel, nickname, message_type, message = None):
|
||||||
message_type = message_type,
|
message_type = message_type,
|
||||||
message = message)
|
message = message)
|
||||||
|
|
||||||
|
def add_quote(author, message):
|
||||||
|
Quote.create(
|
||||||
|
author = author,
|
||||||
|
message = message,
|
||||||
|
datetime = datetime.datetime.now().strftime("%H:%m:%S"))
|
||||||
|
|
||||||
def show_all_messages():
|
def show_all_messages():
|
||||||
for message in LogMessage.select():
|
for message in LogMessage.select():
|
||||||
print "<%s> %s" % (message.nickname, message.message)
|
print("<%s> %s" % (message.nickname, message.message))
|
||||||
|
|
37
README.md
37
README.md
|
@ -1,21 +1,32 @@
|
||||||
LogBot 0.4.2
|
# smooth-operator
|
||||||
============
|
|
||||||
|
|
||||||
Written by Chris Oliver <chris@excid3.com>
|
smooth-operator is a IRC bot which logs everything in a channel and offers more convinient things like notifications about new commits on GitHub, etc. For a roadmap please check the issues on GitHub.
|
||||||
|
|
||||||
Many thanks to Filip Slagter for his contributions.
|
Originally this was written by Chris Oliver <chris@excid3.com> with contributions from Filip Slagter. Now it has diverged quite a lot.
|
||||||
|
|
||||||
Requirements
|
## Requirements
|
||||||
------------
|
|
||||||
LogBot shows logs using flask, and stores logs using peewee. Install these dependencies using ``pip``:
|
smooth-operator shows logs using flask, and stores logs using peewee. Install these dependencies using ``pip``:
|
||||||
|
|
||||||
pip install flask peewee
|
pip install flask peewee
|
||||||
|
|
||||||
Usage
|
## Usage
|
||||||
-----
|
|
||||||
LogBot requires Python 2. It is NOT compatible with Python 3.
|
|
||||||
Configuration is done inside logbot.py.
|
|
||||||
|
|
||||||
python logbot.py
|
smooth-operator requires Python 2. It is NOT compatible with Python 3. Configuration is either done inside logbot.py, or using environment variables. The following environment variables are respected:
|
||||||
|
|
||||||
You can view logs on http://localhost:5000
|
- ``IRC_SERVER``: IRC server
|
||||||
|
- ``IRC_PORT``: IRC server port
|
||||||
|
- ``IRC_SERVER_PASS``: Password for IRC server, if any
|
||||||
|
- ``IRC_CHANNELS``: IRC channels to join, separated by ``,``
|
||||||
|
- ``IRC_NICK``: Nickname
|
||||||
|
- ``IRC_NICK_PASS``: Password to use when authenticating to nickserv, if any
|
||||||
|
|
||||||
|
The bot can be launched using:
|
||||||
|
|
||||||
|
python2 logbot.py
|
||||||
|
|
||||||
|
You can view the logs on http://localhost:5000
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This project is licensed under the GPLv2.
|
||||||
|
|
44
commands.py
Normal file
44
commands.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
from Db import *
|
||||||
|
from irclib import nm_to_n
|
||||||
|
import random
|
||||||
|
|
||||||
|
class Commands:
|
||||||
|
def __init__(self):
|
||||||
|
self.commands = {
|
||||||
|
"quote": self.cmd_quote,
|
||||||
|
"remember_quote": self.cmd_remember_quote
|
||||||
|
}
|
||||||
|
|
||||||
|
def process(self, c, e):
|
||||||
|
msg = e.arguments()[0]
|
||||||
|
if msg.startswith("!"):
|
||||||
|
cmd = msg.split("!")[1].split(" ")[0]
|
||||||
|
if cmd in self.commands:
|
||||||
|
msg = " ".join(msg.split(" ")[1:])
|
||||||
|
self.commands[cmd](c, msg, e.target(), nm_to_n(e.source()))
|
||||||
|
else:
|
||||||
|
print "Unknown command", cmd
|
||||||
|
|
||||||
|
def cmd_quote(self, c, msg, target, source):
|
||||||
|
replies = [
|
||||||
|
"%s once said \"%s\"",
|
||||||
|
"I head from %s that \"%s\"",
|
||||||
|
"A wise man (haha, just kidding, it was actually %s) once said \"%s\""
|
||||||
|
]
|
||||||
|
reply = lambda msg: c.privmsg(target, msg)
|
||||||
|
random_query = Quote.select().order_by(fn.Random())
|
||||||
|
try:
|
||||||
|
one_quote = random_query.get()
|
||||||
|
reply(random.choice(replies) % (one_quote.author, one_quote.message))
|
||||||
|
except: # No quotes
|
||||||
|
reply("I don't know ay quotes :(")
|
||||||
|
|
||||||
|
def cmd_remember_quote(self, c, msg, target, source):
|
||||||
|
reply = lambda msg: c.privmsg(target, msg)
|
||||||
|
|
||||||
|
if (len(msg) > 1):
|
||||||
|
add_quote(msg.split(" ")[0], ' '.join(msg.split(" ")[1:]))
|
||||||
|
reply("I'll try to remember that!")
|
||||||
|
else:
|
||||||
|
reply("I didn't get that :(")
|
||||||
|
|
29
ircbot.py
29
ircbot.py
|
@ -25,7 +25,14 @@ write simpler bots.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from UserDict import UserDict
|
|
||||||
|
# UserDict is moved to collections in Python3
|
||||||
|
# In order to support Python 2.7 this has to be imported
|
||||||
|
# in the following way
|
||||||
|
try:
|
||||||
|
from UserDict import UserDict
|
||||||
|
except ImportError:
|
||||||
|
from collections import UserDict
|
||||||
|
|
||||||
from irclib import SimpleIRCClient
|
from irclib import SimpleIRCClient
|
||||||
from irclib import nm_to_n, irc_lower, all_events
|
from irclib import nm_to_n, irc_lower, all_events
|
||||||
|
@ -160,7 +167,7 @@ class SingleServerIRCBot(SimpleIRCClient):
|
||||||
"""[Internal]"""
|
"""[Internal]"""
|
||||||
before = nm_to_n(e.source())
|
before = nm_to_n(e.source())
|
||||||
after = e.target()
|
after = e.target()
|
||||||
for ch in self.channels.values():
|
for ch in list(self.channels.values()):
|
||||||
if ch.has_user(before):
|
if ch.has_user(before):
|
||||||
ch.change_nick(before, after)
|
ch.change_nick(before, after)
|
||||||
|
|
||||||
|
@ -177,7 +184,7 @@ class SingleServerIRCBot(SimpleIRCClient):
|
||||||
def _on_quit(self, c, e):
|
def _on_quit(self, c, e):
|
||||||
"""[Internal]"""
|
"""[Internal]"""
|
||||||
nick = nm_to_n(e.source())
|
nick = nm_to_n(e.source())
|
||||||
for ch in self.channels.values():
|
for ch in list(self.channels.values()):
|
||||||
if ch.has_user(nick):
|
if ch.has_user(nick):
|
||||||
ch.remove_user(nick)
|
ch.remove_user(nick)
|
||||||
|
|
||||||
|
@ -283,8 +290,6 @@ class IRCDict:
|
||||||
del self.canon_keys[ck]
|
del self.canon_keys[ck]
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self.data)
|
return iter(self.data)
|
||||||
def __contains__(self, key):
|
|
||||||
return self.has_key(key)
|
|
||||||
def clear(self):
|
def clear(self):
|
||||||
self.data.clear()
|
self.data.clear()
|
||||||
self.canon_keys.clear()
|
self.canon_keys.clear()
|
||||||
|
@ -294,15 +299,15 @@ class IRCDict:
|
||||||
import copy
|
import copy
|
||||||
return copy.copy(self)
|
return copy.copy(self)
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.data.keys()
|
return list(self.data.keys())
|
||||||
def items(self):
|
def items(self):
|
||||||
return self.data.items()
|
return list(self.data.items())
|
||||||
def values(self):
|
def values(self):
|
||||||
return self.data.values()
|
return list(self.data.values())
|
||||||
def has_key(self, key):
|
def has_key(self, key):
|
||||||
return irc_lower(key) in self.canon_keys
|
return irc_lower(key) in self.canon_keys
|
||||||
def update(self, dict):
|
def update(self, dict):
|
||||||
for k, v in dict.items():
|
for k, v in list(dict.items()):
|
||||||
self.data[k] = v
|
self.data[k] = v
|
||||||
def get(self, key, failobj=None):
|
def get(self, key, failobj=None):
|
||||||
return self.data.get(key, failobj)
|
return self.data.get(key, failobj)
|
||||||
|
@ -322,16 +327,16 @@ class Channel:
|
||||||
|
|
||||||
def users(self):
|
def users(self):
|
||||||
"""Returns an unsorted list of the channel's users."""
|
"""Returns an unsorted list of the channel's users."""
|
||||||
return self.userdict.keys()
|
return list(self.userdict.keys())
|
||||||
|
|
||||||
def opers(self):
|
def opers(self):
|
||||||
"""Returns an unsorted list of the channel's operators."""
|
"""Returns an unsorted list of the channel's operators."""
|
||||||
return self.operdict.keys()
|
return list(self.operdict.keys())
|
||||||
|
|
||||||
def voiced(self):
|
def voiced(self):
|
||||||
"""Returns an unsorted list of the persons that have voice
|
"""Returns an unsorted list of the persons that have voice
|
||||||
mode set in the channel."""
|
mode set in the channel."""
|
||||||
return self.voiceddict.keys()
|
return list(self.voiceddict.keys())
|
||||||
|
|
||||||
def has_user(self, nick):
|
def has_user(self, nick):
|
||||||
"""Check whether the channel has a user."""
|
"""Check whether the channel has a user."""
|
||||||
|
|
92
irclib.py
92
irclib.py
|
@ -207,8 +207,8 @@ class IRC:
|
||||||
incoming data, if there are any. If that seems boring, look
|
incoming data, if there are any. If that seems boring, look
|
||||||
at the process_forever method.
|
at the process_forever method.
|
||||||
"""
|
"""
|
||||||
sockets = map(lambda x: x._get_socket(), self.connections)
|
sockets = [x._get_socket() for x in self.connections]
|
||||||
sockets = filter(lambda x: x != None, sockets)
|
sockets = [x for x in sockets if x != None]
|
||||||
if sockets:
|
if sockets:
|
||||||
(i, o, e) = select.select(sockets, [], [], timeout)
|
(i, o, e) = select.select(sockets, [], [], timeout)
|
||||||
self.process_data(i)
|
self.process_data(i)
|
||||||
|
@ -342,7 +342,7 @@ class Connection:
|
||||||
self.irclibobj = irclibobj
|
self.irclibobj = irclibobj
|
||||||
|
|
||||||
def _get_socket():
|
def _get_socket():
|
||||||
raise IRCError, "Not overridden"
|
raise IRCError("Not overridden")
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
### Convenience wrappers.
|
### Convenience wrappers.
|
||||||
|
@ -433,10 +433,10 @@ class ServerConnection(Connection):
|
||||||
self.socket.connect((self.server, self.port))
|
self.socket.connect((self.server, self.port))
|
||||||
if ssl:
|
if ssl:
|
||||||
self.ssl = socket.ssl(self.socket)
|
self.ssl = socket.ssl(self.socket)
|
||||||
except socket.error, x:
|
except socket.error as x:
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
self.socket = None
|
self.socket = None
|
||||||
raise ServerConnectionError, "Couldn't connect to socket: %s" % x
|
raise ServerConnectionError("Couldn't connect to socket: %s" % x)
|
||||||
self.connected = 1
|
self.connected = 1
|
||||||
if self.irclibobj.fn_to_add_socket:
|
if self.irclibobj.fn_to_add_socket:
|
||||||
self.irclibobj.fn_to_add_socket(self.socket)
|
self.irclibobj.fn_to_add_socket(self.socket)
|
||||||
|
@ -491,7 +491,7 @@ class ServerConnection(Connection):
|
||||||
new_data = self.ssl.read(2**14)
|
new_data = self.ssl.read(2**14)
|
||||||
else:
|
else:
|
||||||
new_data = self.socket.recv(2**14)
|
new_data = self.socket.recv(2**14)
|
||||||
except socket.error, x:
|
except socket.error as x:
|
||||||
# The server hung up.
|
# The server hung up.
|
||||||
self.disconnect("Connection reset by peer")
|
self.disconnect("Connection reset by peer")
|
||||||
return
|
return
|
||||||
|
@ -500,14 +500,14 @@ class ServerConnection(Connection):
|
||||||
self.disconnect("Connection reset by peer")
|
self.disconnect("Connection reset by peer")
|
||||||
return
|
return
|
||||||
|
|
||||||
lines = _linesep_regexp.split(self.previous_buffer + new_data)
|
lines = _linesep_regexp.split(self.previous_buffer + new_data.decode())
|
||||||
|
|
||||||
# Save the last, unfinished line.
|
# Save the last, unfinished line.
|
||||||
self.previous_buffer = lines.pop()
|
self.previous_buffer = lines.pop()
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "FROM SERVER:", line
|
print("FROM SERVER:", line)
|
||||||
|
|
||||||
if not line:
|
if not line:
|
||||||
continue
|
continue
|
||||||
|
@ -561,7 +561,7 @@ class ServerConnection(Connection):
|
||||||
command = "privnotice"
|
command = "privnotice"
|
||||||
|
|
||||||
for m in messages:
|
for m in messages:
|
||||||
if type(m) is types.TupleType:
|
if type(m) is tuple:
|
||||||
if command in ["privmsg", "pubmsg"]:
|
if command in ["privmsg", "pubmsg"]:
|
||||||
command = "ctcp"
|
command = "ctcp"
|
||||||
else:
|
else:
|
||||||
|
@ -569,15 +569,15 @@ class ServerConnection(Connection):
|
||||||
|
|
||||||
m = list(m)
|
m = list(m)
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "command: %s, source: %s, target: %s, arguments: %s" % (
|
print("command: %s, source: %s, target: %s, arguments: %s" % (
|
||||||
command, prefix, target, m)
|
command, prefix, target, m))
|
||||||
self._handle_event(Event(command, prefix, target, m))
|
self._handle_event(Event(command, prefix, target, m))
|
||||||
if command == "ctcp" and m[0] == "ACTION":
|
if command == "ctcp" and m[0] == "ACTION":
|
||||||
self._handle_event(Event("action", prefix, target, m[1:]))
|
self._handle_event(Event("action", prefix, target, m[1:]))
|
||||||
else:
|
else:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "command: %s, source: %s, target: %s, arguments: %s" % (
|
print("command: %s, source: %s, target: %s, arguments: %s" % (
|
||||||
command, prefix, target, [m])
|
command, prefix, target, [m]))
|
||||||
self._handle_event(Event(command, prefix, target, [m]))
|
self._handle_event(Event(command, prefix, target, [m]))
|
||||||
else:
|
else:
|
||||||
target = None
|
target = None
|
||||||
|
@ -595,8 +595,8 @@ class ServerConnection(Connection):
|
||||||
command = "umode"
|
command = "umode"
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "command: %s, source: %s, target: %s, arguments: %s" % (
|
print("command: %s, source: %s, target: %s, arguments: %s" % (
|
||||||
command, prefix, target, arguments)
|
command, prefix, target, arguments))
|
||||||
self._handle_event(Event(command, prefix, target, arguments))
|
self._handle_event(Event(command, prefix, target, arguments))
|
||||||
|
|
||||||
def _handle_event(self, event):
|
def _handle_event(self, event):
|
||||||
|
@ -660,7 +660,7 @@ class ServerConnection(Connection):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
except socket.error, x:
|
except socket.error as x:
|
||||||
pass
|
pass
|
||||||
self.socket = None
|
self.socket = None
|
||||||
self._handle_event(Event("disconnect", self.server, "", [message]))
|
self._handle_event(Event("disconnect", self.server, "", [message]))
|
||||||
|
@ -743,7 +743,7 @@ class ServerConnection(Connection):
|
||||||
|
|
||||||
def part(self, channels, message=""):
|
def part(self, channels, message=""):
|
||||||
"""Send a PART command."""
|
"""Send a PART command."""
|
||||||
if type(channels) == types.StringType:
|
if type(channels) == bytes:
|
||||||
self.send_raw("PART " + channels + (message and (" " + message)))
|
self.send_raw("PART " + channels + (message and (" " + message)))
|
||||||
else:
|
else:
|
||||||
self.send_raw("PART " + ",".join(channels) + (message and (" " + message)))
|
self.send_raw("PART " + ",".join(channels) + (message and (" " + message)))
|
||||||
|
@ -782,15 +782,16 @@ class ServerConnection(Connection):
|
||||||
The string will be padded with appropriate CR LF.
|
The string will be padded with appropriate CR LF.
|
||||||
"""
|
"""
|
||||||
if self.socket is None:
|
if self.socket is None:
|
||||||
raise ServerNotConnectedError, "Not connected."
|
raise ServerNotConnectedError("Not connected.")
|
||||||
try:
|
try:
|
||||||
|
string += "\r\n"
|
||||||
if self.ssl:
|
if self.ssl:
|
||||||
self.ssl.write(string + "\r\n")
|
self.ssl.write(string.encode())
|
||||||
else:
|
else:
|
||||||
self.socket.send(string + "\r\n")
|
self.socket.send(string.encode())
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "TO SERVER:", string
|
print("TO SERVER:", string)
|
||||||
except socket.error, x:
|
except socket.error as x:
|
||||||
# Ouch!
|
# Ouch!
|
||||||
self.disconnect("Connection reset by peer.")
|
self.disconnect("Connection reset by peer.")
|
||||||
|
|
||||||
|
@ -888,8 +889,8 @@ class DCCConnection(Connection):
|
||||||
self.passive = 0
|
self.passive = 0
|
||||||
try:
|
try:
|
||||||
self.socket.connect((self.peeraddress, self.peerport))
|
self.socket.connect((self.peeraddress, self.peerport))
|
||||||
except socket.error, x:
|
except socket.error as x:
|
||||||
raise DCCConnectionError, "Couldn't connect to socket: %s" % x
|
raise DCCConnectionError("Couldn't connect to socket: %s" % x)
|
||||||
self.connected = 1
|
self.connected = 1
|
||||||
if self.irclibobj.fn_to_add_socket:
|
if self.irclibobj.fn_to_add_socket:
|
||||||
self.irclibobj.fn_to_add_socket(self.socket)
|
self.irclibobj.fn_to_add_socket(self.socket)
|
||||||
|
@ -913,8 +914,8 @@ class DCCConnection(Connection):
|
||||||
self.socket.bind((socket.gethostbyname(socket.gethostname()), 0))
|
self.socket.bind((socket.gethostbyname(socket.gethostname()), 0))
|
||||||
self.localaddress, self.localport = self.socket.getsockname()
|
self.localaddress, self.localport = self.socket.getsockname()
|
||||||
self.socket.listen(10)
|
self.socket.listen(10)
|
||||||
except socket.error, x:
|
except socket.error as x:
|
||||||
raise DCCConnectionError, "Couldn't bind socket: %s" % x
|
raise DCCConnectionError("Couldn't bind socket: %s" % x)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def disconnect(self, message=""):
|
def disconnect(self, message=""):
|
||||||
|
@ -930,7 +931,7 @@ class DCCConnection(Connection):
|
||||||
self.connected = 0
|
self.connected = 0
|
||||||
try:
|
try:
|
||||||
self.socket.close()
|
self.socket.close()
|
||||||
except socket.error, x:
|
except socket.error as x:
|
||||||
pass
|
pass
|
||||||
self.socket = None
|
self.socket = None
|
||||||
self.irclibobj._handle_event(
|
self.irclibobj._handle_event(
|
||||||
|
@ -947,8 +948,8 @@ class DCCConnection(Connection):
|
||||||
self.socket = conn
|
self.socket = conn
|
||||||
self.connected = 1
|
self.connected = 1
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "DCC connection from %s:%d" % (
|
print("DCC connection from %s:%d" % (
|
||||||
self.peeraddress, self.peerport)
|
self.peeraddress, self.peerport))
|
||||||
self.irclibobj._handle_event(
|
self.irclibobj._handle_event(
|
||||||
self,
|
self,
|
||||||
Event("dcc_connect", self.peeraddress, None, None))
|
Event("dcc_connect", self.peeraddress, None, None))
|
||||||
|
@ -956,7 +957,7 @@ class DCCConnection(Connection):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_data = self.socket.recv(2**14)
|
new_data = self.socket.recv(2**14)
|
||||||
except socket.error, x:
|
except socket.error as x:
|
||||||
# The server hung up.
|
# The server hung up.
|
||||||
self.disconnect("Connection reset by peer")
|
self.disconnect("Connection reset by peer")
|
||||||
return
|
return
|
||||||
|
@ -985,11 +986,11 @@ class DCCConnection(Connection):
|
||||||
target = None
|
target = None
|
||||||
for chunk in chunks:
|
for chunk in chunks:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "FROM PEER:", chunk
|
print("FROM PEER:", chunk)
|
||||||
arguments = [chunk]
|
arguments = [chunk]
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "command: %s, source: %s, target: %s, arguments: %s" % (
|
print("command: %s, source: %s, target: %s, arguments: %s" % (
|
||||||
command, prefix, target, arguments)
|
command, prefix, target, arguments))
|
||||||
self.irclibobj._handle_event(
|
self.irclibobj._handle_event(
|
||||||
self,
|
self,
|
||||||
Event(command, prefix, target, arguments))
|
Event(command, prefix, target, arguments))
|
||||||
|
@ -1009,8 +1010,8 @@ class DCCConnection(Connection):
|
||||||
if self.dcctype == "chat":
|
if self.dcctype == "chat":
|
||||||
self.socket.send("\n")
|
self.socket.send("\n")
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print "TO PEER: %s\n" % string
|
print("TO PEER: %s\n" % string)
|
||||||
except socket.error, x:
|
except socket.error as x:
|
||||||
# Ouch!
|
# Ouch!
|
||||||
self.disconnect("Connection reset by peer.")
|
self.disconnect("Connection reset by peer.")
|
||||||
|
|
||||||
|
@ -1181,10 +1182,6 @@ def mask_matches(nick, mask):
|
||||||
r = re.compile(mask, re.IGNORECASE)
|
r = re.compile(mask, re.IGNORECASE)
|
||||||
return r.match(nick)
|
return r.match(nick)
|
||||||
|
|
||||||
_special = "-[]\\`^{}"
|
|
||||||
nick_characters = string.ascii_letters + string.digits + _special
|
|
||||||
_ircstring_translation = string.maketrans(string.ascii_uppercase + "[]\\^",
|
|
||||||
string.ascii_lowercase + "{}|~")
|
|
||||||
|
|
||||||
def irc_lower(s):
|
def irc_lower(s):
|
||||||
"""Returns a lowercased string.
|
"""Returns a lowercased string.
|
||||||
|
@ -1192,7 +1189,12 @@ def irc_lower(s):
|
||||||
The definition of lowercased comes from the IRC specification (RFC
|
The definition of lowercased comes from the IRC specification (RFC
|
||||||
1459).
|
1459).
|
||||||
"""
|
"""
|
||||||
return s.translate(_ircstring_translation)
|
s = s.lower()
|
||||||
|
s = s.replace("[", "{")
|
||||||
|
s = s.replace("]", "}")
|
||||||
|
s = s.replace("\\", "|")
|
||||||
|
s = s.replace("^", "~")
|
||||||
|
return s
|
||||||
|
|
||||||
def _ctcp_dequote(message):
|
def _ctcp_dequote(message):
|
||||||
"""[Internal] Dequote a message according to CTCP specifications.
|
"""[Internal] Dequote a message according to CTCP specifications.
|
||||||
|
@ -1259,16 +1261,16 @@ def ip_numstr_to_quad(num):
|
||||||
"""Convert an IP number as an integer given in ASCII
|
"""Convert an IP number as an integer given in ASCII
|
||||||
representation (e.g. '3232235521') to an IP address string
|
representation (e.g. '3232235521') to an IP address string
|
||||||
(e.g. '192.168.0.1')."""
|
(e.g. '192.168.0.1')."""
|
||||||
n = long(num)
|
n = int(num)
|
||||||
p = map(str, map(int, [n >> 24 & 0xFF, n >> 16 & 0xFF,
|
p = list(map(str, list(map(int, [n >> 24 & 0xFF, n >> 16 & 0xFF,
|
||||||
n >> 8 & 0xFF, n & 0xFF]))
|
n >> 8 & 0xFF, n & 0xFF]))))
|
||||||
return ".".join(p)
|
return ".".join(p)
|
||||||
|
|
||||||
def ip_quad_to_numstr(quad):
|
def ip_quad_to_numstr(quad):
|
||||||
"""Convert an IP address string (e.g. '192.168.0.1') to an IP
|
"""Convert an IP address string (e.g. '192.168.0.1') to an IP
|
||||||
number as an integer given in ASCII representation
|
number as an integer given in ASCII representation
|
||||||
(e.g. '3232235521')."""
|
(e.g. '3232235521')."""
|
||||||
p = map(long, quad.split("."))
|
p = list(map(int, quad.split(".")))
|
||||||
s = str((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
|
s = str((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3])
|
||||||
if s[-1] == "L":
|
if s[-1] == "L":
|
||||||
s = s[:-1]
|
s = s[:-1]
|
||||||
|
@ -1557,4 +1559,4 @@ protocol_events = [
|
||||||
"pong",
|
"pong",
|
||||||
]
|
]
|
||||||
|
|
||||||
all_events = generated_events + protocol_events + numeric_events.values()
|
all_events = generated_events + protocol_events + list(numeric_events.values())
|
||||||
|
|
53
logbot.py
53
logbot.py
|
@ -59,6 +59,7 @@ from pullrequest import PullRequest
|
||||||
from Db import *
|
from Db import *
|
||||||
from flask import *
|
from flask import *
|
||||||
import threading
|
import threading
|
||||||
|
from commands import Commands
|
||||||
|
|
||||||
pat1 = re.compile(r"(^|[\n ])(([\w]+?://[\w\#$%&~.\-;:=,?@\[\]+]*)(/[\w\#$%&~/.\-;:=,?@\[\]+]*)?)", re.IGNORECASE | re.DOTALL)
|
pat1 = re.compile(r"(^|[\n ])(([\w]+?://[\w\#$%&~.\-;:=,?@\[\]+]*)(/[\w\#$%&~/.\-;:=,?@\[\]+]*)?)", re.IGNORECASE | re.DOTALL)
|
||||||
|
|
||||||
|
@ -79,12 +80,12 @@ def urlify2(value):
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
|
||||||
# IRC Server Configuration
|
# IRC Server Configuration
|
||||||
SERVER = "irc.freenode.net"
|
SERVER = os.getenv("IRC_SERVER", "irc.freenode.net")
|
||||||
PORT = 6667
|
PORT = os.getenv("IRC_PORT", 6667)
|
||||||
SERVER_PASS = None
|
SERVER_PASS = os.getenv("IRC_SERVER_PASS", None)
|
||||||
CHANNELS=["#pelux"]
|
CHANNELS = os.getenv("IRC_CHANNELS", "#pelux").split(",")
|
||||||
NICK = "pelux"
|
NICK = os.getenv("IRC_NICK", "pelux")
|
||||||
NICK_PASS = ""
|
NICK_PASS = os.getenv("IRC_NICK_PASS", "")
|
||||||
|
|
||||||
# The local folder to save logs
|
# The local folder to save logs
|
||||||
LOG_FOLDER = "/var/www/html/"
|
LOG_FOLDER = "/var/www/html/"
|
||||||
|
@ -115,13 +116,13 @@ def search(channel = None, nickname = None):
|
||||||
try:
|
try:
|
||||||
channel = Channel.get(Channel.name == channel)
|
channel = Channel.get(Channel.name == channel)
|
||||||
messages = LogMessage.select() \
|
messages = LogMessage.select() \
|
||||||
.where(LogMessage.channel == channel and \
|
.where(LogMessage.channel == channel, \
|
||||||
LogMessage.message.contains(query))
|
LogMessage.message.contains(query))
|
||||||
except:
|
except:
|
||||||
pass # No such channel
|
pass # No such channel
|
||||||
elif nickname:
|
elif nickname:
|
||||||
messages = LogMessage.select() \
|
messages = LogMessage.select() \
|
||||||
.where(LogMessage.nickname == nickname and \
|
.where(LogMessage.nickname == nickname, \
|
||||||
LogMessage.message.contains(query))
|
LogMessage.message.contains(query))
|
||||||
else:
|
else:
|
||||||
messages = LogMessage.select() \
|
messages = LogMessage.select() \
|
||||||
|
@ -135,13 +136,13 @@ def search(channel = None, nickname = None):
|
||||||
|
|
||||||
@flaskapp.route("/channels/<channel>/")
|
@flaskapp.route("/channels/<channel>/")
|
||||||
@flaskapp.route("/channels/<channel>/<day>/")
|
@flaskapp.route("/channels/<channel>/<day>/")
|
||||||
def channel(channel, day = None, query = None):
|
def channel(channel, day = None):
|
||||||
channel = Channel.get(Channel.name == channel)
|
channel = Channel.get(Channel.name == channel)
|
||||||
|
|
||||||
if day:
|
if day:
|
||||||
d = Day.get(Day.date == day)
|
d = Day.get(Day.date == day)
|
||||||
messages = LogMessage.select() \
|
messages = LogMessage.select() \
|
||||||
.where(LogMessage.day == d and \
|
.where(LogMessage.day == d, \
|
||||||
LogMessage.channel == channel)
|
LogMessage.channel == channel)
|
||||||
|
|
||||||
return render_template("messages.html",
|
return render_template("messages.html",
|
||||||
|
@ -164,18 +165,17 @@ def channels():
|
||||||
|
|
||||||
def append_line(filename, line):
|
def append_line(filename, line):
|
||||||
data = open(filename, "rb").readlines()[:-2]
|
data = open(filename, "rb").readlines()[:-2]
|
||||||
data += [line, "\n", "\n</body>", "\n</html>"]
|
data += [line.encode(), "\n".encode(), "\n</body>".encode(), "\n</html>".encode()]
|
||||||
write_lines(filename, data)
|
write_lines(filename, data)
|
||||||
|
|
||||||
def write_lines(filename, lines):
|
def write_lines(filename, lines):
|
||||||
f = open(filename, "wb")
|
with open(filename, "wb") as f:
|
||||||
f.writelines(lines)
|
f.writelines(lines)
|
||||||
f.close()
|
|
||||||
|
|
||||||
def write_string(filename, string):
|
def write_string(filename, string):
|
||||||
f = open(filename, "wb")
|
with open(filename, "wb") as f:
|
||||||
f.write(string)
|
f.write(string.encode())
|
||||||
f.close()
|
|
||||||
|
|
||||||
color_pattern = re.compile(r'(\[\d{1,2}m)')
|
color_pattern = re.compile(r'(\[\d{1,2}m)')
|
||||||
"Pattern that matches ANSI color codes and the text that follows"
|
"Pattern that matches ANSI color codes and the text that follows"
|
||||||
|
@ -204,16 +204,17 @@ class Logbot(SingleServerIRCBot):
|
||||||
self.chans = [x.lower() for x in channels]
|
self.chans = [x.lower() for x in channels]
|
||||||
self.set_ftp()
|
self.set_ftp()
|
||||||
self.nick_pass = nick_pass
|
self.nick_pass = nick_pass
|
||||||
|
self.commands = Commands()
|
||||||
|
|
||||||
print "Logbot %s" % __version__
|
print("Logbot %s" % __version__)
|
||||||
print "Connecting to %s:%i..." % (server, port)
|
print("Connecting to %s:%i..." % (server, port))
|
||||||
print "Press Ctrl-C to quit"
|
print("Press Ctrl-C to quit")
|
||||||
|
|
||||||
def quit(self):
|
def quit(self):
|
||||||
self.connection.disconnect("Quitting...")
|
self.connection.disconnect("Quitting...")
|
||||||
|
|
||||||
def color(self, user):
|
def color(self, user):
|
||||||
return "#%s" % md5(user).hexdigest()[:6]
|
return "#%s" % md5(user.encode()).hexdigest()[:6]
|
||||||
|
|
||||||
def set_ftp(self, ftp=None):
|
def set_ftp(self, ftp=None):
|
||||||
self.ftp = ftp
|
self.ftp = ftp
|
||||||
|
@ -223,6 +224,7 @@ class Logbot(SingleServerIRCBot):
|
||||||
|
|
||||||
if event_name == "nick":
|
if event_name == "nick":
|
||||||
message = params["new"]
|
message = params["new"]
|
||||||
|
target = params["chan"]
|
||||||
elif event_name == "kick":
|
elif event_name == "kick":
|
||||||
message = "%s kicked %s from %s. Reason: %s" % (nm_to_n(params["kicker"]),
|
message = "%s kicked %s from %s. Reason: %s" % (nm_to_n(params["kicker"]),
|
||||||
params["user"], params["channel"], params["reason"])
|
params["user"], params["channel"], params["reason"])
|
||||||
|
@ -257,7 +259,7 @@ class Logbot(SingleServerIRCBot):
|
||||||
|
|
||||||
def on_all_raw_messages(self, c, e):
|
def on_all_raw_messages(self, c, e):
|
||||||
"""Display all IRC connections in terminal"""
|
"""Display all IRC connections in terminal"""
|
||||||
if DEBUG: print e.arguments()[0]
|
if DEBUG: print(e.arguments()[0])
|
||||||
|
|
||||||
def on_welcome(self, c, e):
|
def on_welcome(self, c, e):
|
||||||
"""Join channels after successful connection"""
|
"""Join channels after successful connection"""
|
||||||
|
@ -320,6 +322,7 @@ class Logbot(SingleServerIRCBot):
|
||||||
def on_pubmsg(self, c, e):
|
def on_pubmsg(self, c, e):
|
||||||
# if e.arguments()[0].startswith(NICK):
|
# if e.arguments()[0].startswith(NICK):
|
||||||
# c.privmsg(e.target(), self.format["help"])
|
# c.privmsg(e.target(), self.format["help"])
|
||||||
|
self.commands.process(c, e)
|
||||||
self.write_event("pubmsg", e)
|
self.write_event("pubmsg", e)
|
||||||
|
|
||||||
def on_pubnotice(self, c, e):
|
def on_pubnotice(self, c, e):
|
||||||
|
@ -327,7 +330,7 @@ class Logbot(SingleServerIRCBot):
|
||||||
|
|
||||||
def on_privmsg(self, c, e):
|
def on_privmsg(self, c, e):
|
||||||
# c.privmsg(nm_to_n(e.source()), self.format["help"])
|
# c.privmsg(nm_to_n(e.source()), self.format["help"])
|
||||||
pas
|
pass
|
||||||
|
|
||||||
def on_quit(self, c, e):
|
def on_quit(self, c, e):
|
||||||
nick = nm_to_n(e.source())
|
nick = nm_to_n(e.source())
|
||||||
|
@ -340,7 +343,7 @@ class Logbot(SingleServerIRCBot):
|
||||||
self.write_event("topic", e)
|
self.write_event("topic", e)
|
||||||
|
|
||||||
def connect_ftp():
|
def connect_ftp():
|
||||||
print "Using FTP %s..." % (FTP_SERVER)
|
print("Using FTP %s..." % (FTP_SERVER))
|
||||||
f = ftplib.FTP(FTP_SERVER, FTP_USER, FTP_PASS)
|
f = ftplib.FTP(FTP_SERVER, FTP_USER, FTP_PASS)
|
||||||
f.cwd(FTP_FOLDER)
|
f.cwd(FTP_FOLDER)
|
||||||
return f
|
return f
|
||||||
|
@ -350,6 +353,7 @@ def main():
|
||||||
create_tables()
|
create_tables()
|
||||||
|
|
||||||
t = threading.Thread(target=flaskapp.run, kwargs={"host": "0.0.0.0"})
|
t = threading.Thread(target=flaskapp.run, kwargs={"host": "0.0.0.0"})
|
||||||
|
t.daemon = True
|
||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
# Create the logs directory
|
# Create the logs directory
|
||||||
|
@ -368,7 +372,6 @@ def main():
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
if FTP_SERVER: bot.ftp.quit()
|
if FTP_SERVER: bot.ftp.quit()
|
||||||
bot.quit()
|
bot.quit()
|
||||||
t.join()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -69,7 +69,7 @@ class PullRequest:
|
||||||
for repo in self.repos:
|
for repo in self.repos:
|
||||||
r = requests.get(repo["uri"])
|
r = requests.get(repo["uri"])
|
||||||
if r.status_code != 200:
|
if r.status_code != 200:
|
||||||
print "Error fetching %s", repo["name"]
|
print("Error fetching %s", repo["name"])
|
||||||
break
|
break
|
||||||
|
|
||||||
prs = r.json()
|
prs = r.json()
|
||||||
|
@ -83,4 +83,4 @@ class PullRequest:
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
p = PullRequest()
|
p = PullRequest()
|
||||||
for line in p.check_all():
|
for line in p.check_all():
|
||||||
print line["message"]
|
print(line["message"])
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue