################################################################################
#
# bulletin.py
#
# This module implements a bulletin board system, allowing people to post and
# read messages to various bulletins. This is *not* a substitute for forums. It
# is not nearly as functionally complete as any freely available web-based
# forum. This is meant for posting notes and notices, not for carrying out
# conversations.
#
# contains one command, "bulletin". Syntax is:
# bulletin
# bulletin read <board> [article number]
# bulletin post <board> <title>
# bulletin delete <board> [article number]
# bulletin create <board> [groups]
#
# Post makes use of a character's notepad, from the editor module.
#
################################################################################
from mudsys import add_cmd
import mud, storage, char, auxiliary, time, string, hooks
# our table of bulletins. Maps name to bulletin
__bulletins__ = { }
# the file we save our bulletin boards to
__bulletin_file__ = "../lib/misc/bulletins"
class Post:
'''Implements one bulletin board post'''
def __init__(self, name, time, title, mssg, set = None):
'''Prepares the post for use'''
if not set == None:
self.__poster__ = set.readString("poster")
self.__time__ = set.readString("time")
self.__title__ = set.readString("title")
self.__mssg__ = set.readString("mssg")
else:
self.__poster__ = name
self.__time__ = time
self.__title__ = title
self.__mssg__ = mssg
def store(self):
'''returns a storage set representation of the post'''
set = storage.StorageSet()
set.storeString("poster", self.__poster__)
set.storeString("time", self.__time__)
set.storeString("title", self.__title__)
set.storeString("mssg", self.__mssg__)
return set
# various getters and setters for the Post class
def setPoster(self, name): self.__poster__ = poster
def setTime(self, time): self.__time__ = time
def setTitle(self, title): self.__title__ = title
def setMssg(self, mssg): self.__mssg__ = mssg
def getPoster(self): return self.__poster__
def getTime(self): return self.__time__
def getTitle(self): return self.__title__
def getMssg(self): return self.__mssg__
class Bulletin:
'''Implements a bulletin board'''
def __init__(self, set = None):
'''Prepares the bulletin board for use'''
self.__posts__ = []
self.__groups__ = ""
if not set == None:
self.__groups__ = set.readString("groups")
for post in set.readList("posts").sets():
self.__posts__.append(Post(None, None, None, None, post))
def store(self):
'''returns a storage set representation of the board'''
set = storage.StorageSet()
posts = storage.StorageList()
set.storeString("groups", self.__groups__)
set.storeList("posts", posts)
for post in self.__posts__:
posts.add(post.store())
return set
def post(self, ch, title, mssg):
'''posts a message onto the bulletin board. Each message is a tuple
comprised of the poster\'s name, the time of posting, the message
title, and the message body.'''
self.__posts__.insert(0, Post(ch.name, time.ctime(), title, mssg))
def setGroups(self, groups):
'''sets the groups that have access to this board.'''
self.__groups__ = groups
def getGroups(self):
'''returns the groups that have access to this board.'''
return self.__groups__
def getPosts(self):
'''returns the posts made on the bulletin.'''
return self.__posts__
################################################################################
# interaction functions
################################################################################
def save_bulletins():
'''saves all of the bulletin boards to a file'''
set = storage.StorageSet()
list = storage.StorageList()
set.storeList("list", list)
for key,val in __bulletins__.iteritems():
one_set = storage.StorageSet()
one_set.storeString("key", key)
one_set.storeSet("val", val.store())
list.add(one_set)
set.write(__bulletin_file__)
set.close()
def load_bulletins():
set = storage.StorageSet(__bulletin_file__)
for bulletin in set.readList("list").sets():
key = bulletin.readString("key")
__bulletins__[key] = Bulletin(bulletin.readSet("val"))
set.close()
return
def do_list_bulletins(ch):
'''lists all of the bulletins to a character'''
buf = " %-10s %-28s %-12s %s\n" % ("Bulletins", "Time", "Poster", "Title")
buf = buf + "--------------------------------------------------------------------------------\n"
for key in __bulletins__.keys():
group = __bulletins__[key].getGroups()
if group == "" or ch.isInGroup(group):
if len(__bulletins__[key].getPosts()) == 0:
buf = buf + " %-10s no posts\n" % key
else:
post_one = __bulletins__[key].getPosts()[0]
buf = (buf + " %-10s %-28s %-12s %s\n" %
(key, post_one.getTime(), post_one.getPoster(),
post_one.getTitle()))
ch.page(buf)
return
def do_list_one_bulletin(ch, key):
'''lists the topics on one bulletin board to a character'''
if len(__bulletins__[key].getPosts()) == 0:
ch.send("The " + key + " bulletin is currently empty.")
else:
i = 1
buf = " %-3s %-28s %-12s %s\n" % ("Num", "Time", "Poster", "Title")
buf = buf + "--------------------------------------------------------------------------------\n"
for post in __bulletins__[key].getPosts():
buf = (buf + " %-3d %-28s %-12s %s\n" %
(i, post.getTime(), post.getPoster(), post.getTitle()))
i = i + 1
ch.page(buf)
def do_post(ch, key, arg):
'''posts a message to a bulletin board'''
if not __bulletins__.has_key(key):
ch.send("Not bulletin named " + key + " exists.")
elif (not __bulletins__[key].getGroups() == "" and
not ch.isInGroup(__bulletins__[key].getGroups())):
ch.send("You are not authorized to post on " + key + ".")
elif not type(arg) == str:
ch.send("You must provide a title for your post.")
elif ch.notepad == "":
ch.send("Your notepad is currently empty. Try writing something.")
else:
board = __bulletins__[key]
board.post(ch, arg, ch.notepad)
save_bulletins()
ch.send("Message posted.")
def do_read(ch, key, arg):
'''read a specific messge on a board, or list the board messages'''
if not __bulletins__.has_key(key):
ch.send("No bulletin named " + key + " exists.")
elif (not __bulletins__[key].getGroups() == "" and
not ch.isInGroup(__bulletins__[key].getGroups())):
ch.send("You are not authorized to read from " + key + ".")
elif arg == None:
do_list_one_bulletin(ch, key)
else:
try:
num = string.atoi(arg) - 1
if num < 0:
raise IndexError()
post = __bulletins__[key].getPosts()[num]
lheader = "By " + post.getPoster() + ": " + post.getTitle()
header = "%-50s %29s" % (lheader, post.getTime())
ch.page(header + "\n" +
"--------------------------------------------------------------------------------\n" +
post.getMssg())
except ValueError:
ch.send("You must provide a post number to read.")
except IndexError:
ch.send("That post number does not exist.")
def do_delete(ch, key, arg):
'''deleted a post from a board, or an entire board'''
if not __bulletins__.has_key(key):
ch.send("No bulletin named " + key + " exists.")
elif (not __bulletins__[key].getGroups() == "" and
not ch.isInGroup(__bulletins__[key].getGroups())):
ch.send("You are not authorized to delete from " + key + ".")
elif ch.isInGroup("admin") and arg == None:
ch.send("You must confirm the deletion of an entire bulletin.")
elif ch.isInGroup("admin") and arg == "confirm":
ch.send("You delete the bulletin, " + key + ".")
__bulletins__.pop(key)
save_bulletins()
else:
try:
num = string.atoi(arg) - 1
if num < 0:
raise IndexError()
post = __bulletins__[key].getPosts()[num]
if post.getPoster() == ch.name or ch.isInGroup("admin"):
ch.send("Post deleted.")
__bulletins__[key].getPosts().remove(post)
save_bulletins()
else:
ch.send("You cannot delete \"" + post.getTitle() + "\"")
except ValueError:
ch.send("You must provide a post number to delete.")
except IndexError:
ch.send("That post number does not exist.")
################################################################################
# player commands
################################################################################
def cmd_bulletin(ch, cmd, arg):
'''The entrypoint into the board system. Allows people to view or post
messages to bulletin boards. Admin can create/delete boards or messages.
Syntax:
bulletin
bulletin read <board> [article number]
bulletin post <board> <title>
bulletin delete <board> [article number]
bulletin create <board> [groups]
'''
# if we have no argument, list the board info
if arg == '':
do_list_bulletins(ch)
return
# try parsing out our arguments
try:
subcmd, board, arg = mud.parse_args(ch, True, cmd, arg,
"word word | string")
except: return
# figure out what subcommand we were trying to do
subcmd = subcmd.lower()
board = board.lower()
if subcmd == "read":
do_read(ch, board, arg)
elif subcmd == "post":
do_post(ch, board, arg)
elif subcmd == "delete":
do_delete(ch, board, arg)
elif subcmd == "create" and ch.isInGroup("admin"):
# create a new bulletin board, with group restrictions if neccessary
if __bulletins__.has_key(board):
ch.send("That board already exists.")
else:
__bulletins__[board] = Bulletin()
ch.send("New bulletin, " + board + ", created.")
if type(arg) == str:
__bulletins__[board].setGroups(arg)
ch.send("Bulletin groups set to: " + arg)
save_bulletins()
else:
# let them know what the valid subcommands are
buf = "Valid board subcommands are read, post, delete"
if ch.isInGroup("admin"): buf = buf + ", create"
buf = buf + "."
ch.send(ch, buf)
################################################################################
# hooks
################################################################################
def bulletin_display_hook(info):
'''displays the bulletin board info to a character when he enters game'''
ch, = hooks.parse_info(info)
do_list_bulletins(ch)
################################################################################
# initialization and unloading
################################################################################
load_bulletins()
hooks.add("char_to_game", bulletin_display_hook)
def __unload__():
'''things that need to be detached when the module is un/reloaded'''
hooks.remove("char_to_game", bulletin_display_hook)
################################################################################
# add our commands
################################################################################
add_cmd("bulletin", None, cmd_bulletin, "unconscious", "flying", "player",
False, False)