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