Merge pull request #796 from Gluejar/dj111

Dj111
pull/95/head
eshellman 2018-07-27 16:12:29 -04:00 committed by GitHub
commit 923a79df18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
90 changed files with 1414 additions and 1509 deletions

View File

@ -3,7 +3,7 @@ from itertools import islice
from lxml import etree
import datetime
import urlparse
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.utils.http import urlquote
import pytz

View File

@ -2,7 +2,7 @@ from itertools import islice
import datetime
import urlparse
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.utils.http import urlquote
import json
import pytz

View File

@ -10,7 +10,7 @@ from tastypie.exceptions import BadRequest
from django.conf.urls import url
from django.contrib import auth
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.urls import reverse
from regluit.core import models
import regluit.core.isbn
@ -170,6 +170,7 @@ class FreeResource(ModelResource):
return models.Ebook.objects.none()
class Meta:
queryset = models.Ebook.objects.all()
authentication = ApiKeyAuthentication()
fields = [ 'provider', 'rights' ]
limit = 0

View File

@ -1,6 +1,6 @@
from tastypie.api import Api
from django.conf.urls import patterns, url, include
from django.conf.urls import url, include
from django.views.generic.base import TemplateView
from regluit.api import resources

View File

@ -6,7 +6,7 @@ import logging
from django.contrib import auth
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.shortcuts import render, render_to_response
from django.template import RequestContext
from django.views.decorators.csrf import csrf_exempt
@ -152,7 +152,7 @@ class ApiHelpView(TemplateView):
# if user is logged in, pass in the user's API key
u = auth.get_user(self.request)
if u.is_authenticated():
if u.is_authenticated:
api_key = ApiKey.objects.filter(user=u)[0].key
context['api_key'] = api_key

View File

@ -22,7 +22,7 @@ class Migration(migrations.Migration):
('rght', models.PositiveIntegerField(editable=False, db_index=True)),
('tree_id', models.PositiveIntegerField(editable=False, db_index=True)),
('level', models.PositiveIntegerField(editable=False, db_index=True)),
('parent', mptt.fields.TreeForeignKey(related_name='children', blank=True, to='bisac.BisacHeading', null=True)),
('parent', mptt.fields.TreeForeignKey(on_delete=models.CASCADE, related_name='children', blank=True, to='bisac.BisacHeading', null=True)),
],
options={
'abstract': False,

View File

@ -6,7 +6,7 @@ class BisacHeading(MPTTModel):
full_label = models.CharField(max_length=100, unique=True)
label = models.CharField(max_length=60, unique=False)
notation = models.CharField(max_length=9, unique=False)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children', db_index=True)
class MPTTMeta:
order_insertion_by = ['notation']

View File

@ -1,4 +1,4 @@
from django.conf.urls import patterns, url, include
from django.conf.urls import url, include
from .views import tree
urlpatterns = [

View File

@ -1,12 +1,20 @@
def is_preview(request):
from django.conf import settings
return {'jquery_home': settings.JQUERY_HOME, 'jquery_ui_home': settings.JQUERY_UI_HOME, 'is_preview': settings.IS_PREVIEW, 'show_google_analytics': settings.SHOW_GOOGLE_ANALYTICS}
from django.conf import settings
return {
'jquery_home': settings.JQUERY_HOME,
'jquery_ui_home': settings.JQUERY_UI_HOME,
'jquery_ui_theme': settings.JQUERY_UI_THEME,
'is_preview': settings.IS_PREVIEW,
'show_google_analytics': settings.SHOW_GOOGLE_ANALYTICS
}
def count_unseen(request):
if request.user.is_anonymous():
count = 0
else:
from notification.models import Notice
count = Notice.objects.unseen_count_for(request.user)
return {'unseen_count': count}
try:
if request.user.is_anonymous:
count = 0
else:
from notification.models import Notice
count = Notice.objects.unseen_count_for(request.user)
except AttributeError:
count = 0
return {'unseen_count': count}

View File

@ -3,7 +3,7 @@
#
from django import forms
from django.contrib.admin import ModelAdmin, register
from django.core.urlresolvers import reverse
from django.urls import reverse
from selectable.forms import (
AutoCompleteSelectWidget,

View File

@ -375,6 +375,9 @@ def dl_online(ebook):
if ebook.format != 'online':
pass
elif ebook.url.find(u'dropbox.com/s/') >= 0:
if ebook.url.find(u'dl=0') >= 0:
dl_url = ebook.url.replace(u'dl=0', u'dl=1')
return make_dl_ebook(dl_url, ebook)
response = requests.get(ebook.url, headers={"User-Agent": settings.USER_AGENT})
if response.status_code == 200:
match_dl = DROPBOX_DL.search(response.content)

View File

@ -152,7 +152,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('type', models.CharField(max_length=4)),
('value', models.CharField(max_length=250)),
('edition', models.ForeignKey(related_name='identifiers', to='core.Edition', null=True)),
('edition', models.ForeignKey(on_delete=models.CASCADE, related_name='identifiers', to='core.Edition', null=True)),
],
),
migrations.CreateModel(
@ -168,7 +168,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('marc_link_target', models.CharField(default=b'UNGLUE', max_length=6, verbose_name=b'MARC record link targets', choices=[(b'DIRECT', b'Raw link'), (b'UNGLUE', b'Unglue.it link')])),
('user', models.OneToOneField(related_name='libpref', to=settings.AUTH_USER_MODEL)),
('user', models.OneToOneField(on_delete=models.CASCADE, related_name='libpref', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
@ -189,7 +189,7 @@ class Migration(migrations.Migration):
('amount', models.DecimalField(max_digits=10, decimal_places=0)),
('description', models.TextField(null=True)),
('limit', models.IntegerField(default=0)),
('campaign', models.ForeignKey(related_name='premiums', to='core.Campaign', null=True)),
('campaign', models.ForeignKey(on_delete=models.CASCADE, related_name='premiums', to='core.Campaign', null=True)),
],
),
migrations.CreateModel(
@ -220,7 +220,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(unique=True, max_length=255)),
('publisher', models.ForeignKey(related_name='alternate_names', to='core.Publisher', null=True)),
('publisher', models.ForeignKey(on_delete=models.CASCADE, related_name='alternate_names', to='core.Publisher', null=True)),
],
),
migrations.CreateModel(
@ -235,9 +235,9 @@ class Migration(migrations.Migration):
name='Relator',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('author', models.ForeignKey(to='core.Author')),
('edition', models.ForeignKey(related_name='relators', to='core.Edition')),
('relation', models.ForeignKey(default=1, to='core.Relation')),
('author', models.ForeignKey(on_delete=models.CASCADE, to='core.Author')),
('edition', models.ForeignKey(on_delete=models.CASCADE, related_name='relators', to='core.Edition')),
('relation', models.ForeignKey(on_delete=models.CASCADE, default=1, to='core.Relation')),
],
options={
'db_table': 'core_author_editions',
@ -251,7 +251,7 @@ class Migration(migrations.Migration):
('email', models.CharField(max_length=100, blank=True)),
('rights_holder_name', models.CharField(max_length=100)),
('can_sell', models.BooleanField(default=False)),
('owner', models.ForeignKey(related_name='rights_holder', to=settings.AUTH_USER_MODEL)),
('owner', models.ForeignKey(on_delete=models.CASCADE, related_name='rights_holder', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
@ -286,7 +286,7 @@ class Migration(migrations.Migration):
('goodreads_user_link', models.CharField(max_length=200, null=True, blank=True)),
('avatar_source', models.PositiveSmallIntegerField(default=4, null=True, choices=[(0, b'No Avatar, Please'), (1, b'Gravatar'), (2, b'Twitter'), (3, b'Facebook'), (4, b'Unglueitar')])),
('badges', models.ManyToManyField(related_name='holders', to='core.Badge')),
('user', models.OneToOneField(related_name='profile', to=settings.AUTH_USER_MODEL)),
('user', models.OneToOneField(on_delete=models.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
@ -295,7 +295,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('was', models.IntegerField(unique=True)),
('moved', models.DateTimeField(auto_now_add=True)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True)),
('user', models.ForeignKey(on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL, null=True)),
],
),
migrations.CreateModel(
@ -314,7 +314,7 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('created', models.DateTimeField(auto_now_add=True)),
('user', models.OneToOneField(related_name='wishlist', to=settings.AUTH_USER_MODEL)),
('user', models.OneToOneField(on_delete=models.CASCADE, related_name='wishlist', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
@ -330,7 +330,7 @@ class Migration(migrations.Migration):
('publication_range', models.CharField(max_length=50, null=True)),
('featured', models.DateTimeField(db_index=True, null=True, blank=True)),
('is_free', models.BooleanField(default=False)),
('selected_edition', models.ForeignKey(related_name='selected_works', to='core.Edition', null=True)),
('selected_edition', models.ForeignKey(on_delete=models.CASCADE, related_name='selected_works', to='core.Edition', null=True)),
],
options={
'ordering': ['title'],
@ -344,17 +344,17 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='wishes',
name='wishlist',
field=models.ForeignKey(to='core.Wishlist'),
field=models.ForeignKey(on_delete=models.CASCADE, to='core.Wishlist'),
),
migrations.AddField(
model_name='wishes',
name='work',
field=models.ForeignKey(related_name='wishes', to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='wishes', to='core.Work'),
),
migrations.AddField(
model_name='waswork',
name='work',
field=models.ForeignKey(to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, to='core.Work'),
),
migrations.AddField(
model_name='subject',
@ -364,16 +364,16 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='publisher',
name='name',
field=models.ForeignKey(related_name='key_publisher', to='core.PublisherName'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='key_publisher', to='core.PublisherName'),
),
migrations.AddField(
model_name='offer',
name='work',
field=models.ForeignKey(related_name='offers', to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='offers', to='core.Work'),
),
migrations.AddField(
model_name='identifier',
name='work',
field=models.ForeignKey(related_name='identifiers', to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='identifiers', to='core.Work'),
),
]

View File

@ -18,82 +18,82 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='hold',
name='library',
field=models.ForeignKey(related_name='holds', to='libraryauth.Library'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='holds', to='libraryauth.Library'),
),
migrations.AddField(
model_name='hold',
name='user',
field=models.ForeignKey(related_name='holds', to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='holds', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='hold',
name='work',
field=models.ForeignKey(related_name='holds', to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='holds', to='core.Work'),
),
migrations.AddField(
model_name='gift',
name='acq',
field=models.ForeignKey(related_name='gifts', to='core.Acq'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='gifts', to='core.Acq'),
),
migrations.AddField(
model_name='gift',
name='giver',
field=models.ForeignKey(related_name='gifts', to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='gifts', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='edition',
name='publisher_name',
field=models.ForeignKey(related_name='editions', to='core.PublisherName', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='editions', to='core.PublisherName', null=True),
),
migrations.AddField(
model_name='edition',
name='work',
field=models.ForeignKey(related_name='editions', to='core.Work', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='editions', to='core.Work', null=True),
),
migrations.AddField(
model_name='ebookfile',
name='edition',
field=models.ForeignKey(related_name='ebook_files', to='core.Edition'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='ebook_files', to='core.Edition'),
),
migrations.AddField(
model_name='ebook',
name='edition',
field=models.ForeignKey(related_name='ebooks', to='core.Edition'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='ebooks', to='core.Edition'),
),
migrations.AddField(
model_name='ebook',
name='user',
field=models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True),
field=models.ForeignKey(on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL, null=True),
),
migrations.AddField(
model_name='claim',
name='rights_holder',
field=models.ForeignKey(related_name='claim', to='core.RightsHolder'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='claim', to='core.RightsHolder'),
),
migrations.AddField(
model_name='claim',
name='user',
field=models.ForeignKey(related_name='claim', to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='claim', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='claim',
name='work',
field=models.ForeignKey(related_name='claim', to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='claim', to='core.Work'),
),
migrations.AddField(
model_name='celerytask',
name='user',
field=models.ForeignKey(related_name='tasks', to=settings.AUTH_USER_MODEL, null=True),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='tasks', to=settings.AUTH_USER_MODEL, null=True),
),
migrations.AddField(
model_name='campaignaction',
name='campaign',
field=models.ForeignKey(related_name='actions', to='core.Campaign'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='actions', to='core.Campaign'),
),
migrations.AddField(
model_name='campaign',
name='edition',
field=models.ForeignKey(related_name='campaigns', to='core.Edition', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='campaigns', to='core.Edition', null=True),
),
migrations.AddField(
model_name='campaign',
@ -103,12 +103,12 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='campaign',
name='publisher',
field=models.ForeignKey(related_name='campaigns', to='core.Publisher', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='campaigns', to='core.Publisher', null=True),
),
migrations.AddField(
model_name='campaign',
name='work',
field=models.ForeignKey(related_name='campaigns', to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='campaigns', to='core.Work'),
),
migrations.AddField(
model_name='author',
@ -118,22 +118,22 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='acq',
name='lib_acq',
field=models.ForeignKey(related_name='loans', to='core.Acq', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='loans', to='core.Acq', null=True),
),
migrations.AddField(
model_name='acq',
name='user',
field=models.ForeignKey(related_name='acqs', to=settings.AUTH_USER_MODEL),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='acqs', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='acq',
name='watermarked',
field=models.ForeignKey(to='booxtream.Boox', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, to='booxtream.Boox', null=True),
),
migrations.AddField(
model_name='acq',
name='work',
field=models.ForeignKey(related_name='acqs', to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='acqs', to='core.Work'),
),
migrations.AlterUniqueTogether(
name='identifier',

View File

@ -38,17 +38,17 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='workrelation',
name='from_work',
field=models.ForeignKey(related_name='works_related_from', to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='works_related_from', to='core.Work'),
),
migrations.AddField(
model_name='workrelation',
name='to_work',
field=models.ForeignKey(related_name='works_related_to', to='core.Work'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='works_related_to', to='core.Work'),
),
migrations.AddField(
model_name='edition',
name='note',
field=models.ForeignKey(to='core.EditionNote', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, to='core.EditionNote', null=True),
),
migrations.AddField(
model_name='work',

View File

@ -14,6 +14,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='ebookfile',
name='ebook',
field=models.ForeignKey(related_name='ebook_files', to='core.Ebook', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='ebook_files', to='core.Ebook', null=True),
),
]

View File

@ -28,12 +28,12 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='edition',
name='note',
field=models.ForeignKey(blank=True, to='core.EditionNote', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, blank=True, to='core.EditionNote', null=True),
),
migrations.AlterField(
model_name='edition',
name='publisher_name',
field=models.ForeignKey(related_name='editions', blank=True, to='core.PublisherName', null=True),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='editions', blank=True, to='core.PublisherName', null=True),
),
migrations.AlterField(
model_name='userprofile',

View File

@ -22,7 +22,7 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.contrib.contenttypes.fields import GenericRelation
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.core.files.base import ContentFile
from django.db import models
from django.db.models import F, Q
@ -122,7 +122,7 @@ class Key(models.Model):
class CeleryTask(models.Model):
created = models.DateTimeField(auto_now_add=True)
task_id = models.CharField(max_length=255)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="tasks", null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="tasks", null=True)
description = models.CharField(max_length=2048, null=True) # a description of what the task is
function_name = models.CharField(max_length=1024) # used to reconstitute the AsyncTask with which to get status
function_args = models.IntegerField(null=True) # not full generalized here -- takes only a single arg for now.
@ -157,7 +157,7 @@ class Premium(models.Model):
TIERS = {"supporter":25, "patron":50, "bibliophile":100} #should load this from fixture
created = models.DateTimeField(auto_now_add=True)
type = models.CharField(max_length=2, choices=PREMIUM_TYPES)
campaign = models.ForeignKey("Campaign", related_name="premiums", null=True)
campaign = models.ForeignKey("Campaign", on_delete=models.CASCADE, related_name="premiums", null=True)
amount = models.DecimalField(max_digits=10, decimal_places=0, blank=False)
description = models.TextField(null=True, blank=False)
limit = models.IntegerField(default=0)
@ -189,10 +189,10 @@ class CampaignAction(models.Model):
# anticipated types: activated, withdrawn, suspended, restarted, succeeded, failed, unglued
type = models.CharField(max_length=15)
comment = models.TextField(null=True, blank=True)
campaign = models.ForeignKey("Campaign", related_name="actions", null=False)
campaign = models.ForeignKey("Campaign", on_delete=models.CASCADE, related_name="actions", null=False)
class Offer(models.Model):
work = models.ForeignKey("Work", related_name="offers", null=False)
work = models.ForeignKey("Work", on_delete=models.CASCADE, related_name="offers", null=False)
price = models.DecimalField(max_digits=6, decimal_places=2, null=True, blank=False)
license = models.PositiveSmallIntegerField(null=False, default=INDIVIDUAL,
choices=OFFER_CHOICES)
@ -218,15 +218,15 @@ class Acq(models.Model):
expires = models.DateTimeField(null=True)
refreshes = models.DateTimeField(auto_now_add=True)
refreshed = models.BooleanField(default=True)
work = models.ForeignKey("Work", related_name='acqs', null=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='acqs')
work = models.ForeignKey("Work", on_delete=models.CASCADE, related_name='acqs', null=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='acqs')
license = models.PositiveSmallIntegerField(null=False, default=INDIVIDUAL,
choices=ACQ_CHOICES)
watermarked = models.ForeignKey("booxtream.Boox", null=True)
watermarked = models.ForeignKey("booxtream.Boox", on_delete=models.CASCADE, null=True)
nonce = models.CharField(max_length=32, null=True)
# when the acq is a loan, this points at the library's acq it's derived from
lib_acq = models.ForeignKey("self", related_name="loans", null=True)
lib_acq = models.ForeignKey("self", on_delete=models.CASCADE, related_name="loans", null=True)
class mock_ebook(object):
def __init__(self, acq):
@ -358,9 +358,9 @@ post_save.connect(config_acq, sender=Acq)
class Hold(models.Model):
created = models.DateTimeField(auto_now_add=True)
work = models.ForeignKey("Work", related_name='holds', null=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='holds', null=False)
library = models.ForeignKey(Library, related_name='holds', null=False)
work = models.ForeignKey("Work", on_delete=models.CASCADE, related_name='holds', null=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='holds', null=False)
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='holds', null=False)
def __unicode__(self):
return '%s for %s at %s' % (self.work, self.user.username, self.library)
@ -390,8 +390,8 @@ class Campaign(models.Model):
activated = models.DateTimeField(null=True, db_index=True,)
paypal_receiver = models.CharField(max_length=100, blank=True)
amazon_receiver = models.CharField(max_length=100, blank=True)
work = models.ForeignKey("Work", related_name="campaigns", null=False)
managers = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="campaigns", null=False)
work = models.ForeignKey("Work", on_delete=models.CASCADE, related_name="campaigns", null=False)
managers = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="campaigns")
# status: INITIALIZED, ACTIVE, SUSPENDED, WITHDRAWN, SUCCESSFUL, UNSUCCESSFUL
status = models.CharField( max_length=15, null=True, blank=False, default="INITIALIZED",
db_index=True, choices=STATUS_CHOICES)
@ -400,9 +400,9 @@ class Campaign(models.Model):
(BUY2UNGLUE, 'Buy-to-unglue campaign'),
(THANKS, 'Thanks-for-ungluing campaign'),
))
edition = models.ForeignKey("Edition", related_name="campaigns", null=True)
edition = models.ForeignKey("Edition", on_delete=models.CASCADE, related_name="campaigns", null=True)
email = models.CharField(max_length=100, blank=True)
publisher = models.ForeignKey("Publisher", related_name="campaigns", null=True)
publisher = models.ForeignKey("Publisher", on_delete=models.CASCADE, related_name="campaigns", null=True)
do_watermark = models.BooleanField(default=True)
use_add_ask = models.BooleanField(default=True)
charitable = models.BooleanField(default=False)
@ -442,7 +442,7 @@ class Campaign(models.Model):
self.activated = None
self.update_left()
self.save()
self.managers = old_managers
self.managers.set(old_managers)
# clone associated premiums
for premium in new_premiums:
@ -1034,7 +1034,7 @@ class Campaign(models.Model):
rights=self.license,
provider="Unglue.it",
url=settings.BASE_URL_SECURE + reverse('download_campaign', args=[self.work_id, format]),
version='unglued',
version_label='unglued',
)
old_ebooks = Ebook.objects.exclude(pk=ebook.pk).filter(
edition=self.work.preferred_edition,
@ -1084,7 +1084,7 @@ class Campaign(models.Model):
class Wishlist(models.Model):
created = models.DateTimeField(auto_now_add=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='wishlist')
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='wishlist')
works = models.ManyToManyField('Work', related_name='wishlists', through='Wishes')
def __unicode__(self):
@ -1117,8 +1117,8 @@ class Wishlist(models.Model):
class Wishes(models.Model):
created = models.DateTimeField(auto_now_add=True, db_index=True,)
source = models.CharField(max_length=15, blank=True, db_index=True,)
wishlist = models.ForeignKey('Wishlist')
work = models.ForeignKey('Work', related_name='wishes')
wishlist = models.ForeignKey('Wishlist', on_delete=models.CASCADE)
work = models.ForeignKey('Work', on_delete=models.CASCADE, related_name='wishes')
class Meta:
db_table = 'core_wishlist_works'
@ -1148,7 +1148,7 @@ ANONYMOUS_AVATAR = '/static/images/header/avatar.png'
(NO_AVATAR, GRAVATAR, TWITTER, FACEBOOK, UNGLUEITAR) = AVATARS
class Libpref(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='libpref')
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='libpref')
marc_link_target = models.CharField(
max_length=6,
default='UNGLUE',
@ -1158,7 +1158,7 @@ class Libpref(models.Model):
class UserProfile(models.Model):
created = models.DateTimeField(auto_now_add=True)
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='profile')
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='profile')
tagline = models.CharField(max_length=140, blank=True)
pic_url = models.URLField(blank=True)
home_url = models.URLField(blank=True)
@ -1354,9 +1354,9 @@ class Press(models.Model):
class Gift(models.Model):
# the acq will contain the recipient, and the work
acq = models.ForeignKey('Acq', related_name='gifts')
acq = models.ForeignKey('Acq', on_delete=models.CASCADE, related_name='gifts')
to = models.CharField(max_length=75, blank=True) # store the email address originally sent to, not necessarily the email of the recipient
giver = models.ForeignKey(User, related_name='gifts')
giver = models.ForeignKey(User, on_delete=models.CASCADE, related_name='gifts')
message = models.TextField(max_length=512, default='')
used = models.DateTimeField(null=True)

