diff --git a/ceo/library.py b/ceo/library.py index c360f29..13a31ef 100644 --- a/ceo/library.py +++ b/ceo/library.py @@ -9,7 +9,8 @@ CONFIG_FILE = "/etc/csc/library.cf" cfg = {} def configure(): - """ Load configuration + """ + Load configuration """ cfg_fields = [ "library_connect_string" ] @@ -20,19 +21,32 @@ def configure(): sqlhub.processConnection = connectionForURI(cfg["library_connect_string"]) class Book(SQLObject): + """ + A book. This does all the stuff we could + ever want to do with a book. + """ isbn = StringCol() title = StringCol() - description = StringCol() year = StringCol() publisher = StringCol() authors = SQLRelatedJoin("Author") signouts = SQLMultipleJoin("Signout") def sign_out(self, u): + """ + Call this with a username to sign out + a book. + """ s = Signout(username=u, book=self, outdate=datetime.today(), indate=None) def sign_in(self, u): + """ + Call this to check a book back in to + the library. Username is used to + disambiguate in case more than one + copy of this book has been signed out. + """ s = self.signouts.filter(AND(Signout.q.indate==None, Signout.q.username==u)) if s.count() > 0: s.orderBy(Signout.q.outdate).limit(1).getOne(None).sign_in() @@ -41,6 +55,10 @@ class Book(SQLObject): raise Exception("PEBKAC: Book not signed out!") def __str__(self): + """ + Magic drugs to make books display + nicely. + """ book = "%s [%s]" % (self.title, self.year) book += "\nBy: " for a in self.authors: @@ -64,22 +82,30 @@ class Book(SQLObject): class Author(SQLObject): + """ + An author can author many books, and a book + can have many authors. This lets us map + both ways. + """ name = StringCol() books = RelatedJoin("Book") class Signout(SQLObject): + """ + An instance of a signout associates usernames, + books, signout dates, and return dates to mark + that a book has been signed out by a particular + user. + """ username = StringCol() book = ForeignKey("Book") outdate = DateCol() indate = DateCol() -# def __init__(self, u, b, o, i): -# username = u -# book = b -# outdate = o -# indate = i - def sign_in(self): + """ + Terminate the signout (return the book). + """ self.indate = datetime.today() def _get_due_date(self): @@ -90,8 +116,4 @@ class Signout(SQLObject): return self.outdate + timedelta(weeks=2) if __name__ == "__main__": - configure() - Book.createTable() - Author.createTable() - Signout.createTable() print "This functionality isn't implemented yet." diff --git a/ceo/urwid/library.py b/ceo/urwid/library.py index 60fea84..e04a3fe 100644 --- a/ceo/urwid/library.py +++ b/ceo/urwid/library.py @@ -11,6 +11,9 @@ import ceo.library as lib def library(data): + """ + Create the main menu for the library system. + """ menu = make_menu([ ("Checkout Book", checkout_book, None), ("Return Book", return_book, None), @@ -21,22 +24,40 @@ def library(data): push_window(menu, "Library") def search_books(data): + """ + Define menus for searching books. + """ menu = make_menu([ ("Overdue Books", overdue_books, None), ]) push_window(menu, "Book Search") def overdue_books(data): + """ + Display a list of all books that are overdue. + """ None def checkout_book(data): + """ + Display the book checkout wizard. + """ push_wizard("Checkout", [CheckoutPage, BookSearchPage, ConfirmPage]) def return_book(data): + """ + Display the book return wizard. + """ push_wizard("Checkout", [CheckinPage, ConfirmPage]) class BookSearchPage(WizardPanel): + """ + The page used when searching for books. + """ def init_widgets(self): + """ + Initialize the widgets and state variables. + """ self.search = None self.state["book"] = None self.isbn = SingleEdit("ISBN: ") @@ -51,6 +72,9 @@ class BookSearchPage(WizardPanel): ] def check(self): + """ + Validate input and update state. + """ if self.state["book"] is None: push_window(SearchPage(self.isbn.get_edit_text(), self.title.get_edit_text(), @@ -62,7 +86,16 @@ class BookSearchPage(WizardPanel): class CheckoutPage(WizardPanel): + """ + The initial page when checking out a book. + """ def init_widgets(self): + """ + Initialize widgets and set up state. + + user -> the username to sign the book to + task -> used for the confirmation dialog + """ self.state["user"] = "ERROR" self.state["task"] = "sign_out" self.user = SingleEdit("Username: ") @@ -77,7 +110,16 @@ class CheckoutPage(WizardPanel): self.state['user'] = self.user.get_edit_text() class ConfirmPage(WizardPanel): + """ + The confirmation screen when checking-in and checking-out + a book. + """ def init_widgets(self): + """ + Initialize widgets and state. + + task -> used to deterimine the action + """ self.user = urwid.Text("Username: ") self.book = urwid.Text("Book: ") @@ -95,11 +137,18 @@ class ConfirmPage(WizardPanel): ] def activate(self): + """ + Ensures that correct data is displayed. + """ self.user.set_text("Username: " + self.state["user"]) if self.state["book"]: self.book.set_text("Book: " + self.state["book"].title) def check(self): + """ + Generally used for validation, but in this case it does + the actual book check-out. + """ #TODO: Validate user at some point (preferrably user entry screen) if self.state["task"] and self.state["task"]=="sign_in": self.state["book"].sign_in(self.state["user"]) @@ -109,7 +158,20 @@ class ConfirmPage(WizardPanel): class SearchPage(urwid.WidgetWrap): + """ + Displays search results. Can search on isbn, + title, or username (for books that are currently + out). + """ def __init__(self, isbn, title, user, state): + """ + This does the actual search, and sets up the screen + when it's done. + + title -> search by (partial) title + isbn -> search by (partial) isbn + user -> search by username (for checked-out books) + """ self.state = state books = [] widgets = [] @@ -130,11 +192,25 @@ class SearchPage(urwid.WidgetWrap): urwid.WidgetWrap.__init__(self, urwid.ListBox(widgets)) def select(self, book): + """ + Marks a book for check-in or check-out. + """ self.state["book"] = book pop_window() class CheckinPage(WizardPanel): + """ + The initial page to start the check-in widget. + """ def init_widgets(self): + """ + Throw some widgets on the screen and set up + some state. + + book -> The book to check out. + user -> Stupid people like books. + task -> What are we doing? (For confirm screen.) + """ self.state["book"] = None self.state["user"] = "ERROR" self.state["task"] = "sign_in" @@ -147,6 +223,11 @@ class CheckinPage(WizardPanel): ] def check(self): + """ + Pushes the search window. + + Should validate usernames. + """ if self.state["book"] is None: push_window(SearchPage(None, None,