summaryrefslogtreecommitdiff
path: root/postgresqleu
diff options
context:
space:
mode:
authorMagnus Hagander2018-12-14 14:43:56 +0000
committerMagnus Hagander2018-12-14 15:31:28 +0000
commit7dea97f90b534f71cbec6d0e5dfbdf237403b1f1 (patch)
tree48c53ef74987f68c05f12fb1e97b02f25a13e45a /postgresqleu
parente0bfd4f892e43db89bc996c1474f59c2dd6a8dc6 (diff)
Fix blankline related warnings
Diffstat (limited to 'postgresqleu')
-rw-r--r--postgresqleu/_initial/__init__.py7
-rw-r--r--postgresqleu/accountinfo/lookups.py1
-rw-r--r--postgresqleu/accountinfo/views.py2
-rw-r--r--postgresqleu/accounting/admin.py10
-rw-r--r--postgresqleu/accounting/forms.py4
-rw-r--r--postgresqleu/accounting/models.py9
-rw-r--r--postgresqleu/accounting/util.py1
-rw-r--r--postgresqleu/accounting/views.py13
-rw-r--r--postgresqleu/adyen/admin.py7
-rw-r--r--postgresqleu/adyen/management/commands/process_adyen_reports.py4
-rw-r--r--postgresqleu/adyen/management/commands/reprocess_raw_adyen_notification.py1
-rwxr-xr-xpostgresqleu/adyen/management/commands/send_adyen_logreport.py2
-rw-r--r--postgresqleu/adyen/models.py6
-rw-r--r--postgresqleu/adyen/util.py11
-rw-r--r--postgresqleu/adyen/views.py5
-rw-r--r--postgresqleu/auth.py4
-rw-r--r--postgresqleu/braintreepayment/admin.py3
-rwxr-xr-xpostgresqleu/braintreepayment/management/commands/send_braintree_logreport.py1
-rwxr-xr-xpostgresqleu/braintreepayment/management/commands/update_braintree_transactions.py1
-rw-r--r--postgresqleu/braintreepayment/models.py2
-rw-r--r--postgresqleu/braintreepayment/util.py1
-rw-r--r--postgresqleu/braintreepayment/views.py6
-rw-r--r--postgresqleu/confreg/admin.py40
-rw-r--r--postgresqleu/confreg/backendforms.py82
-rw-r--r--postgresqleu/confreg/backendlookups.py3
-rw-r--r--postgresqleu/confreg/backendviews.py26
-rw-r--r--postgresqleu/confreg/dbimage.py3
-rw-r--r--postgresqleu/confreg/docsviews.py3
-rw-r--r--postgresqleu/confreg/feedback.py4
-rw-r--r--postgresqleu/confreg/feeds.py1
-rw-r--r--postgresqleu/confreg/forms.py19
-rw-r--r--postgresqleu/confreg/invoicehandler.py5
-rwxr-xr-xpostgresqleu/confreg/jinjabadge.py5
-rw-r--r--postgresqleu/confreg/jinjafunc.py9
-rw-r--r--postgresqleu/confreg/lookups.py2
-rw-r--r--postgresqleu/confreg/management/commands/confreg_expire_additionaloptions.py1
-rw-r--r--postgresqleu/confreg/management/commands/confreg_expire_waitlist.py1
-rw-r--r--postgresqleu/confreg/management/commands/confreg_frequent_reminders.py1
-rw-r--r--postgresqleu/confreg/management/commands/confreg_send_reminders.py4
-rw-r--r--postgresqleu/confreg/management/commands/confreg_warn_purge.py2
-rw-r--r--postgresqleu/confreg/migrations/0028_conferencenews.py1
-rw-r--r--postgresqleu/confreg/mobileviews.py4
-rw-r--r--postgresqleu/confreg/models.py41
-rw-r--r--postgresqleu/confreg/pdfschedule.py9
-rw-r--r--postgresqleu/confreg/regtypes.py13
-rw-r--r--postgresqleu/confreg/reporting.py23
-rw-r--r--postgresqleu/confreg/reportingforms.py2
-rw-r--r--postgresqleu/confreg/reports.py7
-rw-r--r--postgresqleu/confreg/templatetags/alertmap.py1
-rw-r--r--postgresqleu/confreg/templatetags/date_or_string.py1
-rw-r--r--postgresqleu/confreg/templatetags/dictutil.py1
-rw-r--r--postgresqleu/confreg/templatetags/docslink.py1
-rw-r--r--postgresqleu/confreg/templatetags/formutil.py4
-rw-r--r--postgresqleu/confreg/templatetags/join_days.py1
-rw-r--r--postgresqleu/confreg/templatetags/leadingnbsp.py1
-rw-r--r--postgresqleu/confreg/util.py3
-rw-r--r--postgresqleu/confreg/views.py70
-rw-r--r--postgresqleu/confreg/volsched.py6
-rw-r--r--postgresqleu/confsponsor/admin.py10
-rw-r--r--postgresqleu/confsponsor/backendforms.py18
-rw-r--r--postgresqleu/confsponsor/backendviews.py3
-rw-r--r--postgresqleu/confsponsor/benefitclasses/__init__.py2
-rw-r--r--postgresqleu/confsponsor/benefitclasses/attendeelist.py3
-rw-r--r--postgresqleu/confsponsor/benefitclasses/base.py3
-rw-r--r--postgresqleu/confsponsor/benefitclasses/entryvouchers.py2
-rw-r--r--postgresqleu/confsponsor/benefitclasses/imageupload.py3
-rw-r--r--postgresqleu/confsponsor/benefitclasses/providetext.py2
-rw-r--r--postgresqleu/confsponsor/benefitclasses/requireclaiming.py2
-rw-r--r--postgresqleu/confsponsor/benefits.py1
-rw-r--r--postgresqleu/confsponsor/forms.py6
-rw-r--r--postgresqleu/confsponsor/invoicehandler.py3
-rw-r--r--postgresqleu/confsponsor/management/commands/sponsor_generate_discount_invoices.py1
-rw-r--r--postgresqleu/confsponsor/models.py10
-rw-r--r--postgresqleu/confsponsor/util.py1
-rw-r--r--postgresqleu/confsponsor/vatutil.py1
-rw-r--r--postgresqleu/confsponsor/views.py24
-rw-r--r--postgresqleu/confwiki/admin.py6
-rw-r--r--postgresqleu/confwiki/forms.py6
-rw-r--r--postgresqleu/confwiki/models.py7
-rw-r--r--postgresqleu/confwiki/views.py12
-rw-r--r--postgresqleu/elections/admin.py4
-rw-r--r--postgresqleu/elections/forms.py1
-rw-r--r--postgresqleu/elections/models.py3
-rw-r--r--postgresqleu/elections/views.py5
-rw-r--r--postgresqleu/invoices/admin.py12
-rw-r--r--postgresqleu/invoices/forms.py4
-rw-r--r--postgresqleu/invoices/management/commands/process_refunds.py1
-rwxr-xr-xpostgresqleu/invoices/management/commands/send_invoice_reminders.py1
-rw-r--r--postgresqleu/invoices/management/commands/setup_payment_providers.py1
-rw-r--r--postgresqleu/invoices/migrations/0003_initial_invoice_processors.py1
-rw-r--r--postgresqleu/invoices/models.py7
-rw-r--r--postgresqleu/invoices/payment.py2
-rw-r--r--postgresqleu/invoices/templatetags/util.py1
-rw-r--r--postgresqleu/invoices/util.py9
-rw-r--r--postgresqleu/invoices/views.py25
-rw-r--r--postgresqleu/mailqueue/admin.py2
-rwxr-xr-xpostgresqleu/mailqueue/management/commands/send_queued_mail.py1
-rw-r--r--postgresqleu/mailqueue/models.py1
-rw-r--r--postgresqleu/mailqueue/util.py6
-rw-r--r--postgresqleu/membership/admin.py5
-rw-r--r--postgresqleu/membership/forms.py2
-rw-r--r--postgresqleu/membership/invoicehandler.py2
-rw-r--r--postgresqleu/membership/management/commands/membership_nightly.py2
-rw-r--r--postgresqleu/membership/models.py3
-rw-r--r--postgresqleu/membership/views.py7
-rw-r--r--postgresqleu/newsevents/admin.py3
-rw-r--r--postgresqleu/newsevents/feeds.py1
-rw-r--r--postgresqleu/newsevents/management/commands/register_news_twitter.py1
-rw-r--r--postgresqleu/newsevents/management/commands/twitter_post.py3
-rw-r--r--postgresqleu/newsevents/models.py1
-rw-r--r--postgresqleu/newsevents/views.py2
-rw-r--r--postgresqleu/paypal/admin.py3
-rw-r--r--postgresqleu/paypal/management/commands/paypal_fetch.py4
-rwxr-xr-xpostgresqleu/paypal/management/commands/paypal_match.py1
-rw-r--r--postgresqleu/paypal/management/commands/paypal_report.py1
-rw-r--r--postgresqleu/paypal/management/commands/refund_paypal_transaction.py1
-rw-r--r--postgresqleu/paypal/management/commands/verify_paypal_balance.py1
-rw-r--r--postgresqleu/paypal/models.py3
-rw-r--r--postgresqleu/paypal/util.py3
-rw-r--r--postgresqleu/paypal/views.py1
-rw-r--r--postgresqleu/static/views.py2
-rw-r--r--postgresqleu/trustlypayment/admin.py5
-rw-r--r--postgresqleu/trustlypayment/api.py3
-rwxr-xr-xpostgresqleu/trustlypayment/management/commands/send_trustly_logreport.py2
-rw-r--r--postgresqleu/trustlypayment/management/commands/trustly_match_refunds.py1
-rw-r--r--postgresqleu/trustlypayment/management/commands/verify_trustly_balance.py1
-rw-r--r--postgresqleu/trustlypayment/models.py5
-rw-r--r--postgresqleu/trustlypayment/util.py2
-rw-r--r--postgresqleu/trustlypayment/views.py3
-rw-r--r--postgresqleu/urls.py2
-rw-r--r--postgresqleu/util/context_processors.py4
-rw-r--r--postgresqleu/util/db.py7
-rw-r--r--postgresqleu/util/decorators.py4
-rw-r--r--postgresqleu/util/forms.py5
-rw-r--r--postgresqleu/util/jsonutil.py1
-rw-r--r--postgresqleu/util/management/commands/sessioninfo.py2
-rw-r--r--postgresqleu/util/messaging/twitter.py3
-rw-r--r--postgresqleu/util/middleware.py4
-rwxr-xr-xpostgresqleu/util/misc/pgeuinvoice.py6
-rw-r--r--postgresqleu/util/models.py1
-rw-r--r--postgresqleu/util/payment/adyen.py7
-rw-r--r--postgresqleu/util/payment/banktransfer.py1
-rw-r--r--postgresqleu/util/payment/braintree.py2
-rw-r--r--postgresqleu/util/payment/dummy.py1
-rw-r--r--postgresqleu/util/payment/paypal.py2
-rw-r--r--postgresqleu/util/random.py1
-rw-r--r--postgresqleu/util/storage.py3
-rw-r--r--postgresqleu/util/validators.py2
-rw-r--r--postgresqleu/util/widgets.py4
-rw-r--r--postgresqleu/views.py6
150 files changed, 735 insertions, 121 deletions
diff --git a/postgresqleu/_initial/__init__.py b/postgresqleu/_initial/__init__.py
index 60896c5a..2b7075a5 100644
--- a/postgresqleu/_initial/__init__.py
+++ b/postgresqleu/_initial/__init__.py
@@ -4,6 +4,7 @@ from django.contrib import admin
from postgresqleu.util.forms import ConcurrentProtectedModelForm
+
#
# Inject the ConcurrentProjectedModelForm into all ModelAdmins that don't
# explicitly specify override it. Do this by patching out the meaning
@@ -12,8 +13,8 @@ from postgresqleu.util.forms import ConcurrentProtectedModelForm
class ConcurrentInjectedAdmin(admin.ModelAdmin):
form = ConcurrentProtectedModelForm
-admin.ModelAdmin = ConcurrentInjectedAdmin
+admin.ModelAdmin = ConcurrentInjectedAdmin
#
@@ -23,10 +24,12 @@ admin.ModelAdmin = ConcurrentInjectedAdmin
# own injected model from above.
#
_oldreg = admin.site.register
+
+
def _concurrent_injected_register(self, model_or_iterable, admin_class=None, **options):
if admin_class is None:
admin_class = ConcurrentInjectedAdmin
return _oldreg(model_or_iterable, admin_class, **options)
-admin.site.register = types.MethodType(_concurrent_injected_register, admin.AdminSite)
+admin.site.register = types.MethodType(_concurrent_injected_register, admin.AdminSite)
diff --git a/postgresqleu/accountinfo/lookups.py b/postgresqleu/accountinfo/lookups.py
index 64e2f898..b9fa9b6d 100644
--- a/postgresqleu/accountinfo/lookups.py
+++ b/postgresqleu/accountinfo/lookups.py
@@ -23,4 +23,5 @@ class UserLookup(ModelLookup):
# Display for choice listings
return u"%s (%s <%s>)" % (item.username, item.get_full_name(), item.email)
+
registry.register(UserLookup)
diff --git a/postgresqleu/accountinfo/views.py b/postgresqleu/accountinfo/views.py
index 681bdeae..68d93e95 100644
--- a/postgresqleu/accountinfo/views.py
+++ b/postgresqleu/accountinfo/views.py
@@ -10,6 +10,7 @@ import json
from postgresqleu.util.decorators import user_passes_test_or_error
from postgresqleu.auth import user_search, user_import
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
def search(request):
@@ -39,6 +40,7 @@ def search(request):
'e': u['e'],
} for u in users]), content_type='application/json')
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
@transaction.atomic
diff --git a/postgresqleu/accounting/admin.py b/postgresqleu/accounting/admin.py
index 0d65eeec..3e8bc6dd 100644
--- a/postgresqleu/accounting/admin.py
+++ b/postgresqleu/accounting/admin.py
@@ -5,12 +5,15 @@ from django.forms.models import BaseInlineFormSet
from models import AccountClass, AccountGroup, Account, IncomingBalance
from models import JournalEntry, JournalItem, JournalUrl, Object, Year
+
class AccountClassAdmin(admin.ModelAdmin):
list_display = ('name', 'inbalance', 'balancenegative')
+
class AccountAdmin(admin.ModelAdmin):
list_display = ('num', 'name')
+
class JournalItemFormset(BaseInlineFormSet):
def clean(self):
super(JournalItemFormset, self).clean()
@@ -20,26 +23,33 @@ class JournalItemFormset(BaseInlineFormSet):
if s != 0:
raise ValidationError("Journal entry does not balance!")
+
class JournalItemInline(admin.TabularInline):
model = JournalItem
formset = JournalItemFormset
+
class JournalUrlInline(admin.TabularInline):
model = JournalUrl
+
class JournalEntryAdmin(admin.ModelAdmin):
inlines = [JournalItemInline, JournalUrlInline]
list_display = ('__unicode__', 'year', 'seq', 'date', 'closed')
+
class IncomingBalanceAdmin(admin.ModelAdmin):
list_display = ('__unicode__', 'year', 'account', 'amount')
+
class ObjectAdmin(admin.ModelAdmin):
list_display = ('name', 'active')
+
class YearAdmin(admin.ModelAdmin):
readonly_fields = ('year',)
+
admin.site.register(AccountClass, AccountClassAdmin)
admin.site.register(AccountGroup)
admin.site.register(Account, AccountAdmin)
diff --git a/postgresqleu/accounting/forms.py b/postgresqleu/accounting/forms.py
index 1c39098a..7a6f9cc4 100644
--- a/postgresqleu/accounting/forms.py
+++ b/postgresqleu/accounting/forms.py
@@ -5,6 +5,7 @@ from django.forms.models import BaseInlineFormSet
from models import JournalEntry, JournalItem, Object, JournalUrl
+
class JournalEntryForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(JournalEntryForm, self).__init__(*args, **kwargs)
@@ -20,6 +21,7 @@ def PositiveValidator(v):
if v <= 0:
raise ValidationError("Value must be a positive integer")
+
class JournalItemForm(forms.ModelForm):
debit = forms.DecimalField(max_digits=10, decimal_places=2, validators=[PositiveValidator, ], required=False)
credit = forms.DecimalField(max_digits=10, decimal_places=2, validators=[PositiveValidator, ], required=False)
@@ -86,6 +88,7 @@ class JournalItemForm(forms.ModelForm):
credit = self.cleaned_data.has_key('credit') and self.cleaned_data['credit'] or 0
return debit - credit
+
class JournalItemFormset(BaseInlineFormSet):
def clean(self):
super(JournalItemFormset, self).clean()
@@ -98,6 +101,7 @@ class JournalItemFormset(BaseInlineFormSet):
if n == 0:
raise ValidationError("Journal entry must have at least one item!")
+
class JournalUrlForm(forms.ModelForm):
class Meta:
model = JournalUrl
diff --git a/postgresqleu/accounting/models.py b/postgresqleu/accounting/models.py
index fee3d9fc..a261f147 100644
--- a/postgresqleu/accounting/models.py
+++ b/postgresqleu/accounting/models.py
@@ -1,16 +1,19 @@
from django.db import models
from django.core.exceptions import ValidationError
+
def nonzero_validator(value):
if value == 0:
raise ValidationError("Must be non-zero value!")
+
ACCOUNT_OBJECT_CHOICES = (
(0, "Optional"),
(1, "Required"),
(2, "Forbidden"),
)
+
class AccountClass(models.Model):
name = models.CharField(max_length=100)
inbalance = models.BooleanField(null=False, blank=False, default=False)
@@ -23,6 +26,7 @@ class AccountClass(models.Model):
verbose_name = 'Account classes'
ordering = ('name', )
+
class AccountGroup(models.Model):
name = models.CharField(max_length=100)
accountclass = models.ForeignKey(AccountClass, blank=False, default=False, on_delete=models.CASCADE)
@@ -34,6 +38,7 @@ class AccountGroup(models.Model):
class Meta:
ordering = ('name', )
+
class Account(models.Model):
num = models.IntegerField(verbose_name="Account number", unique=True)
group = models.ForeignKey(AccountGroup, null=False, blank=False, on_delete=models.CASCADE)
@@ -47,6 +52,7 @@ class Account(models.Model):
class Meta:
ordering = ('num', )
+
class Year(models.Model):
year = models.IntegerField(primary_key=True)
isopen = models.BooleanField(null=False, blank=False)
@@ -59,6 +65,7 @@ class Year(models.Model):
class Meta:
ordering = ('-year',)
+
class IncomingBalance(models.Model):
year = models.ForeignKey(Year, null=False, blank=False, on_delete=models.CASCADE)
account = models.ForeignKey(Account, to_field='num', null=False, blank=False, on_delete=models.CASCADE)
@@ -82,6 +89,7 @@ class Object(models.Model):
class Meta:
ordering = ('name', )
+
class JournalEntry(models.Model):
year = models.ForeignKey(Year, null=False, blank=False, on_delete=models.CASCADE)
seq = models.IntegerField(null=False, blank=False)
@@ -114,6 +122,7 @@ class JournalItem(models.Model):
return -self.amount
return ""
+
class JournalUrl(models.Model):
journal = models.ForeignKey(JournalEntry, null=False, blank=False, on_delete=models.CASCADE)
url = models.URLField(null=False, blank=False)
diff --git a/postgresqleu/accounting/util.py b/postgresqleu/accounting/util.py
index 61a2d100..3844fe15 100644
--- a/postgresqleu/accounting/util.py
+++ b/postgresqleu/accounting/util.py
@@ -11,6 +11,7 @@ from decimal import Decimal
from models import JournalEntry, JournalItem, JournalUrl
from models import Object, Account, Year
+
class AccountingException(Exception):
pass
diff --git a/postgresqleu/accounting/views.py b/postgresqleu/accounting/views.py
index 700308f7..b94597af 100644
--- a/postgresqleu/accounting/views.py
+++ b/postgresqleu/accounting/views.py
@@ -15,6 +15,7 @@ from models import JournalEntry, JournalItem, JournalUrl, Year, Object
from models import IncomingBalance, Account
from forms import JournalEntryForm, JournalItemForm, JournalItemFormset, JournalUrlForm
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('accounting'))
def index(request):
@@ -29,6 +30,7 @@ def _setup_search(request, term):
if request.session.has_key('searchterm'):
del request.session['searchterm']
+
def _perform_search(request, year):
if request.session.has_key('searchterm'):
searchterm = request.session['searchterm']
@@ -39,6 +41,7 @@ def _perform_search(request, year):
return ('', list(JournalEntry.objects.filter(year=year).order_by('closed', '-date', '-id')))
+
class EntryPaginator(Paginator):
ENTRIES_PER_PAGE = 50
@@ -58,6 +61,7 @@ class EntryPaginator(Paginator):
else:
return self.page_range
+
@login_required
@transaction.atomic
@user_passes_test_or_error(lambda u: u.has_module_perms('accounting'))
@@ -67,7 +71,6 @@ def year(request, year):
_setup_search(request, request.GET['search'])
return HttpResponseRedirect('/accounting/%s/' % year.year)
-
(searchterm, entries) = _perform_search(request, year)
paginator = EntryPaginator(entries)
@@ -84,6 +87,7 @@ def year(request, year):
'searchterm': searchterm,
})
+
@login_required
@transaction.atomic
@user_passes_test_or_error(lambda u: u.has_module_perms('accounting'))
@@ -111,6 +115,7 @@ def new(request, year):
return HttpResponseRedirect('/accounting/e/%s/' % entry.pk)
+
@login_required
@transaction.atomic
@user_passes_test_or_error(lambda u: u.has_module_perms('accounting'))
@@ -178,6 +183,7 @@ def entry(request, entryid):
'searchterm': searchterm,
})
+
def _get_balance_query(objstr='', includeopen=False):
q = """WITH currentyear AS (
SELECT account_id AS accountnum, sum(amount) FILTER (WHERE je.closed) as closedamount, sum(amount) FILTER (WHERE NOT je.closed) as openamount FROM accounting_journalitem ji INNER JOIN accounting_journalentry je ON ji.journal_id=je.id WHERE je.year_id=%(year)s AND je.date <= %(enddate)s """ + objstr + """ GROUP BY account_id
@@ -192,8 +198,10 @@ SELECT ac.name AS acname, ag.name AS agname, anum, a.name,
def _get_sumcol(sourcecol, partition):
return "sum(%s*case when balancenegative then -1 else 1 end) over (partition by %s)" % (sourcecol, partition)
+
def _get_negcol(sourcecol):
return "%s*case when balancenegative then -1 else 1 end" % sourcecol
+
def _get_totalcol(sourcecol):
return "sum(%s) over ()" % sourcecol
@@ -220,6 +228,7 @@ SELECT ac.name AS acname, ag.name AS agname, anum, a.name,
"""
return q
+
def _collate_results(query, queryparam, numvalues):
results = []
lastag = ''
@@ -277,6 +286,7 @@ def _collate_results(query, queryparam, numvalues):
return (results, totalresult)
+
@login_required
@transaction.atomic
@user_passes_test_or_error(lambda u: u.has_module_perms('accounting'))
@@ -357,6 +367,7 @@ SELECT ac.name AS acname, ag.name AS agname, anum, a.name,
'accounts': Account.objects.filter(group__accountclass__inbalance=True),
})
+
@login_required
@transaction.atomic
@user_passes_test_or_error(lambda u: u.has_module_perms('accounting'))
diff --git a/postgresqleu/adyen/admin.py b/postgresqleu/adyen/admin.py
index 2b159173..d3e1a4a8 100644
--- a/postgresqleu/adyen/admin.py
+++ b/postgresqleu/adyen/admin.py
@@ -5,6 +5,7 @@ from django.urls import reverse
from models import RawNotification, Notification
from models import Report, TransactionStatus, AdyenLog, Refund
+
class RawNotificationAdmin(admin.ModelAdmin):
list_display = ('dat', 'confirmed',)
readonly_fields = ('notification_link', )
@@ -16,6 +17,7 @@ class RawNotificationAdmin(admin.ModelAdmin):
return mark_safe('<a href="%s">%s</a>' % (url, n))
notification_link.short_description = 'Notification'
+
class NotificationAdmin(admin.ModelAdmin):
list_display = ('receivedat', 'eventDate', 'merchantAccountCode', 'eventCode', 'live', 'success', 'confirmed', 'pspReference', )
readonly_fields = ('rawnotification_link',)
@@ -27,9 +29,11 @@ class NotificationAdmin(admin.ModelAdmin):
return mark_safe('<a href="%s">%s</a>' % (url, obj))
rawnotification_link.short_description = 'Rawnotification'
+
class ReportAdmin(admin.ModelAdmin):
list_display = ('receivedat', 'downloadedat', 'processedat', 'url',)
+
class TransactionStatusAdmin(admin.ModelAdmin):
list_display = ('pspReference', 'amount', 'settledamount', 'authorizedat', 'capturedat', 'settledat', 'method', 'refund')
readonly_fields = ('notification_link', 'refund_link', )
@@ -50,6 +54,7 @@ class TransactionStatusAdmin(admin.ModelAdmin):
return "Not refunded"
refund_link.short_description = 'Refund'
+
class RefundAdmin(admin.ModelAdmin):
list_display = ('notification', 'receivedat', 'transaction', 'refund_amount')
readonly_fields = ('notification_link', 'transaction_link', )
@@ -67,6 +72,7 @@ class RefundAdmin(admin.ModelAdmin):
return mark_safe('<a href="%s">%s</a>' % (url, obj.transaction.pspReference))
transaction_link.short_description = 'Transaction'
+
class AdyenLogAdmin(admin.ModelAdmin):
list_display = ('timestamp', 'success', 'sentstr', 'pspReference', 'message', )
@@ -78,6 +84,7 @@ class AdyenLogAdmin(admin.ModelAdmin):
return obj.sent and 'Yes' or 'No'
sentstr.short_description = 'Log sent'
+
admin.site.register(RawNotification, RawNotificationAdmin)
admin.site.register(Notification, NotificationAdmin)
admin.site.register(Report, ReportAdmin)
diff --git a/postgresqleu/adyen/management/commands/process_adyen_reports.py b/postgresqleu/adyen/management/commands/process_adyen_reports.py
index 30320bf1..ec9b24d4 100644
--- a/postgresqleu/adyen/management/commands/process_adyen_reports.py
+++ b/postgresqleu/adyen/management/commands/process_adyen_reports.py
@@ -19,6 +19,7 @@ from postgresqleu.adyen.models import AdyenLog, Report, TransactionStatus
from postgresqleu.mailqueue.util import send_simple_mail
from postgresqleu.accounting.util import create_accounting_entry
+
class Command(BaseCommand):
help = 'Download and/or process reports from Adyen'
@@ -61,8 +62,6 @@ class Command(BaseCommand):
# was just a download issue which is most likely.
AdyenLog(message='Failed to download report %s: %s' % (report.url, ex), error=True).save()
-
-
def process_payment_accounting_report(self, report):
sio = StringIO.StringIO(report.contents)
reader = csv.DictReader(sio, delimiter=',')
@@ -202,7 +201,6 @@ class Command(BaseCommand):
msg
)
-
def process_reports(self):
# Process all downloaded but unprocessed reports
diff --git a/postgresqleu/adyen/management/commands/reprocess_raw_adyen_notification.py b/postgresqleu/adyen/management/commands/reprocess_raw_adyen_notification.py
index 6f091a5d..ec2fd198 100644
--- a/postgresqleu/adyen/management/commands/reprocess_raw_adyen_notification.py
+++ b/postgresqleu/adyen/management/commands/reprocess_raw_adyen_notification.py
@@ -29,4 +29,3 @@ class Command(BaseCommand):
process_raw_adyen_notification(rawnotification, POST)
self.stdout.write("Completed reprocessing raw notification {0}".format(rawnotification.id))
-
diff --git a/postgresqleu/adyen/management/commands/send_adyen_logreport.py b/postgresqleu/adyen/management/commands/send_adyen_logreport.py
index 88447a50..bd8ba844 100755
--- a/postgresqleu/adyen/management/commands/send_adyen_logreport.py
+++ b/postgresqleu/adyen/management/commands/send_adyen_logreport.py
@@ -14,6 +14,7 @@ from StringIO import StringIO
from postgresqleu.adyen.models import AdyenLog, Notification, TransactionStatus
from postgresqleu.mailqueue.util import send_simple_mail
+
class Command(BaseCommand):
help = 'Send log information about Adyen events'
@@ -68,4 +69,3 @@ class Command(BaseCommand):
settings.ADYEN_NOTIFICATION_RECEIVER,
'Adyen integration unconfirmed notifications',
sio.getvalue())
-
diff --git a/postgresqleu/adyen/models.py b/postgresqleu/adyen/models.py
index f250f26b..d7d593e3 100644
--- a/postgresqleu/adyen/models.py
+++ b/postgresqleu/adyen/models.py
@@ -1,5 +1,6 @@
from django.db import models
+
class RawNotification(models.Model):
# This class contains the raw http POSTs of all notifications received
# from Adyen. They will only end up unconfirmed here if sometihng
@@ -11,6 +12,7 @@ class RawNotification(models.Model):
def __unicode__(self):
return "%s" % self.dat
+
class Notification(models.Model):
receivedat = models.DateTimeField(null=False, blank=False, auto_now_add=True, unique=True)
rawnotification = models.ForeignKey(RawNotification, null=True, blank=True, on_delete=models.CASCADE)
@@ -35,6 +37,7 @@ class Notification(models.Model):
def __unicode__(self):
return "%s" % self.receivedat
+
class Report(models.Model):
receivedat = models.DateTimeField(null=False, blank=False, auto_now_add=True)
notification = models.ForeignKey(Notification, null=False, blank=False, on_delete=models.CASCADE)
@@ -43,6 +46,7 @@ class Report(models.Model):
contents = models.TextField(null=True, blank=True)
processedat = models.DateTimeField(null=True, blank=True)
+
class TransactionStatus(models.Model):
pspReference = models.CharField(max_length=100, null=False, blank=False, unique=True)
notification = models.ForeignKey(Notification, null=False, blank=False, on_delete=models.CASCADE)
@@ -61,6 +65,7 @@ class TransactionStatus(models.Model):
class Meta:
verbose_name_plural = 'Transaction statuses'
+
class Refund(models.Model):
receivedat = models.DateTimeField(null=False, blank=False, auto_now_add=True)
notification = models.ForeignKey(Notification, null=False, blank=False, on_delete=models.CASCADE)
@@ -70,6 +75,7 @@ class Refund(models.Model):
def __unicode__(self):
return unicode(self.refund_amount)
+
class ReturnAuthorizationStatus(models.Model):
pspReference = models.CharField(max_length=100, null=False, blank=False, primary_key=True)
seencount = models.IntegerField(null=False, default=0)
diff --git a/postgresqleu/adyen/util.py b/postgresqleu/adyen/util.py
index 3cc981d9..7a0604cd 100644
--- a/postgresqleu/adyen/util.py
+++ b/postgresqleu/adyen/util.py
@@ -16,6 +16,7 @@ from postgresqleu.accounting.util import create_accounting_entry
from models import TransactionStatus, Report, AdyenLog, Notification, Refund
+
# Internal exception class
class AdyenProcessingException(Exception):
pass
@@ -116,7 +117,6 @@ def process_authorization(notification):
notification.save()
return
-
if invoice.accounting_object:
# Store the accounting object so we can properly tag the
# fee for it when we process the settlement (since we don't
@@ -158,6 +158,7 @@ def process_authorization(notification):
notification.confirmed = True
notification.save()
+
def process_capture(notification):
if notification.success:
# Successful capture, so we just set when the capture happened
@@ -181,6 +182,7 @@ def process_capture(notification):
notification.confirmed = True
notification.save()
+
def process_refund(notification):
# Store the refund, and send an email!
if notification.success:
@@ -248,6 +250,7 @@ def process_refund(notification):
notification.confirmed = True
notification.save()
+
def process_new_report(notification):
# Just store the fact that this report is available. We'll have an
# asynchronous cronjob that downloads and processes the reports.
@@ -302,9 +305,6 @@ def process_one_notification(notification):
# unverified notifications.
-
-
-
def process_raw_adyen_notification(raw, POST):
# Process a single raw Adyen notification. Must *not* be called in
# a transactional context, as it manages it's own.
@@ -381,14 +381,12 @@ def process_raw_adyen_notification(raw, POST):
return True
-
#
# Accesspoints into the Adyen API
#
# Most of the API is off limits to us due to lack of PCI, but we can do a couple
# of important things like refunding.
#
-
class AdyenAPI(object):
def refund_transaction(self, refundid, transreference, amount):
apiparam = {
@@ -410,7 +408,6 @@ class AdyenAPI(object):
refundid,
e))
-
def _api_call(self, apiurl, apiparam, okresponse):
apijson = json.dumps(apiparam)
diff --git a/postgresqleu/adyen/views.py b/postgresqleu/adyen/views.py
index 8661123e..63ff0c1b 100644
--- a/postgresqleu/adyen/views.py
+++ b/postgresqleu/adyen/views.py
@@ -16,6 +16,7 @@ from postgresqleu.invoices.util import InvoiceManager
from models import RawNotification, AdyenLog, ReturnAuthorizationStatus
from util import process_raw_adyen_notification
+
@transaction.atomic
def adyen_return_handler(request):
sig = calculate_signature(request.GET)
@@ -90,6 +91,7 @@ def adyen_return_handler(request):
'result': request.GET['authResult'],
})
+
@global_login_exempt
@csrf_exempt
def adyen_notify_handler(request):
@@ -126,7 +128,6 @@ def adyen_notify_handler(request):
return HttpResponse('[internal error]', content_type='text/plain')
-
# Rendered views to do bank payment
def _invoice_payment(request, invoice):
method = AdyenBanktransfer()
@@ -137,6 +138,7 @@ def _invoice_payment(request, invoice):
'paymenturl': paymenturl,
})
+
@login_required
def invoicepayment(request, invoiceid):
invoice = get_object_or_404(Invoice, pk=invoiceid, deleted=False, finalized=True)
@@ -145,6 +147,7 @@ def invoicepayment(request, invoiceid):
return _invoice_payment(request, invoice)
+
def invoicepayment_secret(request, invoiceid, secret):
invoice = get_object_or_404(Invoice, pk=invoiceid, deleted=False, finalized=True, recipient_secret=secret)
return _invoice_payment(request, invoice)
diff --git a/postgresqleu/auth.py b/postgresqleu/auth.py
index 776562d5..a84214c7 100644
--- a/postgresqleu/auth.py
+++ b/postgresqleu/auth.py
@@ -35,6 +35,7 @@ from Crypto.Hash import SHA
from Crypto import Random
import time
+
class AuthBackend(ModelBackend):
# We declare a fake backend that always fails direct authentication -
# since we should never be using direct authentication in the first place!
@@ -67,6 +68,7 @@ def login(request):
else:
return HttpResponseRedirect(settings.PGAUTH_REDIRECT)
+
# Handle logout requests by logging out of this site and then
# redirecting to log out from the main site as well.
def logout(request):
@@ -74,6 +76,7 @@ def logout(request):
django_logout(request)
return HttpResponseRedirect("%slogout/" % settings.PGAUTH_REDIRECT)
+
# Receive an authentication response from the main website and try
# to log the user in.
def auth_receive(request):
@@ -204,6 +207,7 @@ def user_search(searchterm=None, userid=None):
return j
+
# Import a user into the local authentication system. Will initially
# make a search for it, and if anything other than one entry is returned
# the import will fail.
diff --git a/postgresqleu/braintreepayment/admin.py b/postgresqleu/braintreepayment/admin.py
index 67e71289..533cec13 100644
--- a/postgresqleu/braintreepayment/admin.py
+++ b/postgresqleu/braintreepayment/admin.py
@@ -2,10 +2,12 @@ from django.contrib import admin
from models import BraintreeTransaction, BraintreeLog
+
class BraintreeTransactionAdmin(admin.ModelAdmin):
list_display = ('transid', 'amount', 'disbursedamount', 'authorizedat', 'settledat', 'disbursedat', 'method')
search_fields = ('transid',)
+
class BraintreeLogAdmin(admin.ModelAdmin):
list_display = ('timestamp', 'success', 'sentstr', 'transid', 'message', )
@@ -17,5 +19,6 @@ class BraintreeLogAdmin(admin.ModelAdmin):
return obj.sent and 'Yes' or 'No'
sentstr.short_description = 'Log sent'
+
admin.site.register(BraintreeTransaction, BraintreeTransactionAdmin)
admin.site.register(BraintreeLog, BraintreeLogAdmin)
diff --git a/postgresqleu/braintreepayment/management/commands/send_braintree_logreport.py b/postgresqleu/braintreepayment/management/commands/send_braintree_logreport.py
index 98cfb89b..c6dae583 100755
--- a/postgresqleu/braintreepayment/management/commands/send_braintree_logreport.py
+++ b/postgresqleu/braintreepayment/management/commands/send_braintree_logreport.py
@@ -12,6 +12,7 @@ from StringIO import StringIO
from postgresqleu.braintreepayment.models import BraintreeLog
from postgresqleu.mailqueue.util import send_simple_mail
+
class Command(BaseCommand):
help = 'Send log information about Braintree events'
diff --git a/postgresqleu/braintreepayment/management/commands/update_braintree_transactions.py b/postgresqleu/braintreepayment/management/commands/update_braintree_transactions.py
index 09f54141..e8b3bb66 100755
--- a/postgresqleu/braintreepayment/management/commands/update_braintree_transactions.py
+++ b/postgresqleu/braintreepayment/management/commands/update_braintree_transactions.py
@@ -20,6 +20,7 @@ from postgresqleu.braintreepayment.models import BraintreeTransaction, Braintree
from postgresqleu.braintreepayment.util import initialize_braintree
from postgresqleu.accounting.util import create_accounting_entry
+
# We need to filter the log messages since libraries used by the
# braintree integration spit out debugging information as INFO.
class LogFilter(object):
diff --git a/postgresqleu/braintreepayment/models.py b/postgresqleu/braintreepayment/models.py
index 041c8f7b..5125ab37 100644
--- a/postgresqleu/braintreepayment/models.py
+++ b/postgresqleu/braintreepayment/models.py
@@ -1,5 +1,6 @@
from django.db import models
+
class BraintreeTransaction(models.Model):
transid = models.CharField(max_length=100, null=False, blank=False, unique=True)
authorizedat = models.DateTimeField(null=False, blank=False)
@@ -13,6 +14,7 @@ class BraintreeTransaction(models.Model):
def __unicode__(self):
return self.transid
+
class BraintreeLog(models.Model):
timestamp = models.DateTimeField(null=False, blank=False, auto_now_add=True)
transid = models.CharField(max_length=100, null=False, blank=False)
diff --git a/postgresqleu/braintreepayment/util.py b/postgresqleu/braintreepayment/util.py
index b258cd6c..6ea6a665 100644
--- a/postgresqleu/braintreepayment/util.py
+++ b/postgresqleu/braintreepayment/util.py
@@ -2,6 +2,7 @@ import braintree
from django.conf import settings
+
def initialize_braintree():
# Set up braintree APIs
braintree.Configuration.configure(
diff --git a/postgresqleu/braintreepayment/views.py b/postgresqleu/braintreepayment/views.py
index 99d43093..e4f94377 100644
--- a/postgresqleu/braintreepayment/views.py
+++ b/postgresqleu/braintreepayment/views.py
@@ -15,9 +15,11 @@ from postgresqleu.mailqueue.util import send_simple_mail
from models import BraintreeTransaction, BraintreeLog
from util import initialize_braintree
+
class BraintreeProcessingException(Exception):
pass
+
def payment_post(request):
nonce = request.POST['payment_method_nonce']
invoice = get_object_or_404(Invoice, pk=request.POST['invoice'], deleted=False, finalized=True)
@@ -68,7 +70,6 @@ def payment_post(request):
'contact': settings.INVOICE_SENDER_EMAIL,
})
-
with transaction.atomic():
# Flag the invoice as paid
manager = InvoiceManager()
@@ -128,6 +129,7 @@ def payment_post(request):
'url': returnurl,
})
+
def _invoice_payment(request, invoice):
initialize_braintree()
token = braintree.ClientToken.generate({})
@@ -137,6 +139,7 @@ def _invoice_payment(request, invoice):
'token': token,
})
+
@login_required
def invoicepayment(request, invoiceid):
invoice = get_object_or_404(Invoice, pk=invoiceid, deleted=False, finalized=True)
@@ -145,6 +148,7 @@ def invoicepayment(request, invoiceid):
return _invoice_payment(request, invoice)
+
def invoicepayment_secret(request, invoiceid, secret):
invoice = get_object_or_404(Invoice, pk=invoiceid, deleted=False, finalized=True, recipient_secret=secret)
return _invoice_payment(request, invoice)
diff --git a/postgresqleu/confreg/admin.py b/postgresqleu/confreg/admin.py
index 80c8a53a..34a8ae50 100644
--- a/postgresqleu/confreg/admin.py
+++ b/postgresqleu/confreg/admin.py
@@ -36,12 +36,14 @@ from postgresqleu.confsponsor.models import Sponsor
from datetime import datetime
import urllib
+
#
# List filters
#
class TrackListFilter(admin.SimpleListFilter):
title = 'Track'
parameter_name = 'track'
+
def lookups(self, request, model_admin):
cid = request.GET.get('conference__id__exact', -1)
if cid >= 0:
@@ -51,9 +53,11 @@ class TrackListFilter(admin.SimpleListFilter):
if self.value():
return queryset.filter(track_id=self.value())
+
class RegtypeListFilter(admin.SimpleListFilter):
title = 'Registration type'
parameter_name = 'regtype'
+
def lookups(self, request, model_admin):
cid = request.GET.get('conference__id__exact', -1)
if cid >= 0:
@@ -63,9 +67,11 @@ class RegtypeListFilter(admin.SimpleListFilter):
if self.value():
return queryset.filter(regtype_id=self.value())
+
class AdditionalOptionListFilter(admin.SimpleListFilter):
title = 'Additional option'
parameter_name = 'addoption'
+
def lookups(self, request, model_admin):
cid = request.GET.get('conference__id__exact', -1)
if cid >= 0:
@@ -75,6 +81,7 @@ class AdditionalOptionListFilter(admin.SimpleListFilter):
if self.value():
return queryset.filter(additionaloptions__id=self.value())
+
#
# General admin classes
#
@@ -86,9 +93,11 @@ class ConferenceSeriesAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtec
'administrators': AutoCompleteSelectMultipleWidget(lookup_class=UserLookup),
}
+
class ConferenceSeriesAdmin(admin.ModelAdmin):
form = ConferenceSeriesAdminForm
+
class ConferenceAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelForm):
class Meta:
model = Conference
@@ -112,11 +121,13 @@ class ConferenceAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedMod
return data
+
class ConferenceAdmin(admin.ModelAdmin):
form = ConferenceAdminForm
list_display = ('conferencename', 'active', 'callforpapersopen', 'callforsponsorsopen', 'feedbackopen', 'startdate', 'enddate')
ordering = ('-startdate', )
+
class ConferenceRegistrationForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelForm):
class Meta:
model = ConferenceRegistration
@@ -215,6 +226,7 @@ class ConferenceRegistrationAdmin(admin.ModelAdmin):
else:
return False
+
class ConferenceSessionForm(ConcurrentProtectedModelForm):
class Meta:
model = ConferenceSession
@@ -276,21 +288,25 @@ class ConferenceSessionAdmin(admin.ModelAdmin):
return HttpResponseRedirect('/admin/confreg/_email_session_speaker/%s/?orig=%s' % (','.join(selected), urllib.quote(urllib.urlencode(request.GET))))
email_recipients.short_description = "Send email to speakers of selected sessions"
+
class ConferenceSessionScheduleSlotAdmin(admin.ModelAdmin):
list_display = ['conference', 'starttime', 'endtime', ]
list_filter = ['conference']
ordering = ['starttime', ]
+
class RegistrationClassAdmin(admin.ModelAdmin):
list_display = ['regclass', 'conference', ]
list_filter = ['conference', ]
ordering = ['conference', 'regclass', ]
+
class RegistrationDayAdmin(admin.ModelAdmin):
list_display = ['day', 'conference', ]
list_filter = ['conference', ]
ordering = ['conference', 'day', ]
+
class RegistrationTypeAdminForm(ConcurrentProtectedModelForm):
class Meta:
model = RegistrationType
@@ -309,6 +325,7 @@ class RegistrationTypeAdminForm(ConcurrentProtectedModelForm):
# that we couldn't list it.
pass
+
class RegistrationTypeAdmin(admin.ModelAdmin):
list_display = ['conference', 'regtype', 'cost', 'sortkey', 'active', 'activeuntil', ]
list_filter = ['conference', ]
@@ -316,9 +333,11 @@ class RegistrationTypeAdmin(admin.ModelAdmin):
filter_horizontal = ('requires_option', )
form = RegistrationTypeAdminForm
+
class ShirtsizeAdmin(admin.ModelAdmin):
list_display = ['shirtsize', 'sortkey', ]
+
class ConferenceAdditionalOptionAdminForm(ConcurrentProtectedModelForm):
class Meta:
model = ConferenceAdditionalOption
@@ -334,6 +353,7 @@ class ConferenceAdditionalOptionAdminForm(ConcurrentProtectedModelForm):
# that we couldn't list it.
pass
+
class ConferenceAdditionalOptionAdmin(admin.ModelAdmin):
list_display = ['conference', 'name', 'maxcount', 'cost', 'used_count', 'confirmed_count', 'unconfirmed_count']
list_filter = ['conference', ]
@@ -360,6 +380,7 @@ class ConferenceAdditionalOptionAdmin(admin.ModelAdmin):
return inst.confirmed_count + inst.unconfirmed_count
used_count.short_description = 'Total used'
+
class SpeakerAdminForm(ConcurrentProtectedModelForm):
class Meta:
model = Speaker
@@ -386,18 +407,21 @@ class SpeakerAdminForm(ConcurrentProtectedModelForm):
raise ValidationError("Maximum image size is 128x128")
return self.cleaned_data['photofile']
+
class SpeakerAdmin(admin.ModelAdmin):
list_display = ['user', 'email', 'fullname', 'has_abstract', 'has_photo']
search_fields = ['fullname', 'user__email']
ordering = ['fullname']
form = SpeakerAdminForm
+
class SpeakerPhotoAdmin(admin.ModelAdmin):
def formfield_for_dbfield(self, db_field, **kwargs):
if db_field.name == 'photo':
kwargs['widget'] = InlinePhotoWidget
return super(SpeakerPhotoAdmin, self).formfield_for_dbfield(db_field, **kwargs)
+
class TrackAdmin(admin.ModelAdmin):
list_filter = ['conference', ]
list_display = ['conference', 'trackname', 'sortkey', 'color', 'incfp', ]
@@ -405,16 +429,19 @@ class TrackAdmin(admin.ModelAdmin):
class Meta:
model = Track
+
class RoomAdmin(admin.ModelAdmin):
list_filter = ['conference', ]
class Meta:
model = Room
+
class ConferenceFeedbackQuestionAdmin(admin.ModelAdmin):
list_display = ['conference', 'sortkey', 'newfieldset', 'question', ]
list_filter = ['conference', ]
+
class PrepaidVoucherInline(admin.TabularInline):
model = PrepaidVoucher
readonly_fields = ['user', 'usedate', ]
@@ -422,6 +449,7 @@ class PrepaidVoucherInline(admin.TabularInline):
extra = 0
can_delete = False
+
class PrepaidBatchAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelForm):
class Meta:
model = PrepaidBatch
@@ -458,6 +486,7 @@ class PrepaidBatchAdmin(admin.ModelAdmin):
return inst.used
used_num.short_description = 'Used vouchers'
+
class PrepaidVoucherAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelForm):
class Meta:
model = PrepaidVoucher
@@ -475,6 +504,7 @@ class PrepaidVoucherAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtecte
except Conference.DoesNotExist:
pass
+
class PrepaidVoucherAdmin(admin.ModelAdmin):
list_display = ['vouchervalue', 'conference', 'buyername', 'usedby', 'usedate', ]
list_filter = ['conference', ]
@@ -490,6 +520,7 @@ class PrepaidVoucherAdmin(admin.ModelAdmin):
return "%s %s" % (obj.user.firstname, obj.user.lastname)
return None
+
class DiscountCodeAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelForm):
class Meta:
model = DiscountCode
@@ -540,11 +571,13 @@ class DiscountCodeAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedM
return cleaned_data
+
class DiscountCodeAdmin(admin.ModelAdmin):
list_display = ['code', 'conference', 'maxuses', 'count', ]
list_filter = ['conference', ]
form = DiscountCodeAdminForm
+
class BulkPaymentAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelForm):
class Meta:
model = BulkPayment
@@ -553,11 +586,13 @@ class BulkPaymentAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedMo
'user': AutoCompleteSelectWidget(lookup_class=UserLookup),
}
+
class BulkPaymentAdmin(admin.ModelAdmin):
form = BulkPaymentAdminForm
list_display = ['adminstring', 'conference', 'user', 'numregs', 'paidat', 'ispaid', ]
list_filter = ['conference', ]
+
class AttendeeMailAdminForm(ConcurrentProtectedModelForm):
class Meta:
model = AttendeeMail
@@ -568,10 +603,12 @@ class AttendeeMailAdminForm(ConcurrentProtectedModelForm):
if 'instance' in kwargs:
self.fields['regclasses'].queryset = RegistrationClass.objects.filter(conference=self.instance.conference)
+
class AttendeeMailAdmin(admin.ModelAdmin):
form = AttendeeMailAdminForm
filter_horizontal = ('regclasses', )
+
class PendingAdditionalOrderAdminForm(ConcurrentProtectedModelForm):
class Meta:
model = PendingAdditionalOrder
@@ -584,10 +621,12 @@ class PendingAdditionalOrderAdminForm(ConcurrentProtectedModelForm):
self.fields['options'].queryset = ConferenceAdditionalOption.objects.filter(conference=self.instance.reg.conference)
self.fields['newregtype'].queryset = RegistrationType.objects.filter(conference=self.instance.reg.conference)
+
class PendingAdditionalOrderAdmin(admin.ModelAdmin):
form = PendingAdditionalOrderAdminForm
list_display = ('reg', 'createtime', 'payconfirmedat')
+
class VolunteerSlotAdminForm(ConcurrentProtectedModelForm):
class Meta:
model = VolunteerSlot
@@ -603,6 +642,7 @@ class VolunteerSlotAdminForm(ConcurrentProtectedModelForm):
raise ValidationError("Max staff can't be less than min staff!")
return data
+
class VolunteerSlotAdmin(admin.ModelAdmin):
form = VolunteerSlotAdminForm
list_filter = ['conference', ]
diff --git a/postgresqleu/confreg/backendforms.py b/postgresqleu/confreg/backendforms.py
index 932fe4a6..7a16369b 100644
--- a/postgresqleu/confreg/backendforms.py
+++ b/postgresqleu/confreg/backendforms.py
@@ -30,10 +30,12 @@ from postgresqleu.confreg.models import valid_status_transitions, get_status_str
from backendlookups import GeneralAccountLookup, RegisteredUsersLookup, SpeakerLookup
+
class _NewFormDataField(django.forms.Field):
required = True
widget = django.forms.HiddenInput
+
class BackendForm(ConcurrentProtectedModelForm):
selectize_multiple_fields = None
json_fields = None
@@ -70,7 +72,6 @@ class BackendForm(ConcurrentProtectedModelForm):
else:
del self.fields['_newformdata']
-
self.fix_fields()
self.fix_selectize_fields(**kwargs)
@@ -160,13 +161,21 @@ class BackendForm(ConcurrentProtectedModelForm):
def validator_field(self):
return self['_validator']
-
def get(self, name, default=None):
# Implement the get operator, for template functions to get a field
return self[name]
+
class BackendConferenceForm(BackendForm):
helplink = 'configuring#conferenceform'
+ markdown_fields = ['promotext', ]
+ selectize_multiple_fields = {
+ 'testers': GeneralAccountLookup(),
+ 'talkvoters': GeneralAccountLookup(),
+ 'staff': GeneralAccountLookup(),
+ 'volunteers': RegisteredUsersLookup(None),
+ }
+
class Meta:
model = Conference
fields = ['active', 'callforpapersopen', 'callforsponsorsopen', 'feedbackopen',
@@ -178,13 +187,6 @@ class BackendConferenceForm(BackendForm):
'asktshirt', 'askfood', 'asknick', 'asktwitter', 'askshareemail', 'askphotoconsent',
'skill_levels', 'additionalintro', 'callforpapersintro', 'sendwelcomemail', 'welcomemail',
'invoice_autocancel_hours', 'attendees_before_waitlist']
- markdown_fields = ['promotext', ]
- selectize_multiple_fields = {
- 'testers': GeneralAccountLookup(),
- 'talkvoters': GeneralAccountLookup(),
- 'staff': GeneralAccountLookup(),
- 'volunteers': RegisteredUsersLookup(None),
- }
def fix_fields(self):
self.selectize_multiple_fields['volunteers'] = RegisteredUsersLookup(self.conference)
@@ -200,19 +202,21 @@ class BackendConferenceForm(BackendForm):
{'id': 'legacy', 'legend': 'Legacy', 'fields': ['schedulewidth', 'pixelsperminute']},
]
+
class BackendSuperConferenceForm(BackendForm):
helplink = 'super_conference#conferenceform'
- class Meta:
- model = Conference
- fields = ['conferencename', 'urlname', 'series', 'startdate', 'enddate', 'location',
- 'timediff', 'contactaddr', 'sponsoraddr', 'confurl', 'administrators',
- 'jinjadir', 'accounting_object', 'vat_registrations', 'vat_sponsorship', ]
selectize_multiple_fields = {
'administrators': GeneralAccountLookup(),
}
accounting_object = django.forms.ChoiceField(choices=[], required=False)
exclude_date_validators = ['startdate', 'enddate']
+ class Meta:
+ model = Conference
+ fields = ['conferencename', 'urlname', 'series', 'startdate', 'enddate', 'location',
+ 'timediff', 'contactaddr', 'sponsoraddr', 'confurl', 'administrators',
+ 'jinjadir', 'accounting_object', 'vat_registrations', 'vat_sponsorship', ]
+
def fix_fields(self):
self.fields['accounting_object'].choices = [('', '----'), ] + [(o.name, o.name) for o in postgresqleu.accounting.models.Object.objects.filter(active=True)]
if not self.instance.id:
@@ -232,30 +236,35 @@ class BackendConferenceSeriesForm(BackendForm):
selectize_multiple_fields = {
'administrators': GeneralAccountLookup(),
}
+
class Meta:
model = ConferenceSeries
fields = ['name', 'sortkey', 'visible', 'administrators', 'intro', ]
+
class BackendTshirtSizeForm(BackendForm):
helplink = "meta"
list_fields = ['shirtsize', 'sortkey', ]
+
class Meta:
model = ShirtSize
fields = ['shirtsize', 'sortkey', ]
+
class BackendRegistrationForm(BackendForm):
helplink = "registrations"
- class Meta:
- model = ConferenceRegistration
- fields = ['firstname', 'lastname', 'email', 'company', 'address', 'country', 'phone',
- 'shirtsize', 'dietary', 'twittername', 'nick', 'shareemail',
- 'regtype', 'additionaloptions']
fieldsets = [
{'id': 'personal_info', 'legend': 'Personal information', 'fields': ['firstname', 'lastname', 'email', 'company', 'address', 'country', 'phone', 'twittername', 'nick']},
{'id': 'reg_info', 'legend': 'Registration information', 'fields': ['regtype', 'additionaloptions', 'shareemail']},
{'id': 'attendee_specifics', 'legend': 'Attendee specifics', 'fields': ['shirtsize', 'dietary']},
]
+ class Meta:
+ model = ConferenceRegistration
+ fields = ['firstname', 'lastname', 'email', 'company', 'address', 'country', 'phone',
+ 'shirtsize', 'dietary', 'twittername', 'nick', 'shareemail',
+ 'regtype', 'additionaloptions']
+
def fix_fields(self):
if self.instance.payconfirmedat:
self.warning_text = "WARNING! This registration has already been completed! Edit with caution!"
@@ -270,10 +279,12 @@ class BackendRegistrationForm(BackendForm):
self.remove_field('shareemail')
self.update_protected_fields()
+
class BackendRegistrationClassForm(BackendForm):
helplink = 'registrations#regclasses'
list_fields = ['regclass', 'badgecolor', 'badgeforegroundcolor']
allow_copy_previous = True
+
class Meta:
model = RegistrationClass
fields = ['regclass', 'badgecolor', 'badgeforegroundcolor']
@@ -291,6 +302,7 @@ class BackendRegistrationClassForm(BackendForm):
badgecolor=source.badgecolor,
badgeforegroundcolor=source.badgeforegroundcolor).save()
+
class BackendRegistrationTypeForm(BackendForm):
helplink = 'registrations#regtypes'
list_fields = ['regtype', 'regclass', 'cost', 'active', 'sortkey']
@@ -362,43 +374,49 @@ class BackendRegistrationTypeForm(BackendForm):
yield 'Could not find registration class {0} for registration type {1}'.format(
source.regclass.regclass, source.regtype)
+
class BackendRegistrationDayForm(BackendForm):
helplink = 'registrations#days'
list_fields = ['day', ]
+
class Meta:
model = RegistrationDay
fields = ['day', ]
+
class BackendAdditionalOptionForm(BackendForm):
helplink = 'registrations#additionaloptions'
list_fields = ['name', 'cost', 'maxcount', 'invoice_autocancel_hours']
vat_fields = {'cost': 'reg'}
auto_cascade_delete_to = ['registrationtype_requires_option', 'conferenceadditionaloption_requires_regtype',
'conferenceadditionaloption_mutually_exclusive', ]
+ coltypes = {
+ 'Maxcount': ['nosearch', ],
+ }
+
class Meta:
model = ConferenceAdditionalOption
fields = ['name', 'cost', 'maxcount', 'public', 'upsellable', 'invoice_autocancel_hours',
'requires_regtype', 'mutually_exclusive']
- coltypes = {
- 'Maxcount': ['nosearch', ],
- }
def fix_fields(self):
self.fields['requires_regtype'].queryset = RegistrationType.objects.filter(conference=self.conference)
self.fields['mutually_exclusive'].queryset = ConferenceAdditionalOption.objects.filter(conference=self.conference).exclude(pk=self.instance.pk)
+
class BackendTrackForm(BackendForm):
helplink = 'schedule#tracks'
list_fields = ['trackname', 'sortkey']
allow_copy_previous = True
- class Meta:
- model = Track
- fields = ['trackname', 'sortkey', 'color', 'incfp']
coltypes = {
'Sortkey': ['nosearch', ],
}
defaultsort = [[1, 'asc']]
+ class Meta:
+ model = Track
+ fields = ['trackname', 'sortkey', 'color', 'incfp']
+
@classmethod
def copy_from_conference(self, targetconf, sourceconf, idlist):
# Tracks are copied straight over, but we disallow duplicates
@@ -414,17 +432,20 @@ class BackendTrackForm(BackendForm):
incfp=source.incfp,
).save()
+
class BackendRoomForm(BackendForm):
helplink = 'schedule#rooms'
list_fields = ['roomname', 'sortkey']
- class Meta:
- model = Room
- fields = ['roomname', 'sortkey']
coltypes = {
'Sortkey': ['nosearch', ],
}
defaultsort = [[1, 'asc']]
+ class Meta:
+ model = Room
+ fields = ['roomname', 'sortkey']
+
+
class BackendTransformConferenceDateTimeForm(django.forms.Form):
timeshift = django.forms.DurationField(required=True, help_text="Shift all times by this much")
@@ -548,6 +569,7 @@ class BackendConferenceSessionForm(BackendForm):
return "no scheduled sessions picked, so no transformation will happen"
return None
+
class BackendConferenceSessionSlotForm(BackendForm):
helplink = 'schedule#slots'
list_fields = ['starttime', 'endtime', ]
@@ -625,6 +647,7 @@ class BackendVolunteerSlotForm(BackendForm):
s.timerange.lower + xform, s.timerange.upper + xform,
)
+
class BackendFeedbackQuestionForm(BackendForm):
helplink = 'feedback#conference'
list_fields = ['newfieldset', 'question', 'sortkey', ]
@@ -671,6 +694,7 @@ class BackendNewDiscountCodeForm(django.forms.Form):
def get_newform_data(self):
return self.cleaned_data['codetype']
+
class DiscountCodeUserManager(object):
title = 'Users'
singular = 'user'
@@ -689,6 +713,7 @@ class DiscountCodeUserManager(object):
except ConferenceRegistration.DoesNotExist:
return None
+
class BackendDiscountCodeForm(BackendForm):
helplink = 'vouchers#discountcodes'
list_fields = ['code', 'validuntil', 'maxuses']
@@ -797,6 +822,7 @@ class TwitterForm(ConcurrentProtectedModelForm):
model = Conference
fields = ['twittersync_active', 'twitterreminders_active']
+
class TwitterTestForm(django.forms.Form):
recipient = django.forms.CharField(max_length=64)
message = django.forms.CharField(max_length=200)
diff --git a/postgresqleu/confreg/backendlookups.py b/postgresqleu/confreg/backendlookups.py
index 5675aaac..fc069706 100644
--- a/postgresqleu/confreg/backendlookups.py
+++ b/postgresqleu/confreg/backendlookups.py
@@ -9,6 +9,7 @@ from models import Conference, ConferenceRegistration, Speaker
import datetime
import json
+
class LookupBase(object):
def __init__(self, conference=None):
self.conference = conference
@@ -35,6 +36,7 @@ class LookupBase(object):
'values': vals,
}), content_type='application/json')
+
class GeneralAccountLookup(LookupBase):
@property
def url(self):
@@ -44,7 +46,6 @@ class GeneralAccountLookup(LookupBase):
def label_from_instance(self):
return lambda x: u'{0} {1} ({2})'.format(x.first_name, x.last_name, x.username)
-
@classmethod
def get_values(self, query):
return [
diff --git a/postgresqleu/confreg/backendviews.py b/postgresqleu/confreg/backendviews.py
index 2f478a05..d40a8d6f 100644
--- a/postgresqleu/confreg/backendviews.py
+++ b/postgresqleu/confreg/backendviews.py
@@ -40,6 +40,7 @@ from backendforms import BackendTshirtSizeForm
from backendforms import BackendNewsForm
from backendforms import TwitterForm, TwitterTestForm
+
def get_authenticated_conference(request, urlname=None, confid=None):
if not request.user.is_authenticated:
raise RedirectException("{0}?{1}".format(settings.LOGIN_URL, urllib.urlencode({'next': request.build_absolute_uri()})))
@@ -58,6 +59,7 @@ def get_authenticated_conference(request, urlname=None, confid=None):
return c
raise PermissionDenied()
+
def backend_process_form(request, urlname, formclass, id, cancel_url='../', saved_url='../', allow_new=True, allow_delete=True, breadcrumbs=None, permissions_already_checked=False, conference=None, bypass_conference_filter=False, instancemaker=None, deleted_url=None):
if not conference and not bypass_conference_filter:
conference = get_authenticated_conference(request, urlname)
@@ -199,6 +201,7 @@ def backend_process_form(request, urlname, formclass, id, cancel_url='../', save
'linked': [(url, handler, handler.get_list(form.instance)) for url, handler in form.linked_objects.items() if form.instance],
})
+
def backend_handle_copy_previous(request, formclass, restpieces, conference):
if len(restpieces) == 1:
# No conference selected yet, so start by doing that
@@ -411,6 +414,7 @@ def edit_conference(request, urlname):
allow_new=False,
allow_delete=False)
+
@superuser_required
def superedit_conference(request, urlname):
if not request.user.is_superuser:
@@ -424,6 +428,7 @@ def superedit_conference(request, urlname):
allow_new=False,
allow_delete=False)
+
@superuser_required
def edit_series(request, rest):
return backend_list_editor(request,
@@ -437,6 +442,7 @@ def edit_series(request, rest):
instancemaker=lambda: ConferenceSeries(),
)
+
@superuser_required
def edit_tshirts(request, rest):
return backend_list_editor(request,
@@ -450,6 +456,7 @@ def edit_tshirts(request, rest):
instancemaker=lambda: ShirtSize(),
)
+
@superuser_required
def new_conference(request):
return backend_process_form(request,
@@ -463,6 +470,7 @@ def new_conference(request):
instancemaker=lambda: Conference(),
)
+
def edit_registration(request, urlname, regid):
return backend_process_form(request,
urlname,
@@ -471,78 +479,91 @@ def edit_registration(request, urlname, regid):
allow_new=False,
allow_delete=False)
+
def edit_regclasses(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendRegistrationClassForm,
rest)
+
def edit_regtypes(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendRegistrationTypeForm,
rest)
+
def edit_regdays(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendRegistrationDayForm,
rest)
+
def edit_additionaloptions(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendAdditionalOptionForm,
rest)
+
def edit_tracks(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendTrackForm,
rest)
+
def edit_rooms(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendRoomForm,
rest)
+
def edit_sessions(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendConferenceSessionForm,
rest)
+
def edit_scheduleslots(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendConferenceSessionSlotForm,
rest)
+
def edit_volunteerslots(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendVolunteerSlotForm,
rest)
+
def edit_feedbackquestions(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendFeedbackQuestionForm,
rest)
+
def edit_discountcodes(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendDiscountCodeForm,
rest)
+
def edit_accesstokens(request, urlname, rest):
return backend_list_editor(request,
urlname,
BackendAccessTokenForm,
rest)
+
def edit_news(request, urlname, rest):
return backend_list_editor(request,
urlname,
@@ -668,7 +689,6 @@ def twitter_integration(request, urlname):
form = TwitterForm(instance=conference)
testform = TwitterTestForm()
-
return render(request, 'confreg/admin_integ_twitter.html', {
'conference': conference,
'form': form,
@@ -676,6 +696,7 @@ def twitter_integration(request, urlname):
'helplink': 'integrations#twitter',
})
+
def _reencode_row(r):
def _reencode_value(v):
if isinstance(v, unicode):
@@ -683,6 +704,7 @@ def _reencode_row(r):
return v
return [_reencode_value(x) for x in r]
+
class DelimitedWriter(object):
def __init__(self, delimiter):
self.delimiter = delimiter
@@ -702,6 +724,7 @@ class DelimitedWriter(object):
for r in rows:
self.writer.writerow(_reencode_row(r))
+
class JsonWriter(object):
def __init__(self):
self.d = {}
@@ -737,6 +760,7 @@ class JsonWriter(object):
r['Access-Control-Allow-Origin'] = '*'
return r
+
def tokendata(request, urlname, token, datatype, dataformat):
conference = get_object_or_404(Conference, urlname=urlname)
if not AccessToken.objects.filter(conference=conference, token=token, permissions__contains=[datatype, ]).exists():
diff --git a/postgresqleu/confreg/dbimage.py b/postgresqleu/confreg/dbimage.py
index 5f7603d0..b1820b5b 100644
--- a/postgresqleu/confreg/dbimage.py
+++ b/postgresqleu/confreg/dbimage.py
@@ -5,6 +5,7 @@ from django.core.files.storage import Storage
from django.core.files import File
from django.utils.deconstruct import deconstructible
+
@deconstructible
class SpeakerImageStorage(Storage):
def __init__(self):
@@ -57,10 +58,10 @@ class SpeakerImageStorage(Storage):
from django.forms.widgets import Widget
from django.utils.safestring import mark_safe
+
class InlinePhotoWidget(Widget):
def render(self, name, value, attrs=None):
return mark_safe(u'<img src="data:image/png;base64,%s"/>' % value)
def value_from_datadict(self, data, files, name):
return self.original_value
-
diff --git a/postgresqleu/confreg/docsviews.py b/postgresqleu/confreg/docsviews.py
index 8f6e8cc8..e7fcf4d0 100644
--- a/postgresqleu/confreg/docsviews.py
+++ b/postgresqleu/confreg/docsviews.py
@@ -13,6 +13,8 @@ from backendviews import get_authenticated_conference
reTitle = re.compile('<h1>([^<]+)</h1>')
_reSvgInline = re.compile('<img alt="([^"]+)" src="([^"]+)\.svg" />')
+
+
def _replaceSvgInline(m):
# Group 1 = alt text
# Group 2 = filename excluding svg
@@ -23,6 +25,7 @@ def _replaceSvgInline(m):
with codecs.open(filename, 'r', 'utf8') as f:
return f.read()
+
def docspage(request, urlname, page):
if urlname:
conference = get_authenticated_conference(request, urlname.rstrip('/'))
diff --git a/postgresqleu/confreg/feedback.py b/postgresqleu/confreg/feedback.py
index 11da5a57..28d5e04e 100644
--- a/postgresqleu/confreg/feedback.py
+++ b/postgresqleu/confreg/feedback.py
@@ -7,12 +7,14 @@ from backendviews import get_authenticated_conference
from collections import OrderedDict
+
def build_graphdata(question, key, options):
optionhash = OrderedDict(zip(options, [0] * len(options)))
for answer in ConferenceFeedbackAnswer.objects.filter(conference=question.conference, question=question).order_by(key).values(key).annotate(Count(key)):
optionhash[answer[key]] = answer['%s__count' % key]
return optionhash.iteritems()
+
def build_feedback_response(question):
r = {'question': question.question, 'id': question.id, }
confid = question.conference.id
@@ -28,6 +30,7 @@ def build_feedback_response(question):
r['graphdata'] = build_graphdata(question, 'rateanswer', range(0, 6))
return r
+
def feedback_report(request, confname):
conference = get_authenticated_conference(request, confname)
@@ -62,6 +65,7 @@ def build_toplists(what, query):
tl['list'] = cursor.fetchall()
yield tl
+
def feedback_sessions(request, confname):
conference = get_authenticated_conference(request, confname)
diff --git a/postgresqleu/confreg/feeds.py b/postgresqleu/confreg/feeds.py
index fcb52c36..c0d3135a 100644
--- a/postgresqleu/confreg/feeds.py
+++ b/postgresqleu/confreg/feeds.py
@@ -8,6 +8,7 @@ import datetime
from postgresqleu.util.db import exec_to_dict
+
class LatestEvents(Feed):
title = "Events - %s" % settings.ORG_NAME
link = "/"
diff --git a/postgresqleu/confreg/forms.py b/postgresqleu/confreg/forms.py
index 5a9604e2..df013082 100644
--- a/postgresqleu/confreg/forms.py
+++ b/postgresqleu/confreg/forms.py
@@ -49,7 +49,6 @@ class ConferenceRegistrationForm(forms.ModelForm):
else:
self.intro_html = mark_safe(u'<p>You are currently editing a registration for somebody other than yourself.</p>')
-
def clean_regtype(self):
newval = self.cleaned_data.get('regtype')
if self.instance and newval == self.instance.regtype:
@@ -132,7 +131,6 @@ class ConferenceRegistrationForm(forms.ModelForm):
return newval
-
def compare_options(self, a, b):
# First check if the sizes are the same
if len(a) != len(b):
@@ -299,6 +297,7 @@ class ConferenceRegistrationForm(forms.ModelForm):
'fields': [self['vouchercode'], ],
}
+
class RegistrationChangeForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(RegistrationChangeForm, self).__init__(*args, **kwargs)
@@ -323,6 +322,7 @@ rating_choices = (
(0, 'N/A'),
)
+
class NewMultiRegForm(forms.Form):
email = forms.EmailField(required=True)
@@ -337,10 +337,12 @@ class NewMultiRegForm(forms.Form):
raise ValidationError("A registration for this email address already exists. For privacy reasons, management of a registration cannot be transferred.")
return e
+
class MultiRegInvoiceForm(forms.Form):
recipient = forms.CharField(max_length=100, required=True)
address = forms.CharField(widget=forms.widgets.Textarea, required=True)
+
class ConferenceSessionFeedbackForm(forms.ModelForm):
topic_importance = forms.ChoiceField(widget=RadioSelect, choices=rating_choices, label='Importance of the topic')
content_quality = forms.ChoiceField(widget=RadioSelect, choices=rating_choices, label='Quality of the content')
@@ -395,6 +397,7 @@ class ConferenceFeedbackForm(forms.Form):
return r.rateanswer
return -1
+
class SpeakerProfileForm(forms.ModelForm):
class Meta:
model = Speaker
@@ -491,17 +494,20 @@ class SessionCopyField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj):
return u"{0}: {1} ({2})".format(obj.conference, obj.title, obj.status_string)
+
class CallForPapersCopyForm(forms.Form):
sessions = SessionCopyField(widget=forms.CheckboxSelectMultiple,
required=True,
queryset=ConferenceSession.objects.filter(id=-1),
label='Select sessions')
+
def __init__(self, conference, speaker, *args, **kwargs):
self.conference = conference
self.speaker = speaker
super(CallForPapersCopyForm, self).__init__(*args, **kwargs)
self.fields['sessions'].queryset = ConferenceSession.objects.select_related('conference').filter(speaker=speaker).exclude(conference=conference).order_by('-conference__startdate', 'title')
+
class SessionSlidesUrlForm(forms.Form):
url = forms.URLField(label='URL', required=False, max_length=1000)
@@ -520,6 +526,7 @@ class SessionSlidesUrlForm(forms.Form):
raise ValidationError("URL does not validate")
return u
+
class SessionSlidesFileForm(forms.Form):
f = forms.FileField(label='Upload', required=False)
license = forms.BooleanField(label='License', required=False, help_text='I confirm that this this file may be redistributed by the conference website')
@@ -542,6 +549,7 @@ class SessionSlidesFileForm(forms.Form):
self.add_error('license', 'You must accept the license')
return cleaned_data
+
class PrepaidCreateForm(forms.Form):
regtype = forms.ModelChoiceField(queryset=RegistrationType.objects.filter(id=-1))
count = forms.IntegerField(min_value=1, max_value=100)
@@ -560,6 +568,7 @@ class PrepaidCreateForm(forms.Form):
self.data.get('count')):
del self.fields['confirm']
+
class EmailSendForm(forms.Form):
ids = forms.CharField(label="List of id's", widget=forms.widgets.HiddenInput())
returnurl = forms.CharField(label="Return url", widget=forms.widgets.HiddenInput())
@@ -578,6 +587,7 @@ class EmailSendForm(forms.Form):
if not readytogo:
del self.fields['confirm']
+
class EmailSessionForm(forms.Form):
sender = forms.EmailField(label="Sending email")
subject = forms.CharField(label="Subject", min_length=10)
@@ -607,8 +617,10 @@ class BulkRegistrationForm(forms.Form):
raise ValidationError('Bulk payments can only be done for 2 or more emails')
return email_list
+
class AttendeeMailForm(forms.ModelForm):
confirm = forms.BooleanField(label="Confirm", required=False)
+
class Meta:
model = AttendeeMail
exclude = ('conference', )
@@ -661,6 +673,7 @@ class WaitlistOfferForm(forms.Form):
raise ValidationError("At least one registration must be selected to make an offer")
return self.cleaned_data
+
class WaitlistSendmailForm(forms.Form):
TARGET_ALL = 0
TARGET_OFFERS = 1
@@ -701,6 +714,7 @@ class WaitlistSendmailForm(forms.Form):
if not self.cleaned_data['confirm']:
raise ValidationError("Please check this box to confirm that you are really sending this email! There is no going back!")
+
class TransferRegForm(forms.Form):
transfer_from = forms.ModelChoiceField(ConferenceRegistration.objects.filter(id=-1))
transfer_to = forms.ModelChoiceField(ConferenceRegistration.objects.filter(id=-1))
@@ -713,6 +727,7 @@ class TransferRegForm(forms.Form):
self.fields['transfer_to'].queryset = ConferenceRegistration.objects.filter(conference=conference, payconfirmedat__isnull=True)
if not (self.data.has_key('transfer_from') and self.data.has_key('transfer_to')):
del self.fields['confirm']
+
def remove_confirm(self):
del self.fields['confirm']
diff --git a/postgresqleu/confreg/invoicehandler.py b/postgresqleu/confreg/invoicehandler.py
index aefd479e..4913f0c5 100644
--- a/postgresqleu/confreg/invoicehandler.py
+++ b/postgresqleu/confreg/invoicehandler.py
@@ -7,6 +7,7 @@ from util import notify_reg_confirmed, expire_additional_options, cancel_registr
from datetime import datetime
+
class InvoiceProcessor(object):
# Process invoices once they're getting paid
#
@@ -97,8 +98,6 @@ class InvoiceProcessor(object):
return "%s/events/%s/register/" % (settings.SITEBASE, reg.conference.urlname)
-
-
class BulkInvoiceProcessor(object):
# Process invoices once they're getting paid
#
@@ -221,7 +220,6 @@ class BulkInvoiceProcessor(object):
return "%s/events/%s/bulkpay/%s/" % (settings.SITEBASE, bp.conference.urlname, invoice.processorid)
-
class AddonInvoiceProcessor(object):
can_refund = False
# Process invoices for additional options added to an existing
@@ -231,6 +229,7 @@ class AddonInvoiceProcessor(object):
# we don't actually need to verify that nothing has changed.
#
# All modifications are already wrapped in a django transaction
+
def process_invoice_payment(self, invoice):
try:
order = PendingAdditionalOrder.objects.get(pk=invoice.processorid)
diff --git a/postgresqleu/confreg/jinjabadge.py b/postgresqleu/confreg/jinjabadge.py
index 63860d2c..ec4c9dc9 100755
--- a/postgresqleu/confreg/jinjabadge.py
+++ b/postgresqleu/confreg/jinjabadge.py
@@ -26,6 +26,7 @@ alignments = {
'right': TA_RIGHT,
}
+
def get_color(col):
if isinstance(col, unicode) or isinstance(col, str):
return colors.getAllNamedColors().get(col)
@@ -34,9 +35,11 @@ def get_color(col):
else:
raise Exception("Unknown color defintion type")
+
def getmm(struct, key):
return struct[key] * mm
+
class JinjaBadge(Flowable):
def __init__(self, js, imgpath):
self.js = js
@@ -146,9 +149,11 @@ def escapejson_filter(v):
# those, but only one if there is more than one.
return re.sub(r'^"|"$', '', json.dumps(v))
+
def test_inlist(v, l):
return v in l
+
class JinjaRenderer(object):
def __init__(self, rootdir, debug=False, border=False, pagebreaks=False):
self.templatedir = os.path.join(rootdir, 'templates')
diff --git a/postgresqleu/confreg/jinjafunc.py b/postgresqleu/confreg/jinjafunc.py
index 0e486e2d..a585bd09 100644
--- a/postgresqleu/confreg/jinjafunc.py
+++ b/postgresqleu/confreg/jinjafunc.py
@@ -169,6 +169,7 @@ def filter_groupby_sort(objects, keyfield, sortkey):
group = [(key, list(group)) for key, group in groupby(objects, lambda x: getattr(x, keyfield))]
return sorted(group, key=lambda y: y[0] and getattr(y[0], sortkey) or None)
+
# Shuffle the order in a list, for example to randomize the order of sponsors
def filter_shuffle(l):
try:
@@ -178,12 +179,15 @@ def filter_shuffle(l):
except:
return l
+
def filter_currency_format(v):
return u"{0} {1:,.2f}".format(unicode(settings.CURRENCY_SYMBOL, 'utf8'), v)
+
def filter_float_str(f, n):
return '{{0:.{0}f}}'.format(int(n)).format(f)
+
# Format a datetime. If it'sa datetime, call strftime. If it's a
# string, assume it's iso format and convert it to a date first.
def filter_datetimeformat(value, fmt):
@@ -255,7 +259,6 @@ def render_jinja_conference_response(request, conference, pagemagic, templatenam
if conference and conference.jinjadir:
c['githash'] = find_git_revision(conference.jinjadir)
-
if dictionary:
c.update(dictionary)
@@ -272,15 +275,13 @@ def render_jinja_conference_response(request, conference, pagemagic, templatenam
return HttpResponse(t.render(**c), content_type='text/html')
-
-
-
# Small sandboxed jinja templates that can be configured in system
def render_sandboxed_template(templatestr, context):
env = ConfSandbox(loader=jinja2.DictLoader({'t': templatestr}))
t = env.get_template('t')
return t.render(context)
+
class JinjaTemplateValidator(object):
def __init__(self, context={}):
self.context = context
diff --git a/postgresqleu/confreg/lookups.py b/postgresqleu/confreg/lookups.py
index 0451fcb2..4e36be8a 100644
--- a/postgresqleu/confreg/lookups.py
+++ b/postgresqleu/confreg/lookups.py
@@ -4,6 +4,7 @@ from selectable.decorators import staff_member_required
from postgresqleu.confreg.models import ConferenceRegistration
+
@staff_member_required
class RegistrationLookup(ModelLookup):
model = ConferenceRegistration
@@ -30,4 +31,5 @@ class RegistrationLookup(ModelLookup):
# Display for choice listings
return u"%s (%s %s)" % (item.attendee and item.attendee.username or '(no account)', item.firstname, item.lastname)
+
registry.register(RegistrationLookup)
diff --git a/postgresqleu/confreg/management/commands/confreg_expire_additionaloptions.py b/postgresqleu/confreg/management/commands/confreg_expire_additionaloptions.py
index 0b8b0a06..54d1fdc6 100644
--- a/postgresqleu/confreg/management/commands/confreg_expire_additionaloptions.py
+++ b/postgresqleu/confreg/management/commands/confreg_expire_additionaloptions.py
@@ -16,6 +16,7 @@ from postgresqleu.mailqueue.util import send_simple_mail
from postgresqleu.confreg.util import expire_additional_options
from postgresqleu.confreg.models import ConferenceRegistration
+
class Command(BaseCommand):
help = 'Expire additional options on pending registrations'
diff --git a/postgresqleu/confreg/management/commands/confreg_expire_waitlist.py b/postgresqleu/confreg/management/commands/confreg_expire_waitlist.py
index 220de7a8..4473b21e 100644
--- a/postgresqleu/confreg/management/commands/confreg_expire_waitlist.py
+++ b/postgresqleu/confreg/management/commands/confreg_expire_waitlist.py
@@ -14,6 +14,7 @@ from postgresqleu.mailqueue.util import send_simple_mail, send_template_mail
from postgresqleu.confreg.models import RegistrationWaitlistEntry, RegistrationWaitlistHistory
+
class Command(BaseCommand):
help = 'Expire conference waitlist offers'
diff --git a/postgresqleu/confreg/management/commands/confreg_frequent_reminders.py b/postgresqleu/confreg/management/commands/confreg_frequent_reminders.py
index 02e28567..11784383 100644
--- a/postgresqleu/confreg/management/commands/confreg_frequent_reminders.py
+++ b/postgresqleu/confreg/management/commands/confreg_frequent_reminders.py
@@ -17,6 +17,7 @@ from postgresqleu.confreg.models import ConferenceRegistration
from postgresqleu.util.messaging.twitter import Twitter
+
class Command(BaseCommand):
help = 'Send confreg frequent reminders'
diff --git a/postgresqleu/confreg/management/commands/confreg_send_reminders.py b/postgresqleu/confreg/management/commands/confreg_send_reminders.py
index f3f12cc8..41e13b97 100644
--- a/postgresqleu/confreg/management/commands/confreg_send_reminders.py
+++ b/postgresqleu/confreg/management/commands/confreg_send_reminders.py
@@ -16,6 +16,7 @@ from postgresqleu.mailqueue.util import send_simple_mail, send_template_mail
from postgresqleu.confreg.models import Conference, Speaker, ConferenceSession
from postgresqleu.confreg.models import ConferenceRegistration
+
class Command(BaseCommand):
help = 'Send confreg reminders'
@@ -96,7 +97,6 @@ class Command(BaseCommand):
whatstr.write("\n\n")
-
def remind_unregistered_speakers(self, whatstr, conference):
# Get speakers that are approved but not registered
speakers = list(Speaker.objects.raw("SELECT s.* FROM confreg_speaker s WHERE EXISTS (SELECT 1 FROM confreg_conferencesession sess INNER JOIN confreg_conferencesession_speaker css ON css.conferencesession_id=sess.id WHERE sess.conference_id=%s AND css.speaker_id=s.id AND sess.status=1 AND sess.lastnotifiedtime<%s) AND NOT EXISTS (SELECT 1 FROM confreg_conferenceregistration r WHERE r.conference_id=%s AND r.attendee_id=s.user_id AND r.payconfirmedat IS NOT NULL)",
@@ -129,7 +129,6 @@ class Command(BaseCommand):
whatstr.write("\n\n")
-
def remind_pending_registrations(self, whatstr, conference):
# Get registrations made which have no invoice, no bulk registration,
# and are not completed. We look at registrations created more than 5
@@ -212,7 +211,6 @@ class Command(BaseCommand):
reg.lastmodified = datetime.now()
reg.save()
-
def remind_empty_submissions(self, whatstr, conference):
# Get all sessions with empty abstract (they forgot to hit save), if they have not been touched in
# 3 days (this will also make the reminder show up every 3 days, and not every day, since we touch
diff --git a/postgresqleu/confreg/management/commands/confreg_warn_purge.py b/postgresqleu/confreg/management/commands/confreg_warn_purge.py
index 42799bf4..3e6e3b74 100644
--- a/postgresqleu/confreg/management/commands/confreg_warn_purge.py
+++ b/postgresqleu/confreg/management/commands/confreg_warn_purge.py
@@ -14,6 +14,7 @@ from postgresqleu.mailqueue.util import send_simple_mail
from postgresqleu.confreg.models import Conference
+
class Command(BaseCommand):
help = 'Send warnings about purging personal data'
@@ -37,4 +38,3 @@ from the conference dashboard:
receivername=conference.conferencename,
bcc=settings.ADMINS[0][1],
)
-
diff --git a/postgresqleu/confreg/migrations/0028_conferencenews.py b/postgresqleu/confreg/migrations/0028_conferencenews.py
index a83ffef2..02e71f88 100644
--- a/postgresqleu/confreg/migrations/0028_conferencenews.py
+++ b/postgresqleu/confreg/migrations/0028_conferencenews.py
@@ -7,6 +7,7 @@ import django.db.models.deletion
import datetime
+
class Migration(migrations.Migration):
dependencies = [
diff --git a/postgresqleu/confreg/mobileviews.py b/postgresqleu/confreg/mobileviews.py
index 1f33d892..0c8d13c1 100644
--- a/postgresqleu/confreg/mobileviews.py
+++ b/postgresqleu/confreg/mobileviews.py
@@ -24,6 +24,7 @@ if settings.DEBUG:
else:
MANIFESTVERSION = 105
+
def index(request, confname):
conference = get_object_or_404(Conference, urlname=confname)
@@ -32,6 +33,7 @@ def index(request, confname):
'html5manifestversion': MANIFESTVERSION,
})
+
def cachemanifest(request, confname):
# We'll just serve this up whenever, no need to check that the
# conference exists. We'll break later :)
@@ -72,7 +74,6 @@ def conferencedata(request, confname, since):
sessiondata = [{'i': r[0], 't': r[1], 'a': markdown.markdown(r[2], safe_mode=True), 'st': r[3].isoformat() + 'Z', 'et': r[4].isoformat() + 'Z', 'r': r[5] and r[5] or '', 's': r[6]} for r in curs.fetchall()]
# sessions = ConferenceSession.objects.select_related('speaker').filter(conference=conference, starttime__isnull=False).order_by('starttime')
-
# Now get all speaker info
curs.execute("SELECT spk.id, spk.fullname, spk.abstract FROM confreg_speaker spk WHERE EXISTS (SELECT 1 FROM confreg_conferencesession_speaker csp INNER JOIN confreg_conferencesession s ON s.id=csp.conferencesession_id WHERE s.conference_id=%(confid)s AND status=1 AND NOT starttime IS NULL AND csp.speaker_id=spk.id) AND spk.lastmodified > %(lastmod)s", {
'confid': conference.id,
@@ -102,6 +103,7 @@ def conferencedata(request, confname, since):
}, resp)
return resp
+
def newsproxy(request, confname):
conference = get_object_or_404(Conference, urlname=confname)
if not conference.newsjson:
diff --git a/postgresqleu/confreg/models.py b/postgresqleu/confreg/models.py
index 1e175aac..ec04ddbe 100644
--- a/postgresqleu/confreg/models.py
+++ b/postgresqleu/confreg/models.py
@@ -50,11 +50,16 @@ STATUS_CHOICES_LONG = (
(3, "Pending speaker confirmation"), # Approved, but not confirmed
(4, "Reserve-listed in case of cancels/changes"), # Reserve list
)
+
+
def get_status_string(val):
return (t for v, t in STATUS_CHOICES if v == val).next()
+
+
def get_status_string_long(val):
return (t for v, t in STATUS_CHOICES_LONG if v == val).next()
+
valid_status_transitions = {
0: {3: 'Talk approved', 2: 'Talk is rejected', 4: 'Talk added to reserve list'},
1: {2: 'Talk withdrawn', },
@@ -63,6 +68,7 @@ valid_status_transitions = {
4: {1: 'Last-minute reservelist', 3: 'Activated from reservelist'},
}
+
def color_validator(value):
if not value.startswith('#'):
raise ValidationError('Color values must start with #')
@@ -74,6 +80,7 @@ def color_validator(value):
except ValueError:
raise ValidationError('Invalid value in color specification')
+
class ConferenceSeries(models.Model):
name = models.CharField(max_length=64, blank=False, null=False)
sortkey = models.IntegerField(null=False, default=100)
@@ -88,6 +95,7 @@ class ConferenceSeries(models.Model):
ordering = ('sortkey', 'name')
verbose_name_plural = "Conference series"
+
class ConferenceSeriesOptOut(models.Model):
# Users opting out of communications about a specific conference
series = models.ForeignKey(ConferenceSeries, null=False, blank=False, on_delete=models.CASCADE)
@@ -98,6 +106,7 @@ class ConferenceSeriesOptOut(models.Model):
('user', 'series'),
)
+
class GlobalOptOut(models.Model):
# Users who are opting out of *all* future communications
user = models.OneToOneField(User, null=False, blank=False, primary_key=True, on_delete=models.CASCADE)
@@ -234,6 +243,7 @@ class Conference(models.Model):
raise ValidationError("Must specify an actual welcome mail if it's enabled!")
return cc
+
class RegistrationClass(models.Model):
conference = models.ForeignKey(Conference, null=False, on_delete=models.CASCADE)
regclass = models.CharField(max_length=64, null=False, blank=False, verbose_name="Registration class")
@@ -274,6 +284,7 @@ class RegistrationClass(models.Model):
d = dict((a, getattr(self, a) and unicode(getattr(self, a))) for a in attribs)
return d
+
class RegistrationDay(models.Model):
conference = models.ForeignKey(Conference, null=False, on_delete=models.CASCADE)
day = models.DateField(null=False, blank=False)
@@ -291,6 +302,7 @@ class RegistrationDay(models.Model):
df = DateFormat(self.day)
return df.format('D jS')
+
class RegistrationType(models.Model):
conference = models.ForeignKey(Conference, null=False, on_delete=models.CASCADE)
regtype = models.CharField(max_length=64, null=False, blank=False, verbose_name="Registration type")
@@ -340,6 +352,7 @@ class RegistrationType(models.Model):
d['days'] = [dd.day.strftime('%Y-%m-%d') for dd in self.days.all()]
return d
+
class ShirtSize(models.Model):
shirtsize = models.CharField(max_length=32)
sortkey = models.IntegerField(default=100, null=False, blank=False)
@@ -350,6 +363,7 @@ class ShirtSize(models.Model):
class Meta:
ordering = ('sortkey', 'shirtsize',)
+
class ConferenceAdditionalOption(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
name = models.CharField(max_length=100, null=False, blank=False)
@@ -383,6 +397,7 @@ class ConferenceAdditionalOption(models.Model):
self.maxcount)
return "%s%s" % (self.name, coststr)
+
class BulkPayment(models.Model):
# User that owns this bulk payment
user = models.ForeignKey(User, null=False, blank=False, on_delete=models.CASCADE)
@@ -425,6 +440,7 @@ class BulkPayment(models.Model):
self.invoice.total_amount,
self.paidat and 'Paid' or 'Not paid yet')
+
class ConferenceRegistration(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
regtype = models.ForeignKey(RegistrationType, null=True, blank=True, verbose_name="Registration type", on_delete=models.CASCADE)
@@ -549,6 +565,7 @@ class ConferenceRegistration(models.Model):
d['additionaloptions'] = [{'id': ao.id, 'name': ao.name} for ao in self.additionaloptions.all()]
return d
+
class RegistrationWaitlistEntry(models.Model):
registration = models.OneToOneField(ConferenceRegistration, primary_key=True, on_delete=models.CASCADE)
enteredon = models.DateTimeField(null=False, blank=False, auto_now_add=True)
@@ -561,6 +578,7 @@ class RegistrationWaitlistEntry(models.Model):
def offers_made(self):
return self.registrationwaitlisthistory_set.filter(text__startswith='Made offer').count()
+
class RegistrationWaitlistHistory(models.Model):
waitlist = models.ForeignKey(RegistrationWaitlistEntry, null=False, blank=False, on_delete=models.CASCADE)
time = models.DateTimeField(null=False, blank=False, auto_now_add=True)
@@ -569,6 +587,7 @@ class RegistrationWaitlistHistory(models.Model):
class Meta:
ordering = ('-time',)
+
class Track(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
trackname = models.CharField(max_length=100, null=False, blank=False, verbose_name="Track name")
@@ -581,6 +600,7 @@ class Track(models.Model):
def __unicode__(self):
return self.trackname
+
class Room(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
roomname = models.CharField(max_length=20, null=False, blank=False, verbose_name="Room name")
@@ -598,6 +618,7 @@ class Room(models.Model):
def _get_upload_path(instance, filename):
return "%s" % instance.id
+
class Speaker(models.Model):
user = models.OneToOneField(User, null=True, blank=True, unique=True, on_delete=models.CASCADE)
fullname = models.CharField(max_length=100, null=False, blank=False)
@@ -636,11 +657,13 @@ class Speaker(models.Model):
class Meta:
ordering = ['fullname', ]
+
class DeletedItems(models.Model):
itemid = models.IntegerField(null=False, blank=False)
type = models.CharField(max_length=16, blank=False, null=False)
deltime = models.DateTimeField(blank=False, null=False)
+
class Speaker_Photo(models.Model):
speaker = models.OneToOneField(Speaker, db_column='id', primary_key=True, on_delete=models.CASCADE)
photo = models.TextField(null=False, blank=False)
@@ -654,6 +677,7 @@ class Speaker_Photo(models.Model):
self.speaker.save()
super(Speaker_Photo, self).delete()
+
class ConferenceSessionScheduleSlot(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
starttime = models.DateTimeField(null=False, blank=False, verbose_name="Start time")
@@ -662,6 +686,7 @@ class ConferenceSessionScheduleSlot(models.Model):
def __unicode__(self):
return "%s - %s" % (self.starttime, self.endtime)
+
class ConferenceSession(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
speaker = models.ManyToManyField(Speaker, blank=True, verbose_name="Speakers")
@@ -749,6 +774,7 @@ class ConferenceSession(models.Model):
class Meta:
ordering = ['starttime', ]
+
class ConferenceSessionSlides(models.Model):
session = models.ForeignKey(ConferenceSession, null=False, blank=False, on_delete=models.CASCADE)
name = models.CharField(max_length=100, null=False, blank=False)
@@ -757,6 +783,7 @@ class ConferenceSessionSlides(models.Model):
_safe_attributes = ('id', 'name', 'url', 'content')
+
class ConferenceSessionVote(models.Model):
session = models.ForeignKey(ConferenceSession, null=False, blank=False, on_delete=models.CASCADE)
voter = models.ForeignKey(User, null=False, blank=False, on_delete=models.CASCADE)
@@ -766,6 +793,7 @@ class ConferenceSessionVote(models.Model):
class Meta:
unique_together = (('session', 'voter',), )
+
class ConferenceSessionFeedback(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
session = models.ForeignKey(ConferenceSession, null=False, blank=False, on_delete=models.CASCADE)
@@ -780,6 +808,7 @@ class ConferenceSessionFeedback(models.Model):
def __unicode__(self):
return unicode("%s - %s (%s)") % (self.conference, self.session, self.attendee)
+
class ConferenceFeedbackQuestion(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
question = models.CharField(max_length=100, null=False, blank=False)
@@ -794,6 +823,7 @@ class ConferenceFeedbackQuestion(models.Model):
class Meta:
ordering = ['conference', 'sortkey', ]
+
class ConferenceFeedbackAnswer(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
question = models.ForeignKey(ConferenceFeedbackQuestion, null=False, blank=False, on_delete=models.CASCADE)
@@ -807,6 +837,7 @@ class ConferenceFeedbackAnswer(models.Model):
class Meta:
ordering = ['conference', 'attendee', 'question', ]
+
class VolunteerSlot(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
timerange = DateTimeRangeField(null=False, blank=False)
@@ -844,6 +875,7 @@ class VolunteerSlot(models.Model):
self._localtz = pytz.timezone(settings.TIME_ZONE)
return self._localtz.localize(time).astimezone(pytz.utc)
+
class VolunteerAssignment(models.Model):
slot = models.ForeignKey(VolunteerSlot, null=False, blank=False, on_delete=models.CASCADE)
reg = models.ForeignKey(ConferenceRegistration, null=False, blank=False, on_delete=models.CASCADE)
@@ -852,6 +884,7 @@ class VolunteerAssignment(models.Model):
_safe_attributes = ('id', 'slot', 'reg', 'vol_confirmed', 'org_confirmed')
+
class PrepaidBatch(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
regtype = models.ForeignKey(RegistrationType, null=False, blank=False, on_delete=models.CASCADE)
@@ -866,6 +899,7 @@ class PrepaidBatch(models.Model):
verbose_name_plural = "Prepaid batches"
ordering = ['conference', 'id', ]
+
class PrepaidVoucher(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
vouchervalue = models.CharField(max_length=100, null=False, blank=False, unique=True)
@@ -879,6 +913,7 @@ class PrepaidVoucher(models.Model):
class Meta:
ordering = ['batch', 'vouchervalue', ]
+
class DiscountCode(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
code = models.CharField(max_length=100, null=False, blank=False)
@@ -908,6 +943,7 @@ class DiscountCode(models.Model):
def count(self):
return self.registrations.count()
+
class AttendeeMail(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
regclasses = models.ManyToManyField(RegistrationClass, blank=False)
@@ -934,7 +970,6 @@ class PendingAdditionalOrder(models.Model):
return u"%s" % (self.reg, )
-
class AggregatedTshirtSizes(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
size = models.ForeignKey(ShirtSize, null=False, blank=False, on_delete=models.CASCADE)
@@ -943,6 +978,7 @@ class AggregatedTshirtSizes(models.Model):
class Meta:
unique_together = (('conference', 'size'), )
+
class AggregatedDietary(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
dietary = models.CharField(max_length=100, null=False, blank=False)
@@ -960,6 +996,7 @@ AccessTokenPermissions = (
('addopts', 'Additional options and counts'),
)
+
class AccessToken(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
token = models.CharField(max_length=200, null=False, blank=False)
@@ -978,7 +1015,6 @@ class AccessToken(models.Model):
return ", ".join(self.permissions)
-
class ConferenceNews(models.Model):
conference = models.ForeignKey(Conference, null=False, on_delete=models.CASCADE)
datetime = models.DateTimeField(blank=False, default=datetime.datetime.now)
@@ -995,6 +1031,7 @@ class ConferenceNews(models.Model):
ordering = ['-datetime', ]
verbose_name_plural = 'Conference News'
+
class ConferenceTweetQueue(models.Model):
conference = models.ForeignKey(Conference, null=False, on_delete=models.CASCADE)
datetime = models.DateTimeField(blank=False, default=datetime.datetime.now)
diff --git a/postgresqleu/confreg/pdfschedule.py b/postgresqleu/confreg/pdfschedule.py
index 6b32b750..cc6fd4d2 100644
--- a/postgresqleu/confreg/pdfschedule.py
+++ b/postgresqleu/confreg/pdfschedule.py
@@ -23,6 +23,7 @@ from reportlab.lib.units import cm, mm
from models import Room, Track, RegistrationDay, ConferenceSession
from backendviews import get_authenticated_conference
+
def _get_pagesize(size, orient):
so = (size, orient)
if so == ('a4', 'p'):
@@ -35,6 +36,7 @@ def _get_pagesize(size, orient):
return landscape(A3)
raise Exception("Unknown papersize")
+
def _setup_canvas(pagesize, orientation):
resp = HttpResponse(content_type='application/pdf')
registerFont(TTFont('DejaVu Serif', "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif.ttf"))
@@ -46,6 +48,7 @@ def _setup_canvas(pagesize, orientation):
return (width, height, canvas, resp)
+
# Build a linear PDF schedule for a single room only. Can do muptiple days, in which
# case each new day will cause a pagebreak.
def build_linear_pdf_schedule(conference, room, tracks, day, colored, pagesize, orientation, titledatefmt):
@@ -116,9 +119,6 @@ def build_linear_pdf_schedule(conference, room, tracks, day, colored, pagesize,
return resp
-
-
-
def build_complete_pdf_schedule(conference, tracks, day, colored, pagesize, orientation, pagesperday, titledatefmt):
pagesperday = int(pagesperday)
@@ -254,7 +254,6 @@ def build_complete_pdf_schedule(conference, tracks, day, colored, pagesize, orie
(tsaw, tsah) = ts.wrap(thisroomwidth-2*mm, timestampstyle.fontSize)
ts.drawOn(canvas, s_left+1*mm, s_top+s_height-tsah-1*mm)
-
if s_height - tsah*1.2 - 2*mm < tsah:
# This can never fit, since it's smaller than our font size!
# Instead, print as much as possible on the same row as the time
@@ -308,6 +307,7 @@ def build_complete_pdf_schedule(conference, tracks, day, colored, pagesize, orie
canvas.save()
return resp
+
class PdfScheduleForm(forms.Form):
room = forms.ModelChoiceField(label='Rooms to include', queryset=None, empty_label='(all rooms)', required=False,
help_text="Selecting all rooms will print a full schedule with each session sized to it's length. Selecting a single room will print that rooms schedule in adaptive sized rows in a table.")
@@ -329,6 +329,7 @@ class PdfScheduleForm(forms.Form):
self.fields['day'].queryset = RegistrationDay.objects.filter(conference=conference)
self.fields['tracks'].queryset = alltracks
+
def pdfschedule(request, confname):
conference = get_authenticated_conference(request, confname)
diff --git a/postgresqleu/confreg/regtypes.py b/postgresqleu/confreg/regtypes.py
index 8c246652..907fa162 100644
--- a/postgresqleu/confreg/regtypes.py
+++ b/postgresqleu/confreg/regtypes.py
@@ -3,6 +3,8 @@
from django.core.exceptions import ValidationError
_specialregtypes = {}
+
+
def validate_speaker_registration(reg):
# This registration is only available if a speaker is *confirmed*
# at this conference.
@@ -15,11 +17,13 @@ def validate_speaker_registration(reg):
).exists():
raise ValidationError('This registration type is only available if you are a confirmed speaker at this conference')
+
_specialregtypes['spk'] = {
'name': 'Confirmed speaker',
'func': validate_speaker_registration,
}
+
def validate_speaker_or_reserve_registration(reg):
# This registration is only available if a speaker is *confirmed*
# or *reserve listed* at this conference.
@@ -32,44 +36,53 @@ def validate_speaker_or_reserve_registration(reg):
).exists():
raise ValidationError('This registration type is only available if you are a confirmed speaker at this conference')
+
_specialregtypes['spkr'] = {
'name': 'Confirmed or reserve speaker',
'func': validate_speaker_or_reserve_registration,
}
+
def validate_staff_registration(reg):
if reg.attendee is None:
raise ValidationError('Staff registrations have to be done by the attendee directly')
if not reg.conference.staff.filter(pk=reg.attendee.pk).exists():
raise ValidationError('This registration type is only available if you are confirmed staff at this conference')
+
_specialregtypes['staff'] = {
'name': 'Confirmed staff',
'func': validate_staff_registration,
}
+
def validate_manual_registration(reg):
# Always validates so we can save the record, and then we just block
# it at confirmation.
pass
+
def confirm_manual_registration(reg):
return "This registration type needs to be manually confirmed. Please await notification from the conference organizers."
+
_specialregtypes['man'] = {
'name': 'Manually confirmed',
'func': validate_manual_registration,
'confirmfunc': confirm_manual_registration,
}
+
special_reg_types = [(k, v['name']) for k, v in _specialregtypes.items()]
+
def validate_special_reg_type(regtypename, reg):
if not _specialregtypes.has_key(regtypename):
raise ValidationError('Invalid registration type record. Internal error.')
_specialregtypes[regtypename]['func'](reg)
+
def confirm_special_reg_type(regtypename, reg):
if not _specialregtypes.has_key(regtypename):
return
diff --git a/postgresqleu/confreg/reporting.py b/postgresqleu/confreg/reporting.py
index cba766a8..61d57975 100644
--- a/postgresqleu/confreg/reporting.py
+++ b/postgresqleu/confreg/reporting.py
@@ -6,9 +6,11 @@ from django.db import connection
from postgresqleu.confreg.models import ConferenceSeries
+
class ReportException(Exception):
pass
+
class Header(object):
def __init__(self, hdr):
self.hdr = hdr
@@ -16,6 +18,7 @@ class Header(object):
def __unicode__(self):
return self.hdr
+
@login_required
def timereport(request):
if not (request.user.is_superuser or ConferenceSeries.objects.filter(administrators=request.user).exists()):
@@ -61,6 +64,7 @@ def timereport(request):
# Dynamically built list of all available report types
reporttypes = []
+
# ##########################################################3
# Base classes for reports
# ##########################################################3
@@ -94,6 +98,7 @@ class MultiConferenceReport(object):
self.graphdata = zip(*allvals)
self.maxpred = maxpred
+
class SingleConferenceReport(object):
def __init__(self, title, conferences):
self.title = title
@@ -122,7 +127,6 @@ class SingleConferenceReport(object):
self.graphdata = zip(*allvals)
-
# ##########################################################3
# Actually report classes
# ##########################################################3
@@ -141,8 +145,11 @@ class ConfirmedRegistrationsReport(MultiConferenceReport):
'max': max,
})
return self.curs.fetchall()
+
+
reporttypes.append(('Confirmed registrations', ConfirmedRegistrationsReport))
+
class SubmittedSessionsReport(MultiConferenceReport):
def __init__(self, title, conferences):
super(SubmittedSessionsReport, self).__init__(title, 'Number of sessions', conferences)
@@ -158,8 +165,11 @@ class SubmittedSessionsReport(MultiConferenceReport):
'max': max,
})
return self.curs.fetchall()
+
+
reporttypes.append(('Submitted sessions', SubmittedSessionsReport))
+
class SubmittingSpeakersReport(MultiConferenceReport):
def __init__(self, title, conferences):
super(SubmittingSpeakersReport, self).__init__(title, 'Number of speakers', conferences)
@@ -175,8 +185,11 @@ class SubmittingSpeakersReport(MultiConferenceReport):
'max': max,
})
return self.curs.fetchall()
+
+
reporttypes.append(('Submitting speakers', SubmittingSpeakersReport))
+
class RegistrationTypesReport(SingleConferenceReport):
def fetch_all_data(self, min, max, startdate):
self.curs.execute("SELECT id, regtype FROM confreg_registrationtype rt WHERE EXISTS (SELECT * FROM confreg_conferenceregistration r WHERE r.regtype_id=rt.id AND r.payconfirmedat IS NOT NULL AND r.conference_id=%(id)s)", {
@@ -191,8 +204,11 @@ class RegistrationTypesReport(SingleConferenceReport):
'startdate': startdate,
})
yield (regtype, self.curs.fetchall())
+
+
reporttypes.append(('Registration types', RegistrationTypesReport))
+
class CountryReport(SingleConferenceReport):
def fetch_all_data(self, min, max, startdate):
self.curs.execute("SELECT DISTINCT country_id FROM confreg_conferenceregistration r WHERE r.payconfirmedat IS NOT NULL AND r.conference_id=%(id)s", {
@@ -207,8 +223,11 @@ class CountryReport(SingleConferenceReport):
'startdate': startdate,
})
yield (countryid, self.curs.fetchall())
+
+
reporttypes.append(('Countries', CountryReport))
+
class AdditionalOptionsReport(SingleConferenceReport):
def fetch_all_data(self, min, max, startdate):
self.curs.execute("SELECT DISTINCT id, name FROM confreg_conferenceadditionaloption ao WHERE conference_id=%(id)s", {
@@ -223,4 +242,6 @@ class AdditionalOptionsReport(SingleConferenceReport):
'startdate': startdate,
})
yield (optionname, self.curs.fetchall())
+
+
reporttypes.append(('Additional options', AdditionalOptionsReport))
diff --git a/postgresqleu/confreg/reportingforms.py b/postgresqleu/confreg/reportingforms.py
index e0878109..02172393 100644
--- a/postgresqleu/confreg/reportingforms.py
+++ b/postgresqleu/confreg/reportingforms.py
@@ -12,6 +12,7 @@ _trendlines = (
('polynomial', 'Polynomial'),
)
+
class TimeReportForm(forms.Form):
reporttype = forms.ChoiceField(required=True, choices=enumerate([r[0] for r in reporttypes], 1), label="Report type")
conferences = GroupedModelMultipleChoiceField('series', required=True, queryset=Conference.objects.all().order_by('-startdate'))
@@ -23,4 +24,3 @@ class TimeReportForm(forms.Form):
if not self.user.is_superuser:
self.fields['conferences'].queryset = Conference.objects.filter(series__administrators=self.user)
-
diff --git a/postgresqleu/confreg/reports.py b/postgresqleu/confreg/reports.py
index 319fa2c6..9277c3af 100644
--- a/postgresqleu/confreg/reports.py
+++ b/postgresqleu/confreg/reports.py
@@ -41,6 +41,7 @@ attendee_report_fields = [
_attendee_report_field_map = dict([(a, (b, c, d)) for a, b, c, d in attendee_report_fields])
+
class ReportFilter(object):
def __init__(self, id, name, queryset=None, querysetcol=None, emptyasnull=True):
self.id = id
@@ -107,6 +108,7 @@ class ReportFilter(object):
else:
return '<input type="text" class="adv_filter_box" name="adv_%s_filter"><br/>' % self.id
+
# Filter by speaker state is more complex than the default filter can handle,
# so it needs a special implementation.
class ReportSpeakerFilter(object):
@@ -131,7 +133,6 @@ class ReportSpeakerFilter(object):
return "<blockquote class=\"adv_filter_wrap\">%s</blockquote><br/>" % (field.widget.render("adv_speakerstate", None), )
-
def attendee_report_filters(conference):
yield ReportFilter('regtype', 'Registration type', RegistrationType.objects.filter(conference=conference), 'regtype')
yield ReportFilter('lastname', 'Last name')
@@ -162,6 +163,7 @@ class ReportWriterBase(object):
def add_row(self, row):
self.rows.append(row)
+
class ReportWriterHtml(ReportWriterBase):
def render(self):
resp = HttpResponse()
@@ -174,6 +176,7 @@ class ReportWriterHtml(ReportWriterBase):
return resp
+
class ReportWriterCsv(ReportWriterBase):
def render(self):
resp = HttpResponse(content_type='text/plain; charset=utf-8')
@@ -183,6 +186,7 @@ class ReportWriterCsv(ReportWriterBase):
return resp
+
class ReportWriterPdf(ReportWriterBase):
def set_orientation(self, orientation):
self.orientation = orientation
@@ -216,6 +220,7 @@ class ReportWriterPdf(ReportWriterBase):
return resp
+
def build_attendee_report(conference, POST):
title = POST['title']
format = POST['format']
diff --git a/postgresqleu/confreg/templatetags/alertmap.py b/postgresqleu/confreg/templatetags/alertmap.py
index 83c5f973..c1cd5fdb 100644
--- a/postgresqleu/confreg/templatetags/alertmap.py
+++ b/postgresqleu/confreg/templatetags/alertmap.py
@@ -3,6 +3,7 @@ from django import template
register = template.Library()
+
@register.filter(name='alertmap')
@stringfilter
def alertmap(value):
diff --git a/postgresqleu/confreg/templatetags/date_or_string.py b/postgresqleu/confreg/templatetags/date_or_string.py
index b775e1af..96438bae 100644
--- a/postgresqleu/confreg/templatetags/date_or_string.py
+++ b/postgresqleu/confreg/templatetags/date_or_string.py
@@ -4,6 +4,7 @@ from datetime import date
register = template.Library()
+
@register.filter
def date_or_string(value):
if value is None:
diff --git a/postgresqleu/confreg/templatetags/dictutil.py b/postgresqleu/confreg/templatetags/dictutil.py
index 56b0bc9e..6828b277 100644
--- a/postgresqleu/confreg/templatetags/dictutil.py
+++ b/postgresqleu/confreg/templatetags/dictutil.py
@@ -2,6 +2,7 @@ from django import template
register = template.Library()
+
@register.filter(name='dictlookup')
def dictlookup(value, key):
return value.get(key, None)
diff --git a/postgresqleu/confreg/templatetags/docslink.py b/postgresqleu/confreg/templatetags/docslink.py
index 0cf03b37..deab9c2e 100644
--- a/postgresqleu/confreg/templatetags/docslink.py
+++ b/postgresqleu/confreg/templatetags/docslink.py
@@ -3,6 +3,7 @@ from django import template
register = template.Library()
+
@register.filter(name='docslink')
@stringfilter
def docslink(value):
diff --git a/postgresqleu/confreg/templatetags/formutil.py b/postgresqleu/confreg/templatetags/formutil.py
index 8a1bdcca..94c5e8aa 100644
--- a/postgresqleu/confreg/templatetags/formutil.py
+++ b/postgresqleu/confreg/templatetags/formutil.py
@@ -2,10 +2,12 @@ from django import template
register = template.Library()
+
@register.filter(is_safe=True)
def label_class(value, arg):
return value.label_tag(attrs={'class': arg})
+
@register.filter(is_safe=True)
def field_class(value, arg):
prevclass = value.field.widget.attrs.get('class', '')
@@ -15,10 +17,12 @@ def field_class(value, arg):
newclass = arg
return value.as_widget(attrs={"class": newclass})
+
@register.filter(is_safe=True)
def ischeckbox(obj):
return obj.field.widget.__class__.__name__ in ("CheckboxInput", "CheckboxSelectMultiple") and not getattr(obj.field, 'regular_field', False)
+
@register.filter(is_safe=True)
def isrequired_error(obj):
if obj.errors and obj.errors[0] == u"This field is required.":
diff --git a/postgresqleu/confreg/templatetags/join_days.py b/postgresqleu/confreg/templatetags/join_days.py
index dd6f4393..95dc24be 100644
--- a/postgresqleu/confreg/templatetags/join_days.py
+++ b/postgresqleu/confreg/templatetags/join_days.py
@@ -2,6 +2,7 @@ from django import template
register = template.Library()
+
@register.filter
def join_days(value):
# Value is a list of RegistrationDay:s
diff --git a/postgresqleu/confreg/templatetags/leadingnbsp.py b/postgresqleu/confreg/templatetags/leadingnbsp.py
index 4dc1f67c..632e8a7b 100644
--- a/postgresqleu/confreg/templatetags/leadingnbsp.py
+++ b/postgresqleu/confreg/templatetags/leadingnbsp.py
@@ -6,6 +6,7 @@ register = template.Library()
re_leadingspace = re.compile('^ +')
+
@register.filter
def leadingnbsp(value):
if value.startswith(' '):
diff --git a/postgresqleu/confreg/util.py b/postgresqleu/confreg/util.py
index a7ac11ab..ae2989a5 100644
--- a/postgresqleu/confreg/util.py
+++ b/postgresqleu/confreg/util.py
@@ -7,9 +7,11 @@ from postgresqleu.mailqueue.util import send_simple_mail, send_template_mail
from models import PrepaidVoucher, DiscountCode, RegistrationWaitlistHistory
from models import ConferenceRegistration
+
class InvoicerowsException(Exception):
pass
+
def invoicerows_for_registration(reg, update_used_vouchers):
# Return the rows that would be used to build an invoice for this
# registration. Format is tuple of (description, num, cost)
@@ -190,7 +192,6 @@ def cancel_registration(reg, is_unconfirmed=False):
reg.delete()
-
def get_invoice_autocancel(*args):
# Each argument is expected to be an integer with number of hours,
# or None if there is no limit
diff --git a/postgresqleu/confreg/views.py b/postgresqleu/confreg/views.py
index 07b3834e..1e5d8add 100644
--- a/postgresqleu/confreg/views.py
+++ b/postgresqleu/confreg/views.py
@@ -65,6 +65,7 @@ from StringIO import StringIO
import json
import markdown
+
#
# Render a conference page. It will load the template using the jinja system
# if the conference is configured for jinja templates.
@@ -81,6 +82,7 @@ def render_conference_response(request, conference, pagemagic, templatename, dic
raise Http404("Template not found")
+
def _get_registration_signups(conference, reg):
# Left join is hard to do efficiently with the django ORM, so let's do a query instead
cursor = connection.cursor()
@@ -91,6 +93,7 @@ def _get_registration_signups(conference, reg):
})
return [dict(zip(['id', 'title', 'deadline', 'closed', 'savedat'], r)) for r in cursor.fetchall()]
+
# Not a view in itself, only called from other views
def _registration_dashboard(request, conference, reg, has_other_multiregs, redir_root):
mails = AttendeeMail.objects.filter(conference=conference, regclasses=reg.regtype.regclass)
@@ -157,6 +160,7 @@ def _registration_dashboard(request, conference, reg, has_other_multiregs, redir
'displayfields': displayfields,
})
+
def confhome(request, confname):
conference = get_object_or_404(Conference, urlname=confname)
@@ -168,6 +172,7 @@ def confhome(request, confname):
return HttpResponseRedirect(conference.confurl)
+
def news_json(request, confname):
news = ConferenceNews.objects.select_related('author').filter(conference__urlname=confname,
datetime__lt=datetime.now(),
@@ -264,7 +269,6 @@ def register(request, confname, whatfor=None):
reg.delete()
return HttpResponseRedirect("{0}canceled/".format(redir_root))
-
form = ConferenceRegistrationForm(request.user, data=request.POST, instance=reg)
if form.is_valid():
reg = form.save(commit=False)
@@ -318,6 +322,7 @@ def register(request, confname, whatfor=None):
'costamount': reg.regtype and reg.regtype.cost or 0,
})
+
@login_required
@transaction.atomic
def changereg(request, confname):
@@ -330,6 +335,7 @@ def changereg(request, confname):
return _registration_dashboard(request, conference, reg, False, '../')
+
@login_required
@transaction.atomic
def multireg(request, confname, regid=None):
@@ -363,7 +369,6 @@ def multireg(request, confname, regid=None):
)
redir_root = './'
-
if request.method == 'POST':
if request.POST['submit'] == 'New registration':
# New registration form
@@ -490,6 +495,7 @@ def _create_and_assign_bulk_payment(user, conference, regs, invoicerows, recipie
return bp
+
@login_required
@transaction.atomic
def multireg_newinvoice(request, confname):
@@ -588,7 +594,6 @@ def multireg_newinvoice(request, confname):
form = MultiRegInvoiceForm()
-
return render_conference_response(request, conference, 'reg', 'confreg/regmulti_invoice.html', {
'form': form,
'invoicerows': invoicerows,
@@ -596,12 +601,14 @@ def multireg_newinvoice(request, confname):
'totalwithvat': totalwithvat,
})
+
@login_required
def multireg_zeropay(request, confname):
conference = get_object_or_404(Conference, urlname=confname)
return render_conference_response(request, conference, 'reg', 'confreg/regmulti_zeropay.html', {
})
+
@login_required
@transaction.atomic
def multireg_bulkview(request, confname, bulkid):
@@ -618,6 +625,7 @@ def multireg_bulkview(request, confname, bulkid):
'invoice': InvoicePresentationWrapper(bp.invoice, '.'),
})
+
@login_required
@transaction.atomic
def multireg_attach(request, token):
@@ -639,12 +647,14 @@ def multireg_attach(request, token):
'reg': reg,
})
+
def feedback_available(request):
conferences = Conference.objects.filter(feedbackopen=True).order_by('startdate')
return render(request, 'confreg/feedback_available.html', {
'conferences': conferences,
})
+
@login_required
@transaction.atomic
def reg_add_options(request, confname):
@@ -842,6 +852,7 @@ def feedback(request, confname):
'is_tester': is_conf_tester,
})
+
@login_required
def feedback_session(request, confname, sessionid):
# Room for optimization: don't get these as separate steps
@@ -1034,6 +1045,7 @@ def _scheduledata(request, conference):
'tracks': tracks,
}
+
def schedule(request, confname):
conference = get_object_or_404(Conference, urlname=confname)
@@ -1041,9 +1053,9 @@ def schedule(request, confname):
if not conference.testers.filter(pk=request.user.id):
return render_conference_response(request, conference, 'schedule', 'confreg/scheduleclosed.html')
-
return render_conference_response(request, conference, 'schedule', 'confreg/schedule.html', _scheduledata(request, conference))
+
def schedulejson(request, confname):
conference = get_authenticated_conference(request, confname)
@@ -1052,6 +1064,7 @@ def schedulejson(request, confname):
indent=2),
content_type='application/json')
+
def sessionlist(request, confname):
conference = get_object_or_404(Conference, urlname=confname)
@@ -1067,6 +1080,7 @@ def sessionlist(request, confname):
'sessions': sessions,
})
+
def schedule_ical(request, confname):
conference = get_object_or_404(Conference, urlname=confname)
@@ -1082,6 +1096,7 @@ def schedule_ical(request, confname):
'servername': request.META['SERVER_NAME'],
}, content_type='text/calendar')
+
def session(request, confname, sessionid, junk=None):
conference = get_object_or_404(Conference, urlname=confname)
@@ -1095,6 +1110,7 @@ def session(request, confname, sessionid, junk=None):
'slides': ConferenceSessionSlides.objects.filter(session=session),
})
+
def session_slides(request, confname, sessionid, slideid):
conference = get_object_or_404(Conference, urlname=confname)
@@ -1107,6 +1123,7 @@ def session_slides(request, confname, sessionid, slideid):
return HttpResponse(slides.content,
content_type='application/pdf')
+
def speaker(request, confname, speakerid, junk=None):
conference = get_object_or_404(Conference, urlname=confname)
if not conference.sessionsactive:
@@ -1122,10 +1139,12 @@ def speaker(request, confname, speakerid, junk=None):
'sessions': sessions,
})
+
def speakerphoto(request, speakerid):
speakerphoto = get_object_or_404(Speaker_Photo, pk=speakerid)
return HttpResponse(base64.b64decode(speakerphoto.photo), content_type='image/jpg')
+
@login_required
def speakerprofile(request, confurlname=None):
if confurlname:
@@ -1169,6 +1188,7 @@ def speakerprofile(request, confurlname=None):
'form': form,
})
+
@login_required
@transaction.atomic
def callforpapers(request, confname):
@@ -1324,6 +1344,7 @@ def callforpapers_edit(request, confname, sessionid):
'session': session,
})
+
@login_required
def public_speaker_lookup(request, confname):
conference = get_object_or_404(Conference, urlname=confname)
@@ -1344,6 +1365,7 @@ def public_speaker_lookup(request, confname):
'values': vals,
}), content_type='application/json')
+
@login_required
@transaction.atomic
def callforpapers_copy(request, confname):
@@ -1378,6 +1400,7 @@ def callforpapers_copy(request, confname):
'form': form,
})
+
@login_required
def callforpapers_delslides(request, confname, sessionid, slideid):
conference = get_object_or_404(Conference, urlname=confname)
@@ -1388,6 +1411,7 @@ def callforpapers_delslides(request, confname, sessionid, slideid):
slide.delete()
return HttpResponseRedirect('../../')
+
@login_required
@transaction.atomic
def callforpapers_confirm(request, confname, sessionid):
@@ -1438,6 +1462,7 @@ def callforpapers_confirm(request, confname, sessionid):
'session': session,
})
+
@login_required
@transaction.atomic
def confirmreg(request, confname):
@@ -1467,7 +1492,6 @@ def confirmreg(request, confname):
'reason': s,
})
-
# Is this registration already on the waitlist?
if hasattr(reg, 'registrationwaitlistentry'):
if reg.registrationwaitlistentry.offeredon:
@@ -1617,7 +1641,6 @@ def confirmreg(request, confname):
if reg.firstname != request.user.first_name or reg.lastname != request.user.last_name:
registration_warnings.append(u"Registration name ({0} {1}) does not match account name ({2} {3}). Please make sure that this is correct, and that you are <strong>not</strong> registering using a different account than your own, as access to the account may be needed during the event!".format(reg.firstname, reg.lastname, request.user.first_name, request.user.last_name))
-
return render_conference_response(request, conference, 'reg', 'confreg/regform_confirm.html', {
'reg': reg,
'invoicerows': invoicerows,
@@ -1663,6 +1686,7 @@ def waitlist_signup(request, confname):
# which will show the waitlist information.
return HttpResponseRedirect("../confirm/")
+
@login_required
@transaction.atomic
def waitlist_cancel(request, confname):
@@ -1694,11 +1718,13 @@ def waitlist_cancel(request, confname):
# which will show the waitlist information.
return HttpResponseRedirect("../confirm/")
+
@login_required
def cancelreg(request, confname):
conference = get_object_or_404(Conference, urlname=confname)
return render_conference_response(request, conference, 'reg', 'confreg/canceled.html')
+
@login_required
@transaction.atomic
def invoice(request, confname, regid):
@@ -1729,6 +1755,7 @@ def invoice(request, confname, regid):
'invoice': InvoicePresentationWrapper(reg.invoice, "%s/events/%s/register/" % (settings.SITEBASE, conference.urlname)),
})
+
@login_required
@transaction.atomic
def invoice_cancel(request, confname, regid):
@@ -1757,6 +1784,7 @@ def invoice_cancel(request, confname, regid):
'reg': reg,
})
+
@login_required
def attendee_mail(request, confname, mailid):
conference = get_object_or_404(Conference, urlname=confname)
@@ -1769,6 +1797,7 @@ def attendee_mail(request, confname, mailid):
'mail': mail,
})
+
@transaction.atomic
def optout(request, token=None):
if token:
@@ -1820,6 +1849,7 @@ def optout(request, token=None):
'series': series,
})
+
@transaction.atomic
def createvouchers(request, confname):
conference = get_authenticated_conference(request, confname)
@@ -1883,6 +1913,7 @@ def createvouchers(request, confname):
'breadcrumbs': (('/events/admin/{0}/prepaid/list/'.format(conference.urlname), 'Prepaid vouchers'),),
})
+
def listvouchers(request, confname):
conference = get_authenticated_conference(request, confname)
@@ -1894,6 +1925,7 @@ def listvouchers(request, confname):
'helplink': 'vouchers',
})
+
def viewvouchers(request, confname, batchid):
conference = get_authenticated_conference(request, confname)
@@ -1915,6 +1947,7 @@ def viewvouchers(request, confname, batchid):
'helplink': 'vouchers',
})
+
@transaction.atomic
def delvouchers(request, confname, batchid, voucherid):
conference = get_authenticated_conference(request, confname)
@@ -1936,6 +1969,7 @@ def delvouchers(request, confname, batchid, voucherid):
return HttpResponseRedirect('/events/admin/{0}/prepaid/list/'.format(confname))
+
@login_required
def viewvouchers_user(request, confname, batchid):
conference = get_object_or_404(Conference, urlname=confname)
@@ -1949,6 +1983,7 @@ def viewvouchers_user(request, confname, batchid):
'vouchers': vouchers,
})
+
def emailvouchers(request, confname, batchid):
conference = get_authenticated_conference(request, confname)
@@ -1969,6 +2004,7 @@ def emailvouchers(request, confname, batchid):
)
return HttpResponse('OK')
+
@login_required
@transaction.atomic
def bulkpay(request, confname):
@@ -2205,6 +2241,7 @@ def talkvote(request, confname):
'helplink': 'callforpapers',
})
+
@login_required
@transaction.atomic
def talkvote_status(request, confname):
@@ -2226,6 +2263,7 @@ def talkvote_status(request, confname):
session.status != session.lastnotifiedstatus and 1 or 0,
), content_type='text/plain')
+
@login_required
@transaction.atomic
def talkvote_vote(request, confname):
@@ -2250,6 +2288,7 @@ def talkvote_vote(request, confname):
avg = 0
return HttpResponse("{0:.2f}".format(avg), content_type='text/plain')
+
@login_required
@transaction.atomic
def talkvote_comment(request, confname):
@@ -2266,6 +2305,7 @@ def talkvote_comment(request, confname):
return HttpResponse(vote.comment, content_type='text/plain')
+
@login_required
@csrf_exempt
@transaction.atomic
@@ -2277,7 +2317,6 @@ def createschedule(request, confname):
):
raise PermissionDenied('You are not an administrator or talk voter for this conference!')
-
if request.method == "POST":
if request.POST.has_key('get'):
# Get the current list of tentatively scheduled talks
@@ -2362,6 +2401,7 @@ def createschedule(request, confname):
'helplink': 'schedule',
})
+
@login_required
def publishschedule(request, confname):
conference = get_authenticated_conference(request, confname)
@@ -2410,6 +2450,7 @@ def publishschedule(request, confname):
'changes': changes,
})
+
def reports(request, confname):
conference = get_authenticated_conference(request, confname)
@@ -2471,6 +2512,7 @@ def simple_report(request, confname):
'helplink': 'reports',
})
+
@login_required
def admin_dashboard(request):
if request.user.is_superuser:
@@ -2501,6 +2543,7 @@ def admin_dashboard(request):
'cross_conference': request.user.is_superuser or ConferenceSeries.objects.filter(administrators=request.user).exists(),
})
+
def admin_dashboard_single(request, urlname):
conference = get_authenticated_conference(request, urlname)
@@ -2516,6 +2559,7 @@ def admin_dashboard_single(request, urlname):
'pending_sessions': conditional_exec_to_scalar(conference.scheduleactive, "SELECT EXISTS (SELECT 1 FROM confreg_conferencesession s WHERE s.conference_id=%(confid)s AND s.status=0)", {'confid': conference.id}),
})
+
def admin_registration_dashboard(request, urlname):
conference = get_authenticated_conference(request, urlname)
@@ -2599,6 +2643,7 @@ WHERE dc.conference_id={1} AND (r.conference_id={1} OR r.conference_id IS NULL)
'helplink': 'registrations',
})
+
def admin_registration_list(request, urlname):
conference = get_authenticated_conference(request, urlname)
@@ -2629,6 +2674,7 @@ def admin_registration_list(request, urlname):
'helplink': 'registrations',
})
+
def admin_registration_single(request, urlname, regid):
conference = get_authenticated_conference(request, urlname)
@@ -2650,6 +2696,7 @@ def admin_registration_single(request, urlname, regid):
'helplink': 'registrations',
})
+
@transaction.atomic
def admin_registration_cancel(request, urlname, regid):
conference = get_authenticated_conference(request, urlname)
@@ -2671,6 +2718,7 @@ def admin_registration_cancel(request, urlname, regid):
'helplink': 'waitlist',
})
+
@transaction.atomic
def admin_registration_clearcode(request, urlname, regid):
conference = get_authenticated_conference(request, urlname)
@@ -2684,6 +2732,7 @@ def admin_registration_clearcode(request, urlname, regid):
reg.save()
return HttpResponseRedirect("../")
+
@transaction.atomic
def admin_waitlist(request, urlname):
conference = get_authenticated_conference(request, urlname)
@@ -2755,6 +2804,7 @@ def admin_waitlist(request, urlname):
'helplink': 'waitlist',
})
+
@transaction.atomic
def admin_waitlist_cancel(request, urlname, wlid):
conference = get_authenticated_conference(request, urlname)
@@ -2908,6 +2958,7 @@ def admin_attendeemail(request, urlname):
'helplink': 'emails',
})
+
def admin_attendeemail_view(request, urlname, mailid):
conference = get_authenticated_conference(request, urlname)
@@ -2920,6 +2971,7 @@ def admin_attendeemail_view(request, urlname, mailid):
'helplink': 'emails',
})
+
@transaction.atomic
def session_notify_queue(request, urlname):
conference = get_authenticated_conference(request, urlname)
@@ -2954,6 +3006,7 @@ def session_notify_queue(request, urlname):
'notifysessions': notifysessions,
})
+
@transaction.atomic
def transfer_reg(request, urlname):
conference = get_authenticated_conference(request, urlname)
@@ -3027,7 +3080,6 @@ def transfer_reg(request, urlname):
txt="Transferred from {0} to {1}".format(fromreg.email, toreg.email)
).save()
-
# Additional options
if fromreg.additionaloptions.exists():
for o in fromreg.additionaloptions.all():
@@ -3247,6 +3299,7 @@ def crossmailoptions(request):
])
return HttpResponse(json.dumps(r), content_type="application/json")
+
# Admin view that's used to send email to multiple users
@superuser_required
@transaction.atomic
@@ -3309,7 +3362,6 @@ def admin_email_session(request, sessionids):
else:
form = EmailSessionForm(initial={'sender': sessions[0].conference.contactaddr, 'returnurl': request.GET.has_key('orig') and request.GET['orig'] or ''})
-
return render(request, 'confreg/admin_email.html', {
'form': form,
'recipientlist': ", ".join([s.name for s in speakers]),
diff --git a/postgresqleu/confreg/volsched.py b/postgresqleu/confreg/volsched.py
index 99522617..c673eba5 100644
--- a/postgresqleu/confreg/volsched.py
+++ b/postgresqleu/confreg/volsched.py
@@ -11,12 +11,14 @@ from views import render_conference_response
from models import Conference, ConferenceRegistration
from models import VolunteerSlot, VolunteerAssignment
+
def _check_admin(request, conference):
if request.user.is_superuser:
return True
else:
return conference.administrators.filter(pk=request.user.id).exists() or conference.series.administrators.filter(pk=request.user.id).exists()
+
def _get_conference_and_reg(request, urlname):
conference = get_object_or_404(Conference, urlname=urlname)
is_admin = _check_admin(request, conference)
@@ -30,6 +32,7 @@ def _get_conference_and_reg(request, urlname):
return (conference, is_admin, reg)
+
@login_required
def volunteerschedule(request, urlname, adm=False):
try:
@@ -61,6 +64,7 @@ def volunteerschedule(request, urlname, adm=False):
'rowerror': request.session.pop('rowerror', None),
})
+
@login_required
@transaction.atomic
def signup(request, urlname, slotid, adm=False):
@@ -77,6 +81,7 @@ def signup(request, urlname, slotid, adm=False):
VolunteerAssignment(slot=slot, reg=reg, vol_confirmed=True, org_confirmed=False).save()
return HttpResponseRedirect('../..')
+
@login_required
@transaction.atomic
def add(request, urlname, slotid, regid, adm=False):
@@ -96,6 +101,7 @@ def add(request, urlname, slotid, regid, adm=False):
VolunteerAssignment(slot=slot, reg=addreg, vol_confirmed=False, org_confirmed=True).save()
return HttpResponseRedirect('../..')
+
@login_required
@transaction.atomic
def remove(request, urlname, slotid, aid, adm=False):
diff --git a/postgresqleu/confsponsor/admin.py b/postgresqleu/confsponsor/admin.py
index 7ef09392..43b4b0c8 100644
--- a/postgresqleu/confsponsor/admin.py
+++ b/postgresqleu/confsponsor/admin.py
@@ -15,6 +15,7 @@ from models import SponsorshipBenefit, SponsorClaimedBenefit
from benefits import get_benefit_class
+
class SponsorshipBenefitInlineFormset(BaseInlineFormSet):
def clean(self):
for f in self.forms:
@@ -29,11 +30,13 @@ class SponsorshipBenefitInlineFormset(BaseInlineFormSet):
if s:
f._errors['class_parameters'] = ErrorList([s])
+
class SponsorshipBenefitInline(admin.TabularInline):
model = SponsorshipBenefit
extra = 1
formset = SponsorshipBenefitInlineFormset
+
class SponsorshipLevelForm(ConcurrentProtectedModelForm):
class Meta:
model = SponsorshipLevel
@@ -43,6 +46,7 @@ class SponsorshipLevelForm(ConcurrentProtectedModelForm):
super(SponsorshipLevelForm, self).__init__(*args, **kwargs)
self.fields['paymentmethods'].label_from_instance = lambda x: x.internaldescription
+
class SponsorshipLevelAdmin(admin.ModelAdmin):
list_filter = ['conference', ]
list_display = ['levelname', 'conference', ]
@@ -58,6 +62,7 @@ class SponsorshipLevelAdmin(admin.ModelAdmin):
return HttpResponseRedirect("/admin/confsponsor/sponsorshiplevel/{0}/copy".format(source_level[0].id))
copy_sponsorshiplevel.short_description = "Copy sponsorship level"
+
class SponsorAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelForm):
class Meta:
model = Sponsor
@@ -81,17 +86,21 @@ class SponsorClaimedBenefitInline(admin.TabularInline):
can_delete = False
max_num = 0
+
class LevelListFilter(admin.SimpleListFilter):
title = 'Level'
parameter_name = 'level'
+
def lookups(self, request, model_admin):
cid = request.GET.get('conference__id__exact', -1)
if cid >= 0:
return ((l.id, l.levelname) for l in SponsorshipLevel.objects.filter(conference__id=cid))
+
def queryset(self, request, queryset):
if self.value():
return queryset.filter(level__id=self.value())
+
class SponsorAdmin(admin.ModelAdmin):
exclude = ('invoice', )
readonly_fields = ('invoice_link', )
@@ -108,6 +117,7 @@ class SponsorAdmin(admin.ModelAdmin):
return ""
invoice_link.short_description = 'Invoice'
+
admin.site.register(SponsorshipContract)
admin.site.register(SponsorshipLevel, SponsorshipLevelAdmin)
admin.site.register(Sponsor, SponsorAdmin)
diff --git a/postgresqleu/confsponsor/backendforms.py b/postgresqleu/confsponsor/backendforms.py
index b5bdab2b..3c4730f2 100644
--- a/postgresqleu/confsponsor/backendforms.py
+++ b/postgresqleu/confsponsor/backendforms.py
@@ -16,25 +16,26 @@ from benefitclasses import all_benefits
import json
+
class BackendSponsorForm(BackendForm):
helplink = 'sponsors#sponsor'
- class Meta:
- model = Sponsor
- fields = ['name', 'displayname', 'url', 'twittername',
- 'invoiceaddr', 'vatstatus', 'vatnumber',
- 'managers', ]
fieldsets = [
{'id': 'base_info', 'legend': 'Basic information', 'fields': ['name', 'displayname', 'url', 'twittername']},
{'id': 'financial', 'legend': 'Financial information', 'fields': ['invoiceaddr', 'vatstatus', 'vatnumber']},
{'id': 'management', 'legend': 'Management', 'fields': ['managers']},
]
-
selectize_multiple_fields = {
'managers': GeneralAccountLookup(),
}
auto_cascade_delete_to = ['sponsor_managers', ]
+ class Meta:
+ model = Sponsor
+ fields = ['name', 'displayname', 'url', 'twittername',
+ 'invoiceaddr', 'vatstatus', 'vatnumber',
+ 'managers', ]
+
class BackendSponsorshipLevelBenefitForm(BackendForm):
helplink = 'sponsors#benefit'
@@ -103,6 +104,7 @@ class BackendSponsorshipLevelBenefitForm(BackendForm):
'map': {k: v['class'].default_params for k, v in all_benefits.items()}
}])
+
class BackendSponsorshipLevelBenefitManager(object):
title = 'Benefits'
singular = 'benefit'
@@ -123,6 +125,7 @@ class BackendSponsorshipLevelBenefitManager(object):
def get_instancemaker(self, masterobj):
return lambda: SponsorshipBenefit(level=masterobj, class_parameters={})
+
class BackendSponsorshipLevelForm(BackendForm):
helplink = 'sponsors#level'
list_fields = ['levelname', 'levelcost', 'available', ]
@@ -141,7 +144,6 @@ class BackendSponsorshipLevelForm(BackendForm):
self.fields['contract'].queryset = SponsorshipContract.objects.filter(conference=self.conference)
self.fields['paymentmethods'].label_from_instance = lambda x: x.internaldescription
-
@classmethod
def copy_from_conference(self, targetconf, sourceconf, idlist):
for id in idlist:
@@ -165,10 +167,12 @@ class BackendSponsorshipLevelForm(BackendForm):
b.level = newlevel
b.save()
+
class BackendSponsorshipContractForm(BackendForm):
helplink = 'sponsors#contract'
list_fields = ['contractname', ]
file_fields = ['contractpdf', ]
+
class Meta:
model = SponsorshipContract
fields = ['contractname', 'contractpdf', ]
diff --git a/postgresqleu/confsponsor/backendviews.py b/postgresqleu/confsponsor/backendviews.py
index 0cfbc0e2..6e36376a 100644
--- a/postgresqleu/confsponsor/backendviews.py
+++ b/postgresqleu/confsponsor/backendviews.py
@@ -6,6 +6,7 @@ from backendforms import BackendSponsorForm
from backendforms import BackendSponsorshipLevelForm
from backendforms import BackendSponsorshipContractForm
+
def edit_sponsor(request, urlname, sponsorid):
conference = get_authenticated_conference(request, urlname)
sponsor = Sponsor.objects.get(conference=conference, pk=sponsorid)
@@ -23,6 +24,7 @@ def edit_sponsor(request, urlname, sponsorid):
('/events/sponsor/admin/{0}/{1}/'.format(urlname, sponsor.pk), sponsor.name),
])
+
def edit_sponsorship_levels(request, urlname, rest):
return backend_list_editor(request,
urlname,
@@ -30,6 +32,7 @@ def edit_sponsorship_levels(request, urlname, rest):
rest,
breadcrumbs=[('/events/sponsor/admin/{0}/'.format(urlname), 'Sponsors'), ])
+
def edit_sponsorship_contracts(request, urlname, rest):
return backend_list_editor(request,
urlname,
diff --git a/postgresqleu/confsponsor/benefitclasses/__init__.py b/postgresqleu/confsponsor/benefitclasses/__init__.py
index cfddab69..45a31337 100644
--- a/postgresqleu/confsponsor/benefitclasses/__init__.py
+++ b/postgresqleu/confsponsor/benefitclasses/__init__.py
@@ -4,9 +4,11 @@ import entryvouchers
import providetext
import attendeelist
+
def _make_benefit(n, c):
all_benefits[n] = {'name': c.description, 'class': c}
+
all_benefits = {}
# We hardcode this list to ensure the integer sequence is the same as it's stored
# in a db. Yes, it's kinda ugly...
diff --git a/postgresqleu/confsponsor/benefitclasses/attendeelist.py b/postgresqleu/confsponsor/benefitclasses/attendeelist.py
index b72e504a..88e219a8 100644
--- a/postgresqleu/confsponsor/benefitclasses/attendeelist.py
+++ b/postgresqleu/confsponsor/benefitclasses/attendeelist.py
@@ -10,6 +10,7 @@ from base import BaseBenefit, BaseBenefitForm
from postgresqleu.confreg.models import ConferenceRegistration
+
class AttendeeListForm(BaseBenefitForm):
confirm = forms.ChoiceField(label="Claim benefit", choices=((0, '* Choose'), (1, 'Claim this benefit'), (2, 'Decline this benefit')))
@@ -18,6 +19,7 @@ class AttendeeListForm(BaseBenefitForm):
raise ValidationError('You must decide if you want to claim this benefit')
return self.cleaned_data['confirm']
+
class AttendeeList(BaseBenefit):
description = "List of attendee email addresses"
param_struct = {}
@@ -59,4 +61,3 @@ class AttendeeList(BaseBenefit):
return "List of attendees will be made available here once the conference is over."
else:
return ""
-
diff --git a/postgresqleu/confsponsor/benefitclasses/base.py b/postgresqleu/confsponsor/benefitclasses/base.py
index 69ea2cc1..7c3c071f 100644
--- a/postgresqleu/confsponsor/benefitclasses/base.py
+++ b/postgresqleu/confsponsor/benefitclasses/base.py
@@ -2,8 +2,10 @@ from django import forms
from postgresqleu.util.validators import validate_json_structure
+
class BaseBenefit(object):
default_params = {}
+
def __init__(self, level, params):
self.level = level
self.params = params
@@ -21,6 +23,7 @@ class BaseBenefit(object):
def save_form(self, form, claim, request):
raise Exception("Form saving not implemented!")
+
class BaseBenefitForm(forms.Form):
def __init__(self, benefit, *args, **kwargs):
self.params = benefit.class_parameters
diff --git a/postgresqleu/confsponsor/benefitclasses/entryvouchers.py b/postgresqleu/confsponsor/benefitclasses/entryvouchers.py
index 550c8441..9e16a81e 100644
--- a/postgresqleu/confsponsor/benefitclasses/entryvouchers.py
+++ b/postgresqleu/confsponsor/benefitclasses/entryvouchers.py
@@ -11,6 +11,7 @@ from postgresqleu.mailqueue.util import send_template_mail
from postgresqleu.confreg.models import RegistrationType, PrepaidBatch, PrepaidVoucher
+
class EntryVouchersForm(BaseBenefitForm):
vouchercount = forms.IntegerField(label='Number of vouchers', min_value=0)
@@ -20,6 +21,7 @@ class EntryVouchersForm(BaseBenefitForm):
self.fields['vouchercount'].validators.append(MaxValueValidator(int(self.params['num'])))
self.fields['vouchercount'].help_text = "Enter the number of vouchers to generate (up to %s). Please note that you cannot generate more vouchers at a later date, so please generate all the ones you want at once. If you do not want any sponsor vouchers, we ask you to please claim the number 0, so we have it for our records." % int(self.params['num'])
+
class EntryVouchers(BaseBenefit):
description = "Claim entry vouchers"
default_params = {"num": 1, "type": ""}
diff --git a/postgresqleu/confsponsor/benefitclasses/imageupload.py b/postgresqleu/confsponsor/benefitclasses/imageupload.py
index f35b4ef2..cd34c302 100644
--- a/postgresqleu/confsponsor/benefitclasses/imageupload.py
+++ b/postgresqleu/confsponsor/benefitclasses/imageupload.py
@@ -7,6 +7,7 @@ from postgresqleu.util.storage import InlineEncodedStorage
from base import BaseBenefit, BaseBenefitForm
+
class ImageUploadForm(BaseBenefitForm):
decline = forms.BooleanField(label='Decline this benefit', required=False)
image = forms.FileField(label='Image file', required=False)
@@ -62,6 +63,7 @@ class ImageUploadForm(BaseBenefitForm):
return self.cleaned_data['image']
+
class ImageUpload(BaseBenefit):
description = 'Require uploaded image'
default_params = {"format": "png", "xres": 0, "yres": 0, "transparent": 0}
@@ -87,4 +89,3 @@ class ImageUpload(BaseBenefit):
def render_claimdata(self, claimedbenefit):
# We don't use the datafield, just the id
return 'Uploaded image: <img src="/events/sponsor/admin/imageview/%s/" />' % claimedbenefit.id
-
diff --git a/postgresqleu/confsponsor/benefitclasses/providetext.py b/postgresqleu/confsponsor/benefitclasses/providetext.py
index 3298bf60..04a00a11 100644
--- a/postgresqleu/confsponsor/benefitclasses/providetext.py
+++ b/postgresqleu/confsponsor/benefitclasses/providetext.py
@@ -3,6 +3,7 @@ from django import forms
from base import BaseBenefit, BaseBenefitForm
+
class ProvideTextForm(BaseBenefitForm):
decline = forms.BooleanField(label='Decline this benefit', required=False)
text = forms.CharField(label='Text', required=False, widget=forms.Textarea)
@@ -34,6 +35,7 @@ class ProvideTextForm(BaseBenefitForm):
raise ValidationError('Must be less than %s words.' % self.params['maxwords'])
return d
+
class ProvideText(BaseBenefit):
description = "Provide text string"
default_params = {"minwords": 0, "maxwords": 0, "minchars": 0, "maxchars": 0}
diff --git a/postgresqleu/confsponsor/benefitclasses/requireclaiming.py b/postgresqleu/confsponsor/benefitclasses/requireclaiming.py
index a3c443a5..fc66b39a 100644
--- a/postgresqleu/confsponsor/benefitclasses/requireclaiming.py
+++ b/postgresqleu/confsponsor/benefitclasses/requireclaiming.py
@@ -3,6 +3,7 @@ from django.core.exceptions import ValidationError
from base import BaseBenefit, BaseBenefitForm
+
class RequireClaimingForm(BaseBenefitForm):
confirm = forms.ChoiceField(label="Claim benefit", choices=((0, '* Choose'), (1, 'Claim this benefit'), (2, 'Decline this benefit')))
@@ -11,6 +12,7 @@ class RequireClaimingForm(BaseBenefitForm):
raise ValidationError('You must decide if you want to claim this benefit')
return self.cleaned_data['confirm']
+
class RequireClaiming(BaseBenefit):
description = "Requires explicit claiming"
param_struct = {}
diff --git a/postgresqleu/confsponsor/benefits.py b/postgresqleu/confsponsor/benefits.py
index f4bbcfaf..bc78ac59 100644
--- a/postgresqleu/confsponsor/benefits.py
+++ b/postgresqleu/confsponsor/benefits.py
@@ -2,5 +2,6 @@ from benefitclasses import all_benefits
benefit_choices = [(k, v['name']) for k, v in all_benefits.items()]
+
def get_benefit_class(benefitid):
return all_benefits[benefitid]['class']
diff --git a/postgresqleu/confsponsor/forms.py b/postgresqleu/confsponsor/forms.py
index bdfe2aa2..3666b07e 100644
--- a/postgresqleu/confsponsor/forms.py
+++ b/postgresqleu/confsponsor/forms.py
@@ -15,6 +15,7 @@ from postgresqleu.util.validators import BeforeValidator, AfterValidator, Twitte
from datetime import date, timedelta
+
def _int_with_default(s, default):
try:
return int(s)
@@ -23,6 +24,7 @@ def _int_with_default(s, default):
except TypeError:
return default
+
class SponsorSignupForm(forms.Form):
name = forms.CharField(label="Company name *", min_length=3, max_length=100, help_text="This name is used on invoices and in internal communication")
displayname = forms.CharField(label="Display name *", min_length=3, max_length=100, help_text="This name is displayed on websites and in public communication")
@@ -88,8 +90,10 @@ class SponsorSignupForm(forms.Form):
return cleaned_data
+
class SponsorSendEmailForm(forms.ModelForm):
confirm = forms.BooleanField(label="Confirm", required=False)
+
class Meta:
model = SponsorMail
exclude = ('conference', )
@@ -107,6 +111,7 @@ class SponsorSendEmailForm(forms.ModelForm):
if not self.cleaned_data['confirm']:
raise ValidationError("Please check this box to confirm that you are really sending this email! There is no going back!")
+
class PurchaseVouchersForm(forms.Form):
regtype = forms.ModelChoiceField(queryset=None, required=True, label="Registration type")
num = forms.IntegerField(required=True, initial=2,
@@ -127,6 +132,7 @@ class PurchaseVouchersForm(forms.Form):
self.fields['regtype'].queryset = RegistrationType.objects.filter(Q(conference=self.conference, active=True, specialtype__isnull=True, cost__gt=0) & activeQ)
del self.fields['confirm']
+
class PurchaseDiscountForm(forms.Form):
code = forms.CharField(required=True, max_length=100, min_length=4,
help_text='Enter the code you want to use to provide the discount.')
diff --git a/postgresqleu/confsponsor/invoicehandler.py b/postgresqleu/confsponsor/invoicehandler.py
index 96791b10..32d07ccc 100644
--- a/postgresqleu/confsponsor/invoicehandler.py
+++ b/postgresqleu/confsponsor/invoicehandler.py
@@ -11,6 +11,7 @@ from models import Sponsor, PurchasedVoucher
from postgresqleu.confreg.models import PrepaidBatch, PrepaidVoucher
import postgresqleu.invoices.models as invoicemodels
+
def confirm_sponsor(sponsor, who):
# Confirm a sponsor, including sending the confirmation email.
# This will save the specified sponsor model as well, but the function
@@ -99,7 +100,6 @@ class InvoiceProcessor(object):
msgtxt,
sendername=sponsor.conference.conferencename)
-
# Return the user to the sponsor page if they have paid.
def get_return_url(self, invoice):
try:
@@ -115,6 +115,7 @@ def get_sponsor_invoice_address(name, invoiceaddr, vatnumber):
else:
return u"{0}\n{1}".format(name, invoiceaddr)
+
# Generate an invoice for sponsorship
def create_sponsor_invoice(user, sponsor):
conference = sponsor.conference
diff --git a/postgresqleu/confsponsor/management/commands/sponsor_generate_discount_invoices.py b/postgresqleu/confsponsor/management/commands/sponsor_generate_discount_invoices.py
index b930c149..c1b059e6 100644
--- a/postgresqleu/confsponsor/management/commands/sponsor_generate_discount_invoices.py
+++ b/postgresqleu/confsponsor/management/commands/sponsor_generate_discount_invoices.py
@@ -15,6 +15,7 @@ from postgresqleu.confsponsor.models import Sponsor
from postgresqleu.mailqueue.util import send_simple_mail, send_template_mail
from postgresqleu.invoices.util import InvoiceManager, InvoiceWrapper
+
class Command(BaseCommand):
help = 'Generate invoices for discount codes'
diff --git a/postgresqleu/confsponsor/models.py b/postgresqleu/confsponsor/models.py
index 28f2c846..b92dc1a3 100644
--- a/postgresqleu/confsponsor/models.py
+++ b/postgresqleu/confsponsor/models.py
@@ -21,6 +21,7 @@ vat_status_choices = (
(2, 'Company is from outside EU'),
)
+
class SponsorshipContract(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
contractname = models.CharField(max_length=100, null=False, blank=False, verbose_name='Contract name')
@@ -37,10 +38,14 @@ class SponsorshipContract(models.Model):
if not self.contractpdf:
self.contractpdf.storage._delete(self.id)
return super(SponsorshipContract, self).save(update_fields=update_fields)
+
def delete_inline_storage(self):
self.contractpdf.storage._delete(self.id)
+
+
pre_delete.connect(delete_inline_storage, sender=SponsorshipContract)
+
class SponsorshipLevel(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
levelname = models.CharField(max_length=100, null=False, blank=False)
@@ -82,6 +87,7 @@ class SponsorshipLevel(models.Model):
return True
return False
+
class SponsorshipBenefit(models.Model):
level = models.ForeignKey(SponsorshipLevel, null=False, blank=False, on_delete=models.CASCADE)
benefitname = models.CharField(max_length=100, null=False, blank=False)
@@ -98,6 +104,7 @@ class SponsorshipBenefit(models.Model):
class Meta:
ordering = ('sortkey', 'benefitname', )
+
class Sponsor(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
name = models.CharField(max_length=100, null=False, blank=False)
@@ -118,6 +125,7 @@ class Sponsor(models.Model):
def __unicode__(self):
return self.name
+
class SponsorClaimedBenefit(models.Model):
sponsor = models.ForeignKey(Sponsor, null=False, blank=False, on_delete=models.CASCADE)
benefit = models.ForeignKey(SponsorshipBenefit, null=False, blank=False, on_delete=models.CASCADE)
@@ -130,6 +138,7 @@ class SponsorClaimedBenefit(models.Model):
class Meta:
unique_together = (('sponsor', 'benefit'),)
+
class SponsorMail(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
levels = models.ManyToManyField(SponsorshipLevel, blank=False)
@@ -143,6 +152,7 @@ class SponsorMail(models.Model):
class Meta:
ordering = ('-sentat',)
+
class PurchasedVoucher(models.Model):
sponsor = models.ForeignKey(Sponsor, null=False, blank=False, on_delete=models.CASCADE)
user = models.ForeignKey(User, null=False, blank=False, on_delete=models.CASCADE)
diff --git a/postgresqleu/confsponsor/util.py b/postgresqleu/confsponsor/util.py
index 3bb51dda..bedf5f0d 100644
--- a/postgresqleu/confsponsor/util.py
+++ b/postgresqleu/confsponsor/util.py
@@ -1,5 +1,6 @@
from postgresqleu.util.db import exec_to_list
+
def get_sponsor_dashboard_data(conference):
return (
["Level", "Confirmed", "Unconfirmed"],
diff --git a/postgresqleu/confsponsor/vatutil.py b/postgresqleu/confsponsor/vatutil.py
index 127a1fa2..4a4c5fd7 100644
--- a/postgresqleu/confsponsor/vatutil.py
+++ b/postgresqleu/confsponsor/vatutil.py
@@ -1,5 +1,6 @@
import requests
+
def validate_eu_vat_number(number):
country = number[:2]
number = number[2:]
diff --git a/postgresqleu/confsponsor/views.py b/postgresqleu/confsponsor/views.py
index 768ecc05..730cbed3 100644
--- a/postgresqleu/confsponsor/views.py
+++ b/postgresqleu/confsponsor/views.py
@@ -29,6 +29,7 @@ from invoicehandler import create_sponsor_invoice, confirm_sponsor, get_sponsor_
from invoicehandler import create_voucher_invoice
from vatutil import validate_eu_vat_number
+
@login_required
def sponsor_dashboard(request):
# We define "past sponsors" as those older than a month - because we have to pick something.
@@ -42,6 +43,7 @@ def sponsor_dashboard(request):
"conferences": conferences,
})
+
def _get_sponsor_and_admin(sponsorid, request, onlyconfirmed=True):
if not onlyconfirmed:
sponsor = get_object_or_404(Sponsor, id=sponsorid)
@@ -55,6 +57,7 @@ def _get_sponsor_and_admin(sponsorid, request, onlyconfirmed=True):
else:
return sponsor, False
+
@login_required
def sponsor_conference(request, sponsorid):
sponsor, is_admin = _get_sponsor_and_admin(sponsorid, request, False)
@@ -84,6 +87,7 @@ def sponsor_conference(request, sponsorid):
'is_admin': is_admin,
})
+
@login_required
def sponsor_manager_delete(request, sponsorid):
sponsor, is_admin = _get_sponsor_and_admin(sponsorid, request)
@@ -98,6 +102,7 @@ def sponsor_manager_delete(request, sponsorid):
messages.info(request, "User %s removed as manager." % user.username)
return HttpResponseRedirect('../../')
+
@login_required
@transaction.atomic
def sponsor_manager_add(request, sponsorid):
@@ -132,6 +137,7 @@ def sponsor_manager_add(request, sponsorid):
messages.warning(request, "Could not find user with email address %s" % request.POST['email'])
return HttpResponseRedirect('../../')
+
@login_required
def sponsor_view_mail(request, sponsorid, mailid):
sponsor, is_admin = _get_sponsor_and_admin(sponsorid, request)
@@ -143,6 +149,7 @@ def sponsor_view_mail(request, sponsorid, mailid):
'mail': mail,
})
+
@login_required
@transaction.atomic
def sponsor_purchase_voucher(request, sponsorid):
@@ -183,6 +190,7 @@ def sponsor_purchase_voucher(request, sponsorid):
'form': form,
})
+
@login_required
@transaction.atomic
def sponsor_purchase_discount(request, sponsorid):
@@ -229,6 +237,7 @@ def sponsor_purchase_discount(request, sponsorid):
'form': form,
})
+
@login_required
def sponsor_signup_dashboard(request, confurlname):
conference = get_object_or_404(Conference, urlname=confurlname)
@@ -245,6 +254,7 @@ def sponsor_signup_dashboard(request, confurlname):
'current': current_signups,
})
+
@login_required
@transaction.atomic
def sponsor_signup(request, confurlname, levelurlname):
@@ -320,6 +330,7 @@ def sponsor_signup(request, confurlname, levelurlname):
'form': form,
})
+
@login_required
@transaction.atomic
def sponsor_claim_benefit(request, sponsorid, benefitid):
@@ -377,7 +388,6 @@ def sponsor_claim_benefit(request, sponsorid, benefitid):
sendername=sponsor.conference.conferencename,
)
-
messages.info(request, "Benefit \"%s\" has been %s." % (benefit, claim.declined and 'declined' or 'claimed'))
return HttpResponseRedirect("/events/sponsor/%s/" % sponsor.id)
else:
@@ -403,6 +413,7 @@ def sponsor_contract(request, contractid):
resp.write(contract.contractpdf.read())
return resp
+
@login_required
def sponsor_admin_dashboard(request, confurlname):
conference = get_authenticated_conference(request, confurlname)
@@ -474,6 +485,7 @@ ORDER BY l.levelcost, l.levelname, s.name, b.sortkey, b.benefitname""", {'confid
'helplink': 'sponsors',
})
+
def _confirm_benefit(request, benefit):
with transaction.atomic():
benefit.confirmed = True
@@ -508,6 +520,7 @@ def _confirm_benefit(request, benefit):
'sponsor': benefit.sponsor
})).save()
+
@login_required
def sponsor_admin_sponsor(request, confurlname, sponsorid):
conference = get_authenticated_conference(request, confurlname)
@@ -570,7 +583,6 @@ def sponsor_admin_sponsor(request, confurlname, sponsorid):
# Any other POST we don't know what it is
return HttpResponseRedirect(".")
-
unclaimedbenefits = SponsorshipBenefit.objects.filter(level=sponsor.level, benefit_class__isnull=False).exclude(sponsorclaimedbenefit__sponsor=sponsor)
claimedbenefits = SponsorClaimedBenefit.objects.filter(sponsor=sponsor).order_by('confirmed', 'benefit__sortkey')
noclaimbenefits = SponsorshipBenefit.objects.filter(level=sponsor.level, benefit_class__isnull=True)
@@ -579,7 +591,6 @@ def sponsor_admin_sponsor(request, confurlname, sponsorid):
if b.benefit.benefit_class:
b.claimhtml = get_benefit_class(b.benefit.benefit_class)(sponsor.level, b.benefit.class_parameters).render_claimdata(b)
-
return render(request, 'confsponsor/admin_sponsor.html', {
'conference': conference,
'sponsor': sponsor,
@@ -591,6 +602,7 @@ def sponsor_admin_sponsor(request, confurlname, sponsorid):
'helplink': 'sponsors',
})
+
@login_required
@transaction.atomic
def sponsor_admin_confirm(request, confurlname, sponsorid):
@@ -602,6 +614,7 @@ def sponsor_admin_confirm(request, confurlname, sponsorid):
return HttpResponseRedirect('../')
+
@login_required
def sponsor_admin_benefit(request, confurlname, benefitid):
conference = get_authenticated_conference(request, confurlname)
@@ -632,6 +645,7 @@ def sponsor_admin_benefit(request, confurlname, benefitid):
'helplink': 'sponsors',
})
+
@login_required
@transaction.atomic
def sponsor_admin_send_mail(request, confurlname):
@@ -681,6 +695,7 @@ def sponsor_admin_send_mail(request, confurlname):
'helplink': 'sponsors',
})
+
@login_required
def sponsor_admin_view_mail(request, confurlname, mailid):
conference = get_authenticated_conference(request, confurlname)
@@ -694,6 +709,7 @@ def sponsor_admin_view_mail(request, confurlname, mailid):
'helplink': 'sponsors',
})
+
@login_required
def sponsor_admin_imageview(request, benefitid):
# Image is fetched as part of a benefit, so find the benefit
@@ -719,6 +735,7 @@ def sponsor_admin_imageview(request, benefitid):
resp.write(f.read())
return resp
+
@superuser_required
def sponsor_admin_test_vat(request, confurlname):
get_object_or_404(Conference, urlname=confurlname)
@@ -731,4 +748,3 @@ def sponsor_admin_test_vat(request, confurlname):
if r:
return HttpResponse("VAT validation error: %s" % r)
return HttpResponse("VAT number is valid")
-
diff --git a/postgresqleu/confwiki/admin.py b/postgresqleu/confwiki/admin.py
index 99257137..f66df665 100644
--- a/postgresqleu/confwiki/admin.py
+++ b/postgresqleu/confwiki/admin.py
@@ -33,6 +33,7 @@ class WikipageAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModel
except Conference.DoesNotExist:
pass
+
class WikipageHistoryInline(admin.TabularInline):
model = WikipageHistory
readonly_fields = ['author', 'publishedat']
@@ -41,6 +42,7 @@ class WikipageHistoryInline(admin.TabularInline):
max_num = 0
extra = 0
+
class WikipageSubscriberInline(admin.TabularInline):
model = WikipageSubscriber
readonly_fields = ['subscriber', ]
@@ -48,10 +50,12 @@ class WikipageSubscriberInline(admin.TabularInline):
max_num = 0
extra = 0
+
class WikipageAdmin(admin.ModelAdmin):
form = WikipageAdminForm
inlines = [WikipageHistoryInline, WikipageSubscriberInline]
+
class AttendeeSignupAdminForm(ConcurrentProtectedModelForm):
class Meta:
model = AttendeeSignup
@@ -65,10 +69,12 @@ class AttendeeSignupAdminForm(ConcurrentProtectedModelForm):
except:
pass
+
class AttendeeSignupAdmin(admin.ModelAdmin):
form = AttendeeSignupAdminForm
list_display = ['signup', 'attendee', ]
list_filter = ['signup__conference', ]
+
admin.site.register(Wikipage, WikipageAdmin)
admin.site.register(AttendeeSignup, AttendeeSignupAdmin)
diff --git a/postgresqleu/confwiki/forms.py b/postgresqleu/confwiki/forms.py
index b8cfa7ae..ef655a08 100644
--- a/postgresqleu/confwiki/forms.py
+++ b/postgresqleu/confwiki/forms.py
@@ -7,11 +7,13 @@ from postgresqleu.util.forms import ConcurrentProtectedModelForm
from postgresqleu.confreg.models import RegistrationType, ConferenceRegistration
from models import Wikipage, Signup, AttendeeSignup
+
class WikipageEditForm(ConcurrentProtectedModelForm):
class Meta:
model = Wikipage
fields = ('contents',)
+
class WikipageAdminEditForm(ConcurrentProtectedModelForm):
def __init__(self, *args, **kwargs):
super(WikipageAdminEditForm, self).__init__(*args, **kwargs)
@@ -73,6 +75,7 @@ class SignupSubmitForm(forms.Form):
return self.cleaned_data['choice']
+
class SignupAdminEditForm(ConcurrentProtectedModelForm):
def __init__(self, *args, **kwargs):
super(SignupAdminEditForm, self).__init__(*args, **kwargs)
@@ -86,8 +89,10 @@ class SignupAdminEditForm(ConcurrentProtectedModelForm):
model = Signup
exclude = ['conference', ]
+
class SignupAdminEditSignupForm(ConcurrentProtectedModelForm):
choice = forms.ChoiceField(required=True)
+
class Meta:
model = AttendeeSignup
fields = ['attendee', 'choice', ]
@@ -112,6 +117,7 @@ class SignupAdminEditSignupForm(ConcurrentProtectedModelForm):
self.fields['choice'].choices = (('', ''), ('yes', 'Yes'), ('', 'No'), )
self.fields['choice'].required = False
+
class SignupSendmailForm(forms.Form):
_recipient_choices = [
('*', '** Pick recipients of mail'),
diff --git a/postgresqleu/confwiki/models.py b/postgresqleu/confwiki/models.py
index a8591241..3a1325af 100644
--- a/postgresqleu/confwiki/models.py
+++ b/postgresqleu/confwiki/models.py
@@ -7,6 +7,7 @@ from postgresqleu.confreg.models import RegistrationType
from postgresqleu.util.diffablemodel import DiffableModel
+
class Wikipage(models.Model, DiffableModel):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
url = models.CharField(max_length=100, null=False, blank=False, validators=[
@@ -36,6 +37,7 @@ class Wikipage(models.Model, DiffableModel):
editor_attendee = models.ManyToManyField(ConferenceRegistration, blank=True, related_name='editor_attendees', verbose_name="Editor attendees")
_unsafe_attributes = ('viewer_regtype', 'editor_regtype', 'viewer_attendee', 'editor_attendee')
+
class Meta:
unique_together = [
('conference', 'url', )
@@ -68,6 +70,7 @@ class Wikipage(models.Model, DiffableModel):
def editor_attendees(self):
return ", ".join([r.fullname for r in self.editor_attendee.all()])
+
# When a page is edited, the old version is copied over to the history. A page that has
# never been edited has no history entry. Permission changes are not tracked.
class WikipageHistory(models.Model):
@@ -84,6 +87,7 @@ class WikipageHistory(models.Model):
('page', 'publishedat',)
)
+
# Subscribers to changes of wikipages
class WikipageSubscriber(models.Model):
page = models.ForeignKey(Wikipage, null=False, blank=False, db_index=True, on_delete=models.CASCADE)
@@ -100,6 +104,7 @@ def validate_options(value):
if len(v) > 100:
raise ValidationError("Options must be less than 100 characters each")
+
def validate_optionvalues(value):
if value == '':
return
@@ -111,6 +116,7 @@ def validate_optionvalues(value):
if int(v) < 0:
raise ValidationError("All option values must be positive numbers!")
+
# Signups - attendees can sign up for events
class Signup(models.Model):
conference = models.ForeignKey(Conference, null=False, blank=False, on_delete=models.CASCADE)
@@ -143,6 +149,7 @@ class Signup(models.Model):
if self.optionvalues:
raise ValidationError({"optionvalues": "Cannot specify optionvalues if options are not specified!"})
+
class AttendeeSignup(models.Model):
signup = models.ForeignKey(Signup, null=False, blank=False, on_delete=models.CASCADE)
attendee = models.ForeignKey(ConferenceRegistration, null=False, blank=False, on_delete=models.CASCADE)
diff --git a/postgresqleu/confwiki/views.py b/postgresqleu/confwiki/views.py
index dd867a91..2fd38526 100644
--- a/postgresqleu/confwiki/views.py
+++ b/postgresqleu/confwiki/views.py
@@ -26,6 +26,7 @@ from models import Signup, AttendeeSignup
from forms import SignupSubmitForm, SignupAdminEditForm, SignupSendmailForm
from forms import SignupAdminEditSignupForm
+
def _check_wiki_permissions(page, reg, readwrite=False):
# Edit access implies both read and write
if page.publicedit:
@@ -41,6 +42,7 @@ def _check_wiki_permissions(page, reg, readwrite=False):
return
raise PermissionDenied("View permission denied")
+
def _check_signup_permissions(signup, reg):
if signup.public:
return
@@ -48,6 +50,7 @@ def _check_signup_permissions(signup, reg):
return
raise PermissionDenied("Signup permission denied")
+
@login_required
def wikipage(request, confurl, wikiurl):
conference = get_object_or_404(Conference, urlname=confurl)
@@ -67,6 +70,7 @@ def wikipage(request, confurl, wikiurl):
'is_subscribed': is_subscribed,
})
+
@login_required
@transaction.atomic
def wikipage_subscribe(request, confurl, wikiurl):
@@ -85,6 +89,7 @@ def wikipage_subscribe(request, confurl, wikiurl):
return HttpResponseRedirect('../')
+
@login_required
def wikipage_history(request, confurl, wikiurl):
conference = get_object_or_404(Conference, urlname=confurl)
@@ -197,6 +202,7 @@ def wikipage_edit(request, confurl, wikiurl):
'diff': diff,
})
+
def admin(request, urlname):
conference = get_authenticated_conference(request, urlname)
@@ -208,6 +214,7 @@ def admin(request, urlname):
'helplink': 'wiki',
})
+
@transaction.atomic
def admin_edit_page(request, urlname, pageid):
conference = get_authenticated_conference(request, urlname)
@@ -338,6 +345,7 @@ def signup(request, urlname, signupid):
'form': form,
})
+
def signup_admin(request, urlname):
conference = get_authenticated_conference(request, urlname)
@@ -349,6 +357,7 @@ def signup_admin(request, urlname):
'helplink': 'signups',
})
+
@transaction.atomic
def signup_admin_edit(request, urlname, signupid):
conference = get_authenticated_conference(request, urlname)
@@ -407,6 +416,7 @@ def signup_admin_edit(request, urlname, signupid):
'helplink': 'signups',
})
+
@transaction.atomic
def signup_admin_editsignup(request, urlname, signupid, id):
conference = get_authenticated_conference(request, urlname)
@@ -446,6 +456,7 @@ def signup_admin_editsignup(request, urlname, signupid, id):
'helplink': 'signups',
})
+
@transaction.atomic
def signup_admin_sendmail(request, urlname, signupid):
conference = get_authenticated_conference(request, urlname)
@@ -509,7 +520,6 @@ def signup_admin_sendmail(request, urlname, signupid):
form = SignupSendmailForm(additional_choices)
numtosend = None
-
return render(request, 'confwiki/signup_sendmail_form.html', {
'conference': conference,
'form': form,
diff --git a/postgresqleu/elections/admin.py b/postgresqleu/elections/admin.py
index fc66fb5c..10d6997d 100644
--- a/postgresqleu/elections/admin.py
+++ b/postgresqleu/elections/admin.py
@@ -3,6 +3,7 @@ from django.forms import ValidationError, ModelForm
from models import Vote, Election, Candidate
+
class VoteAdminForm(ModelForm):
class Meta:
model = Vote
@@ -11,6 +12,7 @@ class VoteAdminForm(ModelForm):
def clean(self):
raise ValidationError("You really shouldn't edit votes! If you *really* need to fix something broken, do it in the db")
+
class VoteAdmin(admin.ModelAdmin):
list_display = ('election', 'voter', 'candidate', 'score')
ordering = ['election', ]
@@ -21,11 +23,13 @@ class ElectionAdmin(admin.ModelAdmin):
list_display = ['name', 'startdate', 'enddate', ]
ordering = ['-startdate', ]
+
class CandidateAdmin(admin.ModelAdmin):
list_display = ['name', 'election', ]
list_filter = ['election', ]
ordering = ['name', ]
+
admin.site.register(Election, ElectionAdmin)
admin.site.register(Candidate, CandidateAdmin)
admin.site.register(Vote, VoteAdmin)
diff --git a/postgresqleu/elections/forms.py b/postgresqleu/elections/forms.py
index 072eea58..125adff8 100644
--- a/postgresqleu/elections/forms.py
+++ b/postgresqleu/elections/forms.py
@@ -7,6 +7,7 @@ from postgresqleu.membership.models import MemberLog
from datetime import datetime
+
class VoteForm(forms.Form):
def __init__(self, election, member, *args, **kwargs):
super(VoteForm, self).__init__(*args, **kwargs)
diff --git a/postgresqleu/elections/models.py b/postgresqleu/elections/models.py
index cccd63f1..29dd66bb 100644
--- a/postgresqleu/elections/models.py
+++ b/postgresqleu/elections/models.py
@@ -1,6 +1,7 @@
from django.db import models
from postgresqleu.membership.models import Member
+
class Election(models.Model):
name = models.CharField(max_length=100, null=False, blank=False)
startdate = models.DateField(null=False, blank=False)
@@ -12,6 +13,7 @@ class Election(models.Model):
def __unicode__(self):
return self.name
+
class Candidate(models.Model):
election = models.ForeignKey(Election, null=False, blank=False, on_delete=models.CASCADE)
name = models.CharField(max_length=100, null=False, blank=False)
@@ -21,6 +23,7 @@ class Candidate(models.Model):
def __unicode__(self):
return "%s (%s)" % (self.name, self.election)
+
class Vote(models.Model):
election = models.ForeignKey(Election, null=False, blank=False, on_delete=models.CASCADE)
voter = models.ForeignKey(Member, null=False, blank=False, on_delete=models.CASCADE)
diff --git a/postgresqleu/elections/views.py b/postgresqleu/elections/views.py
index 9b034594..8b55877b 100644
--- a/postgresqleu/elections/views.py
+++ b/postgresqleu/elections/views.py
@@ -7,6 +7,7 @@ from models import Election, Member, Candidate, Vote
from forms import VoteForm
from datetime import date, timedelta
+
def home(request):
elections = Election.objects.filter(isopen=True).order_by('startdate')
open_elections = [e for e in elections if e.startdate <= date.today() and e.enddate >= date.today()]
@@ -19,6 +20,7 @@ def home(request):
'upcoming': upcoming_elections,
})
+
def election(request, electionid):
election = get_object_or_404(Election, pk=electionid)
if not election.isopen:
@@ -88,12 +90,12 @@ def election(request, electionid):
# Not a POST, so generate an empty form
form = VoteForm(election, member)
-
return render(request, 'elections/form.html', {
'form': form,
'election': election,
})
+
def candidate(request, election, candidate):
candidate = get_object_or_404(Candidate, election=election, pk=candidate)
@@ -101,6 +103,7 @@ def candidate(request, election, candidate):
'candidate': candidate,
})
+
@login_required
def ownvotes(request, electionid):
election = get_object_or_404(Election, pk=electionid)
diff --git a/postgresqleu/invoices/admin.py b/postgresqleu/invoices/admin.py
index f089c6eb..5b75d1f1 100644
--- a/postgresqleu/invoices/admin.py
+++ b/postgresqleu/invoices/admin.py
@@ -9,6 +9,7 @@ from postgresqleu.util.forms import ConcurrentProtectedModelForm
from models import Invoice, InvoiceLog, InvoiceProcessor, InvoicePaymentMethod
from models import InvoiceRefund, VatRate
+
class InvoiceAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelForm):
class Meta:
model = Invoice
@@ -21,31 +22,38 @@ class InvoiceAdminForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelF
if self.cleaned_data.has_key('finalized'):
raise ValidationError("Can't edit email field on a finalized invoice!")
return self.cleaned_data['recipient_email']
+
def clean_recipient_name(self):
if self.cleaned_data.has_key('finalized'):
raise ValidationError("Can't edit name field on a finalized invoice!")
return self.cleaned_data['recipient_name']
+
def clean_recipient_address(self):
if self.cleaned_data.has_key('finalized'):
raise ValidationError("Can't edit address field on a finalized invoice!")
return self.cleaned_data['recipient_address']
+
def clean_title(self):
if self.cleaned_data.has_key('finalized'):
raise ValidationError("Can't edit title field on a finalized invoice!")
return self.cleaned_data['title']
+
def clean_total_amount(self):
if self.cleaned_data.has_key('finalized'):
raise ValidationError("Can't edit total amount field on a finalized invoice!")
return self.cleaned_data['total_amount']
+
def clean_total_vat(self):
if self.cleaned_data.has_key('finalized'):
raise ValidationError("Can't edit total vat field on a finalized invoice!")
return self.cleaned_data['total_vat']
+
def clean_processor(self):
if "processor" in self.changed_data:
raise ValidationError("Sorry, we never allow editing of the processor!")
return self.cleaned_data['processor']
+
class InvoiceAdmin(admin.ModelAdmin):
list_display = ('id', 'title', 'recipient_name', 'total_amount', 'ispaid')
form = InvoiceAdminForm
@@ -53,15 +61,19 @@ class InvoiceAdmin(admin.ModelAdmin):
filter_horizontal = ['allowedmethods', ]
readonly_fields = ['refund', ]
+
class InvoiceLogAdmin(admin.ModelAdmin):
list_display = ('timestamp', 'message_trunc', 'sent',)
+
class InvoiceRefundAdmin(admin.ModelAdmin):
list_display = ('registered', 'issued', 'completed', 'amount', 'vatamount', 'reason')
+
class InvoicePaymentMethodAdmin(admin.ModelAdmin):
list_display = ('name', 'internaldescription', 'classname', )
+
admin.site.register(Invoice, InvoiceAdmin)
admin.site.register(InvoiceProcessor)
admin.site.register(InvoicePaymentMethod, InvoicePaymentMethodAdmin)
diff --git a/postgresqleu/invoices/forms.py b/postgresqleu/invoices/forms.py
index 9924b317..28baaba6 100644
--- a/postgresqleu/invoices/forms.py
+++ b/postgresqleu/invoices/forms.py
@@ -14,6 +14,7 @@ from models import Invoice, InvoiceRow, InvoicePaymentMethod
from postgresqleu.accounting.models import Account, Object
from postgresqleu.invoices.models import VatRate
+
class InvoiceForm(forms.ModelForm):
hidden_until_finalized = ('total_amount', 'total_vat', 'remindersent', )
available_in_finalized = ('recipient_user', 'recipient_email', 'allowedmethods',)
@@ -70,6 +71,7 @@ class InvoiceForm(forms.ModelForm):
self.cleaned_data['accounting_account'] = None
return self.cleaned_data
+
class InvoiceRowForm(forms.ModelForm):
class Meta:
model = InvoiceRow
@@ -86,11 +88,13 @@ class InvoiceRowForm(forms.ModelForm):
if self.cleaned_data['rowamount'] == 0:
raise ValidationError("Must specify an amount!")
return self.cleaned_data['rowamount']
+
def clean_rowcount(self):
if self.cleaned_data['rowcount'] <= 0:
raise ValidationError("Must specify a count!")
return self.cleaned_data['rowcount']
+
class RefundForm(forms.Form):
amount = forms.DecimalField(required=True)
vatamount = forms.DecimalField(required=True)
diff --git a/postgresqleu/invoices/management/commands/process_refunds.py b/postgresqleu/invoices/management/commands/process_refunds.py
index 5e9ab1d3..b591b635 100644
--- a/postgresqleu/invoices/management/commands/process_refunds.py
+++ b/postgresqleu/invoices/management/commands/process_refunds.py
@@ -18,6 +18,7 @@ from postgresqleu.mailqueue.util import send_simple_mail
from datetime import datetime, timedelta
+
class Command(BaseCommand):
help = 'Send off API-based refunds'
diff --git a/postgresqleu/invoices/management/commands/send_invoice_reminders.py b/postgresqleu/invoices/management/commands/send_invoice_reminders.py
index f87ddc27..501e1f89 100755
--- a/postgresqleu/invoices/management/commands/send_invoice_reminders.py
+++ b/postgresqleu/invoices/management/commands/send_invoice_reminders.py
@@ -11,6 +11,7 @@ from datetime import datetime, timedelta
from postgresqleu.invoices.models import Invoice
from postgresqleu.invoices.util import InvoiceWrapper
+
class Command(BaseCommand):
help = 'Send invoice reminders'
diff --git a/postgresqleu/invoices/management/commands/setup_payment_providers.py b/postgresqleu/invoices/management/commands/setup_payment_providers.py
index 325d8f54..3fa52e0e 100644
--- a/postgresqleu/invoices/management/commands/setup_payment_providers.py
+++ b/postgresqleu/invoices/management/commands/setup_payment_providers.py
@@ -8,6 +8,7 @@ from django.db import transaction, connection
from postgresqleu.invoices.models import InvoicePaymentMethod
+
class Command(BaseCommand):
help = 'Set up payment providers'
diff --git a/postgresqleu/invoices/migrations/0003_initial_invoice_processors.py b/postgresqleu/invoices/migrations/0003_initial_invoice_processors.py
index fd057e2d..bed8c545 100644
--- a/postgresqleu/invoices/migrations/0003_initial_invoice_processors.py
+++ b/postgresqleu/invoices/migrations/0003_initial_invoice_processors.py
@@ -3,6 +3,7 @@ from __future__ import unicode_literals
from django.db import migrations, models
+
def create_invoice_processors(apps, schema_editor):
InvoiceProcessor = apps.get_model('invoices', 'InvoiceProcessor')
diff --git a/postgresqleu/invoices/models.py b/postgresqleu/invoices/models.py
index d61e3e8d..137ab71e 100644
--- a/postgresqleu/invoices/models.py
+++ b/postgresqleu/invoices/models.py
@@ -10,6 +10,7 @@ from payment import PaymentMethodWrapper
from postgresqleu.accounting.models import Account
+
class InvoiceProcessor(models.Model):
# The processor name is purely cosmetic
processorname = models.CharField(max_length=50, null=False, blank=False, unique=True)
@@ -20,6 +21,7 @@ class InvoiceProcessor(models.Model):
def __unicode__(self):
return self.processorname
+
class InvoicePaymentMethod(models.Model):
name = models.CharField(max_length=100, null=False, blank=False)
active = models.BooleanField(null=False, blank=False, default=True)
@@ -36,6 +38,7 @@ class InvoicePaymentMethod(models.Model):
class Meta:
ordering = ['sortkey', ]
+
class InvoiceRefund(models.Model):
reason = models.CharField(max_length=500, null=False, blank=True, default='', help_text="Reason for refunding of invoice")
@@ -55,6 +58,7 @@ class InvoiceRefund(models.Model):
def fullamount(self):
return self.amount + self.vatamount
+
class Invoice(models.Model):
# pk = invoice number, which is fully exposed.
@@ -198,6 +202,7 @@ class VatRate(models.Model):
def shortstr(self):
return "%s%% (%s)" % (self.vatpercent, self.shortname)
+
class InvoiceRow(models.Model):
# Invoice rows are only used up until the invoice is finished,
# but allows us to save a half-finished invoice.
@@ -225,6 +230,7 @@ class InvoiceRow(models.Model):
def totalwithvat(self):
return self.totalrow + self.totalvat
+
class InvoiceHistory(models.Model):
invoice = models.ForeignKey(Invoice, null=False, on_delete=models.CASCADE)
time = models.DateTimeField(null=False, blank=False, auto_now_add=True)
@@ -236,6 +242,7 @@ class InvoiceHistory(models.Model):
def __unicode__(self):
return self.txt
+
class InvoiceLog(models.Model):
timestamp = models.DateTimeField(null=False, blank=False, auto_now_add=True)
message = models.TextField(null=False, blank=False)
diff --git a/postgresqleu/invoices/payment.py b/postgresqleu/invoices/payment.py
index 6d0aa9ea..fdd2b8dc 100644
--- a/postgresqleu/invoices/payment.py
+++ b/postgresqleu/invoices/payment.py
@@ -2,6 +2,7 @@
# create a circular dependency between models and util.
from django.utils.safestring import mark_safe
+
class PaymentMethodWrapper(object):
def __init__(self, method, invoice, returnurl=None):
self.method = method
@@ -23,7 +24,6 @@ class PaymentMethodWrapper(object):
except Exception:
self.ok = False
-
@property
def name(self):
return self.method.name
diff --git a/postgresqleu/invoices/templatetags/util.py b/postgresqleu/invoices/templatetags/util.py
index 89b97782..668a622a 100644
--- a/postgresqleu/invoices/templatetags/util.py
+++ b/postgresqleu/invoices/templatetags/util.py
@@ -2,6 +2,7 @@ from django import template
register = template.Library()
+
@register.filter
def stringreplace(value, pattern):
(old, new) = pattern.split(',')
diff --git a/postgresqleu/invoices/util.py b/postgresqleu/invoices/util.py
index 7244db79..3163bc5e 100644
--- a/postgresqleu/invoices/util.py
+++ b/postgresqleu/invoices/util.py
@@ -17,6 +17,7 @@ from Crypto import Random
from postgresqleu.mailqueue.util import send_template_mail
from postgresqleu.accounting.util import create_accounting_entry
+
# Proxy around an invoice that adds presentation information,
# such as the ability to render a return URL for the invoice.
# It also blocks access to unsafe variables that could be used
@@ -26,9 +27,11 @@ class InvoicePresentationWrapper(object):
proxy = True
_unsafe_attributes = ('recipient_user', 'processor', 'allowedmethods', 'paidusing', )
+
def __init__(self, invoice, returnurl):
self.__invoice = invoice
self.__returnurl = returnurl
+
def __getattr__(self, name):
# Most attributes are perfectly safe to return, but there are a couple that needs "sandboxing"
if name in self._unsafe_attributes:
@@ -247,6 +250,7 @@ class InvoiceWrapper(object):
def _standard_logger(message):
print message
+
def _trunc_string(s, l):
# Truncate a string to specified length, adding "..." at the end in case
# it's truncated.
@@ -255,6 +259,7 @@ def _trunc_string(s, l):
return s[:97] + "..."
+
class InvoiceManager(object):
def __init__(self):
pass
@@ -266,6 +271,7 @@ class InvoiceManager(object):
RESULT_DELETED = 4
RESULT_INVALIDAMOUNT = 5
RESULT_PROCESSORFAIL = 6
+
def process_incoming_payment(self, transtext, transamount, transdetails, transcost, incomeaccount, costaccount, extraurls=None, logger=None, method=None):
# If there is no logger specified, just log with print statement
if not logger:
@@ -307,7 +313,6 @@ class InvoiceManager(object):
return self.process_incoming_payment_for_invoice(invoice, transamount, transdetails, transcost, incomeaccount, costaccount, extraurls, logger, method)
-
def process_incoming_payment_for_invoice(self, invoice, transamount, transdetails, transcost, incomeaccount, costaccount, extraurls, logger, method):
# Do the same as process_incoming_payment, but assume that the
# invoice has already been matched by other means.
@@ -641,8 +646,10 @@ class InvoiceManager(object):
class TestProcessor(object):
def process_invoice_payment(self, invoice):
print "Callback processing invoice with title '%s', for my own id %s" % (invoice.title, invoice.processorid)
+
def process_invoice_cancellation(self, invoice):
raise Exception("This processor can't cancel invoices.")
+
def process_invoice_refund(self, invoice):
raise Exception("This processor can't refund invoices.")
diff --git a/postgresqleu/invoices/views.py b/postgresqleu/invoices/views.py
index 3d1dff5c..82dc2c05 100644
--- a/postgresqleu/invoices/views.py
+++ b/postgresqleu/invoices/views.py
@@ -18,31 +18,37 @@ from models import Invoice, InvoiceRow, InvoiceHistory, InvoicePaymentMethod, Va
from forms import InvoiceForm, InvoiceRowForm, RefundForm
from util import InvoiceWrapper, InvoiceManager, InvoicePresentationWrapper
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
def all(request):
return _homeview(request, Invoice.objects.all())
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
def unpaid(request):
return _homeview(request, Invoice.objects.filter(paidat=None, deleted=False, finalized=True), unpaid=True)
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
def pending(request):
return _homeview(request, Invoice.objects.filter(finalized=False, deleted=False), pending=True)
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
def deleted(request):
return _homeview(request, Invoice.objects.filter(deleted=True), deleted=True)
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
def refunded(request):
return _homeview(request, Invoice.objects.filter(refund__isnull=False), refunded=True)
+
# Not a view, just a utility function, thus no separate permissions check
def _homeview(request, invoice_objects, unpaid=False, pending=False, deleted=False, refunded=False, searchterm=None):
# Render a list of all invoices
@@ -100,6 +106,7 @@ def search(request):
messages.info(request, "Showing %s search hits for %s" % (len(invoices), term))
return _homeview(request, invoices, searchterm=term)
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
@transaction.atomic
@@ -182,6 +189,7 @@ def oneinvoice(request, invoicenum):
'vatrates': VatRate.objects.all(),
})
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
@transaction.atomic
@@ -197,8 +205,10 @@ def flaginvoice(request, invoicenum):
# whatever submodule generated the invoice.
mgr = InvoiceManager()
str = StringIO.StringIO()
+
def payment_logger(msg):
str.write(msg)
+
(r, i, p) = mgr.process_incoming_payment(invoice.invoicestr,
invoice.total_amount,
request.POST['reason'],
@@ -215,6 +225,7 @@ def flaginvoice(request, invoicenum):
# so we can just return the user right back
return HttpResponseRedirect("/invoiceadmin/%s/" % invoice.id)
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
@transaction.atomic
@@ -233,6 +244,7 @@ def cancelinvoice(request, invoicenum):
return HttpResponseRedirect("/invoiceadmin/%s/" % invoice.id)
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
@transaction.atomic
@@ -246,6 +258,7 @@ def extend_cancel(request, invoicenum):
return HttpResponseRedirect("/invoiceadmin/%s/" % invoice.id)
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
@transaction.atomic
@@ -282,6 +295,7 @@ def refundinvoice(request, invoicenum):
'globalvat': vinfo['v'],
})
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
def previewinvoice(request, invoicenum):
@@ -293,6 +307,7 @@ def previewinvoice(request, invoicenum):
r.write(wrapper.render_pdf_invoice(True))
return r
+
@login_required
@user_passes_test_or_error(lambda u: u.has_module_perms('invoices'))
@transaction.atomic
@@ -339,6 +354,7 @@ def viewinvoice(request, invoiceid):
'invoice': InvoicePresentationWrapper(invoice, "%s/invoices/%s/" % (settings.SITEBASE, invoice.pk)),
})
+
def viewinvoice_secret(request, invoiceid, invoicesecret):
invoice = get_object_or_404(Invoice, pk=invoiceid, deleted=False, finalized=True, recipient_secret=invoicesecret)
return render(request, 'invoices/userinvoice.html', {
@@ -346,6 +362,7 @@ def viewinvoice_secret(request, invoiceid, invoicesecret):
'fromsecret': True,
})
+
@login_required
def viewinvoicepdf(request, invoiceid):
invoice = get_object_or_404(Invoice, pk=invoiceid)
@@ -356,12 +373,14 @@ def viewinvoicepdf(request, invoiceid):
r.write(base64.b64decode(invoice.pdf_invoice))
return r
+
def viewinvoicepdf_secret(request, invoiceid, invoicesecret):
invoice = get_object_or_404(Invoice, pk=invoiceid, recipient_secret=invoicesecret)
r = HttpResponse(content_type='application/pdf')
r.write(base64.b64decode(invoice.pdf_invoice))
return r
+
@login_required
def viewreceipt(request, invoiceid):
invoice = get_object_or_404(Invoice, pk=invoiceid)
@@ -372,12 +391,14 @@ def viewreceipt(request, invoiceid):
r.write(base64.b64decode(invoice.pdf_receipt))
return r
+
def viewreceipt_secret(request, invoiceid, invoicesecret):
invoice = get_object_or_404(Invoice, pk=invoiceid, recipient_secret=invoicesecret)
r = HttpResponse(content_type='application/pdf')
r.write(base64.b64decode(invoice.pdf_receipt))
return r
+
@login_required
def viewrefundnote(request, invoiceid):
invoice = get_object_or_404(Invoice, pk=invoiceid)
@@ -388,12 +409,14 @@ def viewrefundnote(request, invoiceid):
r.write(base64.b64decode(invoice.refund.refund_pdf))
return r
+
def viewrefundnote_secret(request, invoiceid, invoicesecret):
invoice = get_object_or_404(Invoice, pk=invoiceid, recipient_secret=invoicesecret)
r = HttpResponse(content_type='application/pdf')
r.write(base64.b64decode(invoice.refund.refund_pdf))
return r
+
@login_required
def userhome(request):
invoices = Invoice.objects.filter(recipient_user=request.user, deleted=False, finalized=True)
@@ -401,6 +424,7 @@ def userhome(request):
'invoices': invoices,
})
+
@login_required
def banktransfer(request):
param = {
@@ -412,6 +436,7 @@ def banktransfer(request):
return render(request, 'invoices/banktransfer.html', param)
+
@login_required
@transaction.atomic
def dummy_payment(request, invoiceid, invoicesecret):
diff --git a/postgresqleu/mailqueue/admin.py b/postgresqleu/mailqueue/admin.py
index 801d1163..6529ea18 100644
--- a/postgresqleu/mailqueue/admin.py
+++ b/postgresqleu/mailqueue/admin.py
@@ -4,6 +4,7 @@ from email.parser import Parser
from models import QueuedMail
+
class QueuedMailAdmin(admin.ModelAdmin):
model = QueuedMail
readonly_fields = ('parsed_content', )
@@ -27,4 +28,5 @@ class QueuedMailAdmin(admin.ModelAdmin):
parsed_content.short_description = 'Parsed mail'
+
admin.site.register(QueuedMail, QueuedMailAdmin)
diff --git a/postgresqleu/mailqueue/management/commands/send_queued_mail.py b/postgresqleu/mailqueue/management/commands/send_queued_mail.py
index 686817b5..be674f5a 100755
--- a/postgresqleu/mailqueue/management/commands/send_queued_mail.py
+++ b/postgresqleu/mailqueue/management/commands/send_queued_mail.py
@@ -12,6 +12,7 @@ import smtplib
from postgresqleu.mailqueue.models import QueuedMail
+
class Command(BaseCommand):
help = 'Send queued mail'
diff --git a/postgresqleu/mailqueue/models.py b/postgresqleu/mailqueue/models.py
index f75ca37c..1a0642a9 100644
--- a/postgresqleu/mailqueue/models.py
+++ b/postgresqleu/mailqueue/models.py
@@ -1,5 +1,6 @@
from django.db import models
+
class QueuedMail(models.Model):
sender = models.EmailField(max_length=100, null=False, blank=False)
receiver = models.EmailField(max_length=100, null=False, blank=False)
diff --git a/postgresqleu/mailqueue/util.py b/postgresqleu/mailqueue/util.py
index c075e458..f2a66ced 100644
--- a/postgresqleu/mailqueue/util.py
+++ b/postgresqleu/mailqueue/util.py
@@ -11,22 +11,26 @@ from django.template.loader import get_template
from models import QueuedMail
+
def template_to_string(templatename, attrs={}):
context = {}
context.update(attrs)
context.update(settings_context())
return get_template(templatename).render(context)
+
def send_template_mail(sender, receiver, subject, templatename, templateattr={}, attachments=None, bcc=None, sendername=None, receivername=None):
send_simple_mail(sender, receiver, subject,
template_to_string(templatename, templateattr),
attachments, bcc, sendername, receivername)
+
def _encoded_email_header(name, email):
if name:
return formataddr((str(Header(name, 'utf-8')), email))
return email
+
def send_simple_mail(sender, receiver, subject, msgtxt, attachments=None, bcc=None, sendername=None, receivername=None):
# attachment format, each is a tuple of (name, mimetype,contents)
# content should be *binary* and not base64 encoded, since we need to
@@ -49,13 +53,13 @@ def send_simple_mail(sender, receiver, subject, msgtxt, attachments=None, bcc=No
encoders.encode_base64(part)
msg.attach(part)
-
# Just write it to the queue, so it will be transactionally rolled back
QueuedMail(sender=sender, receiver=receiver, fullmsg=msg.as_string()).save()
# Any bcc is just entered as a separate email
if bcc:
QueuedMail(sender=sender, receiver=bcc, fullmsg=msg.as_string()).save()
+
def send_mail(sender, receiver, fullmsg):
# Send an email, prepared as the full MIME encoded mail already
QueuedMail(sender=sender, receiver=receiver, fullmsg=fullmsg).save()
diff --git a/postgresqleu/membership/admin.py b/postgresqleu/membership/admin.py
index e301ee5b..e07b9c3c 100644
--- a/postgresqleu/membership/admin.py
+++ b/postgresqleu/membership/admin.py
@@ -7,6 +7,7 @@ import urllib
from models import Member, MemberLog, Meeting
+
class ActiveMemberFilter(admin.SimpleListFilter):
title = 'Active'
parameter_name = 'isactive'
@@ -24,6 +25,7 @@ class ActiveMemberFilter(admin.SimpleListFilter):
return queryset.filter(Q(paiduntil__lt=datetime.now()) | Q(paiduntil__isnull=True))
return queryset
+
class MemberAdmin(admin.ModelAdmin):
list_display = ('user', 'fullname', 'country', 'membersince', 'paiduntil', )
ordering = ('user',)
@@ -41,14 +43,17 @@ class MemberAdmin(admin.ModelAdmin):
return HttpResponseRedirect('/admin/membership/_email/?ids=%s&orig=%s' % (','.join(selected), urllib.quote(urllib.urlencode(request.GET))))
email_members.short_description = 'Send email to selected members'
+
class MemberLogAdmin(admin.ModelAdmin):
list_display = ('member', 'timestamp', 'message', )
ordering = ('-timestamp', )
+
class MeetingAdmin(admin.ModelAdmin):
list_display = ('name', 'dateandtime', )
filter_horizontal = ('members', )
+
admin.site.register(Member, MemberAdmin)
admin.site.register(MemberLog, MemberLogAdmin)
admin.site.register(Meeting, MeetingAdmin)
diff --git a/postgresqleu/membership/forms.py b/postgresqleu/membership/forms.py
index f23b0b11..ab3bc352 100644
--- a/postgresqleu/membership/forms.py
+++ b/postgresqleu/membership/forms.py
@@ -4,6 +4,7 @@ from django.conf import settings
from models import Member
+
class MemberForm(forms.ModelForm):
class Meta:
model = Member
@@ -20,5 +21,6 @@ class MemberForm(forms.ModelForm):
raise ValidationError(msg)
return self.cleaned_data['country']
+
class ProxyVoterForm(forms.Form):
name = forms.CharField(min_length=5, max_length=100, help_text="Name of proxy voter. Leave empty to cancel proxy voting.", required=False)
diff --git a/postgresqleu/membership/invoicehandler.py b/postgresqleu/membership/invoicehandler.py
index 864ca5f0..7264c326 100644
--- a/postgresqleu/membership/invoicehandler.py
+++ b/postgresqleu/membership/invoicehandler.py
@@ -4,12 +4,14 @@ from models import Member, MemberLog
from datetime import datetime, timedelta, date
+
class InvoiceProcessor(object):
can_refund = False
# Process invoices once they're getting paid
#
# In the case of membership, that simply means extending the
# membership.
+
def process_invoice_payment(self, invoice):
# We'll get the member from the processorid
try:
diff --git a/postgresqleu/membership/management/commands/membership_nightly.py b/postgresqleu/membership/management/commands/membership_nightly.py
index dddbb65a..3aa13620 100644
--- a/postgresqleu/membership/management/commands/membership_nightly.py
+++ b/postgresqleu/membership/management/commands/membership_nightly.py
@@ -16,6 +16,7 @@ from datetime import datetime, timedelta
from postgresqleu.mailqueue.util import send_template_mail
from postgresqleu.membership.models import Member, MemberLog
+
class Command(BaseCommand):
help = 'Expire members and other nightly tasks'
@@ -40,7 +41,6 @@ class Command(BaseCommand):
m.paiduntil = None
m.save()
-
# Send warnings to members about to expire. We explicitly avoid sending
# a warning in the last 24 hours before expire, so we don't end up sending
# both a warning and an expiry within minutes in case the cronjob runs on
diff --git a/postgresqleu/membership/models.py b/postgresqleu/membership/models.py
index 368a1538..20c5a072 100644
--- a/postgresqleu/membership/models.py
+++ b/postgresqleu/membership/models.py
@@ -6,6 +6,7 @@ from postgresqleu.invoices.models import Invoice
from datetime import date, datetime, timedelta
+
class Member(models.Model):
user = models.OneToOneField(User, null=False, blank=False, primary_key=True, on_delete=models.CASCADE)
fullname = models.CharField(max_length=500, null=False, blank=False,
@@ -42,6 +43,7 @@ class Member(models.Model):
def __unicode__(self):
return "%s (%s)" % (self.fullname, self.user.username)
+
class MemberLog(models.Model):
member = models.ForeignKey(Member, null=False, blank=False, on_delete=models.CASCADE)
timestamp = models.DateTimeField(null=False)
@@ -50,6 +52,7 @@ class MemberLog(models.Model):
def __unicode__(self):
return "%s: %s" % (self.timestamp, self.message)
+
class Meeting(models.Model):
name = models.CharField(max_length=100, null=False, blank=False)
dateandtime = models.DateTimeField(null=False, blank=False)
diff --git a/postgresqleu/membership/views.py b/postgresqleu/membership/views.py
index 42ad3163..fee95bc9 100644
--- a/postgresqleu/membership/views.py
+++ b/postgresqleu/membership/views.py
@@ -21,6 +21,7 @@ import json
import base64
import os
+
@login_required
@transaction.atomic
def home(request):
@@ -141,6 +142,7 @@ def admin_email(request):
'recipientlist': ', '.join(recipients),
})
+
@login_required
def meetings(request):
# Only available for actual members
@@ -162,6 +164,7 @@ def meetings(request):
'meetings': meetinginfo,
})
+
@transaction.atomic
def _meeting(request, member, meeting, isproxy):
if not (member.paiduntil and member.paiduntil >= datetime.today().date()):
@@ -197,6 +200,7 @@ def _meeting(request, member, meeting, isproxy):
'key': key,
})
+
@login_required
def meeting(request, meetingid):
# View a single meeting
@@ -204,10 +208,12 @@ def meeting(request, meetingid):
member = get_object_or_404(Member, user=request.user)
return _meeting(request, member, meeting, False)
+
def meeting_by_key(request, meetingid, token):
key = get_object_or_404(MemberMeetingKey, proxyaccesskey=token)
return _meeting(request, key.member, key.meeting, True)
+
@login_required
@transaction.atomic
def meeting_proxy(request, meetingid):
@@ -267,6 +273,7 @@ def meeting_proxy(request, meetingid):
'form': form,
})
+
# API calls from meeting bot
def meetingcode(request):
secret = request.GET['s']
diff --git a/postgresqleu/newsevents/admin.py b/postgresqleu/newsevents/admin.py
index 49447f5d..5c2bd139 100644
--- a/postgresqleu/newsevents/admin.py
+++ b/postgresqleu/newsevents/admin.py
@@ -8,6 +8,7 @@ from postgresqleu.util.admin import SelectableWidgetAdminFormMixin
from postgresqleu.newsevents.models import News, NewsPosterProfile
+
class NewsPosterProfileForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedModelForm):
class Meta:
model = NewsPosterProfile
@@ -16,6 +17,7 @@ class NewsPosterProfileForm(SelectableWidgetAdminFormMixin, ConcurrentProtectedM
'author': AutoCompleteSelectWidget(lookup_class=UserLookup),
}
+
class NewsPosterProfileAdmin(admin.ModelAdmin):
form = NewsPosterProfileForm
list_display = ('__unicode__', 'rsslink')
@@ -23,5 +25,6 @@ class NewsPosterProfileAdmin(admin.ModelAdmin):
def rsslink(self, author):
return "/feeds/user/{0}/".format(author.urlname)
+
admin.site.register(News)
admin.site.register(NewsPosterProfile, NewsPosterProfileAdmin)
diff --git a/postgresqleu/newsevents/feeds.py b/postgresqleu/newsevents/feeds.py
index 14312fb1..4deb38ab 100644
--- a/postgresqleu/newsevents/feeds.py
+++ b/postgresqleu/newsevents/feeds.py
@@ -10,6 +10,7 @@ import datetime
from postgresqleu.util.db import exec_to_dict
+
class LatestNews(Feed):
title = "News - %s" % settings.ORG_NAME
link = "/"
diff --git a/postgresqleu/newsevents/management/commands/register_news_twitter.py b/postgresqleu/newsevents/management/commands/register_news_twitter.py
index 0158abed..2477b2c7 100644
--- a/postgresqleu/newsevents/management/commands/register_news_twitter.py
+++ b/postgresqleu/newsevents/management/commands/register_news_twitter.py
@@ -11,6 +11,7 @@ from django.conf import settings
import requests_oauthlib
+
class Command(BaseCommand):
help = 'Register with twitter oauth'
diff --git a/postgresqleu/newsevents/management/commands/twitter_post.py b/postgresqleu/newsevents/management/commands/twitter_post.py
index 48ed760a..7ec6f5b9 100644
--- a/postgresqleu/newsevents/management/commands/twitter_post.py
+++ b/postgresqleu/newsevents/management/commands/twitter_post.py
@@ -16,6 +16,7 @@ from postgresqleu.confreg.models import Conference, ConferenceNews, ConferenceTw
from postgresqleu.util.messaging.twitter import Twitter
+
class Command(BaseCommand):
help = 'Post to twitter'
@@ -49,7 +50,6 @@ class Command(BaseCommand):
# Don't post more often than once / 10 seconds, to not trigger flooding.
time.sleep(10)
-
# Find which conferences to tweet from. We will only put out one tweet for each
# conference, expecting to be called again in 5 minutes or so to put out the
# next one.
@@ -84,4 +84,3 @@ class Command(BaseCommand):
continue
else:
print("Failed to post to twitter: %s" % msg)
-
diff --git a/postgresqleu/newsevents/models.py b/postgresqleu/newsevents/models.py
index f872ca25..75124148 100644
--- a/postgresqleu/newsevents/models.py
+++ b/postgresqleu/newsevents/models.py
@@ -1,6 +1,7 @@
from django.db import models
from django.contrib.auth.models import User
+
class NewsPosterProfile(models.Model):
author = models.OneToOneField(User, primary_key=True)
urlname = models.CharField(max_length=50, null=False, blank=False, unique=True)
diff --git a/postgresqleu/newsevents/views.py b/postgresqleu/newsevents/views.py
index dc39197d..958e25fd 100644
--- a/postgresqleu/newsevents/views.py
+++ b/postgresqleu/newsevents/views.py
@@ -5,6 +5,7 @@ import datetime
from postgresqleu.newsevents.models import News
+
def newsitem(request, itemid):
item = get_object_or_404(News.objects.select_related('author'),
pk=itemid, datetime__lte=datetime.datetime.today())
@@ -15,6 +16,7 @@ def newsitem(request, itemid):
'news': news,
})
+
def newsarchive(request):
news = News.objects.filter(datetime__lte=datetime.datetime.today(), inarchive=True)[:10]
allnews = News.objects.filter(datetime__lte=datetime.datetime.today(), inarchive=True)
diff --git a/postgresqleu/paypal/admin.py b/postgresqleu/paypal/admin.py
index 6264d571..c4f0f684 100644
--- a/postgresqleu/paypal/admin.py
+++ b/postgresqleu/paypal/admin.py
@@ -1,17 +1,20 @@
from django.contrib import admin
from models import SourceAccount, TransactionInfo, ErrorLog
+
class TransactionInfoAdmin(admin.ModelAdmin):
list_display = ('timestamp', 'sourceaccount', 'sender', 'amount', 'fee', 'transtext', 'matched', )
list_filter = ('sourceaccount', 'matched', )
ordering = ('-timestamp', )
search_fields = ('paypaltransid', 'sender', 'sendername', 'transtext',)
+
class ErrorLogAdmin(admin.ModelAdmin):
list_display = ('timestamp', 'sent', 'message', )
list_filter = ('sent', )
ordering = ('-timestamp', )
+
admin.site.register(SourceAccount)
admin.site.register(TransactionInfo, TransactionInfoAdmin)
admin.site.register(ErrorLog, ErrorLogAdmin)
diff --git a/postgresqleu/paypal/management/commands/paypal_fetch.py b/postgresqleu/paypal/management/commands/paypal_fetch.py
index 03c9e2ab..ae7d0b50 100644
--- a/postgresqleu/paypal/management/commands/paypal_fetch.py
+++ b/postgresqleu/paypal/management/commands/paypal_fetch.py
@@ -18,6 +18,7 @@ from decimal import Decimal
from postgresqleu.paypal.models import TransactionInfo
from postgresqleu.paypal.util import PaypalAPI
+
class PaypalBaseTransaction(object):
def __init__(self, apistruct):
self.message = None
@@ -83,6 +84,7 @@ class PaypalTransaction(PaypalBaseTransaction):
except Exception, e:
self.message = "Unable to parse: %s" % e
+
class PaypalRefund(PaypalTransaction):
def fetch_details(self, api):
super(PaypalRefund, self).fetch_details(api)
@@ -91,6 +93,7 @@ class PaypalRefund(PaypalTransaction):
else:
self.transinfo.transtext = "Refund of unknown transaction"
+
class PaypalTransfer(PaypalBaseTransaction):
def __init__(self, apistruct):
super(PaypalTransfer, self).__init__(apistruct)
@@ -106,6 +109,7 @@ class PaypalTransfer(PaypalBaseTransaction):
# We cannot fetch more details, but we also don't need more details..
pass
+
class Command(BaseCommand):
help = 'Fetch updated list of transactions from paypal'
diff --git a/postgresqleu/paypal/management/commands/paypal_match.py b/postgresqleu/paypal/management/commands/paypal_match.py
index d45961d0..21606037 100755
--- a/postgresqleu/paypal/management/commands/paypal_match.py
+++ b/postgresqleu/paypal/management/commands/paypal_match.py
@@ -21,6 +21,7 @@ from postgresqleu.invoices.models import InvoicePaymentMethod
from postgresqleu.accounting.util import create_accounting_entry
from postgresqleu.paypal.models import TransactionInfo, ErrorLog
+
class Command(BaseCommand):
help = 'Match pending paypal payments'
diff --git a/postgresqleu/paypal/management/commands/paypal_report.py b/postgresqleu/paypal/management/commands/paypal_report.py
index 3eb70d73..18b9fe57 100644
--- a/postgresqleu/paypal/management/commands/paypal_report.py
+++ b/postgresqleu/paypal/management/commands/paypal_report.py
@@ -13,6 +13,7 @@ from django.conf import settings
from postgresqleu.paypal.models import ErrorLog, TransactionInfo
from postgresqleu.mailqueue.util import send_simple_mail
+
class Command(BaseCommand):
help = 'Send paypal report emails'
diff --git a/postgresqleu/paypal/management/commands/refund_paypal_transaction.py b/postgresqleu/paypal/management/commands/refund_paypal_transaction.py
index b1b5eba2..cc506199 100644
--- a/postgresqleu/paypal/management/commands/refund_paypal_transaction.py
+++ b/postgresqleu/paypal/management/commands/refund_paypal_transaction.py
@@ -12,6 +12,7 @@ import time
from postgresqleu.paypal.models import TransactionInfo
from postgresqleu.paypal.util import PaypalAPI
+
class Command(BaseCommand):
help = 'Refund paypal transactions'
diff --git a/postgresqleu/paypal/management/commands/verify_paypal_balance.py b/postgresqleu/paypal/management/commands/verify_paypal_balance.py
index 8e552dcd..41873d67 100644
--- a/postgresqleu/paypal/management/commands/verify_paypal_balance.py
+++ b/postgresqleu/paypal/management/commands/verify_paypal_balance.py
@@ -15,6 +15,7 @@ from postgresqleu.paypal.util import PaypalAPI
from postgresqleu.accounting.util import get_latest_account_balance
from postgresqleu.mailqueue.util import send_simple_mail
+
class Command(BaseCommand):
help = 'Compare paypal balance to the accounting system'
diff --git a/postgresqleu/paypal/models.py b/postgresqleu/paypal/models.py
index 9c356eac..e2c96493 100644
--- a/postgresqleu/paypal/models.py
+++ b/postgresqleu/paypal/models.py
@@ -2,6 +2,7 @@ from django.db import models
from datetime import datetime
+
class SourceAccount(models.Model):
accountname = models.CharField(max_length=16, null=False, blank=False)
lastsync = models.DateTimeField(null=False, blank=False, default=datetime(2009, 1, 1))
@@ -9,6 +10,7 @@ class SourceAccount(models.Model):
def __unicode__(self):
return self.accountname
+
class TransactionInfo(models.Model):
paypaltransid = models.CharField(max_length=20, null=False, blank=False, unique=True)
timestamp = models.DateTimeField(null=False, blank=False)
@@ -26,6 +28,7 @@ class TransactionInfo(models.Model):
self.matchinfo = msg
self.save()
+
class ErrorLog(models.Model):
timestamp = models.DateTimeField(null=False, blank=False)
message = models.TextField(null=False, blank=False)
diff --git a/postgresqleu/paypal/util.py b/postgresqleu/paypal/util.py
index 324ad587..aeb501a9 100644
--- a/postgresqleu/paypal/util.py
+++ b/postgresqleu/paypal/util.py
@@ -6,6 +6,7 @@ from urlparse import parse_qs
from decimal import Decimal
import itertools
+
class PaypalAPI(object):
def __init__(self):
self.accessparam = {
@@ -19,7 +20,6 @@ class PaypalAPI(object):
else:
self.API_ENDPOINT = 'https://api-3t.paypal.com/nvp'
-
def _api_call(self, command, params):
params.update(self.accessparam)
params['METHOD'] = command
@@ -50,7 +50,6 @@ class PaypalAPI(object):
for k in
('TRANSACTIONID', 'TIMESTAMP', 'EMAIL', 'TYPE', 'AMT', 'FEEAMT', 'NAME')])
-
def get_transaction_details(self, transactionid):
return self._api_call('GetTransactionDetails', {
'TRANSACTIONID': transactionid,
diff --git a/postgresqleu/paypal/views.py b/postgresqleu/paypal/views.py
index eda121a3..d0522f58 100644
--- a/postgresqleu/paypal/views.py
+++ b/postgresqleu/paypal/views.py
@@ -14,6 +14,7 @@ from postgresqleu.accounting.util import create_accounting_entry
from models import TransactionInfo, ErrorLog, SourceAccount
+
@transaction.atomic
def paypal_return_handler(request):
tx = 'UNKNOWN'
diff --git a/postgresqleu/static/views.py b/postgresqleu/static/views.py
index 9c44e112..9c04dd05 100644
--- a/postgresqleu/static/views.py
+++ b/postgresqleu/static/views.py
@@ -1,6 +1,7 @@
from django.http import HttpResponse, Http404
from django.template import loader, TemplateDoesNotExist
+
# Fallback handler for URLs not matching anything else. Fall them
# back to a static template. If that one is not found, send a 404
# error.
@@ -14,4 +15,3 @@ def static_fallback(request, url):
return HttpResponse(t.render())
except TemplateDoesNotExist:
raise Http404('Page not found')
-
diff --git a/postgresqleu/trustlypayment/admin.py b/postgresqleu/trustlypayment/admin.py
index 1d00085d..afda9167 100644
--- a/postgresqleu/trustlypayment/admin.py
+++ b/postgresqleu/trustlypayment/admin.py
@@ -4,9 +4,11 @@ from django.urls import reverse
from models import TrustlyTransaction, TrustlyRawNotification, TrustlyNotification, TrustlyLog
+
class TrustlyTransactionAdmin(admin.ModelAdmin):
list_display = ('orderid', 'invoiceid', 'amount', 'createdat', 'pendingat', 'completedat',)
+
class TrustlyRawNotificationAdmin(admin.ModelAdmin):
list_display = ('dat', 'confirmed')
readonly_fields = ('notification_link',)
@@ -18,6 +20,7 @@ class TrustlyRawNotificationAdmin(admin.ModelAdmin):
return mark_safe('<a href="{0}">{1}</a>'.format(url, n))
notification_link.short_description = 'Notification'
+
class TrustlyNotificationAdmin(admin.ModelAdmin):
list_display = ('receivedat', 'notificationid', 'orderid', 'method', 'amount', 'confirmed')
readonly_fields = ('rawnotification_link',)
@@ -28,6 +31,7 @@ class TrustlyNotificationAdmin(admin.ModelAdmin):
return mark_safe('<a href="{0}">{1}</a>'.format(url, obj))
rawnotification_link.short_description = 'Rawnotification'
+
class TrustlyLogAdmin(admin.ModelAdmin):
list_display = ('timestamp', 'success', 'sentstr', 'message', )
@@ -39,6 +43,7 @@ class TrustlyLogAdmin(admin.ModelAdmin):
return obj.sent and 'Yes' or 'No'
sentstr.short_description = 'Log sent'
+
admin.site.register(TrustlyTransaction, TrustlyTransactionAdmin)
admin.site.register(TrustlyRawNotification, TrustlyRawNotificationAdmin)
admin.site.register(TrustlyNotification, TrustlyNotificationAdmin)
diff --git a/postgresqleu/trustlypayment/api.py b/postgresqleu/trustlypayment/api.py
index 3f248132..a4fca9fd 100644
--- a/postgresqleu/trustlypayment/api.py
+++ b/postgresqleu/trustlypayment/api.py
@@ -8,9 +8,11 @@ from Crypto.PublicKey import RSA
import base64
import urllib2
+
class TrustlyException(Exception):
pass
+
class TrustlyWrapper(object):
def __init__(self, apibase, username, password, privatekey, publickey, notificationurl, currency='EUR', hold_notifications=False):
self.apibase = apibase
@@ -61,7 +63,6 @@ class TrustlyWrapper(object):
else:
raise TrustlyException('Failed to refund orderid {0}'.format(orderid))
-
def get_balance(self):
r = self.apicall('Balance', {})
balance = None
diff --git a/postgresqleu/trustlypayment/management/commands/send_trustly_logreport.py b/postgresqleu/trustlypayment/management/commands/send_trustly_logreport.py
index 07db06a2..c51dc551 100755
--- a/postgresqleu/trustlypayment/management/commands/send_trustly_logreport.py
+++ b/postgresqleu/trustlypayment/management/commands/send_trustly_logreport.py
@@ -14,6 +14,7 @@ from StringIO import StringIO
from postgresqleu.trustlypayment.models import TrustlyLog, TrustlyNotification, TrustlyTransaction
from postgresqleu.mailqueue.util import send_simple_mail
+
class Command(BaseCommand):
help = 'Send log information about Trustly events'
@@ -70,4 +71,3 @@ class Command(BaseCommand):
settings.TRUSTLY_NOTIFICATION_RECEIVER,
'Trustly integration unconfirmed notifications',
sio.getvalue())
-
diff --git a/postgresqleu/trustlypayment/management/commands/trustly_match_refunds.py b/postgresqleu/trustlypayment/management/commands/trustly_match_refunds.py
index 04acc66c..61aed7ae 100644
--- a/postgresqleu/trustlypayment/management/commands/trustly_match_refunds.py
+++ b/postgresqleu/trustlypayment/management/commands/trustly_match_refunds.py
@@ -18,6 +18,7 @@ from postgresqleu.invoices.util import InvoiceManager
from decimal import Decimal
+
class Command(BaseCommand):
help = 'Verify that a Trustly refund has completed, and flag it as such'
diff --git a/postgresqleu/trustlypayment/management/commands/verify_trustly_balance.py b/postgresqleu/trustlypayment/management/commands/verify_trustly_balance.py
index 2c273484..6b43f5b3 100644
--- a/postgresqleu/trustlypayment/management/commands/verify_trustly_balance.py
+++ b/postgresqleu/trustlypayment/management/commands/verify_trustly_balance.py
@@ -15,6 +15,7 @@ from postgresqleu.trustlypayment.util import Trustly
from postgresqleu.accounting.util import get_latest_account_balance
from postgresqleu.mailqueue.util import send_simple_mail
+
class Command(BaseCommand):
help = 'Compare trustly balance to the accounting system'
diff --git a/postgresqleu/trustlypayment/models.py b/postgresqleu/trustlypayment/models.py
index 6473d809..9a84a1f7 100644
--- a/postgresqleu/trustlypayment/models.py
+++ b/postgresqleu/trustlypayment/models.py
@@ -1,5 +1,6 @@
from django.db import models
+
class TrustlyTransaction(models.Model):
createdat = models.DateTimeField(null=False, blank=False)
pendingat = models.DateTimeField(null=True, blank=True)
@@ -12,6 +13,7 @@ class TrustlyTransaction(models.Model):
def __unicode__(self):
return "%s" % self.orderid
+
class TrustlyRawNotification(models.Model):
dat = models.DateTimeField(null=False, blank=False, auto_now_add=True, unique=True)
contents = models.TextField(null=False, blank=False)
@@ -20,6 +22,7 @@ class TrustlyRawNotification(models.Model):
def __unicode__(self):
return "%s" % self.dat
+
class TrustlyNotification(models.Model):
receivedat = models.DateTimeField(null=False, blank=False, auto_now_add=True, unique=True)
rawnotification = models.ForeignKey(TrustlyRawNotification, null=True, blank=True, on_delete=models.CASCADE)
@@ -34,12 +37,14 @@ class TrustlyNotification(models.Model):
def __unicode__(self):
return "%s" % self.receivedat
+
class TrustlyLog(models.Model):
timestamp = models.DateTimeField(null=False, blank=False, auto_now_add=True)
message = models.TextField(null=False, blank=False)
error = models.BooleanField(null=False, blank=False, default=False)
sent = models.BooleanField(null=False, blank=False, default=False)
+
class ReturnAuthorizationStatus(models.Model):
orderid = models.BigIntegerField(null=False, blank=False, primary_key=True)
seencount = models.IntegerField(null=False, default=0)
diff --git a/postgresqleu/trustlypayment/util.py b/postgresqleu/trustlypayment/util.py
index 474b689e..1165d93b 100644
--- a/postgresqleu/trustlypayment/util.py
+++ b/postgresqleu/trustlypayment/util.py
@@ -12,8 +12,8 @@ from api import TrustlyWrapper, TrustlyException
from models import TrustlyTransaction, TrustlyLog
from models import TrustlyNotification
-# Django intgrated wrapper for the trustly API
+# Django intgrated wrapper for the trustly API
class Trustly(TrustlyWrapper):
def __init__(self):
super(Trustly, self).__init__(settings.TRUSTLY_APIBASE,
diff --git a/postgresqleu/trustlypayment/views.py b/postgresqleu/trustlypayment/views.py
index 5716c432..f2368d6d 100644
--- a/postgresqleu/trustlypayment/views.py
+++ b/postgresqleu/trustlypayment/views.py
@@ -12,6 +12,7 @@ from util import Trustly, TrustlyException
from models import TrustlyTransaction, TrustlyRawNotification, TrustlyLog
from models import ReturnAuthorizationStatus
+
@transaction.atomic
def invoicepayment_secret(request, invoiceid, secret):
invoice = get_object_or_404(Invoice, pk=invoiceid, deleted=False, finalized=True, recipient_secret=secret)
@@ -94,11 +95,13 @@ def success(request, invoiceid, secret):
'pendingat': trans.pendingat,
})
+
def failure(request, invoiceid, secret):
return render(request, 'trustlypayment/error.html', {
'url': '/invoices/{0}/{1}/'.format(invoiceid, secret),
})
+
@csrf_exempt
def notification(request):
raw = TrustlyRawNotification(contents=request.body)
diff --git a/postgresqleu/urls.py b/postgresqleu/urls.py
index 59be7f78..e869611d 100644
--- a/postgresqleu/urls.py
+++ b/postgresqleu/urls.py
@@ -311,8 +311,6 @@ if settings.ENABLE_BRAINTREE:
url(r'^p/braintree/$', postgresqleu.braintreepayment.views.payment_post),
])
-
-
# Now extend with some fallback URLs as well
urlpatterns.extend([
# Selectable, only used on admin site for now
diff --git a/postgresqleu/util/context_processors.py b/postgresqleu/util/context_processors.py
index 74e4991a..df79554c 100644
--- a/postgresqleu/util/context_processors.py
+++ b/postgresqleu/util/context_processors.py
@@ -6,6 +6,7 @@
from django.conf import settings
from django.utils.functional import SimpleLazyObject
+
def settings_context(request=None):
return {
'org_name': settings.ORG_NAME,
@@ -23,6 +24,7 @@ def settings_context(request=None):
}
}
+
def settings_context_unicode(request=None):
# Same as settings_context, except convert all strings to unicode assuming
# utf-8.
@@ -32,9 +34,11 @@ def settings_context_unicode(request=None):
c[k] = v.decode('utf8')
return c
+
if settings.ENABLE_MEMBERSHIP:
from postgresqleu.membership.models import Member
+
def member_context(request=None):
def _member():
if not request.user.is_authenticated():
diff --git a/postgresqleu/util/db.py b/postgresqleu/util/db.py
index d3e291cd..2af6661b 100644
--- a/postgresqleu/util/db.py
+++ b/postgresqleu/util/db.py
@@ -1,21 +1,25 @@
from django.db import connection
import collections
+
def exec_no_result(query, params=None):
curs = connection.cursor()
curs.execute(query, params)
+
def exec_to_list(query, params=None):
curs = connection.cursor()
curs.execute(query, params)
return curs.fetchall()
+
def exec_to_dict(query, params=None):
curs = connection.cursor()
curs.execute(query, params)
columns = [col[0] for col in curs.description]
return [dict(zip(columns, row))for row in curs.fetchall()]
+
def exec_to_scalar(query, params=None):
curs = connection.cursor()
curs.execute(query, params)
@@ -25,18 +29,21 @@ def exec_to_scalar(query, params=None):
# If the query returns no rows at all, then just return None
return None
+
def conditional_exec_to_scalar(condition, query, params=None):
if condition:
return exec_to_scalar(query, params)
else:
return False
+
def exec_to_keyed_dict(query, params=None):
curs = connection.cursor()
curs.execute(query, params)
columns = [col[0] for col in curs.description]
return {r[columns[0]]: r for r in (dict(zip(columns, row))for row in curs.fetchall())}
+
def exec_to_grouped_dict(query, params=None):
curs = connection.cursor()
curs.execute(query, params)
diff --git a/postgresqleu/util/decorators.py b/postgresqleu/util/decorators.py
index 55ed1419..4c2a6d69 100644
--- a/postgresqleu/util/decorators.py
+++ b/postgresqleu/util/decorators.py
@@ -3,11 +3,11 @@ from django.utils.decorators import available_attrs
from django.http import HttpResponseForbidden
from django.contrib.auth.decorators import login_required
+
# This is like @user_passes_test, except if the user is logged in
# but does not pass the test we give an error instead of a new
# chance to log in. This is so we don't end up in a redirect loop
# with the community auth system.
-
def user_passes_test_or_error(test_func):
def decorator(view_func):
@wraps(view_func, assigned=available_attrs(view_func))
@@ -20,7 +20,6 @@ def user_passes_test_or_error(test_func):
return decorator
-
# Exclude an URL from global logins, if they are enabled at all
def global_login_exempt(view_func):
def wrapped_view(*args, **kwargs):
@@ -28,6 +27,7 @@ def global_login_exempt(view_func):
wrapped_view.global_login_exempt = True
return wraps(view_func, assigned=available_attrs(view_func))(wrapped_view)
+
# Require superuser
def superuser_required(view_func):
return login_required(user_passes_test_or_error(lambda u: u.is_superuser)(view_func))
diff --git a/postgresqleu/util/forms.py b/postgresqleu/util/forms.py
index 406cfc3e..1cbfa3e1 100644
--- a/postgresqleu/util/forms.py
+++ b/postgresqleu/util/forms.py
@@ -7,10 +7,12 @@ import cPickle
import base64
from itertools import groupby
+
class _ValidatorField(forms.Field):
required = True
widget = forms.HiddenInput
+
class ConcurrentProtectedModelForm(forms.ModelForm):
_validator = _ValidatorField()
@@ -21,6 +23,7 @@ class ConcurrentProtectedModelForm(forms.ModelForm):
def update_protected_fields(self):
self.fields['_validator'].initial = Signer().sign(base64.urlsafe_b64encode(cPickle.dumps(self._filter_initial(), -1)))
+
def __init__(self, *args, **kwargs):
r = super(ConcurrentProtectedModelForm, self).__init__(*args, **kwargs)
self.update_protected_fields()
@@ -71,6 +74,7 @@ class GroupedIterator(forms.models.ModelChoiceIterator):
yield (group,
[self.choice(c) for c in choices])
+
class Grouped(object):
def __init__(self, groupfield, queryset, *args, **kwargs):
self.orderby = queryset.query.order_by
@@ -80,5 +84,6 @@ class Grouped(object):
def _get_choices(self):
return GroupedIterator(self)
+
class GroupedModelMultipleChoiceField(Grouped, forms.ModelMultipleChoiceField):
choices = property(Grouped._get_choices, forms.ModelMultipleChoiceField._set_choices)
diff --git a/postgresqleu/util/jsonutil.py b/postgresqleu/util/jsonutil.py
index 08eb53ac..4a3e641a 100644
--- a/postgresqleu/util/jsonutil.py
+++ b/postgresqleu/util/jsonutil.py
@@ -1,6 +1,7 @@
from datetime import datetime, date
import json
+
class JsonSerializer(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, datetime) or isinstance(obj, date):
diff --git a/postgresqleu/util/management/commands/sessioninfo.py b/postgresqleu/util/management/commands/sessioninfo.py
index 06a88d9c..5027be4b 100644
--- a/postgresqleu/util/management/commands/sessioninfo.py
+++ b/postgresqleu/util/management/commands/sessioninfo.py
@@ -7,6 +7,7 @@ from django.core.management.base import BaseCommand, CommandError
from django.contrib.sessions.models import Session
from django.contrib.auth.models import User
+
class Command(BaseCommand):
help = 'Dump interesting information about a session'
@@ -37,4 +38,3 @@ class Command(BaseCommand):
raise CommandError('Session not found')
except User.DoesNotExist:
raise CommandError('Associated user not found')
-
diff --git a/postgresqleu/util/messaging/twitter.py b/postgresqleu/util/messaging/twitter.py
index 60edcc7d..c01e6dc1 100644
--- a/postgresqleu/util/messaging/twitter.py
+++ b/postgresqleu/util/messaging/twitter.py
@@ -4,6 +4,7 @@ import requests_oauthlib
_cached_twitter_users = {}
+
class Twitter(object):
def __init__(self, conference=None):
if conference:
@@ -18,7 +19,6 @@ class Twitter(object):
token,
secret)
-
def post_tweet(self, tweet):
r = self.tw.post('https://api.twitter.com/1.1/statuses/update.json', data={
'status': tweet,
@@ -89,4 +89,3 @@ class TwitterSetup(object):
tokens = oauth.fetch_access_token('https://api.twitter.com/oauth/access_token')
return tokens
-
diff --git a/postgresqleu/util/middleware.py b/postgresqleu/util/middleware.py
index 91e914cf..778118f8 100644
--- a/postgresqleu/util/middleware.py
+++ b/postgresqleu/util/middleware.py
@@ -4,6 +4,7 @@ from django.conf import settings
import base64
+
class FilterPersistMiddleware(object):
def process_request(self, request):
@@ -45,7 +46,6 @@ class FilterPersistMiddleware(object):
return None
-
class GlobalLoginMiddleware(object):
def process_view(self, request, callback, callback_args, callback_kwargs):
if not settings.GLOBAL_LOGIN_USER or not settings.GLOBAL_LOGIN_PASSWORD:
@@ -71,11 +71,13 @@ class GlobalLoginMiddleware(object):
response['WWW-Authenticate'] = 'Basic realm={0}'.format(settings.SITEBASE)
return response
+
# Ability to redirect using raise()
class RedirectException(Exception):
def __init__(self, url):
self.url = url
+
class RedirectMiddleware(object):
def process_exception(self, request, exception):
if isinstance(exception, RedirectException):
diff --git a/postgresqleu/util/misc/pgeuinvoice.py b/postgresqleu/util/misc/pgeuinvoice.py
index a72edeec..6331b8fa 100755
--- a/postgresqleu/util/misc/pgeuinvoice.py
+++ b/postgresqleu/util/misc/pgeuinvoice.py
@@ -16,6 +16,7 @@ from reportlab.pdfbase.ttfonts import TTFont
import qrencode
import cStringIO as StringIO
+
class PDFBase(object):
def __init__(self, recipient, invoicenum, imagedir, currency):
self.pdfdata = StringIO.StringIO()
@@ -118,12 +119,11 @@ class PDFInvoice(PDFBase):
# Never include bank info on receipts
self.bankinfo = False
-
def addrow(self, title, cost, count, vatrate):
self.rows.append((title, cost, count, vatrate, vatrate and vatrate.vatpercent or 0))
-
ROWS_PER_PAGE = 14
+
def save(self):
# We can fit ROWS_PER_PAGE rows on one page. We might want to do something
# cute to avoid a single row on it's own page in the future, but
@@ -218,7 +218,6 @@ class PDFInvoice(PDFBase):
else:
self.canvas.drawCentredString(10.5*cm, 17.3*cm-h, "This invoice is due: %s" % self.duedate.strftime("%B %d, %Y"))
-
if islastpage:
if not self.receipt:
t = self.canvas.beginText()
@@ -277,7 +276,6 @@ BIC: CMCIFR2A
return self.pdfdata
-
class PDFRefund(PDFBase):
def __init__(self, recipient, invoicedate, refunddate, invoicenum, invoiceamount, invoicevat, refundamount, refundvat, imagedir, currency, paymentmethod):
self.recipient = recipient
diff --git a/postgresqleu/util/models.py b/postgresqleu/util/models.py
index 876ba542..68e9ccce 100644
--- a/postgresqleu/util/models.py
+++ b/postgresqleu/util/models.py
@@ -1,6 +1,7 @@
# Some very simple models used by utilities
from django.db import models
+
class Storage(models.Model):
key = models.CharField(max_length=16, null=False, blank=False)
storageid = models.IntegerField(null=False, blank=False)
diff --git a/postgresqleu/util/payment/adyen.py b/postgresqleu/util/payment/adyen.py
index f9affe9b..e400017a 100644
--- a/postgresqleu/util/payment/adyen.py
+++ b/postgresqleu/util/payment/adyen.py
@@ -18,9 +18,11 @@ from postgresqleu.invoices.util import diff_workdays
from postgresqleu.adyen.models import TransactionStatus
from postgresqleu.adyen.util import AdyenAPI
+
def _escapeVal(val):
return val.replace('\\', '\\\\').replace(':', '\\:')
+
def calculate_signature(param):
param = OrderedDict(sorted(param.items(), key=lambda t: t[0]))
if param.has_key('merchantSig'):
@@ -31,6 +33,7 @@ def calculate_signature(param):
hashlib.sha256)
return base64.b64encode(hm.digest())
+
def _gzip_string(str):
# Compress a string using gzip including header data
s = StringIO.StringIO()
@@ -39,6 +42,7 @@ def _gzip_string(str):
g.close()
return s.getvalue()
+
class _AdyenBase(object):
ADYEN_COMMON = {
'currencyCode': settings.CURRENCY_ABBREV,
@@ -69,6 +73,7 @@ class _AdyenBase(object):
)
_re_adyen = re.compile('^Adyen id ([A-Z0-9]+)$')
+
def _find_invoice_transaction(self, invoice):
m = self._re_adyen.match(invoice.paymentdetails)
if m:
@@ -104,6 +109,7 @@ class _AdyenBase(object):
# up as an exception.
return True
+
class AdyenCreditcard(_AdyenBase):
description = """
Pay using your credit card, including Mastercard, VISA and American Express.
@@ -120,6 +126,7 @@ Pay using your credit card, including Mastercard, VISA and American Express.
raise Exception(reason)
return "Credit Card ({0})".format(trans.method)
+
class AdyenBanktransfer(_AdyenBase):
description = """
Pay using a direct IBAN bank transfer. Due to the unreliable and slow processing
diff --git a/postgresqleu/util/payment/banktransfer.py b/postgresqleu/util/payment/banktransfer.py
index 5b9d62a7..4e335627 100644
--- a/postgresqleu/util/payment/banktransfer.py
+++ b/postgresqleu/util/payment/banktransfer.py
@@ -1,5 +1,6 @@
from urllib import urlencode
+
class Banktransfer(object):
description = """
Using this payment method, you can pay via a regular bank transfer
diff --git a/postgresqleu/util/payment/braintree.py b/postgresqleu/util/payment/braintree.py
index 61705280..81b6d6ad 100644
--- a/postgresqleu/util/payment/braintree.py
+++ b/postgresqleu/util/payment/braintree.py
@@ -3,6 +3,7 @@ import re
from postgresqleu.invoices.models import Invoice
from postgresqleu.braintreepayment.models import BraintreeTransaction
+
class Braintree(object):
description = """
Using this payment method, you can pay using your credit card, including
@@ -17,6 +18,7 @@ Mastercard, VISA and American Express.
return "/invoices/braintree/{0}/".format(invoiceid)
_re_braintree = re.compile('^Braintree id ([a-z0-9]+)$')
+
def _find_invoice_transaction(self, invoice):
m = self._re_braintree.match(invoice.paymentdetails)
if m:
diff --git a/postgresqleu/util/payment/dummy.py b/postgresqleu/util/payment/dummy.py
index 15bfcd10..caaa4608 100644
--- a/postgresqleu/util/payment/dummy.py
+++ b/postgresqleu/util/payment/dummy.py
@@ -1,5 +1,6 @@
from postgresqleu.invoices.models import Invoice
+
class DummyPayment(object):
description = """
This is a payment method purely for debugging. If you see this in production,
diff --git a/postgresqleu/util/payment/paypal.py b/postgresqleu/util/payment/paypal.py
index 066ac5f6..4003c212 100644
--- a/postgresqleu/util/payment/paypal.py
+++ b/postgresqleu/util/payment/paypal.py
@@ -6,6 +6,7 @@ import re
from postgresqleu.paypal.models import TransactionInfo
from postgresqleu.paypal.util import PaypalAPI
+
class Paypal(object):
description = """
Pay using Paypal. You can use this both
@@ -46,6 +47,7 @@ lower fees.
urlencode(param))
_re_paypal = re.compile('^Paypal id ([A-Z0-9]+), ')
+
def _find_invoice_transaction(self, invoice):
m = self._re_paypal.match(invoice.paymentdetails)
if m:
diff --git a/postgresqleu/util/random.py b/postgresqleu/util/random.py
index 4114592e..427da458 100644
--- a/postgresqleu/util/random.py
+++ b/postgresqleu/util/random.py
@@ -1,6 +1,7 @@
from Crypto.Hash import SHA256
from Crypto import Random
+
def generate_random_token():
s = SHA256.new()
r = Random.new()
diff --git a/postgresqleu/util/storage.py b/postgresqleu/util/storage.py
index dfab7747..9d2eb040 100644
--- a/postgresqleu/util/storage.py
+++ b/postgresqleu/util/storage.py
@@ -5,6 +5,7 @@ from django.core.files import File
from django.db import connection
from django.utils.deconstruct import deconstructible
+
@deconstructible
class InlineEncodedStorage(Storage):
def __init__(self, key):
@@ -55,8 +56,10 @@ class InlineEncodedStorage(Storage):
def path(self):
return None
+
def inlineencoded_upload_path(instance, filename):
return "%s" % instance.id
+
def delete_inline_storage(sender, **kwargs):
kwargs['instance'].delete_inline_storage()
diff --git a/postgresqleu/util/validators.py b/postgresqleu/util/validators.py
index 79c7d46f..223aa29b 100644
--- a/postgresqleu/util/validators.py
+++ b/postgresqleu/util/validators.py
@@ -6,6 +6,7 @@ from StringIO import StringIO
import requests
from PIL import Image
+
def validate_lowercase(value):
if value != value.lower():
raise ValidationError("This field must be lowercase only")
@@ -19,6 +20,7 @@ class BeforeValidator(object):
if value >= self.beforedate:
raise ValidationError("Ensure this date is before {0}".format(self.beforedate))
+
class AfterValidator(object):
def __init__(self, afterdate):
self.afterdate = afterdate
diff --git a/postgresqleu/util/widgets.py b/postgresqleu/util/widgets.py
index e1ea0152..071d09aa 100644
--- a/postgresqleu/util/widgets.py
+++ b/postgresqleu/util/widgets.py
@@ -5,6 +5,7 @@ from django.utils.safestring import mark_safe
import datetime
import json
+
class HtmlDateInput(TextInput):
def __init__(self, *args, **kwargs):
kwargs.update({'attrs': {'type': 'date', 'required-pattern': '[0-9]{4}-[0-9]{2}-[0-9]{2}'}})
@@ -15,6 +16,7 @@ class HtmlDateInput(TextInput):
val = val.date()
return super(HtmlDateInput, self).format_value(val)
+
class RequiredFileUploadWidget(forms.FileInput):
def __init__(self, filename=None, attrs=None):
self.filename = filename
@@ -33,6 +35,7 @@ class RequiredFileUploadWidget(forms.FileInput):
output.append(super(RequiredFileUploadWidget, self).render(name, value, attrs))
return mark_safe(u''.join(output))
+
class PrettyPrintJsonWidget(forms.Textarea):
def render(self, name, value, attrs=None, renderer=None):
# This is mighty ugly -- we parse the json and then turn it back into json.
@@ -45,6 +48,7 @@ class PrettyPrintJsonWidget(forms.Textarea):
t = super(PrettyPrintJsonWidget, self).render(name, value, attrs, renderer)
return t
+
class AdminJsonWidget(PrettyPrintJsonWidget):
def render(self, name, value, attrs=None, renderer=None):
attrs['cols'] = 100
diff --git a/postgresqleu/views.py b/postgresqleu/views.py
index b913b96c..3c2057b9 100644
--- a/postgresqleu/views.py
+++ b/postgresqleu/views.py
@@ -11,6 +11,7 @@ from postgresqleu.util.db import exec_to_dict
import datetime
import markdown
+
# Handle the frontpage
def index(request):
events = Conference.objects.filter(promoactive=True, enddate__gte=datetime.datetime.today()).order_by('startdate')
@@ -50,6 +51,7 @@ ORDER BY priosort DESC, datetime DESC LIMIT 5""")
'news': news,
})
+
# Handle the events frontpage
def eventsindex(request):
events = list(Conference.objects.filter(promoactive=True, enddate__gte=datetime.datetime.today()).order_by('startdate'))
@@ -67,6 +69,7 @@ def eventsindex(request):
'cfsopen': [e for e in events if e.callforsponsorsopen],
})
+
# Handle past events list
def pastevents(request):
events = list(Conference.objects.filter(promoactive=True, enddate__gte=datetime.datetime.today()).order_by('startdate'))
@@ -81,6 +84,7 @@ def pastevents(request):
'series': series,
})
+
# Handle event series listing
def eventseries(request, id):
series = get_object_or_404(ConferenceSeries, pk=id)
@@ -92,6 +96,7 @@ def eventseries(request, id):
'past': [e for e in events if e.enddate < datetime.datetime.today().date()],
})
+
# Handle a users list of previous events
@login_required
def attendee_events(request):
@@ -106,6 +111,7 @@ def attendee_events(request):
'series': series,
})
+
# Handle CSRF failures
def csrf_failure(request, reason=''):
resp = render(request, 'csrf_failure.html', {