View File

@ -16,7 +16,7 @@ from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericRelation
from django.core.files.base import ContentFile
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db import models
from django.db.models import F
from django.db.models.signals import post_save, pre_delete
@ -67,8 +67,8 @@ class Identifier(models.Model):
# olib, ltwk, goog, gdrd, thng, isbn, oclc, olwk, doab, gtbg, glue, doi
type = models.CharField(max_length=4, null=False)
value = models.CharField(max_length=250, null=False)
work = models.ForeignKey("Work", related_name="identifiers", null=False)
edition = models.ForeignKey("Edition", related_name="identifiers", null=True)
work = models.ForeignKey("Work", on_delete=models.CASCADE, related_name="identifiers", null=False)
edition = models.ForeignKey("Edition", on_delete=models.CASCADE, related_name="identifiers", null=True)
class Meta:
unique_together = ("type", "value")
@ -122,7 +122,7 @@ class Work(models.Model):
openlibrary_lookup = models.DateTimeField(null=True, blank=True)
num_wishes = models.IntegerField(default=0, db_index=True)
description = models.TextField(default='', null=True, blank=True)
selected_edition = models.ForeignKey("Edition", related_name='selected_works', null=True)
selected_edition = models.ForeignKey("Edition", on_delete=models.CASCADE, related_name='selected_works', null=True)
# repurposed earliest_publication to actually be publication range
publication_range = models.CharField(max_length=50, null=True, blank=True)
featured = models.DateTimeField(null=True, blank=True, db_index=True,)
@ -612,7 +612,7 @@ class Work(models.Model):
return self.get_user_license(lib_user)
def borrowable(self, user):
if user.is_anonymous():
if user.is_anonymous:
return False
lib_license = self.get_lib_license(user)
if lib_license and lib_license.borrowable:
@ -620,7 +620,7 @@ class Work(models.Model):
return False
def lib_thanked(self, user):
if user.is_anonymous():
if user.is_anonymous:
return False
lib_license = self.get_lib_license(user)
if lib_license and lib_license.thanked:
@ -628,7 +628,7 @@ class Work(models.Model):
return False
def in_library(self, user):
if user.is_anonymous():
if user.is_anonymous:
return False
lib_license = self.get_lib_license(user)
if lib_license and lib_license.acqs.count():
@ -706,7 +706,7 @@ class Work(models.Model):
if user is None:
return None
if hasattr(user, 'is_anonymous'):
if user.is_anonymous():
if user.is_anonymous:
return None
return self.user_license(self.acqs.filter(user=user))
else:
@ -732,8 +732,8 @@ class Work(models.Model):
return record_list
class WorkRelation(models.Model):
to_work = models.ForeignKey('Work', related_name='works_related_to')
from_work= models.ForeignKey('Work', related_name='works_related_from')
to_work = models.ForeignKey('Work', on_delete=models.CASCADE, related_name='works_related_to')
from_work= models.ForeignKey('Work', on_delete=models.CASCADE, related_name='works_related_from')
relation = models.CharField(max_length=15, choices=TEXT_RELATION_CHOICES)
@ -766,9 +766,9 @@ class Relation(models.Model):
name = models.CharField(max_length=30, blank=True,)
class Relator(models.Model):
relation = models.ForeignKey('Relation', default=1) #first relation should have code='aut'
author = models.ForeignKey('Author')
edition = models.ForeignKey('Edition', related_name='relators')
relation = models.ForeignKey('Relation', on_delete=models.CASCADE, default=1) #first relation should have code='aut'
author = models.ForeignKey('Author', on_delete=models.CASCADE)
edition = models.ForeignKey('Edition', on_delete=models.CASCADE, related_name='relators')
class Meta:
db_table = 'core_author_editions'
@ -846,12 +846,12 @@ class Subject(models.Model):
class Edition(models.Model):
created = models.DateTimeField(auto_now_add=True)
title = models.CharField(max_length=1000)
publisher_name = models.ForeignKey("PublisherName", related_name="editions", null=True, blank=True)
publisher_name = models.ForeignKey("PublisherName", on_delete=models.CASCADE, related_name="editions", null=True, blank=True)
publication_date = models.CharField(max_length=50, null=True, blank=True, db_index=True)
work = models.ForeignKey("Work", related_name="editions", null=True)
work = models.ForeignKey("Work", on_delete=models.CASCADE, related_name="editions", null=True)
cover_image = models.URLField(null=True, blank=True)
unglued = models.BooleanField(default=False)
note = models.ForeignKey("EditionNote", null=True, blank=True)
note = models.ForeignKey("EditionNote", on_delete=models.CASCADE, null=True, blank=True)
def __unicode__(self):
if self.isbn_13:
@ -1034,7 +1034,7 @@ class EditionNote(models.Model):
class Publisher(models.Model):
created = models.DateTimeField(auto_now_add=True)
name = models.ForeignKey('PublisherName', related_name='key_publisher')
name = models.ForeignKey('PublisherName', on_delete=models.CASCADE, related_name='key_publisher')
url = models.URLField(max_length=1024, null=True, blank=True)
logo_url = models.URLField(max_length=1024, null=True, blank=True)
description = models.TextField(default='', null=True, blank=True)
@ -1045,7 +1045,7 @@ class Publisher(models.Model):
class PublisherName(models.Model):
name = models.CharField(max_length=255, blank=False, unique=True)
publisher = models.ForeignKey('Publisher', related_name='alternate_names', null=True)
publisher = models.ForeignKey('Publisher', on_delete=models.CASCADE, related_name='alternate_names', null=True)
def __unicode__(self):
return self.name
@ -1060,10 +1060,10 @@ class PublisherName(models.Model):
class WasWork(models.Model):
work = models.ForeignKey('Work')
work = models.ForeignKey('Work', on_delete=models.CASCADE)
was = models.IntegerField(unique=True)
moved = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
def safe_get_work(work_id):
"""
@ -1087,10 +1087,10 @@ def path_for_file(instance, filename):
class EbookFile(models.Model):
file = models.FileField(upload_to=path_for_file)
format = models.CharField(max_length=25, choices=settings.FORMATS)
edition = models.ForeignKey('Edition', related_name='ebook_files')
edition = models.ForeignKey('Edition', on_delete=models.CASCADE, related_name='ebook_files')
created = models.DateTimeField(auto_now_add=True)
asking = models.BooleanField(default=False)
ebook = models.ForeignKey('Ebook', related_name='ebook_files', null=True)
ebook = models.ForeignKey('Ebook', on_delete=models.CASCADE, related_name='ebook_files', null=True)
source = models.URLField(null=True, blank=True)
mobied = models.IntegerField(default=0) #-1 indicates a failed conversion attempt
version = None
@ -1157,8 +1157,8 @@ class Ebook(models.Model):
# use 'PD-US', 'CC BY', 'CC BY-NC-SA', 'CC BY-NC-ND', 'CC BY-NC', 'CC BY-ND', 'CC BY-SA', 'CC0'
rights = models.CharField(max_length=255, null=True, choices=cc.CHOICES, db_index=True)
edition = models.ForeignKey('Edition', related_name='ebooks')
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
edition = models.ForeignKey('Edition', on_delete=models.CASCADE, related_name='ebooks')
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
def kindle_sendable(self):
if not self.filesize or self.filesize < send_to_kindle_limit:

View File

@ -13,9 +13,9 @@ class Claim(models.Model):
(u'release', u'Claim has not been accepted.'),
)
created = models.DateTimeField(auto_now_add=True)
rights_holder = models.ForeignKey("RightsHolder", related_name="claim", null=False)
work = models.ForeignKey("Work", related_name="claim", null=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="claim", null=False)
rights_holder = models.ForeignKey("RightsHolder", on_delete=models.CASCADE, related_name="claim", null=False)
work = models.ForeignKey("Work", on_delete=models.CASCADE, related_name="claim", null=False)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="claim", null=False)
status = models.CharField(max_length=7, choices=STATUSES, default='active')
@property
@ -66,7 +66,7 @@ class RightsHolder(models.Model):
created = models.DateTimeField(auto_now_add=True)
email = models.CharField(max_length=100, blank=False, default='')
rights_holder_name = models.CharField(max_length=100, blank=False)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="rights_holder", null=False)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="rights_holder", null=False)
approved = models.BooleanField(default=False)
address = models.CharField(max_length=400, blank=False, default='')
mailing = models.CharField(max_length=400, blank=False, default='')

View File

@ -1,5 +1,5 @@
from django.contrib.sitemaps import Sitemap
from django.core.urlresolvers import reverse
from django.urls import reverse
from regluit.core.models import Work, Edition
class WorkSitemap(Sitemap):

View File

@ -41,6 +41,6 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='deposit',
name='target',
field=models.ForeignKey(related_name='deposits', to='distro.Target'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='deposits', to='distro.Target'),
),
]

View File

@ -57,7 +57,7 @@ class Target(models.Model):
class Deposit(models.Model):
target = models.ForeignKey(Target, related_name="deposits")
target = models.ForeignKey(Target, on_delete=models.CASCADE, related_name="deposits")
isbn = models.CharField(max_length=13)
format = models.CharField(max_length=30)
updated = models.DateTimeField(auto_now_add=True)

View File

@ -12,8 +12,7 @@ from decimal import Decimal as D
from django import forms
from django.conf import settings
from django.contrib.auth.models import User
from django.forms.widgets import RadioSelect
from django.forms.extras.widgets import SelectDateWidget
from django.forms.widgets import RadioSelect, SelectDateWidget
from django.utils.translation import ugettext_lazy as _
from selectable.forms import (

View File

@ -1,7 +1,7 @@
from datetime import date, timedelta
from decimal import Decimal as D
from ckeditor.widgets import CKEditorWidget
from ckeditor_uploader.widgets import CKEditorUploadingWidget
from selectable.forms import (
AutoCompleteSelectMultipleWidget,
@ -10,8 +10,7 @@ from selectable.forms import (
from django import forms
from django.conf import settings
from django.forms.extras.widgets import SelectDateWidget
from django.forms.widgets import RadioSelect
from django.forms.widgets import RadioSelect, SelectDateWidget
from django.utils.translation import ugettext_lazy as _
from django.utils.timezone import now
@ -215,7 +214,7 @@ class ManageCampaignForm(CCDateForm, forms.ModelForm):
'required': 'You must enter the email we should contact you at for this campaign.'
},
)
work_description = forms.CharField(required=False , widget=CKEditorWidget())
work_description = forms.CharField(required=False , widget=CKEditorUploadingWidget())
class Meta:
model = Campaign

View File

@ -3,7 +3,7 @@
{% block title %} Agreement Submitted {% endblock %}
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
{% endblock %}

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
{% load truncatechars %}{% load sass_tags %}
{% load sass_tags %}
<html>
<head>

View File

@ -2,7 +2,7 @@
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
{{ form.media.css }}
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
{{ form.media.js }}

View File

@ -6,6 +6,8 @@ var $j = jQuery.noConflict();
$j(document).ready(function() {
// don't let users modify their pledge amount on this page; it's just here for reference
// if they modified it here we'd have to faff about with validating premiums
if($j('#id_work_id').prop('value')!=""){
$j('#id_preapproval_amount').prop('disabled', true);
}
});
</script>

View File

@ -3,7 +3,7 @@
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
<link href="/static/css/ui.fancytree.min.css" rel="stylesheet" type="text/css">
<style type="text/css">
ul.fancytree-container {

View File

@ -1,4 +1,3 @@
{% load truncatechars %}
{% load lang_utils %}
{% load explore %}{% explore %}
<div class="jsmodule">

View File

@ -64,9 +64,9 @@
</ul>
<ul class="book-list-view">
<li>Sort by:</li>
<li class="view-list"><a {% if order_by = 'popular' %}class="chosen" {% endif %}href="{% url 'faceted_list' path %}?{% if setkw %}setkw={{setkw}}&amp;{% endif %}order_by=popular">popular</a></li>
<li class="view-list"><a {% if order_by = 'newest' %}class="chosen" {% endif %}href="{% url 'faceted_list' path %}?{% if setkw %}setkw={{setkw}}&amp;{% endif %}order_by=newest">newest</a></li>
<li class="view-list"><a {% if order_by = 'title' %}class="chosen" {% endif %}href="{% url 'faceted_list' path %}?{% if setkw %}setkw={{setkw}}&amp;{% endif %}order_by=title">title</a></li>
<li class="view-list"><a {% if order_by == 'popular' %}class="chosen" {% endif %}href="{% url 'faceted_list' path %}?{% if setkw %}setkw={{setkw}}&amp;{% endif %}order_by=popular">popular</a></li>
<li class="view-list"><a {% if order_by == 'newest' %}class="chosen" {% endif %}href="{% url 'faceted_list' path %}?{% if setkw %}setkw={{setkw}}&amp;{% endif %}order_by=newest">newest</a></li>
<li class="view-list"><a {% if order_by == 'title' %}class="chosen" {% endif %}href="{% url 'faceted_list' path %}?{% if setkw %}setkw={{setkw}}&amp;{% endif %}order_by=title">title</a></li>
</ul>
</div>
<div id="content-block-content">

View File

@ -6,7 +6,7 @@
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
{{ transfer_form.media.css }}
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>
{{ transfer_form.media.js }}

View File

@ -1,6 +1,5 @@
{% extends "base.html" %}
{% load truncatechars %}
{% load sass_tags %}
{% block title %}&#151; Support Free eBooks{% endblock %}

View File

@ -3,7 +3,7 @@
{% block title %} Library Admin {% endblock %}
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
<style type="text/css">
.group-border {
border: solid #edf3f4;

View File

@ -2,7 +2,6 @@
{% load el_pagination_tags %}
{% load sass_tags %}
{% load truncatechars %}
{% block title %} &#8212; {{ library }}{% endblock %}
{% block extra_css %}

View File

@ -3,7 +3,7 @@
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>
<script type="text/javascript">

View File

@ -1,7 +1,7 @@
{% extends 'base.html' %}
{% block extra_css %}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
{{ form.media.css }}
<style type="text/css">
div.half {

View File

@ -5,7 +5,7 @@
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
<link href="/static/selectable/css/dj.selectable.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/selectable/js/jquery.dj.selectable.js"></script>

View File

@ -3,7 +3,7 @@
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
{{ form.media.css }}
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>
{{ form.media.js }}

View File

@ -3,7 +3,7 @@
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
{{ form.media.css }}
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>

View File

@ -2,7 +2,6 @@
{% load i18n %}
{% load sass_tags %}
{% load truncatechars %}
{% block title %}{% trans "Notification Settings" %}{% endblock %}
@ -87,7 +86,7 @@ $j(document).ready(function() {
<td colspan="2" id="last"><input type="submit" value="{% trans 'Change' %}"></input></td>
</tr>
</table>
<h3>Pledge Notifications</h3>
<h3>Pledge/Donation Notifications</h3>
<table class="notice_settings table table-striped" width="90%">
<tr>
<th>{% trans "Notify me when..." %}</th>
@ -96,7 +95,7 @@ $j(document).ready(function() {
{% endfor %}
</tr>
{% for row in notice_settings.rows %}
{% if row.notice_type.label|truncatechars:10 == 'pledge_...' %}
{% if row.notice_type.label|truncatechars:10 == 'pledge_...' or row.notice_type.label == 'donation' %}
<tr class="{% cycle 'row1' 'row2' %}">
<td>
<span class="notice_type_description">{% trans row.notice_type.description %}</span>

View File

@ -1,6 +1,5 @@
{% extends 'notification/notice_template.html' %}
{% load truncatechars %}
{% block comments_book %}
<a href="{% url 'work' work.id %}"><img src="{{ work.cover_image_small }}" alt="cover image for {{ work.title }}" /></a>

View File

@ -3,7 +3,7 @@
{% block title %} Rights Holder Agreement {% endblock %}
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript">
onload = function(){

View File

@ -36,7 +36,7 @@
{% endwith %}
{% endifequal %}
</div>
{% if campaign.status = 'ACTIVE' or campaign.status = 'INITIALIZED' %}
{% if campaign.status == 'ACTIVE' or campaign.status == 'INITIALIZED' %}
<div>
<a href="{% url 'manage_campaign' campaign.id %}" class="manage">Manage This Campaign</a>
</div>

View File

@ -3,7 +3,7 @@
{% block title %} for Rightsholders {% endblock %}
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
<link href="/static/selectable/css/dj.selectable.css" type="text/css" media="all" rel="stylesheet" />
<script type="text/javascript" src="{{ jquery_ui_home }}"></script>
<script type="text/javascript" src="/static/selectable/js/jquery.dj.selectable.js"></script>

View File

@ -44,7 +44,7 @@
{% with claim.campaign as campaign %}
<div class="work_campaigns clearfix">
{% if campaign.status = 'ACTIVE' or campaign.status = 'INITIALIZED' %}
{% if campaign.status == 'ACTIVE' or campaign.status == 'INITIALIZED' %}
<div class="campaign_info">
Your {{ campaign.get_type_display }}, "{{ campaign.name }}", is {{ campaign.status }}<br />
Created: {{ campaign.created }}<br />

View File

@ -3,7 +3,7 @@
{% block extra_extra_head %}
{{ block.super }}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
{{ form.media.css }}
<script type="text/javascript" src="{{ jquery_ui_home }}" ></script>
{{ form.media.js }}

View File

@ -1,7 +1,6 @@
{% extends 'base.html' %}
{% load el_pagination_tags %}
{% load truncatechars %}
{% load sass_tags %}
{% block title %} &#8212; {{ supporter.username }}{% endblock %}

View File

@ -25,8 +25,9 @@
{% block extra_css %}
<link type="text/css" rel="stylesheet" href="{% sass_src 'scss/campaign2.scss' %}" />
{% if user.is_staff or user in work.last_campaign.managers.all %}
<link rel="stylesheet" href="/static/css/ui-lightness/jquery-ui-1.8.16.custom.css" type="text/css" media="screen">
<link rel="stylesheet" href="{{ jquery_ui_theme }}" type="text/css" media="screen">
{{ kwform.media.css }}
{% endif %}
{% endblock %}

View File

@ -19,14 +19,14 @@ def bookpanel(context):
supported = False
if campaign and campaign.type == REWARDS:
if campaign.status == 'ACTIVE':
if not user.is_anonymous() and user.transaction_set.filter(campaign__work=work):
if not user.is_anonymous and user.transaction_set.filter(campaign__work=work):
supported = True
context['supported'] = supported
show_pledge = False
if campaign and campaign.type == REWARDS:
if campaign.status == 'ACTIVE':
if user.is_anonymous() or not supported:
if user.is_anonymous or not supported:
show_pledge = True
context['show_pledge'] = show_pledge
@ -39,7 +39,7 @@ def bookpanel(context):
show_purchase = False
if campaign and campaign.type == BUY2UNGLUE:
if user.is_anonymous() or not context.get('license_is_active', False):
if user.is_anonymous or not context.get('license_is_active', False):
if campaign.status == 'ACTIVE':
if not context.get('borrowable', False):
if not library:

View File

@ -10,7 +10,7 @@ def lib_acqs(context):
lib_user = library.user
else:
user = context['request'].user
if user.is_anonymous():
if user.is_anonymous:
return ''
else:
lib_user = (lib.user for lib in user.profile.libraries)

View File

@ -10,7 +10,7 @@ def purchased(context):
try:
work.id # sometimes work is a dict
user = context['request'].user
if user.is_anonymous():
if user.is_anonymous:
return ''
try:
user_license = work.get_user_license(user)

View File

@ -1,186 +0,0 @@
"""
The truncatechars filter is part of Django dev, but we're on 1.3.1
The following is the filter and its dependencies
To use this filter, put "{% load truncatechars %}" at the beginning of your template,
then {{ myvariable|truncatechars:num }}
"""
import unicodedata
from django import template
from django.template import Library
from django.template.defaultfilters import stringfilter
from django.utils.encoding import force_unicode
from django.utils.functional import allow_lazy, SimpleLazyObject
from django.utils.translation import pgettext
register = Library()
class Truncator(SimpleLazyObject):
"""
An object used to truncate text, either by characters or words.
"""
def __init__(self, text):
super(Truncator, self).__init__(lambda: force_unicode(text))
def add_truncation_text(self, text, truncate=None):
if truncate is None:
truncate = pgettext(
'String to return when truncating text',
u'%(truncated_text)s...')
truncate = force_unicode(truncate)
if '%(truncated_text)s' in truncate:
return truncate % {'truncated_text': text}
# The truncation text didn't contain the %(truncated_text)s string
# replacement argument so just append it to the text.
if text.endswith(truncate):
# But don't append the truncation text if the current text already
# ends in this.
return text
return '%s%s' % (text, truncate)
def chars(self, num, truncate=None):
"""
Returns the text truncated to be no longer than the specified number
of characters.
Takes an optional argument of what should be used to notify that the
string has been truncated, defaulting to a translatable string of an
ellipsis (...).
"""
length = int(num)
uniself = unicode(self._wrapped)
text = unicodedata.normalize('NFC', uniself)
# Calculate the length to truncate to (max length - end_text length)
truncate_len = length
for char in self.add_truncation_text('', truncate):
if not unicodedata.combining(char):
truncate_len -= 1
if truncate_len == 0:
break
s_len = 0
end_index = None
for i, char in enumerate(text):
if unicodedata.combining(char):
# Don't consider combining characters
# as adding to the string length
continue
s_len += 1
if end_index is None and s_len > truncate_len:
end_index = i
if s_len > length:
# Return the truncated string
return self.add_truncation_text(text[:end_index or 0],
truncate)
# Return the original string since no truncation was necessary
return text
chars = allow_lazy(chars)
def words(self, num, truncate=None, html=False):
"""
Truncates a string after a certain number of words. Takes an optional
argument of what should be used to notify that the string has been
truncated, defaulting to ellipsis (...).
"""
length = int(num)
if html:
return self._html_words(length, truncate)
return self._text_words(length, truncate)
words = allow_lazy(words)
def _text_words(self, length, truncate):
"""
Truncates a string after a certain number of words.
Newlines in the string will be stripped.
"""
words = self._wrapped.split()
if len(words) > length:
words = words[:length]
return self.add_truncation_text(u' '.join(words), truncate)
return u' '.join(words)
def _html_words(self, length, truncate):
"""
Truncates HTML to a certain number of words (not counting tags and
comments). Closes opened tags if they were correctly closed in the
given HTML.
Newlines in the HTML are preserved.
"""
if length <= 0:
return u''
html4_singlets = (
'br', 'col', 'link', 'base', 'img',
'param', 'area', 'hr', 'input'
)
# Count non-HTML words and keep note of open tags
pos = 0
end_text_pos = 0
words = 0
open_tags = []
while words <= length:
m = re_words.search(self._wrapped, pos)
if not m:
# Checked through whole string
break
pos = m.end(0)
if m.group(1):
# It's an actual non-HTML word
words += 1
if words == length:
end_text_pos = pos
continue
# Check for tag
tag = re_tag.match(m.group(0))
if not tag or end_text_pos:
# Don't worry about non tags or tags after our truncate point
continue
closing_tag, tagname, self_closing = tag.groups()
# Element names are always case-insensitive
tagname = tagname.lower()
if self_closing or tagname in html4_singlets:
pass
elif closing_tag:
# Check for match in open tags list
try:
i = open_tags.index(tagname)
except ValueError:
pass
else:
# SGML: An end tag closes, back to the matching start tag,
# all unclosed intervening start tags with omitted end tags
open_tags = open_tags[i + 1:]
else:
# Add it to the start of the open tags list
open_tags.insert(0, tagname)
if words <= length:
# Don't try to close tags if we don't need to truncate
return self._wrapped
out = self._wrapped[:end_text_pos]
truncate_text = self.add_truncation_text('', truncate)
if truncate_text:
out += truncate_text
# Close any tags still open
for tag in open_tags:
out += '</%s>' % tag
# Return string
return out
# django dev uses filter(is_safe=True) syntax here, but that's not yet available in 1.3.1
@register.filter()
@stringfilter
def truncatechars(value, arg):
"""
Truncates a string after a certain number of characters.
Argument: Number of characters to truncate after.
"""
try:
length = int(arg)
except ValueError: # Invalid literal for int().
return value # Fail silently.
return Truncator(value).chars(length)
truncatechars.is_safe = True

View File

@ -10,7 +10,7 @@ from decimal import Decimal as D
from django.contrib import auth
from django.contrib.auth.models import User
from django.core import mail
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.test import TestCase
from django.test.client import Client
from django.utils.timezone import now
@ -220,7 +220,7 @@ class PledgingUiTests(TestCase):
#self.assertEqual(self.client.session['_auth_user_id'], self.user.pk)
user = auth.get_user(self.client)
assert user.is_authenticated()
assert user.is_authenticated
# load a Work by putting it on the User's wishlist

View File

@ -1,5 +1,5 @@
from django.conf import settings
from django.conf.urls import patterns, url, include
from django.conf.urls import url, include
from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import login_required
from django.contrib.sites.models import Site

View File

@ -29,7 +29,7 @@ from django.core import signing
from django.core.exceptions import ValidationError
from django.core.files.storage import default_storage
from django.core.mail import EmailMessage
from django.core.urlresolvers import reverse, reverse_lazy
from django.urls import reverse, reverse_lazy
from django.core.validators import validate_email
from django.db.models import Q, Count, Sum
from django.forms import Select
@ -171,7 +171,7 @@ def process_kindle_email(request):
download + login/account creation; add kindle email to profile
"""
user = request.user
if user.is_authenticated() and request.session.has_key('kindle_email'):
if user.is_authenticated and request.session.has_key('kindle_email'):
user.profile.kindle_email = request.session['kindle_email']
user.profile.save()
request.session.pop('kindle_email')
@ -194,7 +194,7 @@ def cover_width(work):
def home(request, landing=False):
faves = None
if request.user.is_authenticated() :
if request.user.is_authenticated :
next = request.GET.get('next', False)
if next:
# should happen only for new users
@ -270,7 +270,7 @@ def home(request, landing=False):
reverse=True
)
if request.user.is_authenticated():
if request.user.is_authenticated:
events = latest_actions[:12]
else:
events = latest_actions[:6]
@ -326,7 +326,7 @@ def work(request, work_id, action='display'):
formset = EditionFormSet(instance=work)
# process waiting add request
if not request.user.is_anonymous() and request.session.has_key("add_wishlist"):
if not request.user.is_anonymous and request.session.has_key("add_wishlist"):
add_url = request.session["add_wishlist"]
if add_url == request.path:
request.user.wishlist.add_work(work, "login", notify=True)
@ -334,7 +334,7 @@ def work(request, work_id, action='display'):
process_kindle_email(request)
if request.method == 'POST' and not request.user.is_anonymous():
if request.method == 'POST' and not request.user.is_anonymous:
activetab = '4'
elif action == 'editions':
activetab = '4'
@ -363,7 +363,7 @@ def work(request, work_id, action='display'):
if action == 'preview':
work.last_campaign_status = 'ACTIVE'
if not request.user.is_anonymous():
if not request.user.is_anonymous:
claimform = UserClaimForm(request.user, initial={'work':work.pk, 'user': request.user.id}, prefix = 'claim')
else:
claimform = None
@ -416,7 +416,7 @@ def work(request, work_id, action='display'):
def edition_uploads(request, edition_id):
context = {}
if not request.user.is_authenticated() :
if not request.user.is_authenticated:
return render(request, "admins_only.html")
edition = get_edition(edition_id)
campaign_type = edition.work.last_campaign().type
@ -548,7 +548,7 @@ def googlebooks(request, googlebooks_id):
if edition.new:
# add related editions asynchronously
tasks.populate_edition.delay(edition.isbn_13)
if request.user.is_authenticated():
if request.user.is_authenticated:
request.user.profile.works.add(edition.work)
except bookloader.LookupFailure:
logger.warning("failed to load googlebooks_id %s" % googlebooks_id)
@ -558,7 +558,7 @@ def googlebooks(request, googlebooks_id):
work_url = reverse('work', kwargs={'work_id': edition.work_id})
# process waiting add request
if not request.user.is_anonymous() and request.session.has_key("add_wishlist"):
if not request.user.is_anonymous and request.session.has_key("add_wishlist"):
add_url = request.session["add_wishlist"]
if add_url == request.path:
request.user.wishlist.add_work(edition.work, "login", notify=True)
@ -944,7 +944,7 @@ class PledgeView(FormView):
def get_form_kwargs(self):
assert self.request.user.is_authenticated()
assert self.request.user.is_authenticated
self.work = safe_get_work(self.kwargs["work_id"])
# if there is no campaign or if campaign is not active, we should raise an error
@ -1087,7 +1087,7 @@ class PurchaseView(PledgeView):
return context
def get_form_kwargs(self):
assert self.request.user.is_authenticated()
assert self.request.user.is_authenticated
self.work = safe_get_work(self.kwargs["work_id"])
# if there is no campaign or if campaign is not active, we should raise an error
@ -1166,7 +1166,7 @@ class FundView(FormView):
action = None
def get_form_class(self):
if self.request.user.is_anonymous():
if self.request.user.is_anonymous:
return AnonCCForm
elif self.request.user.profile.account:
return AccountCCForm
@ -1202,7 +1202,7 @@ class FundView(FormView):
data.update(
{'preapproval_amount':self.transaction.needed_amount,
'username':self.request.user.username if self.request.user.is_authenticated() else None,
'username':self.request.user.username if self.request.user.is_authenticated else None,
'work_id':self.transaction.campaign.work_id if self.transaction.campaign else None,
'title':self.transaction.campaign.work.title if self.transaction.campaign else COMPANY_TITLE}
)
@ -1225,7 +1225,7 @@ class FundView(FormView):
return_url = "%s?tid=%s" % (reverse('pledge_complete'), self.transaction.id)
if not self.transaction.campaign:
if self.request.user.is_authenticated():
if self.request.user.is_authenticated:
self.transaction.user = self.request.user
# if there's an email address, put it in the receipt column, so far unused.
self.transaction.receipt = form.cleaned_data.get("email", None)
@ -1233,12 +1233,12 @@ class FundView(FormView):
elif self.transaction.campaign.type == THANKS and self.transaction.user == None:
#anonymous user, just charge the card!
if self.request.user.is_authenticated():
if self.request.user.is_authenticated:
self.transaction.user = self.request.user
# if there's an email address, put it in the receipt column, so far unused.
self.transaction.receipt = form.cleaned_data.get("email", None)
t, url = p.charge(self.transaction, return_url = return_url, token=stripe_token)
elif self.request.user.is_anonymous():
elif self.request.user.is_anonymous:
#somehow the user lost their login
return HttpResponseRedirect(reverse('superlogin'))
elif self.transaction.user.id != self.request.user.id:
@ -1333,7 +1333,7 @@ class PledgeRechargeView(TemplateView):
context = super(PledgeRechargeView, self).get_context_data(**kwargs)
# the following should be true since PledgeView.as_view is wrapped in login_required
assert self.request.user.is_authenticated()
assert self.request.user.is_authenticated
user = self.request.user
work = safe_get_work(self.kwargs["work_id"])
@ -1392,7 +1392,7 @@ class FundCompleteView(TemplateView):
return DownloadView.as_view()(request, work=self.transaction.campaign.work)
else:
if request.user.is_authenticated():
if request.user.is_authenticated:
if self.user_is_ok():
return self.render_to_response(context)
else:
@ -1482,7 +1482,7 @@ class PledgeCancelView(FormView):
# the following should be true since PledgeCancelView.as_view is wrapped in login_required
if self.request.user.is_authenticated():
if self.request.user.is_authenticated:
user = self.request.user
else:
context["error"] = "You are not logged in."
@ -1531,7 +1531,7 @@ class PledgeCancelView(FormView):
campaign_id = self.request.POST.get('campaign_id', self.request.GET.get('campaign_id'))
# this following logic should be extraneous.
if self.request.user.is_authenticated():
if self.request.user.is_authenticated:
user = self.request.user
else:
return HttpResponse("You need to be logged in.")
@ -1607,7 +1607,7 @@ def export_surveys(request, qid, work_id):
label = landing.label
wid = landing.object_id
return [wid, subject.ip_address, run.id, completed, label]
if not request.user.is_authenticated() :
if not request.user.is_authenticated:
return HttpResponseRedirect(reverse('surveys'))
extra_headings = [u'work id', u'subject ip address', u'run id', u'date completed', u'landing label']
return export_answers(request, qid,
@ -1617,7 +1617,7 @@ def export_surveys(request, qid, work_id):
filecode=work_id)
def surveys_summary(request, qid, work_id):
if not request.user.is_authenticated() :
if not request.user.is_authenticated:
return HttpResponseRedirect(reverse('surveys'))
return answer_summary(
request,
@ -1627,7 +1627,7 @@ def surveys_summary(request, qid, work_id):
def new_survey(request, work_id):
if not request.user.is_authenticated() :
if not request.user.is_authenticated:
return HttpResponseRedirect(reverse('surveys'))
my_works = works_user_can_admin( request.user)
if work_id:
@ -1659,7 +1659,7 @@ def new_survey(request, work_id):
return render(request, "manage_survey.html", {"work":work, "form":form})
def surveys(request):
if not request.user.is_authenticated() :
if not request.user.is_authenticated:
return render(request, "surveys.html")
works = works_user_can_admin(request.user)
work_ids = [work.id for work in works]
@ -1667,7 +1667,7 @@ def surveys(request):
return render(request, "surveys.html", {"works":works, "surveys":surveys})
def campaign_admin(request):
if not request.user.is_authenticated() :
if not request.user.is_authenticated:
return render(request, "admins_only.html")
if not request.user.is_staff :
return render(request, "admins_only.html")
@ -1809,7 +1809,7 @@ def supporter(request, supporter_username, template_name, extra_context={}):
activetab = "#3"
# following block to support profile admin form in supporter page
if request.user.is_authenticated() and request.user.username == supporter_username:
if request.user.is_authenticated and request.user.username == supporter_username:
profile_obj = request.user.profile
@ -2166,7 +2166,7 @@ class GoodreadsDisplayView(TemplateView):
gr_client = GoodreadsClient(key=settings.GOODREADS_API_KEY, secret=settings.GOODREADS_API_SECRET)
user = self.request.user
if user.is_authenticated():
if user.is_authenticated:
api_key = ApiKey.objects.filter(user=user)[0].key
context['api_key'] = api_key
@ -2243,7 +2243,7 @@ def goodreads_cb(request):
@csrf_exempt
def goodreads_flush_assoc(request):
user = request.user
if user.is_authenticated():
if user.is_authenticated:
profile = user.profile
profile.goodreads_user_id = None
profile.goodreads_user_name = None
@ -2544,7 +2544,7 @@ def feedback(request, recipient='unglueit@ebookfoundation.org', template='feedba
context['num2'] = request.POST['num2']
else:
if request.user.is_authenticated():
if request.user.is_authenticated:
context['sender'] = request.user.email
try:
context['page'] = request.GET['page']
@ -2639,7 +2639,7 @@ class DownloadView(PurchaseView):
self.lib_thanked = self.work.lib_thanked(self.request.user)
self.data = {
'preapproval_amount':self.get_preapproval_amount(),
'anonymous':True if self.request.user.is_anonymous() else self.request.user.profile.anon_pref,
'anonymous':True if self.request.user.is_anonymous else self.request.user.profile.anon_pref,
}
if self.request.method == 'POST':
self.data.update(self.request.POST.dict())
@ -2664,7 +2664,7 @@ class DownloadView(PurchaseView):
for ebook in work.ebooks().all():
formats[ebook.format] = reverse('download_ebook', args=[ebook.id])
if request.user.is_authenticated():
if request.user.is_authenticated:
#add a fave
request.user.wishlist.add_work(work,'download')
@ -2805,7 +2805,7 @@ def download_ebook(request, ebook_id):
return HttpResponseRedirect(ebook.url)
def download_purchased(request, work_id):
if request.user.is_anonymous():
if request.user.is_anonymous:
HttpResponseRedirect('/accounts/login/download/')
return DownloadView.as_view()(request, work_id=work_id)
@ -2855,12 +2855,12 @@ def receive_gift(request, nonce):
# put nonce in session so we know that a user has redeemed a Gift
request.session['gift_nonce'] = nonce
if gift.used:
if request.user.is_authenticated():
if request.user.is_authenticated:
#check that user hasn't redeemed the gift themselves
if (gift.acq.user_id == request.user.id) and not gift.acq.expired:
return HttpResponseRedirect(reverse('display_gift', args=[gift.id,'existing']))
return render(request, 'gift_error.html', context)
if request.user.is_authenticated():
if request.user.is_authenticated:
user_license = work.get_user_license(request.user)
if user_license and user_license.purchased:
# check if previously purchased- there would be two user licenses if so.
@ -3017,7 +3017,7 @@ def send_to_kindle(request, work_id, javascript='0'):
work = safe_get_work(work_id)
context = {'work':work}
acq = None
if request.user.is_authenticated():
if request.user.is_authenticated:
all_acqs = request.user.acqs.filter(work=work).order_by('-created')
for an_acq in all_acqs:
if not an_acq.expired:
@ -3058,7 +3058,7 @@ def send_to_kindle(request, work_id, javascript='0'):
except ValidationError:
return local_response(request, javascript, context, 3)
request.session['kindle_email'] = kindle_email
elif request.user.is_authenticated():
elif request.user.is_authenticated:
kindle_email = request.user.profile.kindle_email
context['kindle_email'] = kindle_email
@ -3096,7 +3096,7 @@ def send_to_kindle(request, work_id, javascript='0'):
logger.error('Unexpected error: %s', sys.exc_info())
return local_response(request, javascript, context, 1)
if request.POST.has_key('kindle_email') and not request.user.is_authenticated():
if request.POST.has_key('kindle_email') and not request.user.is_authenticated:
return HttpResponseRedirect(reverse('superlogin'))
return local_response(request, javascript, context, 2)

View File

@ -3,7 +3,7 @@ views to edit bibmodels
'''
from django.contrib.auth.decorators import login_required
from django.core.files.storage import default_storage
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db.models import Q
from django.http import (
HttpResponseRedirect,
@ -32,7 +32,7 @@ def user_can_edit_work(user, work):
'''
Check if a user is allowed to edit the work
'''
if user.is_anonymous():
if user.is_anonymous:
return False
elif user.is_staff :
return True
@ -76,7 +76,7 @@ def get_edition(edition_id):
raise Http404 (duplicate-code)
def user_edition(edition, user):
if user and user.is_authenticated() and edition:
if user and user.is_authenticated and edition:
user.profile.works.add(edition.work)
return edition

View File

@ -3,7 +3,7 @@ from decimal import Decimal as D
import logging
from django.conf import settings
from django.core.urlresolvers import reverse, reverse_lazy
from django.urls import reverse, reverse_lazy
from django.forms.models import modelformset_factory
from django.http import HttpResponseRedirect, Http404
from django.shortcuts import render, get_object_or_404
@ -39,7 +39,7 @@ class RHAgree(CreateView):
return super(RHAgree, self).form_valid(form)
def rh_admin(request, facet='top'):
if not request.user.is_authenticated() or not request.user.is_staff:
if not request.user.is_authenticated or not request.user.is_staff:
return render(request, "admins_only.html")
PendingFormSet = modelformset_factory(models.RightsHolder, fields=['approved'], extra=0)
@ -65,7 +65,7 @@ def rh_admin(request, facet='top'):
return render(request, "rights_holders.html", context)
def user_is_rh(user):
if user.is_anonymous():
if user.is_anonymous:
return False
for rh in user.rights_holder.filter(approved=True):
return True
@ -90,7 +90,7 @@ class ClaimView(CreateView):
form.save()
return HttpResponseRedirect(reverse('rightsholders'))
def get_context_data(self, form):
def get_context_data(self, form=None):
try:
work = form.cleaned_data['work']
except AttributeError:
@ -108,7 +108,7 @@ def claim(request):
return ClaimView.as_view()(request)
def rh_tools(request, template_name='rh_intro.html'):
if not request.user.is_authenticated() :
if not request.user.is_authenticated:
return render(request, 'rh_intro.html')
claims = request.user.claim.filter(user=request.user)
campaign_form = "xxx"
@ -198,7 +198,7 @@ def manage_campaign(request, id, ebf=None, action='manage'):
campaign.not_manager = False
campaign.problems = []
if (not request.user.is_authenticated()) or \
if (not request.user.is_authenticated) or \
(not request.user in campaign.managers.all() and not request.user.is_staff):
campaign.not_manager = True
return render(request, 'manage_campaign.html', {'campaign': campaign})

View File

@ -6,4 +6,4 @@ class LibraryAuthConfig(AppConfig):
name = 'regluit.libraryauth'
def ready(self):
from . import signals
from . import signals

View File

@ -1,12 +1,12 @@
from . import models
from selectable.forms import AutoCompleteSelectWidget,AutoCompleteSelectField
from selectable.base import ModelLookup
from selectable.registry import registry
from django import forms
from django.contrib.admin import ModelAdmin, site
from django.contrib.auth.models import User, Group
from django.contrib.auth.models import User
from selectable.base import ModelLookup
from selectable.forms import AutoCompleteSelectWidget, AutoCompleteSelectField
from selectable.registry import registry
from . import models
class UserLookup(ModelLookup):
model = User
@ -16,21 +16,21 @@ registry.register(UserLookup)
class LibraryAdminForm(forms.ModelForm):
user = AutoCompleteSelectField(
UserLookup,
widget=AutoCompleteSelectWidget(UserLookup),
required=True,
)
UserLookup,
widget=AutoCompleteSelectWidget(UserLookup),
required=True,
)
owner = AutoCompleteSelectField(
UserLookup,
widget=AutoCompleteSelectWidget(UserLookup),
required=True,
)
UserLookup,
widget=AutoCompleteSelectWidget(UserLookup),
required=True,
)
class Meta(object):
model = models.Library
widgets= {'group':forms.HiddenInput}
widgets = {'group':forms.HiddenInput}
exclude = ('group', )
class LibraryAdmin(ModelAdmin):
list_display = ('user', )
form = LibraryAdminForm
@ -51,4 +51,4 @@ class EmailPatternAdmin(ModelAdmin):
site.register(models.Library, LibraryAdmin)
site.register(models.Block, BlockAdmin)
site.register(models.CardPattern, CardPatternAdmin)
site.register(models.EmailPattern, EmailPatternAdmin)
site.register(models.EmailPattern, EmailPatternAdmin)

View File

@ -1,16 +1,15 @@
import logging
import requests
from django.http import HttpResponse
from django.shortcuts import redirect
from django.utils.http import urlquote
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage
from social_core.pipeline.social_auth import associate_by_email
from social_django.models import UserSocialAuth
from social_django.middleware import SocialAuthExceptionMiddleware
from social_core.exceptions import (AuthAlreadyAssociated, SocialAuthBaseException)
from social_django.middleware import SocialAuthExceptionMiddleware
ANONYMOUS_AVATAR = '/static/images/header/avatar.png'
(NO_AVATAR, GRAVATAR, TWITTER, FACEBOOK, PRIVATETAR) = (0, 1, 2, 3, 4)
@ -26,7 +25,7 @@ def pic_storage_url(user, backend, url):
pic_file = ContentFile(r.content)
content_type = r.headers.get('content-type', '')
if u'text' in content_type:
logger.warning('Cover return text for pic_url={}'.format(pic_url))
logger.warning('Cover return text for pic_url={}'.format(url))
return None
pic_file.content_type = content_type
default_storage.save(pic_file_name, pic_file)
@ -43,8 +42,8 @@ def selectively_associate_by_email(backend, details, user=None, *args, **kwargs)
This pipeline entry is not 100% secure unless you know that the providers
enabled enforce email verification on their side, otherwise a user can
attempt to take over another user account by using the same (not validated)
email address on some provider.
email address on some provider.
Not using Facebook or Twitter to authenticate a user.
"""
if backend.name in ('twitter', 'facebook'):
@ -61,7 +60,7 @@ def facebook_extra_values(user, extra_data):
return True
except Exception, e:
logger.exception(e)
return
return
def twitter_extra_values(user, extra_data):
try:
@ -74,19 +73,19 @@ def twitter_extra_values(user, extra_data):
user.profile.avatar_source = TWITTER
user.profile.save()
return True
except Exception,e:
except Exception, e:
logger.error(e)
return False
def deliver_extra_data(backend, user, social, response, *args, **kwargs):
if backend.name is 'twitter':
twitter_extra_values( user, social.extra_data)
if backend.name is 'facebook':
facebook_extra_values( user, response)
if backend.name == 'twitter':
twitter_extra_values(user, social.extra_data)
if backend.name == 'facebook':
facebook_extra_values(user, response)
# following is needed because of length limitations in a unique constrain for MySQL
def chop_username(username, *args, **kwargs):
if username and len(username)>222:
if username and len(username) > 222:
return {'username':username[0:222]}
def selective_social_user(backend, uid, user=None, *args, **kwargs):
@ -111,9 +110,9 @@ class SocialAuthExceptionMiddlewareWithoutMessages(SocialAuthExceptionMiddleware
"""
a modification of SocialAuthExceptionMiddleware to pass backend and message without
attempting django.messages
"""
"""
def process_exception(self, request, exception):
if isinstance(exception, SocialAuthBaseException):
backend = getattr(request, 'backend', None)
backend_name = getattr(backend, 'name', 'unknown-backend')

View File

@ -2,12 +2,16 @@
to make a backend named <backend> you need to...
1. make a class <backend>
2. with a function authenticate(self, request, library)
returns true if can request.user can be authenticated to the library, and attaches a credential property to the library object
returns true if can request.user can be authenticated to the library,
and attaches a credential property to the library object
returns fals if otherwise.
3. with a class authenticator
with a process((self, authenticator, success_url, deny_url) method which is expected to return a response
4. make a libraryauth/<backend>_join.html template (authenticator will be in its context) to insert a link or form for a user to join the library
5. if you need to show the user a form, define a model form class form with init method __init__(self, request, library, *args, **kwargs)
with a process((self, authenticator, success_url, deny_url) method
which is expected to return a response
4. make a libraryauth/<backend>_join.html template (authenticator will be in its context)
to insert a link or form for a user to join the library
5. if you need to show the user a form, define a model form class form with init method
__init__(self, request, library, *args, **kwargs)
and model LibraryUser
6. define an admin form to let the library configure its authentication
7. add new auth choice to Library.backend choices and the admin as desired
@ -20,75 +24,78 @@ from django.http import HttpResponseRedirect
from django.shortcuts import render
from .models import Block, IP, LibraryUser, CardPattern, EmailPattern
logger = logging.getLogger(__name__)
class ip:
def authenticate(self,request, library):
def authenticate(self, request, library):
try:
ip = IP(request.META['REMOTE_ADDR'])
blocks = Block.objects.filter(Q(lower=ip) | Q(lower__lte=ip, upper__gte=ip))
for block in blocks:
if block.library==library:
if block.library == library:
logger.info('%s authenticated for %s from %s'%(request.user, library, ip))
library.credential=ip
library.credential = ip
return True
return False
except KeyError:
return False
class authenticator():
def process(self, caller, success_url, deny_url):
return HttpResponseRedirect(deny_url)
form = None
class admin_form(forms.ModelForm):
class Meta:
model = Block
exclude = ("library",)
class cardnum:
def authenticate(self,request, library):
class cardnum:
def authenticate(self, request, library):
return False
class authenticator():
def process(self, caller, success_url, deny_url):
if caller.form and caller.request.method=='POST' and caller.form.is_valid():
if caller.form and caller.request.method == 'POST' and caller.form.is_valid():
library = caller.form.cleaned_data['library']
library.credential = caller.form.cleaned_data['credential']
logger.info('%s authenticated for %s from %s'%(caller.request.user, caller.library, caller.form.cleaned_data.get('number')))
logger.info('%s authenticated for %s from %s' % (
caller.request.user,
caller.library,
caller.form.cleaned_data.get('number'),
))
library.add_user(caller.form.cleaned_data['user'])
return HttpResponseRedirect(success_url)
else:
return render(caller.request, 'libraryauth/library.html', {
'library':caller.library,
'authenticator':caller,
})
return render(caller.request, 'libraryauth/library.html', {
'library':caller.library,
'authenticator':caller,
})
class admin_form(forms.ModelForm):
class Meta:
model = CardPattern
exclude = ("library",)
class form(forms.ModelForm):
credential = forms.RegexField(
label="Enter Your Library Card Number",
max_length=20,
regex=r'^\d+$',
required = True,
help_text = "(digits only)",
error_messages = {'invalid': "digits only!",}
)
label="Enter Your Library Card Number",
max_length=20,
regex=r'^\d+$',
required=True,
help_text="(digits only)",
error_messages={'invalid': "digits only!",}
)
def __init__(self, request, library, *args, **kwargs):
if request.method=="POST":
data=request.POST
if request.method == "POST":
data = request.POST
super(cardnum.form, self).__init__(data=data)
else:
initial={'user':request.user, 'library':library}
initial = {'user':request.user, 'library':library}
super(cardnum.form, self).__init__(initial=initial)
def clean(self):
library = self.cleaned_data.get('library', None)
credential = self.cleaned_data.get('credential', '')
@ -96,23 +103,23 @@ class cardnum:
if card_pattern.is_valid(credential):
return self.cleaned_data
raise forms.ValidationError("the library card number must be VALID.")
class Meta:
model = LibraryUser
widgets = { 'library': forms.HiddenInput, 'user': forms.HiddenInput }
widgets = {'library': forms.HiddenInput, 'user': forms.HiddenInput}
exclude = ()
class email:
def authenticate(self,request, library):
if request.user.is_anonymous():
class email:
def authenticate(self, request, library):
if request.user.is_anonymous:
return False
email = request.user.email
for email_pattern in library.email_auths.all():
if email_pattern.is_valid(email):
logger.info('%s authenticated for %s from %s'%(request.user, library, email))
library.credential=email
library.credential = email
return True
return False
class authenticator():
def process(self, caller, success_url, deny_url):
return HttpResponseRedirect(deny_url)

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
import logging
from django import forms
from django.contrib.auth import get_user_model
from django.contrib.auth.forms import AuthenticationForm, PasswordResetForm
from django.contrib.auth.forms import PasswordResetForm
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from registration.forms import RegistrationForm
@ -12,11 +12,11 @@ logger = logging.getLogger(__name__)
class UserData(forms.Form):
username = forms.RegexField(
label=_("New Username"),
max_length=30,
label=_("New Username"),
max_length=30,
regex=r'^[\w.@+-]+$',
help_text = _("30 characters or fewer."),
error_messages = {
help_text=_("30 characters or fewer."),
error_messages={
'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")
}
)
@ -35,11 +35,12 @@ class UserData(forms.Form):
raise forms.ValidationError(_("Your username is already "+username))
class UserNamePass(UserData):
password1 = forms.CharField(label=_("Password"),
widget=forms.PasswordInput)
password2 = forms.CharField(label=_("Password confirmation"),
password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput)
password2 = forms.CharField(
label=_("Password confirmation"),
widget=forms.PasswordInput,
help_text = _("Enter the same password as above, for verification."))
help_text=_("Enter the same password as above, for verification.")
)
allow_same = True
def clean_password2(self):
password1 = self.cleaned_data.get("password1", "")
@ -59,14 +60,6 @@ class RegistrationFormNoDisposableEmail(RegistrationForm):
raise forms.ValidationError(_("Please supply a permanent email address."))
return self.cleaned_data['email']
class AuthForm(AuthenticationForm):
def __init__(self, request=None, *args, **kwargs):
if request and request.method == 'GET':
saved_un= request.COOKIES.get('un', None)
super(AuthForm, self).__init__(initial={"username":saved_un},*args, **kwargs)
else:
super(AuthForm, self).__init__(*args, **kwargs)
class SocialAwarePasswordResetForm(PasswordResetForm):
def get_users(self, email):
"""
@ -81,40 +74,43 @@ class SocialAwarePasswordResetForm(PasswordResetForm):
if not get_user_model().objects.filter(email__iexact=email, is_active=True).exists():
raise forms.ValidationError("There aren't ungluers with that email address!")
return email
class NewLibraryForm(forms.ModelForm):
username = forms.RegexField(
label=_("Library Username"),
max_length=30,
label=_("Library Username"),
max_length=30,
regex=r'^[\w.@+-]+$',
help_text = _("30 characters or fewer."),
error_messages = {
help_text=_("30 characters or fewer."),
error_messages={
'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")
},
initial = '',
initial='',
)
email = forms.EmailField(
label=_("notification email address for library"),
label=_("notification email address for library"),
max_length=100,
error_messages={'required': 'Please enter an email address for the library.'},
)
def clean_username(self):
username= self.cleaned_data['username']
username = self.cleaned_data['username']
try:
user = User.objects.get(username=username)
raise forms.ValidationError(_("That username is already in use, please choose another."))
raise forms.ValidationError(_(
"That username is already in use, please choose another."
))
except User.DoesNotExist:
self.instance.user = User(username=username)
return username
class Meta:
model = Library
fields = 'name', 'backend', 'email', 'username'
widgets = {'name':forms.TextInput(attrs={'size':'40'})}
class LibraryForm(forms.ModelForm):
class LibraryForm(forms.ModelForm):
class Meta:
model = Library
fields = 'name', 'backend',
fields = 'name', 'backend',

View File

@ -47,9 +47,9 @@ class Migration(migrations.Migration):
('backend', models.CharField(default=b'ip', max_length=10, choices=[(b'ip', b'IP authentication'), (b'cardnum', b'Library Card Number check'), (b'email', b'e-mail pattern check')])),
('name', models.CharField(default=b'', max_length=80)),
('approved', models.BooleanField(default=False)),
('group', models.OneToOneField(related_name='library', null=True, to='auth.Group')),
('owner', models.ForeignKey(related_name='libraries', to=settings.AUTH_USER_MODEL)),
('user', models.OneToOneField(related_name='library', to=settings.AUTH_USER_MODEL)),
('group', models.OneToOneField(on_delete=models.CASCADE, related_name='library', null=True, to='auth.Group')),
('owner', models.ForeignKey(on_delete=models.CASCADE, related_name='libraries', to=settings.AUTH_USER_MODEL)),
('user', models.OneToOneField(on_delete=models.CASCADE, related_name='library', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
@ -58,23 +58,23 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('credential', models.CharField(max_length=30, null=True)),
('date_modified', models.DateTimeField(auto_now=True)),
('library', models.ForeignKey(related_name='library_users', to='libraryauth.Library')),
('user', models.ForeignKey(related_name='user_libraries', to=settings.AUTH_USER_MODEL)),
('library', models.ForeignKey(on_delete=models.CASCADE, related_name='library_users', to='libraryauth.Library')),
('user', models.ForeignKey(on_delete=models.CASCADE, related_name='user_libraries', to=settings.AUTH_USER_MODEL)),
],
),
migrations.AddField(
model_name='emailpattern',
name='library',
field=models.ForeignKey(related_name='email_auths', to='libraryauth.Library'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='email_auths', to='libraryauth.Library'),
),
migrations.AddField(
model_name='cardpattern',
name='library',
field=models.ForeignKey(related_name='cardnum_auths', to='libraryauth.Library'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='cardnum_auths', to='libraryauth.Library'),
),
migrations.AddField(
model_name='block',
name='library',
field=models.ForeignKey(related_name='ip_auths', to='libraryauth.Library'),
field=models.ForeignKey(on_delete=models.CASCADE, related_name='ip_auths', to='libraryauth.Library'),
),
]

View File

@ -1,63 +1,75 @@
# IP address part of this of this copied from https://github.com/benliles/django-ipauth/blob/master/ipauth/models.py
# IP address part of this of this copied from
# https://github.com/benliles/django-ipauth/blob/master/ipauth/models.py
import re
from django.contrib.auth.models import User, Group
from django.contrib.auth.models import Group
from django.conf import settings
from django.core.exceptions import ValidationError
from django.core import validators
from django.db import models
from django.db.models import Q
from django.db.models.signals import post_save
from django.forms import GenericIPAddressField as BaseIPAddressField
from django.utils.translation import ugettext_lazy as _
from django.core.urlresolvers import reverse
from django.urls import reverse
class Library(models.Model):
'''
name and other things derive from the User
'''
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='library')
group = models.OneToOneField(Group, related_name='library', null = True)
backend = models.CharField(max_length=10, choices=(
('ip','IP authentication'),
('cardnum', 'Library Card Number check'),
('email', 'e-mail pattern check'),
),default='ip')
name = models.CharField(max_length=80, default='')
user = models.OneToOneField(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='library',
)
group = models.OneToOneField(
Group,
on_delete=models.CASCADE,
related_name='library',
null=True
)
backend = models.CharField(max_length=10, choices=(
('ip', 'IP authentication'),
('cardnum', 'Library Card Number check'),
('email', 'e-mail pattern check'),
), default='ip')
name = models.CharField(max_length=80, default='')
approved = models.BooleanField(default=False)
owner = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="libraries")
owner = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name="libraries",
)
credential = None
def __unicode__(self):
return unicode(self.name)
def add_user(self, user):
user.groups.add(self.group)
(library_user, created) = LibraryUser.objects.get_or_create(library=self, user=user)
library_user.credential=self.credential
library_user.credential = self.credential
library_user.save()
def has_user(self, user):
return self.group in user.groups.all() or user == self.user
@property
def join_template(self):
if self.approved:
return 'libraryauth/' + self.backend + '_join.html'
else:
return 'libraryauth/unapproved.html'
return 'libraryauth/unapproved.html'
@property
def help_template(self):
return 'libraryauth/' + self.backend + '_help.html'
def get_absolute_url(self):
return reverse('library', args=[self.user.username])
def add_group(sender, created, instance, **kwargs):
if created:
num=''
num = ''
while created:
(group,created)=Group.objects.get_or_create(name=instance.user.username + num)
(group, created) = Group.objects.get_or_create(name=instance.user.username + num)
# make sure not using a group twice!
if created:
created = False
@ -68,7 +80,7 @@ def add_group(sender, created, instance, **kwargs):
created = True
except Library.DoesNotExist:
pass
instance.group=group
instance.group = group
instance.save()
post_save.connect(add_group, sender=Library)
@ -121,7 +133,7 @@ class IP(object):
int = property(_get_int, _set_int)
def _get_str(self):
if self.int!=None:
if self.int != None:
return long_to_ip(self.int)
return ''
@ -166,7 +178,7 @@ class IPAddressFormField(BaseIPAddressField):
return value
def to_python(self, value):
if value==0:
if value == 0:
return IP(0)
if value in validators.EMPTY_VALUES:
return None
@ -178,7 +190,6 @@ class IPAddressFormField(BaseIPAddressField):
code='invalid')
class IPAddressModelField(models.GenericIPAddressField):
__metaclass__ = models.SubfieldBase
empty_strings_allowed = False
def __init__(self, *args, **kwargs):
@ -206,13 +217,14 @@ class IPAddressModelField(models.GenericIPAddressField):
defaults = {'form_class': IPAddressFormField}
defaults.update(kwargs)
return super(models.GenericIPAddressField, self).formfield(**defaults)
def deconstruct(self):
name, path, args, kwargs = super(models.GenericIPAddressField, self).deconstruct()
return name, path, args, kwargs
class Block(models.Model):
library = models.ForeignKey(Library, related_name='ip_auths')
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='ip_auths')
lower = IPAddressModelField(db_index=True, unique=True)
upper = IPAddressModelField(db_index=True, blank=True, null=True)
@ -247,36 +259,35 @@ def luhn_checksum(card_number):
for d in even_digits:
checksum += sum(digits_of(d*2))
return checksum % 10
class CardPattern(models.Model):
library = models.ForeignKey(Library, related_name='cardnum_auths')
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='cardnum_auths')
# match pattern ^\d+#+$
pattern = models.CharField(max_length=20)
checksum = models.BooleanField(default=True)
def is_valid(self, card_number):
match_pattern='^' + self.pattern.replace('#','\d',20) + '$'
if re.match(match_pattern,card_number) is None:
match_pattern = '^' + self.pattern.replace('#', r'\d', 20) + '$'
if re.match(match_pattern, card_number) is None:
return False
if self.checksum:
return luhn_checksum(card_number) == 0
else:
return True
return True
class LibraryUser(models.Model):
library = models.ForeignKey(Library, related_name='library_users')
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='user_libraries')
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='library_users')
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
related_name='user_libraries',
)
credential = models.CharField(max_length=30, null=True)
date_modified = models.DateTimeField(auto_now=True)
class EmailPattern(models.Model):
library = models.ForeignKey(Library, related_name='email_auths')
library = models.ForeignKey(Library, on_delete=models.CASCADE, related_name='email_auths')
# email endswith string
pattern = models.CharField(max_length=20)
def is_valid(self, email):
if email.lower().endswith(self.pattern.lower()):
return True
else:
return False
return email.lower().endswith(self.pattern.lower())

View File

@ -8,16 +8,17 @@ logger = logging.getLogger(__name__)
@receiver(registration.signals.user_activated)
def handle_same_email_account(sender, user, **kwargs):
logger.info('checking %s' % user.username)
old_users=User.objects.exclude(id=user.id).filter(email=user.email)
old_users = User.objects.exclude(id=user.id).filter(email=user.email)
for old_user in old_users:
# decide why there's a previous user with this email
if not old_user.is_active:
# never activated
old_user.delete()
elif old_user.date_joined < user.date_joined:
# relax
# relax
pass
else:
# shouldn't happen; don't want to delete the user in case the user is being used for something
old_user.email= '%s.unglue.it'% old_user.email
else:
# shouldn't happen; don't want to delete the user
# in case the user is being used for something
old_user.email = '%s.unglue.it'% old_user.email

View File

@ -1,5 +1,3 @@
import unicodedata
from django.template import Library
from .. import models
@ -11,7 +9,7 @@ def libname(value):
returns library name .
"""
try:
vl = long( value )
vl = long(value)
lib = models.Library.objects.get(pk=vl)
return lib.__unicode__()
except models.Library.DoesNotExist:

View File

@ -1,19 +1,25 @@
import unittest
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.test import TestCase
from django.contrib.auth.models import User
class TestLibraryAuth(TestCase):
fixtures=['initial_data.json']
fixtures = ['initial_data.json']
def setUp(self):
pass
def test_login(self):
resp = self.client.get(reverse('superlogin'), data={'next': '/'})
self.assertEqual(200, resp.status_code)
self.client.cookies['un'] = 'bob'
resp = self.client.get(reverse('superlogin'), data={'next': '/'})
self.assertEqual(200, resp.status_code)
resp = self.client.post(reverse('superlogin'), data={'username': 'bob'})
self.assertEqual(200, resp.status_code)
def test_pages(self):
resp = self.client.get(reverse('registration_register'))
self.assertEqual(200, resp.status_code)
def test_registration(self):
"""
LibraryAuth Registration creates a new inactive account and a new profile
@ -30,12 +36,12 @@ class TestLibraryAuth(TestCase):
new_user = User.objects.get(username='bob')
self.failUnless(new_user.check_password('secret'))
self.assertTrue(new_user.check_password('secret'))
self.assertEqual(new_user.email, 'bob@example.com')
# New user must not be active.
self.failIf(new_user.is_active)
self.assertFalse(new_user.is_active)
def test_bad_registration(self):
"""
LibraryAuth Registration rejects.
@ -47,13 +53,11 @@ class TestLibraryAuth(TestCase):
'password1': 'secret',
'password2': 'secret'})
self.assertTrue('Please supply a permanent email address' in resp.content)
with self.assertRaises(User.DoesNotExist):
User.objects.get(username='badbob')
def test_is_disposable(self):
from .emailcheck import is_disposable
self.assertFalse(is_disposable('eric@hellman.net'))
self.assertTrue(is_disposable('eric@mailnesia.com'))

View File

@ -1,16 +1,16 @@
from django.conf.urls import patterns, url, include
from django.core.urlresolvers import reverse_lazy
from django.conf.urls import url, include
from django.urls import reverse_lazy
from django.views.generic.base import TemplateView
from django.contrib.auth.decorators import login_required
from django.contrib.auth.views import password_reset
from . import views, models, forms
from . import views, forms
from .views import superlogin
# class to reproduce django 1.4 funtionality
class ExtraContextTemplateView(TemplateView):
extra_context = None
def get_context_data(self, **kwargs):
context = super(self.__class__, self).get_context_data(**kwargs)
context = super(ExtraContextTemplateView, self).get_context_data(**kwargs)
if self.extra_context is not None:
for key, value in self.extra_context.items():
if callable(value):
@ -21,49 +21,59 @@ class ExtraContextTemplateView(TemplateView):
urlpatterns = [
url(r'^libraryauth/(?P<library_id>\d+)/join/$', views.join_library, name='join_library'),
url(r'^libraryauth/(?P<library_id>\d+)/deny/$', TemplateView.as_view(template_name='libraryauth/denied.html'), name='bad_library'),
url(r'^libraryauth/(?P<library_id>\d+)/users/$', views.library, {'template':'libraryauth/users.html'}, name='library_users'),
url(r'^libraryauth/(?P<library_id>\d+)/admin/$', login_required(views.UpdateLibraryView.as_view()), name='library_admin'),
url(r'^libraryauth/(?P<library_id>\d+)/login/$', views.login_as_library, name='library_login'),
url(r'^libraryauth/create/$', login_required(views.CreateLibraryView.as_view()), name='library_create'),
url(r'^libraryauth/(?P<library_id>\d+)/deny/$',
TemplateView.as_view(template_name='libraryauth/denied.html'),
name='bad_library'),
url(r'^libraryauth/(?P<library_id>\d+)/users/$',
views.library, {'template':'libraryauth/users.html'},
name='library_users'),
url(r'^libraryauth/(?P<library_id>\d+)/admin/$',
login_required(views.UpdateLibraryView.as_view()),
name='library_admin'),
url(r'^libraryauth/(?P<library_id>\d+)/login/$', views.login_as_library, name='library_login'),
url(r'^libraryauth/create/$',
login_required(views.CreateLibraryView.as_view()),
name='library_create'),
url(r'^libraryauth/list/$', ExtraContextTemplateView.as_view(
template_name='libraryauth/list.html',
extra_context={'libraries_to_show':'approved'}
), name='library_list'),
template_name='libraryauth/list.html',
extra_context={'libraries_to_show':'approved'}
), name='library_list'),
url(r'^libraryauth/unapproved/$', ExtraContextTemplateView.as_view(
template_name='libraryauth/list.html',
extra_context={'libraries_to_show':'new'}
), name='new_libraries'),
url(r'^accounts/register/$', views.CustomRegistrationView.as_view(), name='registration_register'),
template_name='libraryauth/list.html',
extra_context={'libraries_to_show':'new'}
), name='new_libraries'),
url(r'^accounts/register/$',
views.CustomRegistrationView.as_view(),
name='registration_register'),
url(r'^accounts/superlogin/$', views.superlogin, name='superlogin'),
url(r'^accounts/superlogin/welcome/$', ExtraContextTemplateView.as_view(
template_name='registration/welcome.html',
extra_context={'suppress_search_box': True,}
) ),
template_name='registration/welcome.html',
extra_context={'suppress_search_box': True,}
)),
url(r'^accounts/login/pledge/$', superlogin,
{'template_name': 'registration/from_pledge.html'}),
{'template_name': 'registration/from_pledge.html'}),
url(r'^accounts/login/purchase/$', superlogin,
{'template_name': 'registration/from_purchase.html'}),
{'template_name': 'registration/from_purchase.html'}),
url(r'^accounts/login/add/$', superlogin,
{'template_name': 'registration/from_add.html'}),
{'template_name': 'registration/from_add.html'}),
url(r'^accounts/activate/complete/$', superlogin,
{'template_name': 'registration/activation_complete.html'}),
{'template_name': 'registration/activation_complete.html'}),
url(r'^accounts/login-error/$', superlogin,
{'template_name': 'registration/from_error.html'}),
{'template_name': 'registration/from_error.html'}),
url(r'^accounts/edit/$', views.edit_user, name='edit_user'),
url(r'^accounts/login/welcome/$', ExtraContextTemplateView.as_view(
template_name='registration/welcome.html',
extra_context={'suppress_search_box': True,}
) ),
template_name='registration/welcome.html',
extra_context={'suppress_search_box': True,}
)),
url(r'^accounts/password/change/$',
views.social_aware_password_change,
{'post_change_redirect': reverse_lazy('auth_password_change_done')},
name='libraryauth_password_change'),
views.social_aware_password_change,
{'post_change_redirect': reverse_lazy('auth_password_change_done')},
name='libraryauth_password_change'),
url(r'^password/reset/$',
password_reset,
{'post_reset_redirect': reverse_lazy('auth_password_reset_done'),
'password_reset_form': forms.SocialAwarePasswordResetForm},
name='libraryauth_password_reset'),
password_reset,
{'post_reset_redirect': reverse_lazy('auth_password_reset_done'),
'password_reset_form': forms.SocialAwarePasswordResetForm},
name='libraryauth_password_reset'),
url(r'^socialauth/', include('social_django.urls', namespace='social')),
url('accounts/', include('email_change.urls')),

View File

@ -1,25 +1,26 @@
import logging
import random
from django.conf import settings
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.shortcuts import get_object_or_404, render
from django.contrib.auth.forms import SetPasswordForm
from django.contrib.auth.views import login, password_reset, password_change
from django.contrib.auth import login as login_to_user
from django.contrib.auth import load_backend
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
from django.views.generic.edit import FormView, CreateView, UpdateView, SingleObjectMixin
from django.contrib.auth.forms import SetPasswordForm
from django.contrib.auth.models import User
from django.contrib.auth.views import password_change, LoginView
from django.http import HttpResponseRedirect, Http404
from django.views.generic.edit import CreateView, UpdateView
from registration.backends.model_activation.views import RegistrationView
from . import backends
from .models import Library
from .forms import AuthForm, LibraryForm, NewLibraryForm, RegistrationFormNoDisposableEmail, UserData
from .forms import LibraryForm, NewLibraryForm, RegistrationFormNoDisposableEmail, UserData
logger = logging.getLogger(__name__)
def get_library_or_404(library=None, library_id=None):
def get_library_or_404(library=None, library_id=None):
if library_id:
try:
return get_object_or_404(Library, id=library_id)
@ -28,36 +29,53 @@ def get_library_or_404(library=None, library_id=None):
else:
return get_object_or_404(Library, user__username=library)
def library(request, library=None, library_id=None,
extra_context={},
template='libraryauth/library.html',
def library(
request, library=None, library_id=None,
extra_context={}, template='libraryauth/library.html',
**kwargs):
library=get_library_or_404(library=library, library_id=library_id)
context={ 'library':library,
'is_admin': request.user.is_staff or request.user==library.user,
'is_member': request.user.is_staff or library.has_user(request.user),
}
library = get_library_or_404(library=library, library_id=library_id)
context = {
'library':library,
'is_admin': request.user.is_staff or request.user == library.user,
'is_member': request.user.is_staff or library.has_user(request.user),
}
context.update(extra_context)
return render(request, template, context)
def join_library(request, library_id):
library=get_library_or_404(library_id=library_id)
return Authenticator(request,library).process(
reverse('library',args=[library.user]),
reverse('bad_library',args=[library.id]),
)
library = get_library_or_404(library_id=library_id)
return Authenticator(request, library).process(
reverse('library', args=[library.user]),
reverse('bad_library', args=[library.id]),
)
class SuperLoginView(LoginView):
def get_initial(self):
initial = super(SuperLoginView, self).get_initial()
if self.request.method == 'GET':
saved_un = self.request.COOKIES.get('un', None)
initial["username"] = saved_un
return initial
def get(self, request, *args, **kwargs):
if 'add' in self.request.GET:
self.request.session["add_wishlist"] = self.request.GET["add"]
return super(SuperLoginView, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = super(SuperLoginView, self).get_context_data(**kwargs)
if self.request.method == 'POST' and self.request.user.is_anonymous:
username = self.request.POST.get("username", "")
try:
user = User.objects.get(username=username)
context['socials'] = user.profile.social_auths
except:
pass
return context
def superlogin(request, extra_context={}, **kwargs):
if request.method == 'POST' and request.user.is_anonymous():
username=request.POST.get("username", "")
try:
user=models.User.objects.get(username=username)
extra_context={"socials":user.profile.social_auths}
except:
pass
if request.GET.has_key("add"):
request.session["add_wishlist"]=request.GET["add"]
return login(request, extra_context=extra_context, authentication_form=AuthForm, **kwargs)
return SuperLoginView.as_view(extra_context=extra_context, **kwargs)(request)
def social_aware_password_change(request, **kwargs):
if request.user.has_usable_password():
@ -65,55 +83,56 @@ def social_aware_password_change(request, **kwargs):
return password_change(request, password_change_form=SetPasswordForm, **kwargs)
class Authenticator:
request=None
library=None
request = None
library = None
def __init__(self, request, library, *args, **kwargs):
self.request = request
if isinstance(library , basestring):
if isinstance(library, basestring):
self.library = Library.objects.get(user__username=library)
elif isinstance(library , Library):
self.library=library
elif isinstance(library, Library):
self.library = library
else:
raise Exception
self.backend_class=getattr(backends,self.library.backend)
self.backend_class = getattr(backends, self.library.backend)
form_class = self.backend_class.form
if form_class:
self.form = form_class(request, self.library, *args, **kwargs)
else:
self.form = None
def process(self, success_url, deny_url):
logger.info('authenticator for %s at %s.'%(self.request.user, self.library))
if self.library.has_user(self.request.user):
return HttpResponseRedirect(success_url)
if self.backend_class().authenticate(self.request, self.library):
if self.request.user.is_authenticated():
if self.request.user.is_authenticated:
self.library.add_user(self.request.user)
return HttpResponseRedirect(success_url)
else:
return superlogin(self.request, extra_context={'library':self.library}, template_name='libraryauth/library_login.html')
else:
return self.backend_class.authenticator().process(self, success_url, deny_url)
return superlogin(
self.request,
extra_context={'library':self.library},
template_name='libraryauth/library_login.html'
)
return self.backend_class.authenticator().process(self, success_url, deny_url)
def allowed(self):
return self.backend_class().authenticate(self.request, self.library)
class BaseLibraryView:
model = Library
template_name="libraryauth/edit.html"
model = Library
template_name = "libraryauth/edit.html"
class CreateLibraryView(BaseLibraryView, CreateView):
form_class = NewLibraryForm
def get_initial(self):
return {'email': self.request.user.email}
def form_valid(self, form):
form.instance.owner = self.request.user
form.instance.owner = self.request.user
user = form.instance.user
user.email = form.cleaned_data['email']
user.save()
@ -123,12 +142,12 @@ class CreateLibraryView(BaseLibraryView, CreateView):
form.instance.add_user(self.request.user) # library.owner is a member of library
context_data = self.get_context_data(form=form)
context_data['status'] = 'Library Updated'
return HttpResponseRedirect(reverse('library_admin',args=[form.instance.id]))
return HttpResponseRedirect(reverse('library_admin', args=[form.instance.id]))
class UpdateLibraryView(BaseLibraryView, UpdateView):
pk_url_kwarg = 'library_id'
pk_url_kwarg = 'library_id'
form_class = LibraryForm
def form_valid(self, form):
context_data = self.get_context_data(form=form)
form.instance.save()
@ -137,26 +156,33 @@ class UpdateLibraryView(BaseLibraryView, UpdateView):
def get_backend_form_class(self):
if self.object and self.object.backend:
backend_class=getattr(backends,self.object.backend)
backend_class = getattr(backends, self.object.backend)
return backend_class.admin_form
else:
return None
return None
def get_backend_admin_forms(self):
if self.object and self.object.backend:
backend_models_name = '%s_auths' % self.object.backend
backend_models = getattr(self.object,backend_models_name)
backend_new_form = self.get_backend_form_class()(initial = {'library':self.object}, prefix="new")
backend_old_forms = [self.get_backend_form_class()(instance = backend_model, prefix="backend_%s"%backend_model.id) for backend_model in backend_models.all()]
backend_models = getattr(self.object, backend_models_name)
backend_new_form = self.get_backend_form_class()(
initial={'library': self.object},
prefix="new",
)
backend_old_forms = [self.get_backend_form_class()(
instance=backend_model,
prefix="backend_%s"%backend_model.id,
) for backend_model in backend_models.all()]
return backend_old_forms + [backend_new_form]
else:
return []
return []
def get_context_data(self, backend_form=None, form=None, **kwargs):
context = super(UpdateLibraryView,self).get_context_data(**kwargs)
context = super(UpdateLibraryView, self).get_context_data(**kwargs)
backend_admin_forms = self.get_backend_admin_forms()
if backend_form:
backend_admin_forms = [ backend_form if backend_form.prefix== backend_admin_form.prefix else backend_admin_form for backend_admin_form in backend_admin_forms]
backend_admin_forms = [
backend_form if backend_form.prefix == backend_admin_form.prefix \
else backend_admin_form for backend_admin_form in backend_admin_forms
]
context['backend_admin_forms'] = backend_admin_forms
if form:
context['form'] = form
@ -166,17 +192,17 @@ class UpdateLibraryView(BaseLibraryView, UpdateView):
self.object = self.get_object()
# check permissions
if request.user not in [self.object.owner, self.object.user]:
context_data={'status': 'You\'re not permitted to edit this library.'}
context_data = {'status': 'You\'re not permitted to edit this library.'}
return self.render_to_response(context_data)
form = self.get_form(self.form_class)
return self.render_to_response(self.get_context_data(form=form))
def post(self, request, *args, **kwargs):
# get the user instance (the library)
self.object = self.get_object()
# check permissions
if request.user not in [self.object.owner, self.object.user]:
context_data={'status': 'You\'re not permitted to edit this library.'}
context_data = {'status': 'You\'re not permitted to edit this library.'}
return self.render_to_response(context_data)
# determine if backend form is being submitted
# uses the name of the form's submit button
@ -187,46 +213,53 @@ class UpdateLibraryView(BaseLibraryView, UpdateView):
backend_id = request.POST['id']
if 'backend_submit' in request.POST:
# we're editing the backend
if backend_id is None or backend_id=="None":
if backend_id is None or backend_id == "None":
backend_model_instance = form_model(library=self.object)
form = form_class(data=request.POST, instance=backend_model_instance, prefix="new")
form = form_class(
data=request.POST,
instance=backend_model_instance,
prefix="new"
)
else:
backend_model_instance = form_model.objects.get(id=backend_id)
form = form_class(data=request.POST, instance=backend_model_instance, prefix="backend_%s"%request.POST['id'])
form = form_class(
data=request.POST,
instance=backend_model_instance,
prefix="backend_%s"%request.POST['id'],
)
if form.is_valid():
form.save()
status = 'User Validation Updated.'
context_data = self.get_context_data( form=self.form_class(instance=self.object))
context_data = self.get_context_data(
form=self.form_class(instance=self.object))
else:
status = 'Problem with User Validation.'
context_data = self.get_context_data(backend_form=form, form=self.form_class(instance=self.object))
context_data = self.get_context_data(
backend_form=form, form=self.form_class(instance=self.object))
else:
#deleting a backend
if backend_id is not None and backend_id!="None":
if backend_id is not None and backend_id != "None":
backend_model_instance = form_model.objects.get(id=backend_id)
backend_model_instance.delete()
status = 'Deleted.'
else:
status = 'Nothing to delete.'
context_data = self.get_context_data( form=self.form_class(instance=self.object))
context_data = self.get_context_data(form=self.form_class(instance=self.object))
context_data['status'] = status
return self.render_to_response(context_data)
else:
# just use regular post handler
# just use regular post handler
form = self.get_form(self.form_class)
if form.is_valid():
return self.form_valid(form)
else:
return self.form_invalid(form)
return self.form_invalid(form)
@login_required
def login_as_library(request, library_id):
library=get_library_or_404(library_id=library_id)
def login_as_library(request, library_id):
library = get_library_or_404(library_id=library_id)
if request.user == library.owner:
login_user(request, library.user)
return HttpResponseRedirect(reverse('library_admin',args=[library.id]))
return HttpResponseRedirect(reverse('library_admin', args=[library.id]))
def login_user(request, user):
"""
@ -244,36 +277,35 @@ def login_user(request, user):
return login_to_user(request, user)
robot_qs = {
'user',
'user/register',
'node/add',
}
'user',
'user/register',
'node/add',
}
class CustomRegistrationView(RegistrationView):
form_class = RegistrationFormNoDisposableEmail
def form_valid(self, form):
q = self.request.session.get('q', False)
q = self.request.session.get('q', False)
if q and q in robot_qs:
return self.render_to_response({'form':form})
return super(CustomRegistrationView,self).form_valid(form)
return super(CustomRegistrationView, self).form_valid(form)
def edit_user(request, redirect_to=None):
if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('superlogin'))
form=UserData()
if request.method == 'POST':
if not request.user.is_authenticated:
return HttpResponseRedirect(reverse('superlogin'))
form = UserData()
if request.method == 'POST':
if 'change_username' in request.POST.keys():
form = UserData(request.POST)
form.oldusername = request.user.username
if form.is_valid(): # All validation rules pass, go and change the username
request.user.username=form.cleaned_data['username']
request.user.username = form.cleaned_data['username']
request.user.save()
if 'set_password' in request.POST.keys() and form.cleaned_data.has_key('set_password'):
if 'set_password' in request.POST.keys() and \
form.cleaned_data.has_key('set_password'):
if not request.user.has_usable_password():
request.user.set_password(form.cleaned_data['set_password'])
request.user.save()
return HttpResponseRedirect(redirect_to if redirect_to else reverse('home')) # Redirect after POST
return render(request,'registration/user_change_form.html', {'form': form})
# Redirect after POST
return HttpResponseRedirect(redirect_to if redirect_to else reverse('home'))
return render(request, 'registration/user_change_form.html', {'form': form})

View File

@ -11,7 +11,7 @@ from datetime import datetime
from StringIO import StringIO
from django.conf import settings
from django.core.urlresolvers import reverse
from django.urls import reverse
import regluit.core.cc as cc

View File

@ -19,8 +19,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('guts', models.TextField()),
('created', models.DateTimeField(auto_now_add=True)),
('edition', models.ForeignKey(related_name='MARCRecords', to='core.Edition', null=True)),
('user', models.ForeignKey(related_name='MARCRecords', to=settings.AUTH_USER_MODEL, null=True)),
('edition', models.ForeignKey(on_delete=models.CASCADE, related_name='MARCRecords', to='core.Edition', null=True)),
('user', models.ForeignKey(on_delete=models.CASCADE, related_name='MARCRecords', to=settings.AUTH_USER_MODEL, null=True)),
],
),
]

View File

@ -93,9 +93,9 @@ class MARCRecord(models.Model):
_the_record = None
# note capitalization of related_name
edition = models.ForeignKey(EDITION_MODEL, related_name="MARCRecords", null=True)
edition = models.ForeignKey(EDITION_MODEL, on_delete=models.CASCADE, related_name="MARCRecords", null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="MARCRecords", null=True )
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="MARCRecords", null=True )
created = models.DateTimeField(auto_now_add=True)

View File

@ -1,4 +1,4 @@
from django.conf.urls import patterns, url, include
from django.conf.urls import url, include
from django.contrib.auth.decorators import login_required
from . import views

View File

@ -3,7 +3,7 @@ from xml.sax import SAXParseException
from django.apps import apps
from django.contrib import messages
from django.core.urlresolvers import reverse, reverse_lazy
from django.urls import reverse, reverse_lazy
from django.http import HttpResponseRedirect, HttpResponse, HttpResponseNotFound
from django.views.generic.edit import FormView

View File

@ -17,7 +17,7 @@ django imports
"""
from django.conf import settings
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.utils.timezone import now
"""
@ -486,7 +486,7 @@ class PaymentManager( object ):
else:
transaction.error = p.error_string()
transaction.save()
logger.info("execute_transaction Error: " + p.error_string())
logger.info("execute_transaction Error: {}".format(p.error_string()))
return False
def cancel_transaction(self, transaction):
@ -526,7 +526,7 @@ class PaymentManager( object ):
else:
transaction.error = p.error_string()
transaction.save()
logger.info("Cancel Transaction " + str(transaction.id) + " Failed with error: " + p.error_string())
logger.info("Cancel Transaction {} Failed with error: {}".format(transaction.id, p.error_string()))
return False
else:
@ -665,7 +665,7 @@ class PaymentManager( object ):
else:
transaction.error = p.error_string()
transaction.save()
logger.info("Pay Error: " + p.error_string())
logger.info("Pay Error: {}".format(p.error_string()))
return transaction, None
@ -711,7 +711,7 @@ class PaymentManager( object ):
)
t.save()
# does user have enough credit to transact now?
if user.is_authenticated() and user.credit.available >= amount :
if user.is_authenticated and user.credit.available >= amount :
# YES!
return_path = "{0}?{1}".format(reverse('pledge_complete'),
urllib.urlencode({'tid':t.id}))
@ -958,7 +958,7 @@ class PaymentManager( object ):
else:
transaction.error = p.error_string()
transaction.save()
logger.info("Refund Transaction " + str(transaction.id) + " Failed with error: " + p.error_string())
logger.info("Refund Transaction {} Failed with error: {}".format(str(transaction.id), p.error_string()))
return False
def make_account(self, user=None, host=None, token=None):

View File

@ -31,7 +31,7 @@ class Migration(migrations.Migration):
('date_modified', models.DateTimeField(auto_now=True)),
('date_deactivated', models.DateTimeField(null=True)),
('status', models.CharField(default=b'ACTIVE', max_length=11, choices=[(b'ACTIVE', b'ACTIVE'), (b'DEACTIVATED', b'DEACTIVATED'), (b'EXPIRED', b'EXPIRED'), (b'EXPIRING', b'EXPIRING'), (b'ERROR', b'ERROR')])),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True)),
('user', models.ForeignKey(on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL, null=True)),
],
),
migrations.CreateModel(
@ -41,7 +41,7 @@ class Migration(migrations.Migration):
('balance', models.DecimalField(default=Decimal('0.00'), max_digits=14, decimal_places=2)),
('pledged', models.DecimalField(default=Decimal('0.00'), max_digits=14, decimal_places=2)),
('last_activity', models.DateTimeField(auto_now=True)),
('user', models.OneToOneField(related_name='credit', to=settings.AUTH_USER_MODEL)),
('user', models.OneToOneField(on_delete=models.CASCADE, related_name='credit', to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
@ -52,7 +52,7 @@ class Migration(migrations.Migration):
('timestamp', models.DateTimeField(auto_now=True)),
('action', models.CharField(max_length=16)),
('sent', models.IntegerField(null=True)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True)),
('user', models.ForeignKey(on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL, null=True)),
],
),
migrations.CreateModel(
@ -116,20 +116,20 @@ class Migration(migrations.Migration):
('date_expired', models.DateTimeField(null=True)),
('extra', jsonfield.fields.JSONField(default={}, null=True)),
('anonymous', models.BooleanField(default=False)),
('campaign', models.ForeignKey(to='core.Campaign', null=True)),
('offer', models.ForeignKey(to='core.Offer', null=True)),
('premium', models.ForeignKey(to='core.Premium', null=True)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, null=True)),
('campaign', models.ForeignKey(on_delete=models.CASCADE, to='core.Campaign', null=True)),
('offer', models.ForeignKey(on_delete=models.CASCADE, to='core.Offer', null=True)),
('premium', models.ForeignKey(on_delete=models.CASCADE, to='core.Premium', null=True)),
('user', models.ForeignKey(on_delete=models.CASCADE, to=settings.AUTH_USER_MODEL, null=True)),
],
),
migrations.AddField(
model_name='receiver',
name='transaction',
field=models.ForeignKey(to='payment.Transaction'),
field=models.ForeignKey(on_delete=models.CASCADE, to='payment.Transaction'),
),
migrations.AddField(
model_name='paymentresponse',
name='transaction',
field=models.ForeignKey(to='payment.Transaction'),
field=models.ForeignKey(on_delete=models.CASCADE, to='payment.Transaction'),
),
]

View File

@ -115,10 +115,10 @@ class Transaction(models.Model):
date_expired = models.DateTimeField(null=True)
# associated User, Campaign, and Premium for this Transaction
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
campaign = models.ForeignKey('core.Campaign', null=True)
premium = models.ForeignKey('core.Premium', null=True)
offer = models.ForeignKey('core.Offer', null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
campaign = models.ForeignKey('core.Campaign', on_delete=models.CASCADE, null=True)
premium = models.ForeignKey('core.Premium', on_delete=models.CASCADE, null=True)
offer = models.ForeignKey('core.Offer', on_delete=models.CASCADE, null=True)
extra = JSONField(null=True, default={})
# whether the user wants to be not listed publicly
@ -145,7 +145,7 @@ class Transaction(models.Model):
@property
def needed_amount(self):
if self.user is None or self.user.is_anonymous():
if self.user is None or self.user.is_anonymous:
return self.max_amount
if self.user.credit.available >= self.max_amount:
return 0
@ -153,7 +153,7 @@ class Transaction(models.Model):
@property
def credit_amount(self):
if self.user is None or self.user.is_anonymous():
if self.user is None or self.user.is_anonymous:
return 0
if self.user.credit.available >= self.max_amount:
return self.max_amount
@ -233,7 +233,7 @@ class Transaction(models.Model):
def create(cls, amount=0.00, host=PAYMENT_HOST_NONE, max_amount=0.00, currency='USD',
status=TRANSACTION_STATUS_NONE, campaign=None, user=None, pledge_extra=None,
donation=False):
if user and user.is_anonymous():
if user and user.is_anonymous:
user = None
t = cls.objects.create(
amount=amount,
@ -265,7 +265,7 @@ class PaymentResponse(models.Model):
# local status specific to the api call
status = models.CharField(max_length=32, null=True)
transaction = models.ForeignKey(Transaction, null=False)
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE, null=False)
def __unicode__(self):
return u"PaymentResponse -- api: {0} correlation_id: {1} transaction: {2}".format(
@ -287,7 +287,7 @@ class Receiver(models.Model):
reason = models.CharField(max_length=64)
primary = models.BooleanField(default=True)
txn_id = models.CharField(max_length=64)
transaction = models.ForeignKey(Transaction)
transaction = models.ForeignKey(Transaction, on_delete=models.CASCADE,)
def __unicode__(self):
return u"Receiver -- email: {0} status: {1} transaction: {2}".format(
@ -298,7 +298,7 @@ class Receiver(models.Model):
class CreditLog(models.Model):
# a write only record of Unglue.it Credit Transactions
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
amount = models.DecimalField(default=Decimal('0.00'), max_digits=14, decimal_places=2) # max 999,999,999,999.99
timestamp = models.DateTimeField(auto_now=True)
action = models.CharField(max_length=16)
@ -306,7 +306,7 @@ class CreditLog(models.Model):
sent = models.IntegerField(null=True)
class Credit(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL, related_name='credit')
user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='credit')
balance = models.DecimalField(default=Decimal('0.00'), max_digits=14, decimal_places=2) # max 999,999,999,999.99
pledged = models.DecimalField(default=Decimal('0.00'), max_digits=14, decimal_places=2) # max 999,999,999,999.99
last_activity = models.DateTimeField(auto_now=True)
@ -421,7 +421,7 @@ class Account(models.Model):
date_deactivated = models.DateTimeField(null=True)
# associated User if any
user = models.ForeignKey(settings.AUTH_USER_MODEL, null=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
# status variable
status = models.CharField(max_length=11, choices=STATUS_CHOICES, null=False, default='ACTIVE')

View File

@ -421,7 +421,7 @@ class StripeErrorTest(TestCase):
self.fail("Attempt to create customer did not throw expected exception.")
except stripe.CardError as e:
self.assertEqual(e.code, "card_declined")
self.assertEqual(e.message, "Your card was declined")
self.assertEqual(e.args[0], "Your card was declined")
def test_charge_bad_cust(self):
# expect the card to be declined -- and for us to get CardError
@ -450,7 +450,7 @@ class StripeErrorTest(TestCase):
self.fail("Attempt to create token with bad cc number did not throw expected exception.")
except stripe.CardError as e:
self.assertEqual(e.code, "incorrect_number")
self.assertEqual(e.message, "Your card number is incorrect")
self.assertEqual(e.args[0], "Your card number is incorrect")
def test_invalid_expiry_month(self):
"""Use an invalid month e.g. 13."""
@ -464,7 +464,7 @@ class StripeErrorTest(TestCase):
self.fail("Attempt to create token with invalid expiry month did not throw expected exception.")
except stripe.CardError as e:
self.assertEqual(e.code, "invalid_expiry_month")
self.assertEqual(e.message, "Your card's expiration month is invalid")
self.assertEqual(e.args[0], "Your card's expiration month is invalid")
def test_invalid_expiry_year(self):
"""Use a year in the past e.g. 1970."""
@ -478,7 +478,7 @@ class StripeErrorTest(TestCase):
self.fail("Attempt to create token with invalid expiry year did not throw expected exception.")
except stripe.CardError as e:
self.assertEqual(e.code, "invalid_expiry_year")
self.assertEqual(e.message, "Your card's expiration year is invalid")
self.assertEqual(e.args[0], "Your card's expiration year is invalid")
def test_invalid_cvc(self):
"""Use a two digit number e.g. 99."""
@ -492,7 +492,7 @@ class StripeErrorTest(TestCase):
self.fail("Attempt to create token with invalid cvc did not throw expected exception.")
except stripe.CardError as e:
self.assertEqual(e.code, "invalid_cvc")
self.assertEqual(e.message, "Your card's security code is invalid")
self.assertEqual(e.args[0], "Your card's security code is invalid")
def test_missing_card(self):
"""There is no card on a customer that is being charged"""
@ -504,7 +504,7 @@ class StripeErrorTest(TestCase):
sc.create_charge(10, customer = cust1.id, description="$10 for cust w/ no card")
except stripe.CardError as e:
self.assertEqual(e.code, "missing")
self.assertEqual(e.message, "Cannot charge a customer that has no active card")
self.assertEqual(e.args[0], "Cannot charge a customer that has no active card")
class PledgeScenarioTest(TestCase):
@classmethod
@ -578,7 +578,7 @@ class Processor(baseprocessor.Processor):
else:
customer = sc.create_customer(card=token, description='anonymous user', email=email)
except stripe.StripeError as e:
raise StripelibError(e.message, e)
raise StripelibError(e.args, e)
account = Account(host = PAYMENT_HOST_STRIPE,
account_id = customer.id,
@ -696,7 +696,7 @@ class Processor(baseprocessor.Processor):
transaction.save()
else:
self.errorMessage = p.errorMessage #pass error message up
logger.info("execute_transaction Error: " + p.error_string())
logger.info("execute_transaction Error: {}".format(p.error_string()))
def amount( self ):
return self.transaction.amount
@ -746,11 +746,11 @@ class Processor(baseprocessor.Processor):
# use PaymentResponse to store error
r = PaymentResponse.objects.create(api="stripelib.Execute", correlation_id=None,
timestamp=now(), info=e.message,
timestamp=now(), info=e.args[0],
status=TRANSACTION_STATUS_ERROR, transaction=transaction)
transaction.status = TRANSACTION_STATUS_ERROR
self.errorMessage = e.message # manager puts this on transaction
self.errorMessage = e.args # manager puts this on transaction
transaction.save()
# fire off the fact that transaction failed -- should actually do so only if not a transient error
@ -759,9 +759,8 @@ class Processor(baseprocessor.Processor):
transaction_failed.send(sender=self, transaction=transaction)
# otherwise, report exception to us
else:
logger.exception("transaction id {0}, exception: {1}".format(transaction.id, e.message))
logger.exception("transaction id {0}, exception: {1}".format(transaction.id, e.args))
# raise StripelibError(e.message, e)
else:
self.charge = charge

View File

@ -1,5 +1,5 @@
from django.conf import settings
from django.conf.urls import patterns, url, include
from django.conf.urls import url, include
from regluit.payment import views

View File

@ -14,15 +14,14 @@ django imports
from django.conf import settings
from django.contrib.auth.models import User
from django.contrib.sites.requests import RequestSite
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.http import (
HttpResponse,
HttpRequest,
HttpResponseRedirect,
HttpResponseBadRequest
)
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.shortcuts import render
from django.test.utils import setup_test_environment
from django.utils.timezone import now
from django.views.decorators.csrf import csrf_exempt
@ -278,7 +277,7 @@ def checkStatus(request):
# https://raw.github.com/agiliq/merchant/master/example/app/views.py
def _render(request, template, template_vars={}):
return render_to_response(template, template_vars, RequestContext(request))
return render(request, template, template_vars)
class StripeView(FormView):
template_name="stripe.html"

View File

@ -1,4 +1,4 @@
Django==1.8.14
Django==1.11.14
Fabric==1.6.0
MySQL-python==1.2.5
Pillow==3.4.2
@ -18,28 +18,28 @@ chardet==3.0.4
# pip installing pillow seems to delete distribute
# but having distribute in requirements starting to cause problems
# distribute==0.6.28
django-celery==3.1.17
django-ckeditor==4.5.1
django-celery==3.2.2
django-ckeditor==5.6.1
#django-email-change==0.2.3
git+git://github.com/eshellman/django-email-change.git@57169bdef1c8a41d122e2bab2dcd8564b8fb231d
django-compat==1.0.10
django-contrib-comments==1.7.1
git+git://github.com/eshellman/django-email-change.git@830808b9b9db5f3ca9ec0cb22f8fda5cc2cef12d
django-compat==1.0.15
django-contrib-comments==1.8.0
django-el-pagination==3.2.4
django-extensions==1.6.1
django-jsonfield==1.0.0
#django-kombu==0.9.4
django-maintenancemode==0.11.2
django-mptt==0.8.5
django-mptt==0.8.6
#django-notification==0.2
git+git://github.com/eshellman/django-notification.git@a4620e893e2da220994e0189bf5d980bfbdcf0ad
django-registration==2.1.2
django-selectable==0.9.0
git+git://github.com/eshellman/django-notification.git@92cc14b737d4a10e7e866b2f467ef1f20a89c715
django-registration==2.4.1
django-selectable==1.1.0
django-smtp-ssl==1.0
django-storages==1.5.2
django-tastypie==0.13.3
django-tastypie==0.14.1
#django-transmeta==0.7.3
git+git://github.com/resulto/django-transmeta.git@ad4d7278ba330dcf8c8446f8ae9b2c769ae8684e
fef-questionnaire==4.0.1
#fef-questionnaire==4.0.1
git+git://github.com/EbookFoundation/fef-questionnaire.git@8c3b630eb6171fe9242bf0d3b456dc41de958006
#gitenberg.metadata==0.1.6
git+git://github.com/gitenberg-dev/gitberg-build.git@61a5fb0011e1a547b1eac14dd845ce37dbb5f85a
#git+ssh://git@github.com/gitenberg-dev/metadata.git@0.1.11
@ -47,7 +47,7 @@ github3.py==0.9.5
html5lib==1.0.1
httplib2==0.11.3
isodate==0.5.1
kombu==3.0.35
kombu==3.0.37
lxml==4.2.1
defusedxml==0.4.1
mechanize==0.2.5
@ -94,7 +94,7 @@ cryptography==2.2.2
enum34==1.1.6
idna==2.6
ipaddress==1.0.16
ndg-httpsclient==0.4.2
ndg-httpsclient==0.5.1
pyOpenSSL==18.0.0
pyasn1==0.1.9
pycparser==2.14

View File

@ -40,8 +40,9 @@ MEDIA_ROOT = ''
MEDIA_URL = '/media/'
# set once instead of in all the templates
JQUERY_HOME = "/static/js/jquery-1.7.1.min.js"
JQUERY_UI_HOME = "/static/js/jquery-ui-1.8.16.custom.min.js"
JQUERY_HOME = "/static/js/jquery-1.12.4.min.js"
JQUERY_UI_HOME = "/static/js/jquery-ui-1.12.1.custom.min.js"
JQUERY_UI_THEME = "/static/css/ui-lightness/jquery-ui-1.11.4.min.css"
CKEDITOR_UPLOAD_PATH = ''
CKEDITOR_RESTRICT_BY_USER = True
@ -124,13 +125,12 @@ TEMPLATES = [
]
MIDDLEWARE_CLASSES = (
MIDDLEWARE = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'maintenancemode.middleware.MaintenanceModeMiddleware',
'regluit.libraryauth.auth.SocialAuthExceptionMiddlewareWithoutMessages',
'django.middleware.locale.LocaleMiddleware',
'questionnaire.request_cache.RequestCacheMiddleware',
@ -166,6 +166,7 @@ INSTALLED_APPS = (
'notification',
'email_change',
'ckeditor',
'ckeditor_uploader',
'storages',
'sorl.thumbnail',
'mptt',
@ -187,11 +188,6 @@ SASS_PROCESSOR_INCLUDE_DIRS = [
]
SASS_PROCESSOR_AUTO_INCLUDE = False
# A sample logging configuration. The only tangible logging
# performed by this configuration is to send an email to
# the site admins on every HTTP 500 error.
# See http://docs.djangoproject.com/en/dev/topics/logging for
# more details on how to customize your logging configuration.
LOGGING = {
'version': 1,
'disable_existing_loggers': True,
@ -199,6 +195,10 @@ LOGGING = {
'brief': {
'format': '%(asctime)s %(levelname)s %(name)s[%(funcName)s]: %(message)s',
},
'django.server': {
'()': 'django.utils.log.ServerFormatter',
'format': '[%(server_time)s] %(message)s',
},
},
'filters': {
'require_debug_false': {
@ -219,6 +219,11 @@ LOGGING = {
'backupCount': 5,
'formatter': 'brief',
},
'django.server': {
'level': 'INFO',
'class': 'logging.StreamHandler',
'formatter': 'django.server',
},
},
'loggers': {
'django.request': {
@ -226,10 +231,15 @@ LOGGING = {
'level': 'ERROR',
'propagate': True,
},
'django.server': {
'handlers': ['django.server'],
'level': 'INFO',
'propagate': False,
},
'': {
'handlers': ['file'],
'level': 'INFO',
}
},
}
}
@ -411,13 +421,6 @@ NOTIFICATION_QUEUE_ALL = True
PAYMENT_PROCESSOR = 'stripelib'
# by default, we are not in maintenance mode -- set True in overriding settings files for maintenance mode
# http://pypi.python.org/pypi/django-maintenancemode/
MAINTENANCE_MODE = False
# Sequence of URL path regexes to exclude from the maintenance mode.
MAINTENANCE_IGNORE_URLS = {}
# we should suppress Google Analytics outside of production
SHOW_GOOGLE_ANALYTICS = False

View File

@ -71,8 +71,6 @@ CELERYD_HIJACK_ROOT_LOGGER = False
# a debug_toolbar setting
INTERNAL_IPS = ('127.0.0.1',)
CELERYD_LOG_LEVEL = "INFO"
# decide which of the period tasks to add to the schedule
#CELERYBEAT_SCHEDULE['send_test_email'] = SEND_TEST_EMAIL_JOB
#CELERYBEAT_SCHEDULE['refresh_acqs'] = REFRESH_ACQS_JOB

View File

@ -20,7 +20,9 @@ DATABASES = {
'PASSWORD': '',
'HOST': '',
'PORT': '',
'TEST_CHARSET': 'utf8',
'TEST': {
'CHARSET': 'utf8',
}
}
}

File diff suppressed because one or more lines are too long

5
static/js/jquery-1.12.4.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,9 +1,9 @@
from django.conf.urls import patterns, url, include
from django.conf.urls import url, include
from django.contrib.auth.decorators import login_required
from django.contrib.sitemaps.views import index, sitemap
from django.views.decorators.cache import never_cache
from ckeditor import views as ckedit_views
from ckeditor_uploader import views as ckedit_views
from regluit.admin import site
from regluit.core.sitemaps import WorkSitemap, PublisherSitemap
@ -21,7 +21,7 @@ urlpatterns = [
url(r'', include('regluit.marc.urls')),
url(r'^bisac/', include('regluit.bisac.urls')),
url(r'^selectable/', include('selectable.urls')),
url(r'^admin/', include(site.urls)),
url(r'^admin/', site.urls),
url(r'^comments/', include('django_comments.urls')),
url(r"^notification/", include('notification.urls')),
url(r'^ckeditor/upload/', login_required(ckedit_views.upload), name='ckeditor_upload'),