################################################################################ # # 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)