Merge branch 'master' of github.com:Gluejar/regluit into ry
commit
a35d67329d
|
@ -0,0 +1,23 @@
|
|||
"""
|
||||
a variety of errors can cause works to not get clustered by add_editions, or a new isbn can take time to get incorporated into clustering services.
|
||||
The signature of both problems is a work with only one related edition, a singleton.
|
||||
This script goes through all singleton works and attempts to add_related. 'xx' works are excluded from being source works
|
||||
"""
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db.models import Count
|
||||
from regluit.core import models, bookloader
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "add and merge editions for singleton works"
|
||||
|
||||
def handle(self, **options):
|
||||
print "Number of singleton Works with language!=xx: %s" % models.Work.objects.annotate(num_editions=Count('editions')).filter(num_editions=1).exclude(language='xx').count()
|
||||
|
||||
for work in models.Work.objects.annotate(num_editions=Count('editions')).filter(num_editions=1).exclude(language='xx'):
|
||||
#check that there's still only one edition
|
||||
if work.editions.count() != 1:
|
||||
continue
|
||||
new_editions = bookloader.add_related( work.first_isbn_13() )
|
||||
print "clustered %s editions for work %s" % (len(new_editions),work )
|
||||
print "Updated Number of singleton Works with language!=xx: %s" % models.Work.objects.annotate(num_editions=Count('editions')).filter(num_editions=1).exclude(language='xx').count()
|
|
@ -2,11 +2,11 @@ import json
|
|||
import requests
|
||||
import regluit.core.isbn
|
||||
|
||||
def gluejar_search(q, user_ip='69.243.24.29'):
|
||||
def gluejar_search(q, user_ip='69.243.24.29', page=1):
|
||||
"""normalizes results from the google books search suitable for gluejar
|
||||
"""
|
||||
results = []
|
||||
search_result=googlebooks_search(q, user_ip)
|
||||
search_result=googlebooks_search(q, user_ip, page)
|
||||
if 'items' in search_result.keys():
|
||||
for item in search_result['items']:
|
||||
v = item['volumeInfo']
|
||||
|
@ -48,9 +48,11 @@ def gluejar_search(q, user_ip='69.243.24.29'):
|
|||
return results
|
||||
|
||||
|
||||
def googlebooks_search(q, user_ip):
|
||||
def googlebooks_search(q, user_ip, page):
|
||||
# XXX: need to pass IP address of user in from the frontend
|
||||
headers = {'X-Forwarded-For': user_ip}
|
||||
start = (page - 1) * 10
|
||||
params = {'q': q, 'startIndex': start, 'maxResults': 10}
|
||||
r = requests.get('https://www.googleapis.com/books/v1/volumes',
|
||||
params={'q': q}, headers=headers)
|
||||
params=params, headers=headers)
|
||||
return json.loads(r.content)
|
||||
|
|
|
@ -81,7 +81,7 @@ class BookLoaderTests(TestCase):
|
|||
bookloader.add_related('0441012035')
|
||||
self.assertTrue(models.Edition.objects.count() > 15)
|
||||
self.assertEqual(models.Work.objects.filter(language=lang).count(), 1)
|
||||
self.assertTrue(edition.work.editions.count() > 10)
|
||||
self.assertTrue(edition.work.editions.count() > 9)
|
||||
|
||||
|
||||
def test_populate_edition(self):
|
||||
|
@ -192,8 +192,15 @@ class SearchTests(TestCase):
|
|||
self.assertTrue(r.has_key('isbn_13'))
|
||||
self.assertTrue(r.has_key('googlebooks_id'))
|
||||
|
||||
def test_pagination(self):
|
||||
r1 = search.gluejar_search('melville', page=1)
|
||||
r2 = search.gluejar_search('melville', page=2)
|
||||
isbns1 = set([r['isbn_13'] for r in r1])
|
||||
isbns2 = set([r['isbn_13'] for r in r2])
|
||||
self.assertTrue(isbns1 != isbns2)
|
||||
|
||||
def test_googlebooks_search(self):
|
||||
response = search.googlebooks_search('melville', '69.243.24.29')
|
||||
response = search.googlebooks_search('melville', '69.243.24.29', 1)
|
||||
self.assertEqual(len(response['items']), 10)
|
||||
|
||||
|
||||
|
|
|
@ -7,6 +7,31 @@
|
|||
<script type="text/javascript" src="/static/js/wishlist.js"></script>
|
||||
<script type="text/javascript" src="/static/js/greenpanel.js"></script>
|
||||
<script type="text/javascript" src="/static/js/toggle.js"></script>
|
||||
<script type="text/javascript" src="/static/js/jquery.endless-scroll.js"></script>
|
||||
<script type="text/javascript">
|
||||
var $j = jQuery.noConflict();
|
||||
var page = 1;
|
||||
$j(document).ready(function() {
|
||||
$j(document).endlessScroll({
|
||||
bottomPixels: 250,
|
||||
fireOnce: false,
|
||||
fireDelay: false,
|
||||
insertAfter: "#results-bottom",
|
||||
loader: '<img src="/static/images/loading.gif">',
|
||||
callback: function(p) {
|
||||
page += 1;
|
||||
var url = "?q={{ q }}&page=" + page;
|
||||
$j.get(url, function(html) {
|
||||
var view = $j(".listview").length > 0 ? "list" : "panel";
|
||||
var results = $j(html).find(".book");
|
||||
$j("#results").append(results);
|
||||
if (view === "list") toggleList();
|
||||
else togglePanel();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}Google Books search results{% endblock %}
|
||||
|
@ -37,9 +62,9 @@
|
|||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content-block-content">
|
||||
<div id="results" class="content-block-content">
|
||||
{% for work in results %}
|
||||
<div class="{% cycle 'row1' 'row2' %}">
|
||||
<div class="{% cycle 'row1' 'row2' %} book">
|
||||
{% with work.googlebooks_id as googlebooks_id %}
|
||||
{% with work.last_campaign_status as status %}
|
||||
{% with work.last_campaign.deadline as deadline %}
|
||||
|
@ -56,9 +81,9 @@
|
|||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div id="results-bottom"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -66,4 +91,4 @@
|
|||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block counter %}{% endblock %}
|
||||
{% block counter %}{% endblock %}
|
||||
|
|
|
@ -251,7 +251,7 @@ how do I integrate the your wishlist thing with the tabs thing?
|
|||
It looks like {{ supporter.username }} is just getting started, and hasn't added books just yet.<br /><br />
|
||||
{% endifequal %}
|
||||
{% else %}
|
||||
{% paginate 20 works %}
|
||||
{% lazy_paginate 20 works %}
|
||||
{% for work in works %}
|
||||
<div class="{% cycle 'row1' 'row2' %}">
|
||||
{% with work.last_campaign_status as status %}
|
||||
|
@ -263,7 +263,7 @@ how do I integrate the your wishlist thing with the tabs thing?
|
|||
{% endfor %}
|
||||
<br>
|
||||
<div class="pagination content-block-heading">
|
||||
{% show_pages %}
|
||||
{% show_more %}
|
||||
</div>
|
||||
{% endifequal %}
|
||||
</div>
|
||||
|
|
|
@ -820,14 +820,15 @@ def edit_user(request):
|
|||
|
||||
def search(request):
|
||||
q = request.GET.get('q', None)
|
||||
results = gluejar_search(q, request.META['REMOTE_ADDR'])
|
||||
page = int(request.GET.get('page', 1))
|
||||
results = gluejar_search(q, user_ip=request.META['REMOTE_ADDR'], page=page)
|
||||
|
||||
# flag search result as on wishlist as appropriate
|
||||
if not request.user.is_anonymous():
|
||||
ungluers = userlists.other_users(request.user, 5)
|
||||
else:
|
||||
ungluers = userlists.other_users(None, 5)
|
||||
|
||||
|
||||
works=[]
|
||||
for result in results:
|
||||
try:
|
||||
|
@ -1304,4 +1305,4 @@ def feedback(request):
|
|||
|
||||
def comment(request):
|
||||
latest_comments = Comment.objects.all()[:20]
|
||||
return render(request, "comments.html", {'latest_comments': latest_comments})
|
||||
return render(request, "comments.html", {'latest_comments': latest_comments})
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
|
@ -0,0 +1,132 @@
|
|||
/**
|
||||
* Endless Scroll plugin for jQuery
|
||||
*
|
||||
* v1.4.8
|
||||
*
|
||||
* Copyright (c) 2008 Fred Wu
|
||||
*
|
||||
* Dual licensed under the MIT and GPL licenses:
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* http://www.gnu.org/licenses/gpl.html
|
||||
*/
|
||||
|
||||
/**
|
||||
* Usage:
|
||||
*
|
||||
* // using default options
|
||||
* $(document).endlessScroll();
|
||||
*
|
||||
* // using some custom options
|
||||
* $(document).endlessScroll({
|
||||
* fireOnce: false,
|
||||
* fireDelay: false,
|
||||
* loader: "<div class=\"loading\"><div>",
|
||||
* callback: function(){
|
||||
* alert("test");
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* Configuration options:
|
||||
*
|
||||
* bottomPixels integer the number of pixels from the bottom of the page that triggers the event
|
||||
* fireOnce boolean only fire once until the execution of the current event is completed
|
||||
* fireDelay integer delay the subsequent firing, in milliseconds, 0 or false to disable delay
|
||||
* loader string the HTML to be displayed during loading
|
||||
* data string|function plain HTML data, can be either a string or a function that returns a string,
|
||||
* when passed as a function it accepts one argument: fire sequence (the number
|
||||
* of times the event triggered during the current page session)
|
||||
* insertAfter string jQuery selector syntax: where to put the loader as well as the plain HTML data
|
||||
* callback function callback function, accepts one argument: fire sequence (the number of times
|
||||
* the event triggered during the current page session)
|
||||
* resetCounter function resets the fire sequence counter if the function returns true, this function
|
||||
* could also perform hook actions since it is applied at the start of the event
|
||||
* ceaseFire function stops the event (no more endless scrolling) if the function returns true
|
||||
*
|
||||
* Usage tips:
|
||||
*
|
||||
* The plugin is more useful when used with the callback function, which can then make AJAX calls to retrieve content.
|
||||
* The fire sequence argument (for the callback function) is useful for 'pagination'-like features.
|
||||
*/
|
||||
|
||||
(function($){
|
||||
|
||||
$.fn.endlessScroll = function(options) {
|
||||
|
||||
var defaults = {
|
||||
bottomPixels: 50,
|
||||
fireOnce: true,
|
||||
fireDelay: 150,
|
||||
loader: "<br />Loading...<br />",
|
||||
data: "",
|
||||
insertAfter: "div:last",
|
||||
resetCounter: function() { return false; },
|
||||
callback: function() { return true; },
|
||||
ceaseFire: function() { return false; }
|
||||
};
|
||||
|
||||
var options = $.extend({}, defaults, options);
|
||||
|
||||
var firing = true;
|
||||
var fired = false;
|
||||
var fireSequence = 0;
|
||||
|
||||
if (options.ceaseFire.apply(this) === true) {
|
||||
firing = false;
|
||||
}
|
||||
|
||||
if (firing === true) {
|
||||
$(this).scroll(function() {
|
||||
if (options.ceaseFire.apply(this) === true) {
|
||||
firing = false;
|
||||
return; // Scroll will still get called, but nothing will happen
|
||||
}
|
||||
|
||||
if (this == document || this == window) {
|
||||
var is_scrollable = $(document).height() - $(window).height() <= $(window).scrollTop() + options.bottomPixels;
|
||||
} else {
|
||||
// calculates the actual height of the scrolling container
|
||||
var inner_wrap = $(".endless_scroll_inner_wrap", this);
|
||||
if (inner_wrap.length == 0) {
|
||||
inner_wrap = $(this).wrapInner("<div class=\"endless_scroll_inner_wrap\" />").find(".endless_scroll_inner_wrap");
|
||||
}
|
||||
var is_scrollable = inner_wrap.length > 0 &&
|
||||
(inner_wrap.height() - $(this).height() <= $(this).scrollTop() + options.bottomPixels);
|
||||
}
|
||||
|
||||
if (is_scrollable && (options.fireOnce == false || (options.fireOnce == true && fired != true))) {
|
||||
if (options.resetCounter.apply(this) === true) fireSequence = 0;
|
||||
|
||||
fired = true;
|
||||
fireSequence++;
|
||||
|
||||
$(options.insertAfter).after("<div id=\"endless_scroll_loader\">" + options.loader + "</div>");
|
||||
|
||||
data = typeof options.data == 'function' ? options.data.apply(this, [fireSequence]) : options.data;
|
||||
|
||||
if (data !== false) {
|
||||
$(options.insertAfter).after("<div id=\"endless_scroll_data\">" + data + "</div>");
|
||||
$("div#endless_scroll_data").hide().fadeIn();
|
||||
$("div#endless_scroll_data").removeAttr("id");
|
||||
|
||||
options.callback.apply(this, [fireSequence]);
|
||||
|
||||
if (options.fireDelay !== false || options.fireDelay !== 0) {
|
||||
$("body").after("<div id=\"endless_scroll_marker\"></div>");
|
||||
// slight delay for preventing event firing twice
|
||||
$("div#endless_scroll_marker").fadeTo(options.fireDelay, 1, function() {
|
||||
$(this).remove();
|
||||
fired = false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
fired = false;
|
||||
}
|
||||
}
|
||||
|
||||
$("div#endless_scroll_loader").remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
})(jQuery);
|
|
@ -1,15 +1,24 @@
|
|||
/* Beware of fadeIn/fadeOut jQuery animations; they add an inline "display: block"
|
||||
which overrides display: none in the stylesheet. Sneaky! */
|
||||
/*
|
||||
* Beware of fadeIn/fadeOut jQuery animations; they add an inline
|
||||
* "display: block" which overrides display: none in the stylesheet. Sneaky!
|
||||
*
|
||||
*/
|
||||
|
||||
var $j = jQuery.noConflict();
|
||||
$j(document).ready(function(){
|
||||
$j('#toggle-list').click(function(){
|
||||
$j('.panelview').addClass("listview").removeClass("panelview");
|
||||
$j(this).css({opacity: 1});
|
||||
$j('#toggle-panel').css({opacity: .2});
|
||||
});
|
||||
$j('#toggle-panel').click(function(){
|
||||
$j('.listview').addClass("panelview").removeClass("listview");
|
||||
$j(this).css({opacity: 1});
|
||||
$j('#toggle-list').css({opacity: .2});
|
||||
});
|
||||
|
||||
$j(document).ready(function() {
|
||||
$j('#toggle-list').click(toggleList);
|
||||
$j('#toggle-panel').click(togglePanel);
|
||||
});
|
||||
|
||||
function toggleList() {
|
||||
$j('.panelview').addClass("listview").removeClass("panelview");
|
||||
$j(this).css({opacity: 1});
|
||||
$j('#toggle-panel').css({opacity: .2});
|
||||
}
|
||||
|
||||
function togglePanel() {
|
||||
$j('.listview').addClass("panelview").removeClass("listview");
|
||||
$j(this).css({opacity: 1});
|
||||
$j('#toggle-list').css({opacity: .2});
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue