Merge commit 'public/master' into ceod

This commit is contained in:
Michael Spang 2009-07-29 13:29:42 -04:00
commit 5ce11709ff
4 changed files with 236 additions and 4 deletions

View File

@ -150,6 +150,12 @@ def create_member(username, password, name, program):
addmember = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) addmember = subprocess.Popen(args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = addmember.communicate(password) out, err = addmember.communicate(password)
status = addmember.wait() status = addmember.wait()
# # If the user was created, consider adding them to the mailing list
# if not status:
# listadmin_cfg_file = "/path/to/the/listadmin/config/file"
# mail = subprocess.Popen(["/usr/bin/listadmin", "-f", listadmin_cfg_file, "--add-member", username + "@csclub.uwaterloo.ca"])
# status2 = mail.wait() # Fuck if I care about errors!
except OSError, e: except OSError, e:
raise MemberException(e) raise MemberException(e)

134
ceo/pymazon.py Normal file
View File

@ -0,0 +1,134 @@
#!/usr/bin/python
from xml.dom import minidom, Node
import urllib
import time
class PyMazonError(Exception):
"""Holds information about an error that occured during a pymazon request"""
def __init__(self, messages):
self.__message = '\n'.join(messages)
def __get_message(self):
return self.__message
def __str__(self):
return repr(self.__message)
message = property(fget=__get_message)
class PyMazonBook:
"""Stores information about a book retrieved via PyMazon."""
def __init__(self, title, authors, publisher, year, isbn10, isbn13, edition):
self.__title = title
self.__authors = authors
self.__publisher = publisher
self.__year = year
self.__isbn10 = isbn10
self.__isbn13 = isbn13
self.__edition = edition
def __str__(self):
return 'Title: ' + self.title + '\n' + \
'Author(s): ' + ', '.join(self.authors) + '\n' \
'Publisher: ' + self.publisher + '\n' + \
'Year: ' + self.year + '\n' + \
'ISBN-10: ' + self.isbn10 + '\n' + \
'ISBN-13: ' + self.isbn13 + '\n' + \
'Edition: ' + self.edition
def __get_title(self):
return self.__title
def __get_authors(self):
return self.__authors
def __get_publisher(self):
return self.__publisher
def __get_year(self):
return self.__year
def __get_isbn10(self):
return self.__isbn10
def __get_isbn13(self):
return self.__isbn13
def __get_edition(self):
return self.__edition
title = property(fget=__get_title)
authors = property(fget=__get_authors)
publisher = property(fget=__get_publisher)
year = property(fget=__get_year)
isbn10 = property(fget=__get_isbn10)
isbn13 = property(fget=__get_isbn13)
edition = property(fget=__get_edition)
class PyMazon:
"""A method of looking up book information on Amazon."""
def __init__(self, accesskey):
self.__key = accesskey
self.__last_query_time = 0
def __form_request(self, isbn):
return 'http://webservices.amazon.com/onca/xml?' + \
'Service=AWSECommerceService' + \
'&Version=2008-08-19' + \
'&AWSAccessKeyId=' + self.__key + \
'&Operation=ItemLookup' + \
'&ResponseGroup=ItemAttributes' + \
'&IdType=ISBN' + \
'&SearchIndex=Books' + \
'&ItemId=' + isbn
def __elements_text(self, element, name):
result = []
matching = element.getElementsByTagName(name)
for match in matching:
if len(match.childNodes) != 1:
continue
child = match.firstChild
if child.nodeType != Node.TEXT_NODE:
continue
result.append(child.nodeValue.strip())
return result
def __format_errors(self, errors):
error_list = []
for error in errors:
error_list.extend(self.__elements_text(error, 'Message'))
return error_list
def __extract_single(self, element, name):
matches = self.__elements_text(element, name)
if len(matches) == 0:
return ''
return matches[0]
def lookup(self, isbn):
file = urllib.urlretrieve(self.__form_request(isbn))[0]
xmldoc = minidom.parse(file)
cur_time = time.time()
while cur_time - self.__last_query_time < 1.0:
sleep(cur_time - self.__last_query_time)
cur_time = time.time()
self.__last_query_time = cur_time
errors = xmldoc.getElementsByTagName('Errors')
if len(errors) != 0:
raise PyMazonError, self.__format_errors(errors)
title = self.__extract_single(xmldoc, 'Title')
authors = self.__elements_text(xmldoc, 'Author')
publisher = self.__extract_single(xmldoc, 'Publisher')
year = self.__extract_single(xmldoc, 'PublicationDate')[0:4]
isbn10 = self.__extract_single(xmldoc, 'ISBN')
isbn13 = self.__extract_single(xmldoc, 'EAN')
edition = self.__extract_single(xmldoc, 'Edition')
return PyMazonBook(title, authors, publisher, year, isbn10, isbn13, edition)

View File

@ -5,12 +5,26 @@ from ceo.urwid.widgets import *
from ceo.urwid.window import * from ceo.urwid.window import *
from sqlobject.sqlbuilder import * from sqlobject.sqlbuilder import *
from datetime import datetime, timedelta from datetime import datetime, timedelta
from ceo.pymazon import PyMazon
from ceo.pymazon import PyMazonError
from ceo import conf
from ceo import terms from ceo import terms
import ceo.library as lib import ceo.library as lib
CONFIG_FILE = "/etc/csc/library.cf"
cfg = {}
def configure():
"""
Load configuration
"""
cfg_fields = [ "aws_account_key" ]
temp_cfg = conf.read(CONFIG_FILE)
conf.check_string_fields(CONFIG_FILE, cfg_fields, temp_cfg)
cfg.update(temp_cfg)
def library(data): def library(data):
""" """
@ -20,7 +34,7 @@ def library(data):
("Checkout Book", checkout_book, None), ("Checkout Book", checkout_book, None),
("Return Book", return_book, None), ("Return Book", return_book, None),
("Search Books", search_books, None), ("Search Books", search_books, None),
# ("Add Book", add_book, None), ("Add Book", add_book, None),
("Back", raise_back, None), ("Back", raise_back, None),
]) ])
push_window(menu, "Library") push_window(menu, "Library")
@ -35,12 +49,18 @@ def search_books(data):
]) ])
push_window(menu, "Book Search") push_window(menu, "Book Search")
def add_book(data):
"""
Add book to library. Also stab Sapphyre.
"""
push_wizard("Add Book", [BookAddPage])
def overdue_books(data): def overdue_books(data):
""" """
Display a list of all books that are overdue. Display a list of all books that are overdue.
""" """
oldest = datetime.today() - timedelta(weeks=2) oldest = datetime.today() - timedelta(weeks=2)
overdue = lib.Signout.select(lib.Signout.q.outdate<oldest) overdue = lib.Signout.select(AND(lib.Signout.q.outdate<oldest, lib.Signout.q.indate==None))
widgets = [] widgets = []
@ -83,6 +103,45 @@ def return_book(data):
""" """
push_wizard("Checkout", [CheckinPage, ConfirmPage]) push_wizard("Checkout", [CheckinPage, ConfirmPage])
class BookAddPage(WizardPanel):
"""
Thingy for going on screen to add books.
"""
def init_widgets(self):
"""
Make some widgets.
"""
self.isbn = SingleEdit("ISBN: ")
self.widgets = [
urwid.Text("Adding New Book"),
urwid.Divider(),
self.isbn
]
def check(self):
"""
Do black magic.
"""
configure()
isbn = self.isbn.get_edit_text()
try:
pymazon = PyMazon(cfg["aws_account_key"])
book = pymazon.lookup(isbn)
currents = lib.Book.select(lib.Book.q.isbn==isbn)
if currents.count() == 0:
lib.Book(isbn=isbn, title=book.title,
year=book.year, publisher=book.publisher)
pop_window()
else:
set_status("Book already exists, fucker.")
except PyMazonError, e:
set_status("Amazon thinks this is not a book. Take it up with them.")
return False
class BookSearchPage(WizardPanel): class BookSearchPage(WizardPanel):
""" """
The page used when searching for books. The page used when searching for books.
@ -216,10 +275,14 @@ class SearchPage(urwid.WidgetWrap):
books = lib.Book.select(LIKE(lib.Book.q.title, "%" + title + "%")) books = lib.Book.select(LIKE(lib.Book.q.title, "%" + title + "%"))
elif not isbn is None and not isbn=="": elif not isbn is None and not isbn=="":
books = lib.Book.select(lib.Book.q.isbn==isbn) books = lib.Book.select(lib.Book.q.isbn==isbn)
elif not user is None and not user=="": elif (not (user is None)) and (not (user=="")):
st = lib.Signout.select(AND(lib.Signout.q.username==user, lib.Signout.q.indate==None)) st = lib.Signout.select(AND(lib.Signout.q.username==user, lib.Signout.q.indate==None))
for s in st: for s in st:
books.append(s.book) books.append(s.book)
else:
st = lib.Signout.select(lib.Signout.q.indate==None)
for s in st:
books.append(s.book)
for b in books: for b in books:
widgets.append(urwid.AttrWrap(ButtonText(self.select, b, str(b)), widgets.append(urwid.AttrWrap(ButtonText(self.select, b, str(b)),

31
debian/changelog vendored
View File

@ -1,8 +1,37 @@
ceo (0.4.19) stable testing; urgency=low ceo (0.4.24) stable testing; urgency=low
* Bump standards version. * Bump standards version.
-- Michael Spang <mspang@uwaterloo.ca> Wed, 29 Jul 2009 07:31:24 -0400 -- Michael Spang <mspang@uwaterloo.ca> Wed, 29 Jul 2009 07:31:24 -0400
ceo (0.4.23) stable testing; urgency=low
* CEO library now only finds books that are signed out as being overdue.
-- Michael Gregson <mgregson@csclub.uwaterloo.ca> Wed, 11 Mar 2009 03:30:01 -0500
ceo (0.4.22) stable testing; urgency=low
* CEO now closes window when it should. (Sorry)
-- Michael Gregson <mgregson@csclub.uwaterloo.ca> Wed, 11 Mar 2009 02:25:01 -0500
ceo (0.4.21) stable testing; urgency=low
* CEO Library can now add boox.
-- Michael Gregson <mgregson@csclub.uwaterloo.ca> Wed, 11 Mar 2009 02:09:01 -0500
ceo (0.4.20) stable testing; urgency=low
* Update kadmin headers
-- David Bartley <dtbartle@csclub.uwaterloo.ca> Tue, 24 Feb 2009 16:08:12 -0500
ceo (0.4.19) stable testing; urgency=low
* Rebuild for lenny.
-- Michael Spang <mspang@uwaterloo.ca> Tue, 17 Feb 2009 22:23:30 -0500
ceo (0.4.18) stable testing; urgency=low ceo (0.4.18) stable testing; urgency=low