From 3da65af7c8c033f9aea4800505f70c646e8de25f Mon Sep 17 00:00:00 2001 From: Daniel DiPaolo Date: Sun, 14 Sep 2003 07:38:26 +0000 Subject: [PATCH] * Beginnings of news stuff, yay --- plugins/News.py | 141 ++++++++++++++++++++++++++++++++++++++++++---- test/test_News.py | 46 +++++++++++++++ 2 files changed, 177 insertions(+), 10 deletions(-) create mode 100644 test/test_News.py diff --git a/plugins/News.py b/plugins/News.py index 7a6a410a7..12db44187 100644 --- a/plugins/News.py +++ b/plugins/News.py @@ -1,7 +1,7 @@ #!/usr/bin/env python ### -# Copyright (c) 2002, Jeremiah Fincher +# Copyright (c) 2003, Daniel DiPaolo # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -38,11 +38,11 @@ from baseplugin import * import sqlite +import ircdb import utils import privmsgs import callbacks - def configure(onStart, afterConnect, advanced): # This will be called by setup.py to configure this module. onStart and # afterConnect are both lists. Append to onStart the commands you would @@ -52,7 +52,24 @@ def configure(onStart, afterConnect, advanced): onStart.append('load News') example = utils.wrapLines(""" - + !listnews + Strike: News for #sourcereview: (#1) Test; (#3) Expiration test +five-million-and-one; (#5) no expire + !readnews 1 + Strike: no expiration (Subject: "Test", added by Strike on 10:15 +PM, September 03, 2003, expires at 12:00 AM, September 12, 2003) + !addnews 5000 Another test news item: Here is the news text, much +longer than the subject should be. The subject should be short and sweet like +a headline whereas the text can be a lot more detailed. + Strike: The operation succeeded. + !listnews + Strike: News for #sourcereview: (#1) Test; (#3) Expiration test +five-million-and-one; (#5) no expire; (#7) Another test news item + !readnews 7 + Strike: Here is the news text, much longer than the subject should +be. The subject should be short and sweet like a headline whereas the text can +be a lot more detailed. (Subject: "Another test news item", added by Strike on +07:12 PM, September 12, 2003, expires at 08:36 PM, September 12, 2003) """) class News(callbacks.Privmsg, ChannelDBHandler): @@ -68,6 +85,7 @@ class News(callbacks.Privmsg, ChannelDBHandler): cursor = db.cursor() cursor.execute("""CREATE TABLE news ( id INTEGER PRIMARY KEY, + subject TEXT, item TEXT, added_at TIMESTAMP, expires_at TIMESTAMP, @@ -77,13 +95,104 @@ class News(callbacks.Privmsg, ChannelDBHandler): return db def addnews(self, irc, msg, args): - """[] + """[] : - Adds a given news item of to a channel. If isn't 0, - that news item will expire seconds from now. is - only necessary if the message isn't sent in the channel itself. + Adds a given news item of to a channel with the given . + If isn't 0, that news item will expire seconds from + now. is only necessary if the message isn't sent in the + channel itself. """ - pass + channel = privmsgs.getChannel(msg, args) + # Check if they have the appropriate capability. + capability = ircdb.makeChannelCapability(channel, 'news') + if not ircdb.checkCapability(msg.prefix, capability): + irc.error(msg, conf.replyNoCapability % capability) + return + # Parse out the args + i = None + for i, arg in enumerate(args): + if arg.endswith(':'): + i += 1 + break + if not i: + raise callbacks.ArgumentError + added_at = int(time.time()) + expire_interval = int(args[0]) + expires = expire_interval and (added_at + expire_interval) + subject = ' '.join(args[1:i]) + text = ' '.join(args[i:]) + # Set the other stuff needed for the insert. + if ircdb.users.hasUser(msg.prefix): + name = ircdb.users.getUserName(msg.prefix) + else: + name = msg.nick + + db = self.getDb(channel) + cursor = db.cursor() + cursor.execute("INSERT INTO news VALUES (NULL, %s, %s, %s, %s, %s)", + subject[:-1], text, added_at, expires, name) + db.commit() + irc.reply(msg, conf.replySuccess) + + def readnews(self, irc, msg, args): + """[] + + Display the text for news item with id from . + is only necessary if the message isn't sent in the channel + itself. + """ + channel = privmsgs.getChannel(msg, args) + id = privmsgs.getArgs(args) + db = self.getDb(channel) + cursor = db.cursor() + cursor.execute("""SELECT news.item, news.subject, news.added_at, + news.expires_at, news.added_by FROM news + WHERE news.id = %s""", id) + if cursor.rowcount == 0: + irc.error(msg, 'No news item matches that id.') + else: + item, subject, added_at, expires_at, added_by = cursor.fetchone() + s = '%s (Subject: "%s", added by %s on %s' % \ + (item, subject, added_by, + time.strftime(conf.humanTimestampFormat, + time.localtime(int(added_at)))) + if int(expires_at) > 0: + s += ', expires at %s)' % \ + time.strftime(conf.humanTimestampFormat, + time.localtime(int(expires_at))) + else: + s += ')' + irc.reply(msg, s) + + def listnews(self, irc, msg, args): + """[] + + Display the news items for in the format of "id) subject". + is only necessary if the message isn't sent in the channel + itself. + """ + channel = privmsgs.getChannel(msg, args) + db = self.getDb(channel) + cursor = db.cursor() + cursor.execute("""SELECT news.id, news.subject FROM news + WHERE (news.expires_at > %s) + OR (news.expires_at = 0)""", + int(time.time())) + if cursor.rowcount == 0: + irc.error(msg, 'No news items for channel: %s' % channel) + else: + items = [] + for (id, subject) in cursor.fetchall(): + items.append('(#%s) %s' % (id, subject)) + totalResults = len(items) + if ircutils.shrinkList(items, '; ', 400): + s = 'News for %s (%s of %s shown): %s' % \ + (channel, len(items), totalResults, '; '.join(items)) + else: + s = 'News for %s: %s' % (channel, '; '.join(items)) + irc.reply(msg, s) + + def removenews(self, irc, msg, args): """[] @@ -91,8 +200,18 @@ class News(callbacks.Privmsg, ChannelDBHandler): Removes the news item with id from . is only necessary if the message isn't sent in the channel itself. """ - pass - + channel = privmsgs.getChannel(msg, args) + id = privmsgs.getArgs(args) + db = self.getDb(channel) + cursor = db.cursor() + cursor.execute("""SELECT news.id FROM news WHERE news.id = %s""", id) + if cursor.rowcount == 0: + irc.error(msg, 'No news item matches that id.') + else: + cursor.execute("""DELETE FROM news WHERE news.id = %s""", id) + db.commit() + irc.reply(msg, conf.replySuccess) + def changenews(self, irc, msg, args): """[] @@ -111,6 +230,8 @@ class News(callbacks.Privmsg, ChannelDBHandler): """ pass + + Class = News # vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: diff --git a/test/test_News.py b/test/test_News.py new file mode 100644 index 000000000..dda0a85d3 --- /dev/null +++ b/test/test_News.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +### +# Copyright (c) 2003, Daniel DiPaolo +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +### + +from test import * + +import utils + +class NewsTestCase(PluginTestCase): + plugins = ('News',) + def testAddNews(self): + self.assertNotError('addnews 0 subject: foo') + self.assertNotError('addnews #somechannel subject: foo') + + def testListNews(self): + self.assertNotError('listnews') + +# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78: +