Added search for books that are signed out.
[mspang/pyceo.git] / ceo / library.py
1 from sqlobject import *
2 from sqlobject.sqlbuilder import *
3 from ceo import conf
4 from ceo import members
5 from ceo import terms
6 import time
7 from datetime import datetime, timedelta
8
9 CONFIG_FILE = "/etc/csc/library.cf"
10
11 cfg = {}
12
13 def configure():
14     """
15     Load configuration
16     """
17     cfg_fields = [ "library_connect_string" ]
18     
19     temp_cfg = conf.read(CONFIG_FILE)
20     conf.check_string_fields(CONFIG_FILE, cfg_fields, temp_cfg)
21     cfg.update(temp_cfg)
22     
23     sqlhub.processConnection = connectionForURI(cfg["library_connect_string"])
24
25 class Book(SQLObject):
26     """
27     A book.  This does all the stuff we could
28     ever want to do with a book.
29     """
30     isbn = StringCol()
31     title = StringCol()
32     year = StringCol()
33     publisher = StringCol()
34     authors = SQLRelatedJoin("Author")
35     signouts = SQLMultipleJoin("Signout")
36
37     def sign_out(self, u):
38         """
39         Call this with a username to sign out
40         a book.
41         """
42         if members.registered(u, terms.current()):
43             s = Signout(username=u, book=self,
44                         outdate=datetime.today(), indate=None)
45
46     def sign_in(self, u):
47         """
48         Call this to check a book back in to
49         the library.  Username is used to
50         disambiguate in case more than one
51         copy of this book has been signed out.
52         """
53         s = self.signouts.filter(AND(Signout.q.indate==None, Signout.q.username==u))
54         if s.count() > 0:
55             list(s.orderBy(Signout.q.outdate).limit(1))[0].sign_in()
56             return True
57         else:
58             raise Exception("PEBKAC:  Book not signed out!")
59
60     def __str__(self):
61         """
62         Magic drugs to make books display
63         nicely.
64         """
65         book = "%s [%s]" % (self.title, self.year)
66         book += "\nBy: "
67         for a in self.authors:
68             book += a.name
69             book += ", "
70
71         if self.authors.count() < 1:
72             book += "(unknown)"
73
74         book = book.strip(", ")
75
76         signouts = self.signouts.filter(Signout.q.indate==None)
77         if signouts.count() > 0:
78             book += "\nSigned Out: "
79             for s in signouts:
80                 book += s.username + " (" + s.due_date + "), "
81
82         book = book.strip(", ")
83         
84         return book
85
86
87 class Author(SQLObject):
88     """
89     An author can author many books, and a book
90     can have many authors.  This lets us map
91     both ways.
92     """
93     name = StringCol()
94     books = RelatedJoin("Book")
95
96 class Signout(SQLObject):
97     """
98     An instance of a signout associates usernames,
99     books, signout dates, and return dates to mark
100     that a book has been signed out by a particular
101     user.
102     """
103     username = StringCol()
104     book = ForeignKey("Book")
105     outdate = DateCol()
106     indate = DateCol()
107
108     def sign_in(self):
109         """
110         Terminate the signout (return the book).
111         """
112         self.indate = datetime.today()
113
114     def _get_due_date(self):
115         """
116         Compute the due date of the book based on the sign-out
117         date.
118         """
119         return self.outdate + timedelta(weeks=2)
120
121 if __name__ == "__main__":
122     print "This functionality isn't implemented yet."