added files
This commit is contained in:
parent
2869955951
commit
d3aefba165
22
index/README.txt
Executable file
22
index/README.txt
Executable file
|
@ -0,0 +1,22 @@
|
|||
Settings assumes mysql db name of 'idx' - change if your db is something else
|
||||
|
||||
Requires django-tagging from svn:
|
||||
svn checkout http://django-tagging.googlecode.com/svn/trunk/ tagging-trunk
|
||||
|
||||
Requires python-dateutil
|
||||
Requires elementtree: sudo easy_install elementtree
|
||||
Requires simplejson: sudo easy_install simplejson
|
||||
|
||||
Setup DB:
|
||||
mysql -u root
|
||||
mysql> create database idx;
|
||||
mysql> quit;
|
||||
|
||||
Create tables:
|
||||
python manage.py syncdb (or python dropandcreatedb.py)
|
||||
|
||||
Run Server:
|
||||
python manage.py runserver
|
||||
|
||||
Open Browser:
|
||||
http://localhost:8000
|
0
index/__init__.py
Executable file
0
index/__init__.py
Executable file
0
index/books/__init__.py
Executable file
0
index/books/__init__.py
Executable file
80
index/books/admin.py
Executable file
80
index/books/admin.py
Executable file
|
@ -0,0 +1,80 @@
|
|||
from books.models import *
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
def showCategories(obj):
|
||||
cats = obj.categories.iterator()
|
||||
s = ''
|
||||
for c in cats:
|
||||
s += c.name + " "
|
||||
return s
|
||||
|
||||
def labelID(obj):
|
||||
s = ''
|
||||
if obj.box:
|
||||
try:
|
||||
loc = Location.objects.get(pk=obj.box.id)
|
||||
s += loc.code + "/"
|
||||
except:
|
||||
s += ""
|
||||
s += obj.box.box_no + "/"
|
||||
# if obj.box.location:
|
||||
# s += obj.box.location.code + "/"
|
||||
s += str(obj.id)
|
||||
return s
|
||||
|
||||
class BookImageInline(admin.TabularInline):
|
||||
model = Image
|
||||
extra = 3
|
||||
|
||||
class BookAdmin(admin.ModelAdmin):
|
||||
ordering = ('title',)
|
||||
search_fields = ['title', 'description']
|
||||
inlines = [BookImageInline]
|
||||
save_on_top = True;
|
||||
|
||||
class HardwareAdmin(admin.ModelAdmin):
|
||||
ordering = ('-id',)
|
||||
list_display = ('title', labelID, 'box', 'category', 'tags',)
|
||||
list_filter = ('category', 'box', 'tags',)
|
||||
list_editable = ('box', 'tags',)
|
||||
search_fields = ['title', 'description',]
|
||||
save_as = True
|
||||
save_on_top = True
|
||||
radio_fields = {'category': admin.HORIZONTAL}
|
||||
|
||||
class HardwareInline(admin.StackedInline):
|
||||
model = Hardware
|
||||
extra = 5
|
||||
save_on_top = True;
|
||||
|
||||
class BoxAdmin(admin.ModelAdmin):
|
||||
ordering = ('-id',)
|
||||
search_fields = ['box_no', 'description']
|
||||
list_display = ('box_no', 'location', 'tags',)
|
||||
inlines = [HardwareInline]
|
||||
list_filter = ('location',)
|
||||
list_editable = ('location', 'tags',)
|
||||
save_on_top = True;
|
||||
|
||||
class CatalogueAdmin(admin.ModelAdmin):
|
||||
ordering = ('title',)
|
||||
search_fields = ['title', 'artist']
|
||||
save_on_top = True;
|
||||
|
||||
class Link(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
class HardwareCategoryAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
admin.site.register(Hardware, HardwareAdmin)
|
||||
admin.site.register(Box, BoxAdmin)
|
||||
admin.site.register(HardwareCategory, HardwareCategoryAdmin)
|
||||
#admin.site.register(Link)
|
||||
admin.site.register(HardwareLink)
|
||||
admin.site.register(Catalogue, CatalogueAdmin)
|
||||
admin.site.register(Book, BookAdmin)
|
||||
admin.site.register(Owner)
|
||||
admin.site.register(Location)
|
||||
|
58
index/books/fields.py
Executable file
58
index/books/fields.py
Executable file
|
@ -0,0 +1,58 @@
|
|||
from django.db import models
|
||||
from django import forms
|
||||
from django.utils.text import capfirst
|
||||
|
||||
class MultiSelectFormField(forms.MultipleChoiceField):
|
||||
widget = forms.CheckboxSelectMultiple
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.max_choices = kwargs.pop('max_choices', 0)
|
||||
super(MultiSelectFormField, self).__init__(*args, **kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
if not value and self.required:
|
||||
raise forms.ValidationError(self.error_messages['required'])
|
||||
if value and self.max_choices and len(value) > self.max_choices:
|
||||
raise forms.ValidationError('You must select a maximum of %s choice%s.'
|
||||
% (apnumber(self.max_choices), pluralize(self.max_choices)))
|
||||
return value
|
||||
|
||||
class MultiSelectField(models.Field):
|
||||
__metaclass__ = models.SubfieldBase
|
||||
|
||||
def get_internal_type(self):
|
||||
return "CharField"
|
||||
|
||||
def get_choices_default(self):
|
||||
return self.get_choices(include_blank=False)
|
||||
|
||||
def _get_FIELD_display(self, field):
|
||||
value = getattr(self, field.attname)
|
||||
choicedict = dict(field.choices)
|
||||
|
||||
def formfield(self, **kwargs):
|
||||
# don't call super, as that overrides default widget if it has choices
|
||||
defaults = {'required': not self.blank, 'label': capfirst(self.verbose_name),
|
||||
'help_text': self.help_text, 'choices':self.choices}
|
||||
if self.has_default():
|
||||
defaults['initial'] = self.get_default()
|
||||
defaults.update(kwargs)
|
||||
return MultiSelectFormField(**defaults)
|
||||
|
||||
def get_db_prep_value(self, value):
|
||||
if isinstance(value, basestring):
|
||||
return value
|
||||
elif isinstance(value, list):
|
||||
return ",".join(value)
|
||||
|
||||
def to_python(self, value):
|
||||
if isinstance(value, list):
|
||||
return value
|
||||
return value.split(",")
|
||||
|
||||
def contribute_to_class(self, cls, name):
|
||||
super(MultiSelectField, self).contribute_to_class(cls, name)
|
||||
if self.choices:
|
||||
func = lambda self, fieldname = name, choicedict = dict(self.choices):",".join([choicedict.get(value,value) for value in getattr(self,fieldname)])
|
||||
setattr(cls, 'get_%s_display' % self.name, func)
|
||||
|
226
index/books/isbnlookup.py
Executable file
226
index/books/isbnlookup.py
Executable file
|
@ -0,0 +1,226 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
import types
|
||||
import time
|
||||
import string
|
||||
import fileinput
|
||||
import re
|
||||
import urllib
|
||||
import isbnvalidate
|
||||
from dateutil.parser import parse as parseDate
import elementtree.ElementTree as ET
|
||||
import feedparser
|
||||
import simplejson
|
||||
|
||||
|
||||
def myDate(datestr):
|
||||
dateObj = parseDate(datestr)
|
||||
month = dateObj.month
|
||||
yr = dateObj.year
|
||||
d = {
|
||||
'year': yr,
|
||||
'month': month
|
||||
}
|
||||
return d
|
||||
|
||||
def getHtmlFromUrl(url):
|
||||
try:
|
||||
u = urllib.urlopen(url)
|
||||
t = u.read()
|
||||
u.close
|
||||
except:
|
||||
return False
|
||||
return t
|
||||
|
||||
def getimagesrc(isbn):
|
||||
if (len(isbn) == 13):
|
||||
newisbn = isbnvalidate.convertISBN13toISBN10(isbn)
|
||||
isbn = newisbn.strip()
|
||||
|
||||
inf = urllib.urlopen('http://www.amazon.com/gp/product/images/' + isbn)
|
||||
allhtml = inf.read()
|
||||
inf.close()
|
||||
imghtml = re.search('<div id="imageViewerDiv"><img src="(.*?)" id="prodImage" /></div>', allhtml)
|
||||
|
||||
imgsrc1 = imghtml.group(1)
|
||||
return imgsrc1
|
||||
|
||||
|
||||
|
||||
#TODO: Try avoiding wrapping entire search in 'try'.
|
||||
def ChaptersCa(isbn):
|
||||
url = 'http://www.chapters.ca/books/details/default.asp?ISBN=' + isbn
|
||||
html = getHtmlFromUrl(url)
|
||||
if not html:
|
||||
return False
|
||||
if (string.find(html, 'chapters.indigo.ca: Error:') >= 0):
|
||||
return False
|
||||
titlehtml = re.search('<h1>(.*?)</h1>', html)
|
||||
authorhtml = re.search('<p class="link">Author: (<a href=.*</a>)</p>', html)
|
||||
dimensionshtml = re.search('<label>Dimensions:</label>(.*?)</p>', html)
|
||||
publisherhtml = re.search('<label>Publisher:</label>(.*?)</p>', html)
|
||||
publishedhtml = re.search('<label>Published:</label>(.*?)</p>', html)
|
||||
#print (titlehtml, authorhtml, dimensionshtml, publisherhtml, publishedhtml)
|
||||
try:
|
||||
authorlinks = authorhtml.group(1).strip()
|
||||
authors = re.findall('<a .*?>(.*?)</a>', authorlinks) # returns list of authors
|
||||
|
||||
for a in authors:
|
||||
if re.search('See more ', a):
|
||||
tmp = a
|
||||
authors.remove(a)
|
||||
d = {}
|
||||
|
||||
d['source'] = "ChaptersCa"
|
||||
d['pages'] = dimensionshtml.group(1).split(",")[0].strip()
|
||||
d['dimensions'] = dimensionshtml.group(1).split(",")[1].strip()
|
||||
# dimensions = dimensionshtml.group(1).strip()
|
||||
d['publisher'] = publisherhtml.group(1).strip()
|
||||
d['published'] = myDate(publishedhtml.group(1).strip())
|
||||
d['title'] = titlehtml.group(1).strip()
|
||||
d['coverimg'] = getimagesrc(isbn)
|
||||
d['url'] = url
|
||||
d['authors'] = authors
|
||||
except:
|
||||
return False
|
||||
return d
|
||||
|
||||
#TODO: Regex failing. Test.
|
||||
def Amazon(isbn):
|
||||
url = 'http://www.amazon.com/gp/search/ref=sr_adv_b/?field-isbn=' + isbn
|
||||
html = getHtmlFromUrl(url)
|
||||
if not html:
|
||||
return False
|
||||
if (string.find(html, 'Your search did not match any products.') >= 0):
|
||||
return False
|
||||
titlehtml = re.search('<span id="btAsinTitle" style="">(.*?)</span>', html)
|
||||
paperbackhtml = re.search('<li><b>Paperback:</b>(.*?)</li>', html)
|
||||
weighthtml = re.search('<li><b>Shipping Weight:</b>(.*?)\(.*?\)</li>', html)
|
||||
publisherhtml = re.search('<li><b>Publisher:</b>(.*?) \((.*?)\)</li>', html)
|
||||
authors = re.findall('<a href=".*?">(.*?)</a> \(Author\)', html) # returns list of authors
|
||||
try:
|
||||
d = {}
|
||||
d['source'] = 'Amazon'
|
||||
d['pages'] = paperbackhtml.group(1).strip()
|
||||
d['dimensions'] = weighthtml.group(1).strip()
|
||||
d['publisher'] = publisherhtml.group(1).strip()
|
||||
d['published'] = myDate(publisherhtml.group(2).strip())
|
||||
d['title'] = titlehtml.group(1).strip()
|
||||
d['coverimg'] = getimagesrc(isbn)
|
||||
d['url'] = url
|
||||
except:
|
||||
return False
|
||||
# sourceurl = 'http://www.amazon.com/gp/search/ref=sr_adv_b/?field-isbn=' + isbn
|
||||
return d
|
||||
|
||||
#TODO: Dont return False if a single key does not exist
|
||||
def ISBNdb(isbn):
|
||||
ISBNdb_KEY = 'HLRQD9WN'
|
||||
# http://isbndb.com/api/books.xml?access_key=HLRQD9WN&index1=isbn&value1=1400082463
|
||||
url = 'http://isbndb.com/api/books.xml?access_key=' + ISBNdb_KEY + '&index1=isbn&value1=' + isbn
|
||||
try:
|
||||
xml = getHtmlFromUrl(url)
|
||||
tree = ET.XML(xml)
|
||||
except:
|
||||
return False
|
||||
results = tree.find("BookList").get("total_results")
|
||||
if (results < 1):
|
||||
return False
|
||||
d = {}
|
||||
d['source'] = 'ISBNdb'
|
||||
try:
|
||||
book = tree.getchildren()[0].getchildren()[0]
|
||||
d['title'] = book.findtext("Title")
|
||||
titleLong = book.findtext("TitleLong").strip()
|
||||
if (titleLong != ''):
|
||||
d['title'] = titleLong
|
||||
d['publisher'] = book.findtext("PublisherText")
|
||||
d['summary'] = book.findtext("Summary")
|
||||
d['notes'] = book.findtext("Notes")
|
||||
authorsTxt = book.findtext("AuthorsText")
|
||||
d['authors'] = authorsTxt.split(",")
|
||||
except:
|
||||
return False
|
||||
return d
|
||||
|
||||
#TODO: Fetch weblinks.
|
||||
#TODO: Clean-up to not go to exception when can't find a single attribute
|
||||
#TODO: Go through XML and fetch more relevant fields.
|
||||
#TODO: Make URL more specific to look for ISBN codes. [IMP!!]
|
||||
def GoogleBooks(isbn):
|
||||
url = 'http://books.google.com/books/feeds/volumes?q=' + isbn
|
||||
try:
|
||||
feed = feedparser.parse(url)
|
||||
book = feed.entries[0]
|
||||
except:
|
||||
return False
|
||||
try:
|
||||
d = {}
|
||||
d['source'] = 'GoogleBooks'
|
||||
d['title'] = book.title
|
||||
# d['summary'] = book.description
|
||||
d['pages'] = book.dc_format
|
||||
d['author'] = [book.author]
|
||||
d['publisher'] = book.publisher
|
||||
except:
|
||||
return False
|
||||
return d
|
||||
|
||||
#TODO: Don't return book! Return dict according to our fields.
|
||||
#TODO: Fetch Chapters in a meaningful way
|
||||
#TODO: Add relevant fields - first_sentence, etc.
|
||||
def OpenLibrary(isbn):
|
||||
if (len(isbn) == 10):
|
||||
url1 = 'http://openlibrary.org/api/things?query={%22type%22%3A+%22\%2Ftype\%2Fedition%22%2C+%22isbn_10%22%3A+%22' + isbn + '%22}&prettyprint=true&text=true'
|
||||
elif (len(isbn) == 13):
|
||||
url1 = 'http://openlibrary.org/api/things?query={%22type%22%3A+%22\%2Ftype\%2Fedition%22%2C+%22isbn_13%22%3A+%22' + isbn + '%22}&prettyprint=true&text=true'
|
||||
else:
|
||||
return False
|
||||
json = getHtmlFromUrl(url1)
|
||||
print json
|
||||
if not json:
|
||||
return False
|
||||
j = simplejson.loads(json)
|
||||
if (j['status'] != 'ok' or len(j['result']) == 0):
|
||||
return False
|
||||
olId = j['result'][0]
|
||||
url2 = "http://openlibrary.org/api/get?key=" + olId
|
||||
json2 = getHtmlFromUrl(url2)
|
||||
book = simplejson.loads(json2)
|
||||
return book
|
||||
|
||||
#TODO: write regex parser for LookUpByIsbn to return esp. Reviews
|
||||
def LookUpByIsbn(isbn):
|
||||
url = "http://www.lookupbyisbn.com/itemDetail.aspx?type=Books&id=" + isbn
|
||||
return False
|
||||
|
||||
|
||||
def searchAll(isbn, **kwargs):
|
||||
sources = [OpenLibrary, GoogleBooks, ISBNdb, Amazon, ChaptersCa]
|
||||
return getAggregate(sources, isbn)
|
||||
|
||||
#TODO: Handle specific cases of 'author' and 'weblink' fields. Also, other lists, like Chapters.
|
||||
def getAggregate(sources, isbn, **kwargs):
|
||||
if not isbnvalidate.isValidISBN(isbn):
|
||||
return {'errors': "Invalid ISBN"}
|
||||
# if kwargs['isbnformat'] == 10 and len(isbn) == 13:
|
||||
# isbn = isbnvalidate.convertISBN13toISBN10(isbn)
|
||||
# if kwargs['isbnformat'] == 13 and len(isbn) == 10:
|
||||
# isbn = isbnvalidate.convertISBN10toI3(isbn)
|
||||
|
||||
results = []
|
||||
for source in sources:
|
||||
rDict = source(isbn)
|
||||
if (rDict):
|
||||
results.append(rDict)
|
||||
dFinal = {}
|
||||
for result in results:
|
||||
for key in r.keys():
|
||||
if (key not in dFinal.keys()):
|
||||
dFinal[key] = result[key]
|
||||
return dFinal
|
||||
|
||||
|
||||
|
||||
|
||||
|
418
index/books/isbnlookup2.py
Executable file
418
index/books/isbnlookup2.py
Executable file
|
@ -0,0 +1,418 @@
|
|||
#!/usr/bin/python
|
||||
# Usage: searchAll(isbn) with isbn passed as a string.
|
||||
# Returns values defined in returnDict
|
||||
|
||||
import sys
|
||||
import types
|
||||
import time
|
||||
import string
|
||||
import fileinput
|
||||
import re
|
||||
import urllib
|
||||
import isbnvalidate
|
||||
from dateutil.parser import parse as parseDate
import elementtree.ElementTree as ET
|
||||
import feedparser
|
||||
import simplejson
|
||||
|
||||
# ISBNlist = [ '9780596001322', '9781590593912', '9780596003135', '0596102062', '0131103628', '1905789041', '1400082463' ]
|
||||
|
||||
def searchAll(isbn, **kwargs):
|
||||
sources = [OpenLibrary, GoogleBooks, ISBNdb, Amazon, ChaptersCa]
|
||||
# sources = [Amazon]
|
||||
return getAggregate(sources, isbn)
|
||||
|
||||
def getAggregate(sources, isbn, **kwargs):
|
||||
if not isbnvalidate.isValidISBN(isbn):
|
||||
return {'errors': "Invalid ISBN"}
|
||||
returnDict = {
|
||||
'title': u'',
|
||||
'titleLong': u'',
|
||||
'authors': [],
|
||||
'weblinks': [],
|
||||
'published': {},
|
||||
'publisher': u'',
|
||||
'isbn': u'',
|
||||
'first_sentence': u'',
|
||||
'chapters': [],
|
||||
'netReviews': [],
|
||||
'summaries': [],
|
||||
'pages': 0,
|
||||
'dimensions': u'',
|
||||
'weight': 0,
|
||||
'relatedBooks': [],
|
||||
'tags': [],
|
||||
'sources': [],
|
||||
'imageUrls': [],
|
||||
'coverImage': u''
|
||||
}
|
||||
# if kwargs['isbnformat'] == 10 and len(isbn) == 13:
|
||||
# isbn = isbnvalidate.convertISBN13toISBN10(isbn)
|
||||
# if kwargs['isbnformat'] == 13 and len(isbn) == 10:
|
||||
# isbn = isbnvalidate.convertISBN10toI3(isbn)
|
||||
results = []
|
||||
for source in sources:
|
||||
rDict = source(isbn)
|
||||
if (rDict):
|
||||
results.append(rDict)
|
||||
lists = []
|
||||
# lists = ['authors', 'weblinks', 'chapters', 'netReviews', 'summaries', 'relatedBooks', 'source']
|
||||
for result in results:
|
||||
for key in result.keys():
|
||||
if returnDict.has_key(key):
|
||||
if isinstance(result[key], list):
|
||||
if key not in lists:
|
||||
lists.append(key)
|
||||
for r in result[key]:
|
||||
returnDict[key].append(r)
|
||||
else:
|
||||
returnDict[key] = result[key]
|
||||
for l in lists:
|
||||
if len(returnDict[l]) > 1:
|
||||
returnDict[l] = unique(returnDict[l])
|
||||
returnDict['isbn'] = isbn
|
||||
returnDict['coverImage'] = getCoverImageUrl(isbn)
|
||||
|
||||
return returnDict
|
||||
|
||||
|
||||
def ChaptersCa(isbn):
|
||||
url = 'http://www.chapters.ca/books/details/default.asp?ISBN=' + isbn
|
||||
html = getHtmlFromUrl(url)
|
||||
if not html:
|
||||
return False
|
||||
if (string.find(html, 'chapters.indigo.ca: Error:') >= 0):
|
||||
return False
|
||||
titlehtml = re.search('<h1>(.*?)</h1>', html)
|
||||
authorhtml = re.search('<p class="link">Author: (<a href=.*</a>)</p>', html)
|
||||
dimensionshtml = re.search('<label>Dimensions:</label>(.*?)</p>', html)
|
||||
publisherhtml = re.search('<label>Publisher:</label>(.*?)</p>', html)
|
||||
publishedhtml = re.search('<label>Published:</label>(.*?)</p>', html)
|
||||
|
||||
#print (titlehtml, authorhtml, dimensionshtml, publisherhtml, publishedhtml)
|
||||
try:
|
||||
authorlinks = authorhtml.group(1).strip()
|
||||
authors = re.findall('<a .*?>(.*?)</a>', authorlinks) # returns list of authors
|
||||
i = 0
|
||||
for a in authors:
|
||||
if re.search('See more ', a):
|
||||
authors.remove(a)
|
||||
else:
|
||||
authors[i] = a.strip()
|
||||
if (authors[i] == ''):
|
||||
authors.remove(a)
|
||||
i += 1
|
||||
except:
|
||||
authors = []
|
||||
|
||||
d = {}
|
||||
d['sources'] = [{'name': 'ChaptersCa', 'url': url}]
|
||||
|
||||
try:
|
||||
d['pages'] = dimensionshtml.group(1).split(",")[0].strip()
|
||||
d['dimensions'] = dimensionshtml.group(1).split(",")[1].strip()
|
||||
except:
|
||||
pass
|
||||
# dimensions = dimensionshtml.group(1).strip()
|
||||
try:
|
||||
d['publisher'] = publisherhtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['published'] = myDate(publishedhtml.group(1).strip())
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['title'] = titlehtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['imageUrls'] = [getimagesrc(isbn)]
|
||||
except:
|
||||
pass
|
||||
|
||||
d['authors'] = authors
|
||||
return d
|
||||
|
||||
def Amazon(isbn):
|
||||
url = 'http://www.amazon.com/gp/search/ref=sr_adv_b/?field-isbn=' + isbn
|
||||
html = getHtmlFromUrl(url)
|
||||
if not html:
|
||||
return False
|
||||
if (string.find(html, 'Your search did not match any products.') >= 0):
|
||||
return False
|
||||
titlehtml = re.search('<span id="btAsinTitle" style="">(.*?)</span>', html)
|
||||
paperbackhtml = re.search('<li><b>Paperback:</b>(.*?)</li>', html)
|
||||
weighthtml = re.search('<li><b>Shipping Weight:</b>(.*?)\(.*?\)</li>', html)
|
||||
publisherhtml = re.search('<li><b>Publisher:</b>(.*?) \((.*?)\)</li>', html)
|
||||
authors = re.findall('<a href=".*?">(.*?)</a> \(Author\)', html) # returns list of authors
|
||||
d = {}
|
||||
d['sources'] = [{'name': 'Amazon', 'url': url}]
|
||||
try:
|
||||
d['pages'] = paperbackhtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['dimensions'] = weighthtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['publisher'] = publisherhtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['published'] = myDate(publisherhtml.group(2).strip())
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['title'] = titlehtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
# sourceurl = 'http://www.amazon.com/gp/search/ref=sr_adv_b/?field-isbn=' + isbn
|
||||
|
||||
d['authors'] = authors
|
||||
|
||||
return d
|
||||
|
||||
|
||||
def ISBNdb(isbn):
|
||||
ISBNdb_KEY = 'HLRQD9WN'
|
||||
# http://isbndb.com/api/books.xml?access_key=HLRQD9WN&index1=isbn&value1=1400082463
|
||||
url = 'http://isbndb.com/api/books.xml?access_key=' + ISBNdb_KEY + '&index1=isbn&value1=' + isbn
|
||||
try:
|
||||
xml = getHtmlFromUrl(url)
|
||||
tree = ET.XML(xml)
|
||||
except:
|
||||
return False
|
||||
results = tree.find("BookList").get("total_results")
|
||||
if (results < 1):
|
||||
return False
|
||||
d = {}
|
||||
d['sources'] = [{'name': 'ISBNdb', 'url': url}]
|
||||
try:
|
||||
book = tree.getchildren()[0].getchildren()[0]
|
||||
except:
|
||||
return False
|
||||
|
||||
try:
|
||||
d['titleLong'] = book.findtext("TitleLong").strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['title'] = book.findtext("Title")
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['publisher'] = book.findtext("PublisherText")
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['summaries'] = [book.findtext("Summary")]
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['notes'] = book.findtext("Notes")
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
authors = book.findtext("AuthorsText").split(",")
|
||||
i = 0
|
||||
for a in authors:
|
||||
if a.strip() == '':
|
||||
authors.remove(a)
|
||||
except:
|
||||
pass
|
||||
|
||||
return d
|
||||
|
||||
#TODO: Make URL more specific to look for ISBN codes. [IMP!!] - Alden
|
||||
def GoogleBooks(isbn):
|
||||
url = 'http://books.google.com/books/feeds/volumes?q=' + isbn
|
||||
try:
|
||||
feed = feedparser.parse(url)
|
||||
book = feed.entries[0]
|
||||
except:
|
||||
return False
|
||||
d = {}
|
||||
d['sources'] = [{'name': 'GoogleBooks', 'url': url}]
|
||||
try:
|
||||
d['title'] = book.title
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['summaries'] = [book.dc_description]
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['pages'] = book.dc_format
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['author'] = [book.dc_creator]
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['publisher'] = book.publisher
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['published'] = myDate(book.dc_date)
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['weblinks'] = []
|
||||
for link in book['links']:
|
||||
l = {'url': link['href'], 'description': link['rel'] }
|
||||
d['weblinks'].append(l)
|
||||
except:
|
||||
pass
|
||||
|
||||
return d
|
||||
|
||||
def OpenLibrary(isbn):
|
||||
# 'http://openlibrary.org/api/things?query={%22type%22%3A+%22\%2Ftype\%2Fedition%22%2C+%22isbn_13%22%3A+%221400082463%22}&prettyprint=true&text=true'
|
||||
if (len(isbn) == 10):
|
||||
url1 = 'http://openlibrary.org/api/things?query={%22type%22%3A+%22\%2Ftype\%2Fedition%22%2C+%22isbn_10%22%3A+%22' + isbn + '%22}&prettyprint=true&text=true'
|
||||
elif (len(isbn) == 13):
|
||||
url1 = 'http://openlibrary.org/api/things?query={%22type%22%3A+%22\%2Ftype\%2Fedition%22%2C+%22isbn_13%22%3A+%22' + isbn + '%22}&prettyprint=true&text=true'
|
||||
else:
|
||||
return False
|
||||
json = getHtmlFromUrl(url1)
|
||||
# print json
|
||||
if not json:
|
||||
return False
|
||||
j = simplejson.loads(json)
|
||||
if (j['status'] != 'ok' or len(j['result']) == 0):
|
||||
return False
|
||||
olId = j['result'][0]
|
||||
url2 = "http://openlibrary.org/api/get?key=" + olId
|
||||
|
||||
try:
|
||||
json2 = getHtmlFromUrl(url2)
|
||||
book = simplejson.loads(json2)
|
||||
r = book['result']
|
||||
except:
|
||||
return False
|
||||
|
||||
d = {}
|
||||
d['sources'] = [{'name': "OpenLibrary", 'url': url2}]
|
||||
|
||||
try:
|
||||
d['first_sentence'] = r['first_sentence']['value']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['pages'] = r['number_of_pages']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['dimensions'] = r['physical_dimensions']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['published'] = myDate(r['publish_date'])
|
||||
except:
|
||||
pass
|
||||
|
||||
chapters = []
|
||||
try:
|
||||
for chapter in r['table_of_contents']:
|
||||
c = {}
|
||||
c['title'] = chapter['title']
|
||||
c['synopsis'] = ''
|
||||
c['link'] = ''
|
||||
chapters.append(c)
|
||||
d['chapters'] = chapters
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['weight'] = r['weight']
|
||||
except:
|
||||
pass
|
||||
|
||||
tags = []
|
||||
try:
|
||||
for tag in r['subjects']:
|
||||
tags.append(tag)
|
||||
d['tags'] = tags
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['titleLong'] = r['subtitle']
|
||||
except:
|
||||
pass
|
||||
|
||||
return d
|
||||
|
||||
#TODO: write regex parser for LookUpByIsbn to return esp. Reviews. - Alden (low priority)
|
||||
def LookUpByIsbn(isbn):
|
||||
url = "http://www.lookupbyisbn.com/itemDetail.aspx?type=Books&id=" + isbn
|
||||
return False
|
||||
|
||||
#TODO: Write regex parser for CB-India computer books. -Alden (low priority)
|
||||
def CBIndia(isbn):
|
||||
return False
|
||||
|
||||
#TODO: This seems like a fairly large collection of Indian books
|
||||
def FirstAndSecond(isbn):
|
||||
url = "http://www.firstandsecond.com/store/books/info/search.asp?styp=isb&isb=" + isbn
|
||||
return False
|
||||
|
||||
|
||||
def myDate(datestr):
|
||||
dateObj = parseDate(datestr)
|
||||
month = dateObj.month
|
||||
yr = dateObj.year
|
||||
day = dateObj.day
|
||||
d = {
|
||||
'year': yr,
|
||||
'month': month,
|
||||
'day': day
|
||||
}
|
||||
return d
|
||||
|
||||
|
||||
def getHtmlFromUrl(url):
|
||||
try:
|
||||
u = urllib.urlopen(url)
|
||||
t = u.read()
|
||||
u.close
|
||||
except:
|
||||
return False
|
||||
return t
|
||||
|
||||
def getCoverImageUrl(isbn):
|
||||
if (len(isbn) == 13):
|
||||
newisbn = isbnvalidate.convertISBN13toISBN10(isbn)
|
||||
isbn = newisbn.strip()
|
||||
try:
|
||||
inf = urllib.urlopen('http://www.amazon.com/gp/product/images/' + isbn)
|
||||
allhtml = inf.read()
|
||||
inf.close()
|
||||
imghtml = re.search('<div id="imageViewerDiv"><img src="(.*?)" id="prodImage" /></div>', allhtml)
|
||||
imgsrc1 = imghtml.group(1)
|
||||
except:
|
||||
# print "Unable to retrieve book cover image"
|
||||
return ''
|
||||
return imgsrc1
|
||||
|
||||
def unique(seq):
|
||||
checked = []
|
||||
for e in seq:
|
||||
if e not in checked:
|
||||
checked.append(e)
|
||||
return checked
|
380
index/books/isbnlookup2.py.THIS
Normal file
380
index/books/isbnlookup2.py.THIS
Normal file
|
@ -0,0 +1,380 @@
|
|||
#!/usr/bin/python
|
||||
# (c) CAMP - http://camputer.org
|
||||
# Licensed GPLv3
|
||||
|
||||
import sys
|
||||
import types
|
||||
import time
|
||||
import string
|
||||
import fileinput
|
||||
import re
|
||||
import urllib
|
||||
import isbnvalidate
|
||||
from dateutil.parser import parse as parseDate
import elementtree.ElementTree as ET
|
||||
import feedparser
|
||||
import simplejson
|
||||
|
||||
#ISBNlist = [ '9780596001322', '9781590593912', '9780596003135', '0596102062', '0131103628', '1905789041', '1400082463' ]
|
||||
|
||||
returnDict = {
|
||||
'title': u'',
|
||||
'titleLong': u'',
|
||||
'authors': [],
|
||||
'weblinks': [],
|
||||
'published': {},
|
||||
'publisher': u'',
|
||||
'isbn': u'',
|
||||
'first_sentence': u'',
|
||||
'chapters': [],
|
||||
'netReviews': [],
|
||||
'summaries': [],
|
||||
'pages': 0,
|
||||
'dimensions': u'',
|
||||
'weight': 0,
|
||||
'relatedBooks': [],
|
||||
'tags': [],
|
||||
'source': [],
|
||||
'imageUrls': []
|
||||
}
|
||||
|
||||
def searchAll(isbn, **kwargs):
|
||||
sources = [OpenLibrary, ISBNdb, Amazon, ChaptersCa]
|
||||
return getAggregate(sources, isbn)
|
||||
|
||||
#TODO: Author field sometimes has a space.
|
||||
def getAggregate(sources, isbn, **kwargs):
|
||||
if not isbnvalidate.isValidISBN(isbn):
|
||||
return {'errors': "Invalid ISBN"}
|
||||
# if kwargs['isbnformat'] == 10 and len(isbn) == 13:
|
||||
# isbn = isbnvalidate.convertISBN13toISBN10(isbn)
|
||||
# if kwargs['isbnformat'] == 13 and len(isbn) == 10:
|
||||
# isbn = isbnvalidate.convertISBN10toI3(isbn)
|
||||
results = []
|
||||
for source in sources:
|
||||
rDict = source(isbn)
|
||||
if (rDict):
|
||||
results.append(rDict)
|
||||
lists = []
|
||||
# lists = ['authors', 'weblinks', 'chapters', 'netReviews', 'summaries', 'relatedBooks', 'source']
|
||||
for result in results:
|
||||
for key in result.keys():
|
||||
if returnDict.has_key(key):
|
||||
if isinstance(result[key], list):
|
||||
if key not in lists:
|
||||
lists.append(key)
|
||||
for r in result[key]:
|
||||
if r:
|
||||
returnDict[key].append(r)
|
||||
else:
|
||||
returnDict[key] = result[key]
|
||||
for l in lists:
|
||||
if len(returnDict[l]) > 1:
|
||||
returnDict[l] = unique(returnDict[l])
|
||||
returnDict['isbn'] = isbn
|
||||
return returnDict
|
||||
|
||||
|
||||
def ChaptersCa(isbn):
|
||||
url = 'http://www.chapters.ca/books/details/default.asp?ISBN=' + isbn
|
||||
html = getHtmlFromUrl(url)
|
||||
if not html:
|
||||
return False
|
||||
if (string.find(html, 'chapters.indigo.ca: Error:') >= 0):
|
||||
return False
|
||||
titlehtml = re.search('<h1>(.*?)</h1>', html)
|
||||
authorhtml = re.search('<p class="link">Author: (<a href=.*</a>)</p>', html)
|
||||
dimensionshtml = re.search('<label>Dimensions:</label>(.*?)</p>', html)
|
||||
publisherhtml = re.search('<label>Publisher:</label>(.*?)</p>', html)
|
||||
publishedhtml = re.search('<label>Published:</label>(.*?)</p>', html)
|
||||
|
||||
#print (titlehtml, authorhtml, dimensionshtml, publisherhtml, publishedhtml)
|
||||
try:
|
||||
authorlinks = authorhtml.group(1).strip()
|
||||
authors = re.findall('<a .*?>(.*?)</a>', authorlinks) # returns list of authors
|
||||
for a in authors:
|
||||
if re.search('See more ', a):
|
||||
authors.remove(a)
|
||||
except:
|
||||
authors = []
|
||||
|
||||
d = {}
|
||||
d['source'] = [{'name': 'ChaptersCa', 'url': url}]
|
||||
|
||||
try:
|
||||
d['pages'] = dimensionshtml.group(1).split(",")[0].strip()
|
||||
d['dimensions'] = dimensionshtml.group(1).split(",")[1].strip()
|
||||
except:
|
||||
pass
|
||||
# dimensions = dimensionshtml.group(1).strip()
|
||||
try:
|
||||
d['publisher'] = publisherhtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['published'] = myDate(publishedhtml.group(1).strip())
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['title'] = titlehtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['coverimg'] = getimagesrc(isbn)
|
||||
except:
|
||||
pass
|
||||
|
||||
d['authors'] = authors
|
||||
return d
|
||||
|
||||
#TODO: Regex failing. Test. - Alden
|
||||
def Amazon(isbn):
|
||||
url = 'http://www.amazon.com/gp/search/ref=sr_adv_b/?field-isbn=' + isbn
|
||||
html = getHtmlFromUrl(url)
|
||||
if not html:
|
||||
return False
|
||||
if (string.find(html, 'Your search did not match any products.') >= 0):
|
||||
return False
|
||||
titlehtml = re.search('<span id="btAsinTitle" style="">(.*?)</span>', html)
|
||||
paperbackhtml = re.search('<li><b>Paperback:</b>(.*?)</li>', html)
|
||||
weighthtml = re.search('<li><b>Shipping Weight:</b>(.*?)\(.*?\)</li>', html)
|
||||
publisherhtml = re.search('<li><b>Publisher:</b>(.*?) \((.*?)\)</li>', html)
|
||||
authors = re.findall('<a href=".*?">(.*?)</a> \(Author\)', html) # returns list of authors
|
||||
d = {}
|
||||
d['source'] = [{'name': 'Amazon', 'url': url}]
|
||||
try:
|
||||
d['pages'] = paperbackhtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['dimensions'] = weighthtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['publisher'] = publisherhtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['published'] = myDate(publisherhtml.group(2).strip())
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['title'] = titlehtml.group(1).strip()
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['coverimg'] = getimagesrc(isbn)
|
||||
except:
|
||||
pass
|
||||
# sourceurl = 'http://www.amazon.com/gp/search/ref=sr_adv_b/?field-isbn=' + isbn
|
||||
return d
|
||||
|
||||
|
||||
def ISBNdb(isbn):
|
||||
ISBNdb_KEY = 'HLRQD9WN'
|
||||
# http://isbndb.com/api/books.xml?access_key=HLRQD9WN&index1=isbn&value1=1400082463
|
||||
url = 'http://isbndb.com/api/books.xml?access_key=' + ISBNdb_KEY + '&index1=isbn&value1=' + isbn
|
||||
try:
|
||||
xml = getHtmlFromUrl(url)
|
||||
tree = ET.XML(xml)
|
||||
except:
|
||||
return False
|
||||
results = tree.find("BookList").get("total_results")
|
||||
if (results < 1):
|
||||
return False
|
||||
d = {}
|
||||
d['source'] = [{'name': 'ISBNdb', 'url': url}]
|
||||
try:
|
||||
book = tree.getchildren()[0].getchildren()[0]
|
||||
except:
|
||||
return False
|
||||
|
||||
try:
|
||||
d['titleLong'] = book.findtext("TitleLong").strip()
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['title'] = book.findtext("Title")
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['publisher'] = book.findtext("PublisherText")
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['summaries'] = [book.findtext("Summary")]
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['notes'] = book.findtext("Notes")
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
authorsTxt = book.findtext("AuthorsText")
|
||||
d['authors'] = authorsTxt.split(",")
|
||||
except:
|
||||
pass
|
||||
|
||||
return d
|
||||
|
||||
#TODO: Fetch weblinks. - Sanj
|
||||
#TODO: Go through XML and fetch more relevant fields. - Sanj
|
||||
#TODO: Make URL more specific to look for ISBN codes. [IMP!!] - Alden
|
||||
def GoogleBooks(isbn):
|
||||
url = 'http://books.google.com/books/feeds/volumes?q=' + isbn
|
||||
try:
|
||||
feed = feedparser.parse(url)
|
||||
book = feed.entries[0]
|
||||
except:
|
||||
return False
|
||||
d = {}
|
||||
d['source'] = [{'name': 'GoogleBooks', 'url': url}]
|
||||
try:
|
||||
d['title'] = book.title
|
||||
except:
|
||||
pass
|
||||
# d['summary'] = book.description
|
||||
try:
|
||||
d['pages'] = book.dc_format
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['author'] = [book.author]
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
d['publisher'] = book.publisher
|
||||
except:
|
||||
pass
|
||||
return d
|
||||
|
||||
def OpenLibrary(isbn):
|
||||
# 'http://openlibrary.org/api/things?query={%22type%22%3A+%22\%2Ftype\%2Fedition%22%2C+%22isbn_13%22%3A+%221400082463%22}&prettyprint=true&text=true'
|
||||
if (len(isbn) == 10):
|
||||
url1 = 'http://openlibrary.org/api/things?query={%22type%22%3A+%22\%2Ftype\%2Fedition%22%2C+%22isbn_10%22%3A+%22' + isbn + '%22}&prettyprint=true&text=true'
|
||||
elif (len(isbn) == 13):
|
||||
url1 = 'http://openlibrary.org/api/things?query={%22type%22%3A+%22\%2Ftype\%2Fedition%22%2C+%22isbn_13%22%3A+%22' + isbn + '%22}&prettyprint=true&text=true'
|
||||
else:
|
||||
return False
|
||||
json = getHtmlFromUrl(url1)
|
||||
print json
|
||||
if not json:
|
||||
return False
|
||||
j = simplejson.loads(json)
|
||||
if (j['status'] != 'ok' or len(j['result']) == 0):
|
||||
return False
|
||||
olId = j['result'][0]
|
||||
url2 = "http://openlibrary.org/api/get?key=" + olId
|
||||
try:
|
||||
json2 = getHtmlFromUrl(url2)
|
||||
book = simplejson.loads(json2)
|
||||
r = book['result']
|
||||
except:
|
||||
return False
|
||||
d = {}
|
||||
d['source'] = [{'name': "OpenLibrary", 'url': url2}]
|
||||
try:
|
||||
d['first_sentence'] = r['first_sentence']['value']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['pages'] = r['number_of_pages']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['dimensions'] = r['physical_dimensions']
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['published'] = myDate(r['publish_date'])
|
||||
except:
|
||||
pass
|
||||
|
||||
chapters = []
|
||||
try:
|
||||
for chapter in r['table_of_contents']:
|
||||
chapters.append(chapter['title'])
|
||||
d['chapters'] = chapters
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['weight'] = r['weight']
|
||||
except:
|
||||
pass
|
||||
|
||||
tags = []
|
||||
try:
|
||||
for tag in r['subjects']:
|
||||
tags.append(tag)
|
||||
d['tags'] = tags
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
d['titleLong'] = r['subtitle']
|
||||
except:
|
||||
pass
|
||||
|
||||
return d
|
||||
|
||||
#TODO: write regex parser for LookUpByIsbn to return esp. Reviews. - Alden (low priority)
|
||||
def LookUpByIsbn(isbn):
|
||||
url = "http://www.lookupbyisbn.com/itemDetail.aspx?type=Books&id=" + isbn
|
||||
return False
|
||||
|
||||
#TODO: Write regex parser for CB-India computer books. -Alden (low priority)
|
||||
def CBIndia(isbn):
|
||||
return False
|
||||
|
||||
|
||||
def myDate(datestr):
|
||||
dateObj = parseDate(datestr)
|
||||
month = dateObj.month
|
||||
yr = dateObj.year
|
||||
day = dateObj.day
|
||||
d = {
|
||||
'year': yr,
|
||||
'month': month,
|
||||
'day': day
|
||||
}
|
||||
return d
|
||||
|
||||
def getHtmlFromUrl(url):
|
||||
try:
|
||||
u = urllib.urlopen(url)
|
||||
t = u.read()
|
||||
u.close
|
||||
except:
|
||||
return False
|
||||
return t
|
||||
|
||||
def getimagesrc(isbn):
|
||||
if (len(isbn) == 13):
|
||||
newisbn = isbnvalidate.convertISBN13toISBN10(isbn)
|
||||
isbn = newisbn.strip()
|
||||
|
||||
inf = urllib.urlopen('http://www.amazon.com/gp/product/images/' + isbn)
|
||||
allhtml = inf.read()
|
||||
inf.close()
|
||||
imghtml = re.search('<div id="imageViewerDiv"><img src="(.*?)" id="prodImage" /></div>', allhtml)
|
||||
|
||||
imgsrc1 = imghtml.group(1)
|
||||
return imgsrc1
|
||||
|
||||
def unique(seq):
|
||||
checked = []
|
||||
for e in seq:
|
||||
if e not in checked:
|
||||
checked.append(e)
|
||||
return checked
|
166
index/books/isbnvalidate.py
Executable file
166
index/books/isbnvalidate.py
Executable file
|
@ -0,0 +1,166 @@
|
|||
##############################################################################
|
||||
#
|
||||
# Copyright (c) 2006 Zope Corporation and Contributors.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# This software is subject to the provisions of the Zope Public License,
|
||||
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
||||
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
||||
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
##############################################################################
|
||||
"""Kirbi ISBN handling functions
|
||||
"""
|
||||
|
||||
class InvalidISBN(ValueError):
|
||||
"""This is not a valid ISBN-10 or ISBN-13"""
|
||||
|
||||
def filterDigits(input):
|
||||
""" Strip the input of all non-digits, but retain last X if present. """
|
||||
input = input.strip()
|
||||
digits = [c for c in input if c.isdigit()]
|
||||
# an X may appear as check digit in ISBN-10
|
||||
if input[-1].upper() == 'X':
|
||||
digits.append('X')
|
||||
return ''.join(digits)
|
||||
|
||||
def checksumISBN10(digits):
|
||||
""" Return ISBN-10 check digit as a string of len 1 (may be 0-9 or X)
|
||||
References:
|
||||
http://www.isbn-international.org/en/userman/chapter4.html#usm4_4
|
||||
http://www.bisg.org/isbn-13/conversions.html
|
||||
"""
|
||||
sum = 0
|
||||
for i, weight in enumerate(range(10,1,-1)):
|
||||
sum += int(digits[i]) * weight
|
||||
check = 11 - sum % 11
|
||||
if check == 10: return 'X'
|
||||
elif check == 11: return '0'
|
||||
return str(check)
|
||||
|
||||
def checksumEAN(digits):
|
||||
""" Return EAN check digit as a string (may be 0-9)
|
||||
Every ISBN-13 is a valid EAN
|
||||
Reference:
|
||||
http://www.bisg.org/isbn-13/conversions.html
|
||||
"""
|
||||
sum = 0
|
||||
for i, d in enumerate(digits[:12]):
|
||||
weight = i%2*2+1
|
||||
sum += int(d) * weight
|
||||
check = 10 - sum % 10
|
||||
if check == 10: return '0'
|
||||
return str(check)
|
||||
|
||||
def validatedEAN(digits):
|
||||
if not digits:
|
||||
return None
|
||||
if len(digits) != 13:
|
||||
digits = filterDigits(digits)
|
||||
if len(digits) != 13:
|
||||
return None
|
||||
if digits[-1] == checksumEAN(digits):
|
||||
return digits
|
||||
|
||||
def validatedISBN10(digits):
|
||||
if not digits:
|
||||
return None
|
||||
if len(digits) != 10:
|
||||
digits = filterDigits(digits)
|
||||
if len(digits) != 10:
|
||||
return None
|
||||
if digits[-1] == checksumISBN10(digits):
|
||||
return digits
|
||||
|
||||
def validatedISBN13(digits):
|
||||
if not digits:
|
||||
return None
|
||||
if digits.strip()[:3] not in ['978','979']:
|
||||
return None
|
||||
return validatedEAN(digits)
|
||||
|
||||
def isValidISBN10(digits):
|
||||
return validatedISBN10(digits) is not None
|
||||
|
||||
def isValidISBN13(digits):
|
||||
return validatedISBN13(digits) is not None
|
||||
|
||||
def isValidEAN(digits):
|
||||
return validatedEAN(digits) is not None
|
||||
|
||||
def isValidISBN(digits):
|
||||
return isValidISBN10(digits) or isValidISBN13(digits)
|
||||
|
||||
def convertISBN10toISBN13(digits):
|
||||
if len(digits) > 10:
|
||||
digits = filterDigits(digits)
|
||||
if len(digits) != 10:
|
||||
raise InvalidISBN, '%s is not a valid ISBN-10'
|
||||
else:
|
||||
digits = '978' + digits[:-1]
|
||||
return digits + checksumEAN(digits)
|
||||
|
||||
def convertISBN13toISBN10(digits):
|
||||
if len(digits) > 13:
|
||||
digits = filterDigits(digits)
|
||||
if len(digits) != 13:
|
||||
raise InvalidISBN, '%s is not a valid ISBN-13'
|
||||
if digits.startswith('978'):
|
||||
digits = digits[3:-1]
|
||||
return digits + checksumISBN10(digits)
|
||||
elif digits.startswith('979'):
|
||||
raise InvalidISBN, '%s is a valid ISBN-13 but has no ISBN-10 equivalent'
|
||||
else:
|
||||
raise InvalidISBN, '%s is not a valid ISBN-13 (wrong prefix)'
|
||||
|
||||
def toISBN13(digits):
|
||||
digits = filterDigits(digits)
|
||||
if isValidISBN13(digits): return digits
|
||||
else:
|
||||
return convertISBN10toISBN13(digits)
|
||||
|
||||
# Note: ISBN group identifiers related to languages
|
||||
# http://www.isbn-international.org/en/identifiers/allidentifiers.html
|
||||
# http://www.loc.gov/standards/iso639-2/php/code_list.php
|
||||
lang_groups = {
|
||||
'en':(0,1),'fr':(2,),'de':(3,),'jp':(4,), 'ru':(5,),
|
||||
'es':(84, # Spain
|
||||
950, 987, # Argentina
|
||||
956, # Chile
|
||||
958, # Colombia
|
||||
959, # Cuba
|
||||
968, 970, # Mexico
|
||||
980, # Venezuela
|
||||
9942, 9978, # Ecuador
|
||||
9945, 99934, # Dominican Republic
|
||||
9962, # Panama
|
||||
9968, # Costa Rica (and 9977)
|
||||
9972, # Peru
|
||||
9974, # Uruguay
|
||||
99922, 99939, # Guatemala
|
||||
99923, # El Salvador
|
||||
99924, # Nicaragua
|
||||
99925, 99953, # Paraguay
|
||||
99926, # Honduras
|
||||
),
|
||||
'pt':(85, # Brazil
|
||||
972, 989, # Portugal
|
||||
),
|
||||
}
|
||||
|
||||
group_lang = {}
|
||||
|
||||
for lang, groups in lang_groups.iteritems():
|
||||
for group in groups:
|
||||
group_lang[str(group)] = lang
|
||||
|
||||
def convertISBN13toLang(isbn13):
|
||||
assert len(isbn13)==13
|
||||
registration_group_field = isbn13[3:8]
|
||||
for i in range(1,6):
|
||||
possible_group = registration_group_field[:i]
|
||||
if possible_group in group_lang:
|
||||
return group_lang[possible_group]
|
||||
return None
|
228
index/books/models.py
Executable file
228
index/books/models.py
Executable file
|
@ -0,0 +1,228 @@
|
|||
from django.db import models
|
||||
from thumbs import ImageWithThumbsField
|
||||
from django.contrib.auth.models import User, Group
|
||||
from tagging.fields import TagField
|
||||
from tagging.models import Tag
|
||||
from myfields import ISBNField
|
||||
from books.fields import MultiSelectField, MultiSelectFormField
|
||||
|
||||
class Book(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
isbn = models.CharField(max_length=20, help_text='ISBN Code - digits only, no dashes, etc.', unique=True)
|
||||
pages = models.CharField(max_length=100, blank=True)
|
||||
weight = models.CharField(max_length=100, blank=True)
|
||||
dimensions = models.CharField(max_length=120, blank=True, help_text='no. of pages and dimensions of book')
|
||||
published = models.DateField(blank=True)
|
||||
first_sentence = models.TextField(blank=True)
|
||||
publisher = models.CharField(max_length=255, blank=True)
|
||||
description = models.TextField(blank=True)
|
||||
owner = models.ForeignKey('Owner', blank=True)
|
||||
location = models.ForeignKey('Location', blank=True)
|
||||
tags = TagField("Tags", blank=True, help_text="Enter as many tags as you like, separated by commas")
|
||||
autotags = TagField("AutoTags", blank=True, help_text="Will be auto filled by lookup script")
|
||||
authors = models.ManyToManyField('Author')
|
||||
mainimg = ImageWithThumbsField(upload_to='images/uploads', blank=True, sizes=((125,125),(200,200)), height_field="image_height", width_field='image_width')
|
||||
added_by = models.ForeignKey(User, editable=False)
|
||||
date_added = models.DateTimeField(auto_now=True, editable=False)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
class ChapterEntry(models.Model):
|
||||
title = models.TextField()
|
||||
synopsis = models.TextField(blank=True)
|
||||
link = models.URLField(max_length=255, blank=True)
|
||||
book = models.ForeignKey(Book)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
class Weblink(models.Model):
|
||||
url = models.URLField()
|
||||
description = models.CharField(max_length=255, blank=True)
|
||||
book = models.ForeignKey(Book)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.url
|
||||
|
||||
class Author(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
bio = models.TextField(blank=True)
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class WebReview(models.Model):
|
||||
txt = models.TextField(blank=True)
|
||||
book = models.ForeignKey(Book)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.txt
|
||||
|
||||
class Summary(models.Model):
|
||||
txt = models.TextField(blank=True)
|
||||
book = models.ForeignKey(Book)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.txt
|
||||
|
||||
class RelatedBook(models.Model):
|
||||
url = models.URLField(blank=True)
|
||||
title = models.CharField(max_length=255)
|
||||
isbn = models.CharField(max_length=16, blank=True)
|
||||
book = models.ForeignKey(Book)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
class ImageUrl(models.Model):
|
||||
typ = models.CharField(max_length=255)
|
||||
url = models.URLField(blank=True)
|
||||
book = models.ForeignKey(Book)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.url
|
||||
|
||||
class Source(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
url = models.URLField()
|
||||
book = models.ForeignKey(Book)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Image(models.Model):
|
||||
image = ImageWithThumbsField(upload_to='images/uploads', sizes=((125,125),(200,200)), height_field='height', width_field='width')
|
||||
book = models.ForeignKey(Book)
|
||||
typ = models.CharField(max_length=255)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.image
|
||||
|
||||
class Owner(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Location(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
code = models.CharField(max_length=10, unique=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s (%s)" % (self.name, self.code)
|
||||
|
||||
|
||||
##################################### CATALOGUES ######################################################
|
||||
|
||||
|
||||
class Catalogue(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
artist = models.CharField(max_length=255, blank=True)
|
||||
exhibition = models.CharField(max_length=255, blank=True)
|
||||
published_date = models.DateField(blank=True, verbose_name="Published on")
|
||||
condition = models.TextField(blank=True)
|
||||
description = models.TextField(blank=True)
|
||||
owner = models.ForeignKey('Owner', blank=True)
|
||||
location = models.ForeignKey(Location, blank=True)
|
||||
tags = TagField("Tags", blank=True, help_text="Enter as many tags as you like, separated by commas")
|
||||
added_by = models.ForeignKey(User, editable=False)
|
||||
date_added = models.DateTimeField(auto_now=True, editable=False)
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Catalogues"
|
||||
|
||||
|
||||
##################################### HARDWARE ######################################################
|
||||
|
||||
HARDWARE_CATEGORY_CHOICES = (
|
||||
('artworks', 'Artworks'),
|
||||
('control', 'Control'),
|
||||
('cables', 'Cables'),
|
||||
('connectors', 'Connectors'),
|
||||
('computer', 'Computer'),
|
||||
('storage', 'Storage Devices'),
|
||||
('av', 'Audio / Video Equipment'),
|
||||
('electronics', 'Electronics'),
|
||||
('electrical', 'Electrical & Lighting'),
|
||||
('mechanical', 'Mechanical Parts'),
|
||||
('media', 'Media'),
|
||||
('tools', 'Tools'),
|
||||
('supplies', 'Supplies'),
|
||||
('other', 'Other'),
|
||||
)
|
||||
|
||||
class Box(models.Model):
|
||||
box_no = models.CharField(max_length=255, blank=True, unique=True)
|
||||
description = models.TextField(blank=True)
|
||||
owner = models.ForeignKey('Owner', blank=True, null=True)
|
||||
location = models.ForeignKey(Location, blank=True, null=True)
|
||||
tags = TagField("Tags", blank=True, help_text="Enter as many tags as you like, separated by commas")
|
||||
|
||||
def __unicode__(self):
|
||||
s = ''
|
||||
if self.location:
|
||||
s += self.location.code + "/"
|
||||
s += self.box_no
|
||||
return s
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Boxes"
|
||||
|
||||
class Hardware(models.Model):
|
||||
title = models.CharField(max_length=255, verbose_name="Title / Name")
|
||||
category = models.ForeignKey("HardwareCategory", blank=True, null=True)
|
||||
# category = MultiSelectField(max_length=355, choices=HARDWARE_CATEGORY_CHOICES, verbose_name="Category")
|
||||
model_number = models.CharField(max_length=255, blank=True)
|
||||
serial_number = models.CharField(max_length=255, blank=True)
|
||||
description = models.TextField(blank=True)
|
||||
quantity = models.IntegerField(blank=True, null=True, default=1, help_text="This will NOT create separate entries for the item. Use 'Save as New' to duplicate items")
|
||||
# location = models.ForeignKey(Location, blank=True)
|
||||
tags = TagField("Tags", blank=True, help_text="Enter as many tags as you like, separated by commas")
|
||||
# added_by = models.ForeignKey(User, editable=False)
|
||||
date_added = models.DateTimeField(auto_now=True, editable=False)
|
||||
links = models.ManyToManyField('HardwareLink', blank=True, null=True)
|
||||
box = models.ForeignKey('Box', blank=True, null=True)
|
||||
published = models.BooleanField(default=False)
|
||||
image = models.ImageField(upload_to='hw_images/', blank=True, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.labelID()
|
||||
|
||||
def labelID(self):
|
||||
s = ''
|
||||
if self.box:
|
||||
try:
|
||||
loc = Location.objects.get(pk=self.box.id)
|
||||
s += loc.code + "/"
|
||||
except:
|
||||
s += ""
|
||||
s += self.box.box_no + "/"
|
||||
# if obj.box.location:
|
||||
# s += obj.box.location.code + "/"
|
||||
s += str(self.id)
|
||||
return s
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Hardware"
|
||||
|
||||
class HardwareCategory(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Hardware Category"
|
||||
verbose_name_plural = "Hardware Categories"
|
||||
|
||||
class HardwareLink(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
url = models.URLField()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
|
15
index/books/myfields.py
Executable file
15
index/books/myfields.py
Executable file
|
@ -0,0 +1,15 @@
|
|||
from django.db import models
|
||||
from isbnvalidate import isValidISBN
|
||||
from django import forms
|
||||
|
||||
class ISBNField(models.Field):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['max_length'] = 13
|
||||
super(ISBNField, self).__init__(*args, **kwargs)
|
||||
|
||||
def clean(self, value):
|
||||
if not isValidISBN(value):
|
||||
raise forms.ValidationError("not a valid ISBN")
|
||||
else:
|
||||
return value
|
164
index/books/thumbs.py
Executable file
164
index/books/thumbs.py
Executable file
|
@ -0,0 +1,164 @@
|
|||
# -*- encoding: utf-8 -*-
|
||||
"""
|
||||
django-thumbs by Antonio Melé
|
||||
http://django.es
|
||||
"""
|
||||
from django.db.models import ImageField
|
||||
from django.db.models.fields.files import ImageFieldFile
|
||||
from PIL import Image
|
||||
from django.core.files.base import ContentFile
|
||||
import cStringIO
|
||||
|
||||
def generate_thumb(img, thumb_size, format):
|
||||
"""
|
||||
Generates a thumbnail image and returns a ContentFile object with the thumbnail
|
||||
|
||||
Parameters:
|
||||
===========
|
||||
img File object
|
||||
|
||||
thumb_size desired thumbnail size, ie: (200,120)
|
||||
|
||||
format format of the original image ('jpeg','gif','png',...)
|
||||
(this format will be used for the generated thumbnail, too)
|
||||
"""
|
||||
|
||||
img.seek(0) # see http://code.djangoproject.com/ticket/8222 for details
|
||||
image = Image.open(img)
|
||||
|
||||
# Convert to RGB if necessary
|
||||
if image.mode not in ('L', 'RGB'):
|
||||
image = image.convert('RGB')
|
||||
|
||||
# get size
|
||||
thumb_w, thumb_h = thumb_size
|
||||
# If you want to generate a square thumbnail
|
||||
if thumb_w == thumb_h:
|
||||
# quad
|
||||
xsize, ysize = image.size
|
||||
# get minimum size
|
||||
minsize = min(xsize,ysize)
|
||||
# largest square possible in the image
|
||||
xnewsize = (xsize-minsize)/2
|
||||
ynewsize = (ysize-minsize)/2
|
||||
# crop it
|
||||
image2 = image.crop((xnewsize, ynewsize, xsize-xnewsize, ysize-ynewsize))
|
||||
# load is necessary after crop
|
||||
image2.load()
|
||||
# thumbnail of the cropped image (with ANTIALIAS to make it look better)
|
||||
image2.thumbnail(thumb_size, Image.ANTIALIAS)
|
||||
else:
|
||||
# not quad
|
||||
image2 = image
|
||||
image2.thumbnail(thumb_size, Image.ANTIALIAS)
|
||||
|
||||
io = cStringIO.StringIO()
|
||||
# PNG and GIF are the same, JPG is JPEG
|
||||
if format.upper()=='JPG':
|
||||
format = 'JPEG'
|
||||
|
||||
image2.save(io, format)
|
||||
return ContentFile(io.getvalue())
|
||||
|
||||
class ImageWithThumbsFieldFile(ImageFieldFile):
|
||||
"""
|
||||
See ImageWithThumbsField for usage example
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ImageWithThumbsFieldFile, self).__init__(*args, **kwargs)
|
||||
self.sizes = self.field.sizes
|
||||
|
||||
if self.sizes:
|
||||
def get_size(self, size):
|
||||
if not self:
|
||||
return ''
|
||||
else:
|
||||
split = self.url.rsplit('.',1)
|
||||
thumb_url = '%s.%sx%s.%s' % (split[0],w,h,split[1])
|
||||
return thumb_url
|
||||
|
||||
for size in self.sizes:
|
||||
(w,h) = size
|
||||
setattr(self, 'url_%sx%s' % (w,h), get_size(self, size))
|
||||
|
||||
def save(self, name, content, save=True):
|
||||
super(ImageWithThumbsFieldFile, self).save(name, content, save)
|
||||
|
||||
if self.sizes:
|
||||
for size in self.sizes:
|
||||
(w,h) = size
|
||||
split = self._name.rsplit('.',1)
|
||||
thumb_name = '%s.%sx%s.%s' % (split[0],w,h,split[1])
|
||||
|
||||
# you can use another thumbnailing function if you like
|
||||
thumb_content = generate_thumb(content, size, split[1])
|
||||
|
||||
thumb_name_ = self.storage.save(thumb_name, thumb_content)
|
||||
|
||||
if not thumb_name == thumb_name_:
|
||||
raise ValueError('There is already a file named %s' % thumb_name)
|
||||
|
||||
def delete(self, save=True):
|
||||
name=self.name
|
||||
super(ImageWithThumbsFieldFile, self).delete(save)
|
||||
if self.sizes:
|
||||
for size in self.sizes:
|
||||
(w,h) = size
|
||||
split = name.rsplit('.',1)
|
||||
thumb_name = '%s.%sx%s.%s' % (split[0],w,h,split[1])
|
||||
try:
|
||||
self.storage.delete(thumb_name)
|
||||
except:
|
||||
pass
|
||||
|
||||
class ImageWithThumbsField(ImageField):
|
||||
attr_class = ImageWithThumbsFieldFile
|
||||
"""
|
||||
Usage example:
|
||||
==============
|
||||
photo = ImageWithThumbsField(upload_to='images', sizes=((125,125),(300,200),)
|
||||
|
||||
To retrieve image URL, exactly the same way as with ImageField:
|
||||
my_object.photo.url
|
||||
To retrieve thumbnails URL's just add the size to it:
|
||||
my_object.photo.url_125x125
|
||||
my_object.photo.url_300x200
|
||||
|
||||
Note: The 'sizes' attribute is not required. If you don't provide it,
|
||||
ImageWithThumbsField will act as a normal ImageField
|
||||
|
||||
How it works:
|
||||
=============
|
||||
For each size in the 'sizes' atribute of the field it generates a
|
||||
thumbnail with that size and stores it following this format:
|
||||
|
||||
available_filename.[width]x[height].extension
|
||||
|
||||
Where 'available_filename' is the available filename returned by the storage
|
||||
backend for saving the original file.
|
||||
|
||||
Following the usage example above: For storing a file called "photo.jpg" it saves:
|
||||
photo.jpg (original file)
|
||||
photo.125x125.jpg (first thumbnail)
|
||||
photo.300x200.jpg (second thumbnail)
|
||||
|
||||
With the default storage backend if photo.jpg already exists it will use these filenames:
|
||||
photo_.jpg
|
||||
photo_.125x125.jpg
|
||||
photo_.300x200.jpg
|
||||
|
||||
Note: django-thumbs assumes that if filename "any_filename.jpg" is available
|
||||
filenames with this format "any_filename.[widht]x[height].jpg" will be available, too.
|
||||
|
||||
To do:
|
||||
======
|
||||
Add method to regenerate thubmnails
|
||||
|
||||
"""
|
||||
def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, sizes=None, **kwargs):
|
||||
self.verbose_name=verbose_name
|
||||
self.name=name
|
||||
self.width_field=width_field
|
||||
self.height_field=height_field
|
||||
self.sizes = sizes
|
||||
super(ImageField, self).__init__(**kwargs)
|
183
index/books/views.py
Executable file
183
index/books/views.py
Executable file
|
@ -0,0 +1,183 @@
|
|||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import render_to_response
|
||||
# from django.contrib.auth import authenticate, login, logout
|
||||
from books.models import *
|
||||
from django.utils import simplejson
|
||||
from django import forms
|
||||
from django.forms.models import inlineformset_factory
|
||||
from isbnlookup2 import searchAll
|
||||
#from django.contrib.auth.messages import *
|
||||
import datetime
|
||||
import sys
|
||||
from django.template import RequestContext
|
||||
from dateutil.parser import parse as parseDate
|
||||
|
||||
class BookForm(forms.ModelForm):
|
||||
title = forms.CharField(widget = forms.TextInput(attrs = {'class': 'autoisbn'}))
|
||||
authors = forms.CharField(widget = forms.TextInput(attrs = {'class': 'autoisbn'}), required=False)
|
||||
dimensions = forms.CharField(widget = forms.TextInput(attrs = {'class': 'autoisbn'}), required=False)
|
||||
publisher = forms.CharField(widget = forms.TextInput(attrs = {'class': 'autoisbn'}), required=False)
|
||||
published = forms.CharField(widget = forms.TextInput(attrs = {'class': 'autoisbn'}), required=False)
|
||||
pages = forms.CharField(widget = forms.TextInput(attrs = {'class': 'autoisbn'}), required=False)
|
||||
weight = forms.CharField(widget = forms.TextInput(attrs = {'class': 'autoisbn'}), required=False)
|
||||
first_sentence = forms.CharField(widget = forms.TextInput(attrs = {'class': 'autoisbn'}), required=False)
|
||||
tags = forms.CharField(widget = forms.TextInput(attrs = {'size': '50'}), required=False)
|
||||
autotags = forms.CharField(widget = forms.TextInput(attrs = {'size': '50', 'class' : 'autoisbn'}), required=False)
|
||||
|
||||
class Meta:
|
||||
model = Book
|
||||
|
||||
def dateformat(datestr):
|
||||
return datetime.date(*time.strptime(datestr, "%B %d, %Y")[0:3]).isoformat()
|
||||
|
||||
def index(request):
|
||||
books = Book.objects.all()
|
||||
|
||||
return render_to_response("index.html", {'books': books})
|
||||
|
||||
# return render_to_response("index.html", context_instance=RequestContext(request))
|
||||
|
||||
@login_required
|
||||
def add(request):
|
||||
linksInline = inlineformset_factory(Book, Weblink)
|
||||
reviewsInline = inlineformset_factory(Book, WebReview)
|
||||
summariesInline = inlineformset_factory(Book, Summary)
|
||||
relatedBookInline = inlineformset_factory(Book, RelatedBook)
|
||||
imageUrlInline = inlineformset_factory(Book, ImageUrl)
|
||||
chapterInline = inlineformset_factory(Book, ChapterEntry)
|
||||
sourcesInline = inlineformset_factory(Book, Source)
|
||||
#
|
||||
if (request.method == 'POST'):
|
||||
bookform = BookForm(request.POST)
|
||||
# bookform.published = dateformat(bookform.published)
|
||||
linksFormset = linksInline(request.POST, prefix='weblinks')
|
||||
reviewsFormset = reviewsInline(request.POST, prefix='webreviews')
|
||||
summariesFormset = summariesInline(request.POST, prefix='summaries')
|
||||
relatedBookFormset = relatedBookInline(request.POST, prefix='relatedbooks')
|
||||
imageUrlFormset = imageUrlInline(request.POST, prefix='imageurls')
|
||||
chapterFormset = chapterInline(request.POST, prefix='chapters')
|
||||
sourcesFormset = sourcesInline(request.POST, prefix='sources')
|
||||
if bookform.is_valid():
|
||||
newbook = bookform.save(commit=False)
|
||||
newbook.added_by = request.user
|
||||
request.session['owner'] = newbook.owner.id
|
||||
request.session['location'] = newbook.location.id
|
||||
newbook.published = parseDate(bookform.cleaned_data['published'])
|
||||
newbook.save()
|
||||
astring = bookform.cleaned_data['authors']
|
||||
alist = astring.split(';')
|
||||
authors = []
|
||||
for a in alist:
|
||||
if (a.strip() != ''):
|
||||
au = Author(name = a)
|
||||
au.save()
|
||||
authors.append(au)
|
||||
newbook.authors = authors
|
||||
# weblinks = linksFormset.save()
|
||||
# reviews = reviewsFormset.save()
|
||||
# summaries = summariesFormset.save()
|
||||
# relatedBooks = relatedBookFormset.save()
|
||||
# imageUrls = imageUrlFormset.save()
|
||||
# chapters = chapterFormset.save()
|
||||
# newbook.weblinks = weblinks
|
||||
newbook.save()
|
||||
|
||||
for f in linksFormset.forms:
|
||||
if f.is_valid():
|
||||
f.cleaned_data['book'] = newbook
|
||||
if f.cleaned_data.has_key('url'):
|
||||
f.save()
|
||||
|
||||
for f in summariesFormset.forms:
|
||||
if f.is_valid():
|
||||
f.cleaned_data['book'] = newbook
|
||||
if f.cleaned_data.has_key('txt'):
|
||||
f.save()
|
||||
|
||||
for f in relatedBookFormset.forms:
|
||||
if f.is_valid():
|
||||
f.cleaned_data['book'] = newbook
|
||||
if f.cleaned_data.has_key('url'):
|
||||
f.save()
|
||||
|
||||
for f in imageUrlFormset.forms:
|
||||
if f.is_valid():
|
||||
f.cleaned_data['book'] = newbook
|
||||
if f.cleaned_data.has_key('url'):
|
||||
f.save()
|
||||
|
||||
for f in chapterFormset.forms:
|
||||
if f.is_valid():
|
||||
f.cleaned_data['book'] = newbook
|
||||
if f.cleaned_data.has_key('link'):
|
||||
f.save()
|
||||
|
||||
for f in sourcesFormset.forms:
|
||||
if f.is_valid():
|
||||
f.cleaned_data['book'] = newbook
|
||||
if f.cleaned_data.has_key('name'):
|
||||
f.save()
|
||||
|
||||
# if f.cleaned_data['url'] != '':
|
||||
# f.save()
|
||||
# weblink = form.save(commit=False)
|
||||
# weblink.book = newbook
|
||||
# if form.is_valid():
|
||||
# weblink = Weblink()
|
||||
# weblink['url'] = form.cleaned_data['url']
|
||||
# weblink['description'] = form.cleaned_data['description']
|
||||
# weblink['book'] = newbook
|
||||
# weblink.save()
|
||||
# weblink.book = thisBook
|
||||
# weblink.save()
|
||||
request.user.message_set.create(message="Your book was added successfully.")
|
||||
return HttpResponseRedirect("/add")
|
||||
else:
|
||||
linksFormset = linksInline(prefix='weblinks')
|
||||
reviewsFormset = reviewsInline(prefix='webreviews')
|
||||
summariesFormset = summariesInline(prefix='summaries')
|
||||
relatedBookFormset = relatedBookInline(prefix='relatedbooks')
|
||||
imageUrlFormset = imageUrlInline(prefix='imageurls')
|
||||
chapterFormset = chapterInline(prefix='chapters')
|
||||
sourcesFormset = sourcesInline(prefix='sources')
|
||||
bookform = BookForm()
|
||||
# formsets = [linksFormset, chapterFormset]
|
||||
formsets = [linksFormset, reviewsFormset, summariesFormset, relatedBookFormset, imageUrlFormset, chapterFormset, sourcesFormset]
|
||||
defaultsD = {}
|
||||
if request.session.has_key('location'):
|
||||
defaultsD['location'] = request.session['location']
|
||||
if request.session.has_key('owner'):
|
||||
defaultsD['owner'] = request.session['owner']
|
||||
# print repr(defaultsD)
|
||||
return render_to_response("addbook.html", {'form': bookform, 'formsets': formsets, 'defaults': defaultsD}, context_instance=RequestContext(request))
|
||||
|
||||
def isbnLookup(request):
|
||||
isbn = request.GET.get('isbn')
|
||||
isbnDict = searchAll(isbn)
|
||||
if (request.is_ajax()):
|
||||
return HttpResponse(simplejson.dumps(isbnDict), mimetype='application/javascript')
|
||||
else:
|
||||
|
||||
#Ideally we would not have an if and else statement doing the same thing ;-)
|
||||
return HttpResponse(simplejson.dumps(isbnDict), mimetype='application/javascript')
|
||||
|
||||
def addLocation(request):
|
||||
if request.is_ajax():
|
||||
locationName = request.GET['name']
|
||||
l = Location(name = locationName)
|
||||
l.save()
|
||||
return HttpResponse(l.id)
|
||||
else:
|
||||
return HttpResponse(str(o.id))
|
||||
|
||||
def addOwner(request):
|
||||
if request.is_ajax():
|
||||
ownerName = request.GET['name']
|
||||
o = Owner(name = ownerName)
|
||||
o.save()
|
||||
return HttpResponse(str(o.id))
|
||||
else:
|
||||
return HttpResponse("you are not ajax.")
|
||||
|
||||
|
0
index/catalogues/__init__.py
Executable file
0
index/catalogues/__init__.py
Executable file
10
index/catalogues/admin.py
Executable file
10
index/catalogues/admin.py
Executable file
|
@ -0,0 +1,10 @@
|
|||
from catalogues.models import *
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class CatalogueAdmin(admin.ModelAdmin):
|
||||
ordering = ('title',)
|
||||
search_fields = ['title', 'artist']
|
||||
|
||||
admin.site.register(Catalogue, CatalogueAdmin)
|
||||
|
24
index/catalogues/models.py
Executable file
24
index/catalogues/models.py
Executable file
|
@ -0,0 +1,24 @@
|
|||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from books.models import Owner, Location
|
||||
from tagging.fields import TagField
|
||||
from tagging.models import Tag
|
||||
|
||||
class Catalogue(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
artist = models.CharField(max_length=255, blank=True)
|
||||
exhibition = models.CharField(max_length=255, blank=True)
|
||||
published_date = models.DateField(blank=True, verbose_name="Published on")
|
||||
condition = models.TextField(blank=True)
|
||||
description = models.TextField(blank=True)
|
||||
owner = models.ForeignKey(Owner, blank=True)
|
||||
location = models.ForeignKey(Location, blank=True)
|
||||
tags = TagField("Tags", blank=True, help_text="Enter as many tags as you like, separated by commas")
|
||||
added_by = models.ForeignKey(User, editable=False)
|
||||
date_added = models.DateTimeField(auto_now=True, editable=False)
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Catalogues"
|
||||
|
8
index/catalogues/views.py
Executable file
8
index/catalogues/views.py
Executable file
|
@ -0,0 +1,8 @@
|
|||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import render_to_response
|
||||
from catalogue.models import *
|
||||
from django import forms
|
||||
|
||||
def add(request):
|
||||
return render_to_response("addcatalogue.html") #, {'form': bookform, 'formset': formset})
|
||||
|
20
index/dropandcreatedb.py
Executable file
20
index/dropandcreatedb.py
Executable file
|
@ -0,0 +1,20 @@
|
|||
import sys
|
||||
import os
|
||||
from settings import DATABASE_NAME
|
||||
|
||||
try:
|
||||
import settings # Assumed to be in the same directory.
|
||||
except ImportError:
|
||||
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
|
||||
sys.exit(1)
|
||||
|
||||
filename = "/tmp/tmp.txt"
|
||||
tmpfile = open(filename, "w")
|
||||
tmpfile.write("DROP DATABASE %s;\nCREATE DATABASE %s;\n" % (DATABASE_NAME, DATABASE_NAME) )
|
||||
tmpfile.close()
|
||||
|
||||
os.system("mysql -u root < " + filename)
|
||||
os.system("python manage.py syncdb --noinput")
|
||||
os.system("python manage.py createsuperuser --username admin --email user@user.com")
|
||||
|
||||
|
0
index/harddrives/__init__.py
Normal file
0
index/harddrives/__init__.py
Normal file
13
index/harddrives/admin.py
Executable file
13
index/harddrives/admin.py
Executable file
|
@ -0,0 +1,13 @@
|
|||
from harddrives.models import *
|
||||
from django.contrib import admin
|
||||
|
||||
class FileAdmin(admin.ModelAdmin):
|
||||
search_fields = ('fullPath',)
|
||||
list_display = ('filename', 'fullPath', 'hd',)
|
||||
list_filter = ['hd']
|
||||
|
||||
class HardDriveAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
||||
admin.site.register(HardDrive, HardDriveAdmin)
|
||||
admin.site.register(File, FileAdmin)
|
53
index/harddrives/importFromTxtFiles.py
Normal file
53
index/harddrives/importFromTxtFiles.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
import os
|
||||
from os.path import join
|
||||
from models import HardDrive, File
|
||||
|
||||
ERROR_LOG = open("errors.txt", "a")
|
||||
|
||||
def loopThroughDir(path):
|
||||
dir = os.listdir(path)
|
||||
for f in dir:
|
||||
if f.endswith('txt'):
|
||||
addHardDrive(f, path)
|
||||
ERROR_LOG.close()
|
||||
|
||||
def addHardDrive(filename, path):
|
||||
filePath = u''
|
||||
filePath = join(path, filename)
|
||||
hdName = filename.replace(".txt", "")
|
||||
file = open(filePath)
|
||||
if hardDriveExists(hdName):
|
||||
return False
|
||||
else:
|
||||
hd = HardDrive(name = hdName)
|
||||
hd.save()
|
||||
print hdName
|
||||
for f in file:
|
||||
addFile(f, hd)
|
||||
|
||||
def addFile(filePath, hd):
|
||||
filename = u''
|
||||
filename = getFileNameFromPath(filePath)
|
||||
newfile = File(filename = filename, fullPath = filePath, hd = hd)
|
||||
try:
|
||||
newfile.save()
|
||||
except:
|
||||
err = hd.name + ":\n"
|
||||
err += filePath + "\n\n"
|
||||
ERROR_LOG.write(err)
|
||||
print "added " + filename
|
||||
|
||||
def hardDriveExists(hdName):
|
||||
return False
|
||||
|
||||
def getFileNameFromPath(filePath):
|
||||
return os.path.basename(filePath)
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
if len(sys.argv) < 2:
|
||||
print "usage: %s <directory path>" % sys.argv[0]
|
||||
sys.exit()
|
||||
else:
|
||||
path = sys.argv[1]
|
||||
loopThroughDir(path)
|
20
index/harddrives/models.py
Normal file
20
index/harddrives/models.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
from django.db import models
|
||||
|
||||
class HardDrive(models.Model):
|
||||
name = models.CharField(max_length = 255, unique = True)
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
# volumeLabel = models.CharField(max_length = 255)
|
||||
|
||||
|
||||
class File(models.Model):
|
||||
filename = models.CharField(max_length = 512)
|
||||
fullPath = models.TextField()
|
||||
hd = models.ForeignKey(HardDrive)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.fullPath
|
||||
|
||||
|
||||
|
||||
# Create your models here.
|
1
index/harddrives/views.py
Normal file
1
index/harddrives/views.py
Normal file
|
@ -0,0 +1 @@
|
|||
# Create your views here.
|
0
index/hardware/__init__.py
Executable file
0
index/hardware/__init__.py
Executable file
12
index/hardware/admin.py
Executable file
12
index/hardware/admin.py
Executable file
|
@ -0,0 +1,12 @@
|
|||
from hardware.models import *
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
class HardwareAdmin(admin.ModelAdmin):
|
||||
ordering = ('title',)
|
||||
list_display = ('title', 'category', 'box',)
|
||||
list_filter = ('category', 'box',)
|
||||
search_fields = ['title', 'description']
|
||||
|
||||
admin.site.register(Hardware, HardwareAdmin)
|
||||
admin.site.register(Link)
|
50
index/hardware/models.py
Normal file
50
index/hardware/models.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from books.models import Owner, Location
|
||||
from tagging.fields import TagField
|
||||
from tagging.models import Tag
|
||||
from books.fields import MultiSelectField, MultiSelectFormField
|
||||
|
||||
CATEGORY_CHOICES = (
|
||||
('artworks', 'Artworks'),
|
||||
('control', 'Control'),
|
||||
('cables', 'Cables'),
|
||||
('connectors', 'Connectors'),
|
||||
('computer', 'Computer'),
|
||||
('storage', 'Storage Devices'),
|
||||
('av', 'Audio / Video Equipment'),
|
||||
('electronics', 'Electronics'),
|
||||
('electrical', 'Electrical & Lighting'),
|
||||
('mechanical', 'Mechanical Parts'),
|
||||
('media', 'Media'),
|
||||
('tools', 'Tools'),
|
||||
('supplies', 'Supplies'),
|
||||
('other', 'Other'),
|
||||
)
|
||||
|
||||
class Hardware(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
model_number = models.CharField(max_length=255, blank=True)
|
||||
serial_number = models.CharField(max_length=255, blank=True)
|
||||
description = models.TextField(blank=True)
|
||||
owner = models.ForeignKey(Owner, blank=True)
|
||||
location = models.ForeignKey(Location, blank=True)
|
||||
tags = TagField("Tags", blank=True, help_text="Enter as many tags as you like, separated by commas")
|
||||
added_by = models.ForeignKey(User, editable=False)
|
||||
date_added = models.DateTimeField(auto_now=True, editable=False)
|
||||
category = MultiSelectField(max_length=355, choices=CATEGORY_CHOICES, verbose_name="Category")
|
||||
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name_plural = "Hardware"
|
||||
|
||||
class Link(models.Model):
|
||||
name = models.CharField(max_length=255)
|
||||
url = models.URLField()
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
8
index/hardware/views.py
Executable file
8
index/hardware/views.py
Executable file
|
@ -0,0 +1,8 @@
|
|||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.shortcuts import render_to_response
|
||||
from hardware.models import *
|
||||
from django import forms
|
||||
|
||||
#def add(request):
|
||||
#return render_to_response("addhardware.html") #, {'form': bookform, 'formset': formset})
|
||||
|
11
index/manage.py
Executable file
11
index/manage.py
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/python
|
||||
from django.core.management import execute_manager
|
||||
try:
|
||||
import settings # Assumed to be in the same directory.
|
||||
except ImportError:
|
||||
import sys
|
||||
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
execute_manager(settings)
|
57
index/media/css/base.css
Executable file
57
index/media/css/base.css
Executable file
|
@ -0,0 +1,57 @@
|
|||
body {
|
||||
background: #000;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#header {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
background: #333;
|
||||
color: #333;
|
||||
height: 40px;
|
||||
margin-bottom: 4px;
|
||||
padding: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
-webkit-border-radius: 5px;
|
||||
}
|
||||
|
||||
#buttons {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
#pageTitle {
|
||||
width: 100%;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
font-size: 18px;
|
||||
padding-top: 8px;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 2px;
|
||||
padding-top: 6px;
|
||||
float: left;
|
||||
border: 2px solid #000;
|
||||
background: #000;
|
||||
color: #00f;
|
||||
height: 20px;
|
||||
margin-left: 5px;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
width: 100px;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button a {
|
||||
color: #f33;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.button a:hover {
|
||||
color: yellow;
|
||||
}
|
||||
|
151
index/media/css/form.css
Executable file
151
index/media/css/form.css
Executable file
|
@ -0,0 +1,151 @@
|
|||
#isbnlookup {
|
||||
color: blue;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#loading {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#userFields {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#userFields input {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
#userFields input, textarea, select {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#lookupIsbn {
|
||||
width: 8em;
|
||||
background: #db1010;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
border: 1px solid #f39b0f;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#lookupIsbn:hover {
|
||||
background-color: #f39b0f;
|
||||
|
||||
}
|
||||
|
||||
#userFields textarea {
|
||||
width: 50%;
|
||||
}
|
||||
#autoFields {
|
||||
float: left;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
#autoFields input {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#formErrors {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
text-align: center;
|
||||
color: #f00;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
background: yellow;
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.loadingimage {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.button_loadingimage {
|
||||
display: none;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.formset {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.formset_title {
|
||||
cursor: pointer;
|
||||
margin-bottom: 3px;
|
||||
margin-left: 40%;
|
||||
font-weight: bold;
|
||||
border: 1px solid #f00;
|
||||
text-align: center;
|
||||
-moz-border-radius: 10px;
|
||||
width: 10em;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.formset_no_results {
|
||||
font-size: 12px;
|
||||
color: #f00;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.formset_forms {
|
||||
display: none;
|
||||
border: 1px dotted #f00;
|
||||
}
|
||||
|
||||
.formset_form {
|
||||
border: 1px dotted #f00;
|
||||
}
|
||||
|
||||
#formsets {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.addButton {
|
||||
font-style: bold;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
color: #00f;
|
||||
}
|
||||
|
||||
label {
|
||||
color: #f19f9f;
|
||||
font-weight: bold 70%;
|
||||
position: relative;
|
||||
left: 15px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#submitBtn {
|
||||
width: 40%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#submitButton {
|
||||
width: 20px;
|
||||
background-color: #1d0213;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border: 1px solid #f39b0f;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#submitButton:hover {
|
||||
color: yellow;
|
||||
}
|
||||
|
||||
input, textarea {
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
#isbn input {
|
||||
width: 13em;
|
||||
}
|
BIN
index/media/images/loading.gif
Executable file
BIN
index/media/images/loading.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 847 B |
BIN
index/media/images/plus.gif
Executable file
BIN
index/media/images/plus.gif
Executable file
Binary file not shown.
After Width: | Height: | Size: 119 B |
146
index/media/js/bookform.js
Executable file
146
index/media/js/bookform.js
Executable file
|
@ -0,0 +1,146 @@
|
|||
$(document).ready(function() {
|
||||
$('#lookupIsbn').click(isbnLookup);
|
||||
|
||||
//To handle colour changing on focus / blur of form elems:
|
||||
$('input, textarea').focus(function() {
|
||||
$(this).css("background", "#fff");
|
||||
}).blur(function() {
|
||||
$(this).css("background", "#ccc");
|
||||
});
|
||||
|
||||
//To add Owner / Location fields dynamically.
|
||||
$('.addButton').click(function() {
|
||||
var fieldName = $(this).attr("data_field");
|
||||
var value = prompt("Please type the name of the new " + fieldName + "you would like to add:");
|
||||
if (value != null && $.trim(value) != '') {
|
||||
var url = "/add" + fieldName + "/";
|
||||
$.get(url, {
|
||||
'name': value
|
||||
}, function(response) {
|
||||
addedId = response;
|
||||
var html = '';
|
||||
html += '<option value="' + addedId + '" selected="selected">' + value + "</option>";
|
||||
selectId = "#id_" + fieldName;
|
||||
$(selectId).append(html);
|
||||
});
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
//TODO: Make this a function that actually validates.
|
||||
function isValidIsbn(isbn) {
|
||||
if ($.trim(isbn) != '') {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Function fired on start loading ISBN Lookup
|
||||
function doLoading() {
|
||||
$('.autoisbn').css("background", "#f00").attr("disabled", "true");
|
||||
$('#lookupIsbn').fadeOut();
|
||||
$('#loading').fadeIn();
|
||||
$('.loadingimage').fadeIn();
|
||||
$('.button_loadingimage').fadeIn();
|
||||
}
|
||||
|
||||
//Function fired when ISBN Lookup is loaded
|
||||
function stopLoading() {
|
||||
$('.autoisbn').removeAttr("disabled").css("background", "#fff");
|
||||
$('#loading').hide();
|
||||
$('.loadingimage').fadeOut();
|
||||
$('.button_loadingimage').fadeOut();
|
||||
$('#lookupIsbn').fadeIn();
|
||||
}
|
||||
|
||||
//Fetch ISBN Lookup data and populate relevant fields.
|
||||
function isbnLookup() {
|
||||
isbn = $('#id_isbn').val();
|
||||
if (isValidIsbn(isbn)) {
|
||||
doLoading();
|
||||
$.getJSON("/isbnlookup/", {
|
||||
'isbn': isbn
|
||||
}, function(data) {
|
||||
if (data.errors && data.errors != '') {
|
||||
$('#formErrors').html(data.errors);
|
||||
stopLoading();
|
||||
} else {
|
||||
// alert(data.title);
|
||||
$('#id_title').val(data.title);
|
||||
$('#id_dimensions').val(data.dimensions);
|
||||
var publishedStr = getStrFromDate(data.published);
|
||||
$('#id_published').val(publishedStr);
|
||||
$('#id_publisher').val(data.publisher);
|
||||
if (data.weight != 0) {
|
||||
$('#id_weight').val(data.weight);
|
||||
}
|
||||
if (data.pages != 0) {
|
||||
$('#id_pages').val(data.pages);
|
||||
}
|
||||
if (data.tags.length > 0) {
|
||||
var tString = '';
|
||||
for (t in data.tags) {
|
||||
tString += data.tags[t] + ", ";
|
||||
}
|
||||
$('#id_autotags').val(tString);
|
||||
}
|
||||
$('#id_first_sentence').val(data.first_sentence);
|
||||
//TODO: Formsets should be referencable by prefixes.
|
||||
formsets[0].populate(data.weblinks);
|
||||
formsets[1].populate(data.netReviews);
|
||||
formsets[2].populate(data.summaries);
|
||||
formsets[3].populate(data.relatedBooks);
|
||||
formsets[4].populate(data.imageUrls);
|
||||
formsets[5].populate(data.chapters);
|
||||
formsets[6].populate(data.sources);
|
||||
var authorString = '';
|
||||
for (author in data.authors) {
|
||||
authorString += data.authors[author] + "; ";
|
||||
}
|
||||
// alert(authorString);
|
||||
$('#id_authors').val(authorString);
|
||||
stopLoading();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//Isbn Lookup passes date as a dict - convert to string.
|
||||
function getStrFromDate(d) {
|
||||
var str = '';
|
||||
if (d.year) {
|
||||
str += d.year
|
||||
if (d.month) {
|
||||
str += '-' + d.month
|
||||
if (d.day) {
|
||||
str += '-' + d.day
|
||||
}
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
//#################################################
|
||||
//BEGIN Formset functions
|
||||
//#################################################
|
||||
|
||||
var prefixes = ['weblinks', 'webreviews', 'summaries', 'relatedbooks', 'imageurls', 'chapters', 'sources']
|
||||
|
||||
//TODO: more elegant way to calculate length of buttons
|
||||
$(document).ready(function() {
|
||||
formsets = [];
|
||||
for (var p in prefixes) {
|
||||
formsets[p] = new Formset(prefixes[p]);
|
||||
}
|
||||
|
||||
$('.formset_title').hover(function() {
|
||||
$(this).css('border-color', '#fff');
|
||||
$(this).css('color', '#f00');
|
||||
}, function() {
|
||||
$(this).css('border-color', '#f00');
|
||||
$(this).css('color', '#fff');
|
||||
});
|
||||
});
|
||||
|
||||
|
192
index/media/js/formset.js
Normal file
192
index/media/js/formset.js
Normal file
|
@ -0,0 +1,192 @@
|
|||
/*
|
||||
*@class Formset class
|
||||
*@property {String} prefix same prefix as defined in django view while instantiating formset.
|
||||
*@property {String} prefixStr prefix string to
|
||||
*@property {String} jqPrefix just a helpful prefix with '#_id' prepended to use in jQuery selector strings
|
||||
*@property {jQuery Object} totalFormsElem the Input field of the TOTAL_FORMS field for this formset. (Django: management_form)
|
||||
*@property {jQuery Object} cloneObj a jQuery element that is a clone of a single form in the formset.
|
||||
*@property {jQuery Object} titleElem The div that contains the title of the formset
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
*@constructor
|
||||
*@param {String} Prefix for this formset (same as used in django during instantiation)
|
||||
*/
|
||||
var Formset = function(prefix) {
|
||||
var that = this;
|
||||
this.prefix = prefix;
|
||||
this.jqPrefix = '#id_' + prefix;
|
||||
this.prefixStr = 'id_' + this.prefix + '-';
|
||||
this.totalFormsElem = $(that.jqPrefix + '-TOTAL_FORMS');
|
||||
this.cloneObj = function() {
|
||||
var that = this;
|
||||
return $('#' + that.prefix + ' > .formset_forms').children('.formset_form:first').clone()
|
||||
}
|
||||
this.titleElem = $('#' + that.prefix + ' > .formset_title');
|
||||
this.formsetElem = $('#' + that.prefix + ' > .formset_forms');
|
||||
this.titleElem.click(function() {
|
||||
that.formsetElem.toggle('slow', function() {
|
||||
thisTop = that.titleElem.offset().top;
|
||||
$(document).scrollTop(thisTop);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
*Toggles display of formset (except for title element), also scrolls the page to the top of the title element.
|
||||
* TODO: fix the scroll being weird or get rid of it.
|
||||
*/
|
||||
Formset.prototype.toggleDisplay = function() {
|
||||
var that = this;
|
||||
that.formsetElem.toggle('slow', function() {
|
||||
thisTop = that.titleElem.offset().top;
|
||||
$(document).scrollTop(thisTop);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Get total no of forms in formset.
|
||||
* @returns {Int} Total no of forms according to formset metadata.
|
||||
*/
|
||||
Formset.prototype.getTotal = function() {
|
||||
return parseInt(this.totalFormsElem.val());
|
||||
}
|
||||
|
||||
/*
|
||||
* Set total no of forms in formset.
|
||||
*@param {Int} No of forms to set formset metadata to.
|
||||
*/
|
||||
Formset.prototype.setTotal = function(newNo) {
|
||||
this.totalFormsElem.val(newNo);
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Increment formset metadata total by one
|
||||
*/
|
||||
Formset.prototype.increment = function() {
|
||||
var currTotal = this.getTotal();
|
||||
var newTotal = currTotal + 1;
|
||||
this.setTotal(newTotal);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Formset.prototype.getFieldName = function(idStr) {
|
||||
// var thisId = jqObj.attr('id');
|
||||
// var thisPrefixStr = 'id_' + this.prefix + '-';
|
||||
var that = this;
|
||||
var prefixLength = this.prefixStr.length + 2;
|
||||
var thisField = idStr.substring(prefixLength);
|
||||
console.log(that.prefixStr);
|
||||
return thisField;
|
||||
}
|
||||
|
||||
/*
|
||||
*@returns {Array} returns array of strings representing field names present in this formset.
|
||||
*/
|
||||
Formset.prototype.getFields = function() {
|
||||
var that = this;
|
||||
var fields = [];
|
||||
that.cloneObj().find('input').each(function() {
|
||||
if ($(this).attr('type') != 'hidden') {
|
||||
var thisField = that.getFieldName($(this).attr('id'))
|
||||
if (thisField != 'DELETE') {
|
||||
fields.push(thisField);
|
||||
}
|
||||
}
|
||||
});
|
||||
that.cloneObj().find('textarea').each(function() {
|
||||
if ($(this).attr('type') != 'hidden') {
|
||||
var thisField = that.getFieldName($(this).attr('id'))
|
||||
if (thisField != 'DELETE') {
|
||||
fields.push(thisField);
|
||||
}
|
||||
}
|
||||
});
|
||||
return fields;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a form to the formset. Use this method from the outside.
|
||||
* @param {Int} No of forms to add (Optional), defaults to 1.
|
||||
*/
|
||||
Formset.prototype.add = function(no) {
|
||||
if (!no) {
|
||||
var no = 1;
|
||||
}
|
||||
var that = this;
|
||||
for (var i=0; i < no; i++) {
|
||||
var e = this.cloneObj();
|
||||
//TODO: Figure out how to deal with changing 'for' attribute on labels correctly.
|
||||
/*
|
||||
e.find('label').each(function() {
|
||||
var newId = that.incrementId($(this).attr('for'));
|
||||
// $(this).attr('id', newId);
|
||||
$(this).attr('for', newId);
|
||||
});
|
||||
*/
|
||||
e.find('input').each(function() {
|
||||
$(this).attr('id', that.incrementId($(this).attr('id')));
|
||||
$(this).attr('name', that.incrementName($(this).attr('id')));
|
||||
});
|
||||
e.find('textarea').each(function() {
|
||||
$(this).attr('id', that.incrementId($(this).attr('id')));
|
||||
$(this).attr('name', that.incrementName($(this).attr('id')));
|
||||
});
|
||||
this.increment();
|
||||
this.formsetElem.append(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
*@param {String} id of element to increment
|
||||
*@returns {String} incremented id
|
||||
*/
|
||||
Formset.prototype.incrementId = function(idStr) {
|
||||
var newTotal = this.getTotal() + 1;
|
||||
var newId = this.prefixStr + newTotal.toString() + '-' + this.getFieldName(idStr);
|
||||
return newId;
|
||||
}
|
||||
|
||||
/*
|
||||
*@param {String} name of element to increment
|
||||
*@returns {String} incremented name
|
||||
*/
|
||||
Formset.prototype.incrementName = function(idStr) {
|
||||
var newTotal = this.getTotal() + 1;
|
||||
var newId = this.prefix + '-' + newTotal.toString() + '-' + this.getFieldName(idStr);
|
||||
return newId;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populates a formset with an array of JSON data
|
||||
*@param {JSON Array} like so - [{'field1': 'some value', 'field2': 'some more value'}, {'field1': 'foo', 'field2': 'bar'}]
|
||||
*@returns true once done
|
||||
*/
|
||||
|
||||
Formset.prototype.populate = function(data) {
|
||||
var that = this;
|
||||
var noOfEntries = data.length;
|
||||
if (data.length > 0) {
|
||||
// that.titleElem.html(that.titleElem.html() + " " + noOfEntries.toString());
|
||||
that.titleElem.children('.formset_no_results').html(noOfEntries.toString());
|
||||
var totalFormsToShow = noOfEntries + 3;
|
||||
var newFormsToAdd = totalFormsToShow - this.getTotal();
|
||||
this.add(newFormsToAdd);
|
||||
var fields = this.getFields();
|
||||
for (var f in fields) {
|
||||
var fieldName = fields[f];
|
||||
for (var d in data) {
|
||||
if (data[d]) {
|
||||
var val = data[d][fieldName];
|
||||
$(that.jqPrefix + '-' + d.toString() + '-' + fieldName).val(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
19
index/media/js/jquery.js
vendored
Executable file
19
index/media/js/jquery.js
vendored
Executable file
File diff suppressed because one or more lines are too long
92
index/settings.py
Normal file
92
index/settings.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
# Django settings for index project.
|
||||
import os
|
||||
from os.path import join
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATE_DEBUG = DEBUG
|
||||
|
||||
PROJECT_PATH = os.path.dirname(__file__)
|
||||
|
||||
ADMINS = (
|
||||
# ('Your Name', 'your_email@domain.com'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
DATABASE_ENGINE = 'mysql' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
||||
DATABASE_NAME = 'idx' # Or path to database file if using sqlite3.
|
||||
DATABASE_USER = 'root' # Not used with sqlite3.
|
||||
DATABASE_PASSWORD = '' # Not used with sqlite3.
|
||||
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
|
||||
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.
|
||||
|
||||
# Local time zone for this installation. Choices can be found here:
|
||||
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||
# although not all choices may be available on all operating systems.
|
||||
# If running in a Windows environment this must be set to the same as your
|
||||
# system time zone.
|
||||
TIME_ZONE = 'America/Chicago'
|
||||
|
||||
# Language code for this installation. All choices can be found here:
|
||||
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
SITE_ID = 1
|
||||
|
||||
# If you set this to False, Django will make some optimizations so as not
|
||||
# to load the internationalization machinery.
|
||||
USE_I18N = True
|
||||
|
||||
# Absolute path to the directory that holds media.
|
||||
# Example: "/home/media/media.lawrence.com/"
|
||||
MEDIA_ROOT = join(PROJECT_PATH, 'media')
|
||||
|
||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||
# trailing slash if there is a path component (optional in other cases).
|
||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
LOGIN_URL = '/login/'
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
|
||||
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
||||
# trailing slash.
|
||||
# Examples: "http://foo.com/media/", "/media/".
|
||||
ADMIN_MEDIA_PREFIX = '/admin/media/'
|
||||
|
||||
# Make this unique, and don't share it with anybody.
|
||||
SECRET_KEY = ')o1)c68=b9k5z@af=_@s31)pcp58yxo@5@$b5!^_vlijibziq1'
|
||||
|
||||
# List of callables that know how to import templates from various sources.
|
||||
TEMPLATE_LOADERS = (
|
||||
'django.template.loaders.filesystem.load_template_source',
|
||||
'django.template.loaders.app_directories.load_template_source',
|
||||
# 'django.template.loaders.eggs.load_template_source',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
)
|
||||
|
||||
ROOT_URLCONF = 'urls'
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
join(PROJECT_PATH, 'templates'),
|
||||
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
|
||||
# Always use forward slashes, even on Windows.
|
||||
# Don't forget to use absolute paths, not relative paths.
|
||||
)
|
||||
|
||||
INSTALLED_APPS = (
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.sites',
|
||||
'django.contrib.admin',
|
||||
'books',
|
||||
'harddrives',
|
||||
'tagging',
|
||||
'south',
|
||||
)
|
171
index/templates/addbook.html
Normal file
171
index/templates/addbook.html
Normal file
|
@ -0,0 +1,171 @@
|
|||
{% extends 'site_base.html' %}
|
||||
|
||||
{% block extra_head %}
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
{% if defaults.location %}
|
||||
var locationId = {{ defaults.location }}
|
||||
$('#id_location').children().each(function() {
|
||||
if ($(this).attr("value") == locationId) {
|
||||
$(this).attr("selected", "selected");
|
||||
}
|
||||
});
|
||||
{% endif %}
|
||||
{% if defaults.owner %}
|
||||
var ownerId = {{ defaults.owner }}
|
||||
$('#id_owner').children().each(function() {
|
||||
if ($(this).attr("value") == ownerId) {
|
||||
$(this).attr("selected", "selected");
|
||||
}
|
||||
});
|
||||
{% endif %}
|
||||
});
|
||||
</script>
|
||||
<script type="text/javascript" src="/media/js/formset.js"></script>
|
||||
<script type="text/javascript" src="/media/js/bookform.js"></script>
|
||||
|
||||
<link rel="stylesheet" href="/media/css/form.css" />
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<form action="/add/" method="POST" enctype="multipart/formdata">
|
||||
|
||||
<div id="formErrors">
|
||||
<div id="loading">Loading...</div>
|
||||
{{ form.errors }}
|
||||
|
||||
<div id="messages">
|
||||
{% if messages %}
|
||||
<ul>
|
||||
{% for message in messages %}
|
||||
<li>{{ message }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="userFields">
|
||||
|
||||
<div id="isbn">
|
||||
|
||||
<label class="fixedWidth" for="id_isbn">ISBN Code:</label><br /> {{ form.isbn}} <button id="lookupIsbn" onclick="return false;">Lookup ISBN</button>
|
||||
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<label class="fixedWidth" for="id_tags">Tags: </label><br />
|
||||
{{ form.tags }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label class="fixedWidth" for="id_description">Description: </label><br />
|
||||
{{ form.description }}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_owner">Owner: </label><br />
|
||||
{{ form.owner }} <span class="addButton" data_field="owner"><img src="/media/images/plus.gif"></a></span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_location">Location: </label><br />
|
||||
{{ form.location }} <span class="addButton" data_field="location"><img src="/media/images/plus.gif"></span>
|
||||
</p>
|
||||
|
||||
<p id="submitBtn">
|
||||
<input type="submit" value="Submit" id="submitButton" />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div id="autoFields">
|
||||
<p>
|
||||
<label for="id_title">Title: </label><br />
|
||||
{{ form.title}}
|
||||
<img class="loadingimage" src="/media/images/loading.gif">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_authors">Authors: </label><br />
|
||||
{{ form.authors}}
|
||||
<img class="loadingimage" src="/media/images/loading.gif">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_publisher">Publisher: </label><br />
|
||||
{{ form.publisher }}
|
||||
<img class="loadingimage" src="/media/images/loading.gif">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_published">Published: </label><br />
|
||||
{{ form.published }}
|
||||
<img class="loadingimage" src="/media/images/loading.gif">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_autotags">AutoTags: </label>
|
||||
{{ form.autotags }}
|
||||
<img class="loadingimage" src="/media/images/loading.gif">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_pages">Pages: </label><br />
|
||||
{{ form.pages }}
|
||||
<img class="loadingimage" src="/media/images/loading.gif">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_weight">Weight: </label><br />
|
||||
{{ form.weight }}
|
||||
<img class="loadingimage" src="/media/images/loading.gif">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_dimensions">Dimensions: </label><br />
|
||||
{{ form.dimensions }}
|
||||
<img class="loadingimage" src="/media/images/loading.gif">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="id_first_sentence">First Sentence: </label><br />
|
||||
{{ form.first_sentence }}
|
||||
<img class="loadingimage" src="/media/images/loading.gif">
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div id="formsets">
|
||||
{% for formset in formsets %}
|
||||
<div id="{{formset.prefix}}" class="formset">
|
||||
<div class="formset_title">
|
||||
{{formset.prefix}} <span class="formset_no_results"></span>
|
||||
<!-- <img class="button_loadingimage" src="/media/images/loading.gif"> -->
|
||||
</div>
|
||||
<div class='formset_meta'>
|
||||
{{ formset.management_form }}
|
||||
</div>
|
||||
<div class="formset_forms">
|
||||
{% for form in formset.forms %}
|
||||
<div class="formset_form">
|
||||
{{ form.as_p }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
17
index/templates/base.html
Executable file
17
index/templates/base.html
Executable file
|
@ -0,0 +1,17 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src="/media/js/jquery.js"></script>
|
||||
{% block head %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}
|
||||
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
20
index/templates/index.html
Executable file
20
index/templates/index.html
Executable file
|
@ -0,0 +1,20 @@
|
|||
{% extends 'site_base.html' %}
|
||||
{% block title %} Home {% endblock %}
|
||||
{% block extra_head %}
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
<ul>
|
||||
{% for book in books %}
|
||||
<li data_id="{{ book.id }}"><a href="/book/{{ book.id }}">{{ book.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endblock %}
|
||||
|
||||
|
30
index/templates/login.html
Executable file
30
index/templates/login.html
Executable file
|
@ -0,0 +1,30 @@
|
|||
{% extends 'site_base.html' %}
|
||||
|
||||
{% block title %}
|
||||
Login
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if form.errors %}
|
||||
<p>Your username and password didn't match. Please try again.</p>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" action="{% url django.contrib.auth.views.login %}">
|
||||
<table>
|
||||
<tr>
|
||||
<td>{{ form.username.label_tag }}</td>
|
||||
<td>{{ form.username }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>{{ form.password.label_tag }}</td>
|
||||
<td>{{ form.password }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<input type="submit" value="login" />
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
6
index/templates/logout.html
Executable file
6
index/templates/logout.html
Executable file
|
@ -0,0 +1,6 @@
|
|||
{% extends 'site_base.html' %}
|
||||
{% block title %} Logout {% endblock %}
|
||||
{% block content %}
|
||||
{{ title }}
|
||||
{% endblock %}
|
||||
|
46
index/templates/site_base.html
Executable file
46
index/templates/site_base.html
Executable file
|
@ -0,0 +1,46 @@
|
|||
{% extends 'base.html' %}
|
||||
{% block head %}
|
||||
<link rel="stylesheet" href="/media/css/base.css" />
|
||||
<title>{% block title %} {% endblock %} </title>
|
||||
{% block extra_head %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div id="header">
|
||||
<div id="pageTitle">
|
||||
The Index . ( ) .
|
||||
</div>
|
||||
<div id="buttons">
|
||||
<div class="button">
|
||||
{% if user.is_authenticated %}
|
||||
<a href="/logout">Logout</a>
|
||||
{% else %}
|
||||
<a href="/login">Login</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% block extra_buttons %}
|
||||
<div class="button">
|
||||
<a href="/add/">Books</a>
|
||||
</div>
|
||||
<div class="button">
|
||||
<a href="/admin/books/catalogue/add/">Catalogues</a>
|
||||
</div>
|
||||
<div class="button">
|
||||
<a href="/admin/books/hardware/">Hardware</a>
|
||||
</div>
|
||||
<div class="button">
|
||||
<a href="/admin/harddrives/file/">Hard-Drives</a>
|
||||
</div>
|
||||
{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
31
index/urls.py
Executable file
31
index/urls.py
Executable file
|
@ -0,0 +1,31 @@
|
|||
from django.conf.urls.defaults import *
|
||||
from settings import PROJECT_PATH
|
||||
from os.path import join
|
||||
|
||||
# Uncomment the next two lines to enable the admin:
|
||||
from django.contrib import admin
|
||||
admin.autodiscover()
|
||||
|
||||
urlpatterns = patterns('',
|
||||
# Example:
|
||||
# (r'^index/', include('index.foo.urls')),
|
||||
(r'^login/$', 'django.contrib.auth.views.login', {'template_name': 'login.html'}),
|
||||
(r'^logout/$', 'django.contrib.auth.views.logout', {'template_name': 'logout.html'}),
|
||||
(r'^$', 'books.views.index'),
|
||||
# (r'^addhardware/(.*)', 'hardware.views.addhardware'),
|
||||
(r'^add/$', 'books.views.add'),
|
||||
(r'^addlocation/$', 'books.views.addLocation'),
|
||||
(r'addowner/$', 'books.views.addOwner'),
|
||||
(r'^(\w+)/add/$', 'books.views.add'),
|
||||
(r'^isbnlookup/$', 'books.views.isbnLookup'),
|
||||
(r'^media/(?P<path>.*)$', 'django.views.static.serve',
|
||||
{'document_root': join(PROJECT_PATH, 'media')}),
|
||||
|
||||
# Uncomment the admin/doc line below and add 'django.contrib.admindocs'
|
||||
# to INSTALLED_APPS to enable admin documentation:
|
||||
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||
# (r'^admin/', include('django.contrib.admin.urls')),
|
||||
# Uncomment the next line to enable the admin:
|
||||
(r'^admin/(.*)', admin.site.root),
|
||||
|
||||
)
|
Loading…
Reference in New Issue
Block a user