Merge pull request #202 from bornhack/st/cleanup

Cleanup
This commit is contained in:
Stephan Telling 2018-03-04 16:17:50 +01:00 committed by GitHub
commit ba3eaa6546
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 134 additions and 151 deletions

View file

@ -1,5 +1,4 @@
from django.contrib import admin
from .models import ProductCategory, Product
@ -12,5 +11,3 @@ class ProductCategoryAdmin(admin.ModelAdmin):
class ProductAdmin(admin.ModelAdmin):
list_display = ['name', 'price', 'category', 'in_stock']
list_editable = ['in_stock']

View file

@ -1,5 +1,3 @@
from django.apps import AppConfig

View file

@ -1,5 +1,4 @@
from django.db import models
from utils.models import CampRelatedModel

View file

@ -6,4 +6,3 @@ class MenuView(ListView):
model = ProductCategory
template_name = "bar_menu.html"
context_object_name = "categories"

View file

@ -1,6 +1,4 @@
from django.conf import settings
from .models import Camp
from django.utils import timezone
def camp(request):

View file

@ -17,10 +17,8 @@ class CampViewMixin(object):
if queryset:
# check if we have a foreignkey to Camp, filter if so
for field in queryset.model._meta.fields:
if field.name=="camp" and field.related_model._meta.label == "camps.Camp":
if field.name == "camp" and field.related_model._meta.label == "camps.Camp":
return queryset.filter(camp=self.camp)
# Camp relation not found, or queryset is empty, return it unaltered
return queryset

View file

@ -2,12 +2,14 @@ from camps.models import Camp
from django.utils import timezone
from django.contrib import admin
def get_current_camp():
try:
return Camp.objects.get(camp__contains=timezone.now())
except Camp.DoesNotExist:
return False
class CampPropertyListFilter(admin.SimpleListFilter):
"""
SimpleListFilter to filter models by camp when camp is
@ -27,7 +29,6 @@ class CampPropertyListFilter(admin.SimpleListFilter):
for camp in unique_camps:
yield (camp.slug, camp.title)
def queryset(self, request, queryset):
# if self.value() is None return everything
if not self.value():
@ -45,4 +46,3 @@ class CampPropertyListFilter(admin.SimpleListFilter):
if item.camp != camp:
queryset = queryset.exclude(pk=item.pk)
return queryset

View file

@ -1,5 +1,8 @@
from django.contrib import admin
from .models import *
from .models import (
InfoItem,
InfoCategory
)
@admin.register(InfoItem)

View file

@ -1,5 +1,3 @@
from django.apps import AppConfig

View file

@ -11,22 +11,22 @@ class InfoCategory(CampRelatedModel):
camp = models.ForeignKey(
'camps.Camp',
related_name = 'infocategories',
on_delete = models.PROTECT
related_name='infocategories',
on_delete=models.PROTECT
)
headline = models.CharField(
max_length = 100,
help_text = "The headline of this info category"
max_length=100,
help_text="The headline of this info category"
)
anchor = models.SlugField(
help_text = "The HTML anchor to use for this info category."
help_text="The HTML anchor to use for this info category."
)
weight = models.PositiveIntegerField(
help_text = 'Determines sorting/ordering. Heavier categories sink to the bottom. Categories with the same weight are ordered alphabetically. Defaults to 100.',
default = 100,
help_text='Determines sorting/ordering. Heavier categories sink to the bottom. Categories with the same weight are ordered alphabetically. Defaults to 100.',
default=100,
)
def clean(self):
@ -45,26 +45,26 @@ class InfoItem(CampRelatedModel):
category = models.ForeignKey(
'info.InfoCategory',
related_name = 'infoitems',
on_delete = models.PROTECT
related_name='infoitems',
on_delete=models.PROTECT
)
headline = models.CharField(
max_length = 100,
help_text = "Headline of this info item."
max_length=100,
help_text="Headline of this info item."
)
anchor = models.SlugField(
help_text = "The HTML anchor to use for this info item."
help_text="The HTML anchor to use for this info item."
)
body = models.TextField(
help_text = 'Body of this info item. Markdown is supported.'
help_text='Body of this info item. Markdown is supported.'
)
weight = models.PositiveIntegerField(
help_text = 'Determines sorting/ordering. Heavier items sink to the bottom. Items with the same weight are ordered alphabetically. Defaults to 100.',
default = 100,
help_text='Determines sorting/ordering. Heavier items sink to the bottom. Items with the same weight are ordered alphabetically. Defaults to 100.',
default=100,
)
@property
@ -78,5 +78,3 @@ class InfoItem(CampRelatedModel):
def __str__(self):
return '%s (%s)' % (self.headline, self.category)

View file

@ -1,5 +1,5 @@
from django.contrib import admin
from .models import *
from .models import OutgoingIrcMessage
admin.site.register(OutgoingIrcMessage)

View file

@ -1,5 +1,3 @@
from django.apps import AppConfig

View file

@ -1,5 +1,6 @@
from django.conf import settings
import logging, irc3
import logging
import irc3
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('bornhack.%s' % __name__)
@ -24,5 +25,5 @@ def do_work():
irc3.IrcBot(**config).run(forever=True)
except Exception as E:
logger.exception("Got exception inside do_work for %s" % self.workermodule)
raise
raise E

View file

@ -1,5 +1,3 @@
from django.apps import AppConfig

View file

@ -1,5 +1,3 @@
from django.db import models
from django.utils import encoding
from django.utils.text import slugify

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,6 +1,7 @@
from django.views.generic import ListView, DetailView
from django.utils import timezone
from .models import *
from .models import NewsItem
class NewsIndex(ListView):
model = NewsItem

View file

@ -1,6 +1,7 @@
from django.contrib import admin
from .models import Profile
@admin.register(Profile)
class OrderAdmin(admin.ModelAdmin):
actions = ['approve_public_credit_names']

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,7 +1,14 @@
from channels.generic.websockets import JsonWebsocketConsumer
from camps.models import Camp
from .models import Event, EventInstance, Favorite, EventLocation, EventType, Speaker
from .models import (
Event,
EventInstance,
Favorite,
EventLocation,
EventType,
Speaker
)
class ScheduleConsumer(JsonWebsocketConsumer):

View file

@ -3,8 +3,9 @@ from django.shortcuts import redirect
from django.urls import reverse
from . import models
from django.contrib import messages
import sys, mimetypes
from django.http import Http404, HttpResponse
import sys
import mimetypes
class EnsureCFSOpenMixin(SingleObjectMixin):
@ -12,7 +13,9 @@ class EnsureCFSOpenMixin(SingleObjectMixin):
# do not permit editing if call for speakers is not open
if not self.camp.call_for_speakers_open:
messages.error(request, "The Call for Speakers is not open.")
return redirect(reverse('proposal_list', kwargs={'camp_slug': self.camp.slug}))
return redirect(
reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})
)
# alright, continue with the request
return super().dispatch(request, *args, **kwargs)
@ -23,8 +26,10 @@ class CreateProposalMixin(SingleObjectMixin):
# set camp and user before saving
form.instance.camp = self.camp
form.instance.user = self.request.user
speaker = form.save()
return redirect(reverse('proposal_list', kwargs={'camp_slug': self.camp.slug}))
form.save()
return redirect(
reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})
)
class EnsureUnapprovedProposalMixin(SingleObjectMixin):
@ -54,7 +59,9 @@ class EnsureUserOwnsProposalMixin(SingleObjectMixin):
# make sure that this proposal belongs to the logged in user
if self.get_object().user.username != request.user.username:
messages.error(request, "No thanks")
return redirect(reverse('proposal_list', kwargs={'camp_slug': self.camp.slug}))
return redirect(
reverse('proposal_list', kwargs={'camp_slug': self.camp.slug})
)
# alright, continue with the request
return super().dispatch(request, *args, **kwargs)
@ -83,7 +90,10 @@ class PictureViewMixin(SingleObjectMixin):
def get_picture_response(self, path):
if 'runserver' in sys.argv or 'runserver_plus' in sys.argv:
# this is a local devserver situation, guess mimetype from extension and return picture directly
response = HttpResponse(self.picture, content_type=mimetypes.types_map[".%s" % self.picture.name.split(".")[-1]])
response = HttpResponse(
self.picture,
content_type=mimetypes.types_map[".%s" % self.picture.name.split(".")[-1]]
)
else:
# make nginx serve the picture using X-Accel-Redirect
# (this works for nginx only, other webservers use x-sendfile)

View file

@ -1,7 +1,6 @@
import uuid
import os
import icalendar
import CommonMark
import logging
from datetime import timedelta
@ -10,12 +9,9 @@ from django.contrib.postgres.fields import DateTimeRangeField
from django.contrib import messages
from django.db import models
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.dispatch import receiver
from django.utils.text import slugify
from django.conf import settings
from django.core.urlresolvers import reverse_lazy
from django.core.exceptions import ValidationError
from django.core.urlresolvers import reverse_lazy, reverse
from django.core.files.storage import FileSystemStorage
from django.urls import reverse
from django.apps import apps
@ -644,7 +640,6 @@ class Speaker(CampRelatedModel):
def get_large_picture_url(self):
return self.get_picture_url('large')
def serialize(self):
data = {
'name': self.name,

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,4 +1,3 @@
import datetime
import logging
import os
@ -12,7 +11,6 @@ from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from django.urls import reverse
from django.db.models import Q
from django.template import Engine, Context
import icalendar
@ -34,7 +32,7 @@ from . import models
logger = logging.getLogger("bornhack.%s" % __name__)
############## ical calendar ########################################################
# ical calendar
class ICSView(CampViewMixin, View):
@ -90,7 +88,7 @@ class ICSView(CampViewMixin, View):
return response
############## proposals ########################################################
# proposals
class ProposalListView(LoginRequiredMixin, CampViewMixin, ListView):
@ -241,7 +239,7 @@ class EventProposalDetailView(LoginRequiredMixin, CampViewMixin, EnsureUserOwnsP
template_name = 'eventproposal_detail.html'
################## speakers ###############################################
# speakers
@method_decorator(require_safe, name='dispatch')
@ -268,7 +266,7 @@ class SpeakerListView(CampViewMixin, ListView):
template_name = 'speaker_list.html'
################## events ##############################################
# events
class EventListView(CampViewMixin, ListView):
@ -281,7 +279,7 @@ class EventDetailView(CampViewMixin, DetailView):
template_name = 'schedule_event_detail.html'
################## schedule #############################################
# schedule
class NoScriptScheduleView(CampViewMixin, TemplateView):
@ -293,13 +291,12 @@ class NoScriptScheduleView(CampViewMixin, TemplateView):
return context
class ScheduleView(CampViewMixin, TemplateView):
template_name = 'schedule_overview.html'
def get_context_data(self, *args, **kwargs):
context = super(ScheduleView, self).get_context_data(**kwargs)
context['schedule_midnight_offset_hours'] = settings.SCHEDULE_MIDNIGHT_OFFSET_HOURS;
context['schedule_midnight_offset_hours'] = settings.SCHEDULE_MIDNIGHT_OFFSET_HOURS
return context
@ -308,8 +305,8 @@ class CallForSpeakersView(CampViewMixin, TemplateView):
return '%s_call_for_speakers.html' % self.camp.slug
# control center
################## control center #############################################
class ProgramControlCenter(CampViewMixin, TemplateView):
template_name = "control/index.html"

View file

@ -40,6 +40,7 @@ def available_from(product):
return "None"
available_from.short_description = 'Available from'
def available_to(product):
if product.available_in.upper:
return product.available_in.upper.strftime("%c")

View file

@ -2,6 +2,7 @@ from django.apps import AppConfig
import logging
logger = logging.getLogger("bornhack.%s" % __name__)
class ShopConfig(AppConfig):
name = 'shop'

View file

@ -1,8 +1,9 @@
from vendor.coinify.coinify_api import CoinifyAPI
from vendor.coinify.coinify_callback import CoinifyCallback
from .models import CoinifyAPIRequest, CoinifyAPIInvoice, CoinifyAPICallback
from django.conf import settings
import json, logging
import json
import logging
import requests
logger = logging.getLogger("bornhack.%s" % __name__)
@ -34,7 +35,7 @@ def save_coinify_callback(request, order):
# now attempt to parse json
try:
parsed = json.loads(request.body.decode('utf-8'))
except Exception as E:
except Exception:
parsed = ''
# save this callback to db
@ -89,8 +90,8 @@ def handle_coinify_api_response(req, order):
if req.response['success']:
# save this new coinify invoice to the DB
coinifyinvoice = process_coinify_invoice_json(
invoicejson = req.response['data'],
order = order,
invoicejson=req.response['data'],
order=order,
)
return coinifyinvoice
else:

View file

@ -1,6 +1,3 @@
from django.conf import settings
def current_order(request):
if request.user.is_authenticated():
order = None
@ -11,5 +8,3 @@ def current_order(request):
return {'current_order': order}
return {}

View file

@ -1,6 +1,7 @@
import hashlib
from django.conf import settings
def calculate_epay_hash(order, request):
hashstring = (
'{merchant_number}{description}11{amount}DKK'
@ -10,9 +11,9 @@ def calculate_epay_hash(order, request):
description=order.description,
amount=order.total*100,
order_id=order.pk,
accept_url = order.get_epay_accept_url(request),
cancel_url = order.get_cancel_url(request),
callback_url = order.get_epay_callback_url(request),
accept_url=order.get_epay_accept_url(request),
cancel_url=order.get_cancel_url(request),
callback_url=order.get_epay_callback_url(request),
md5_secret=settings.EPAY_MD5_SECRET,
)
epay_hash = hashlib.md5(hashstring.encode('utf-8')).hexdigest()
@ -24,6 +25,7 @@ def validate_epay_callback(query):
for key, value in query.items():
if key != 'hash':
hashstring += value
hash = hashlib.md5((hashstring + settings.EPAY_MD5_SECRET).encode('utf-8')).hexdigest()
hash = hashlib.md5(
(hashstring + settings.EPAY_MD5_SECRET).encode('utf-8')
).hexdigest()
return hash == query['hash']

View file

@ -1,5 +1,4 @@
from django import forms
from .models import Order
class AddToOrderForm(forms.Form):

View file

@ -1,5 +1,3 @@
from psycopg2.extras import DateTimeTZRange
from django.db.models import QuerySet
from django.utils import timezone

View file

@ -1,8 +1,4 @@
import io
import logging
import hashlib
import base64
import qrcode
from django.conf import settings
from django.db import models
@ -202,7 +198,7 @@ class Order(CreatedUpdatedModel):
if request:
messages.success(request, "Created %s tickets of type: %s" % (order_product.quantity, order_product.product.ticket_type.name))
# and mark the OPR as handed_out=True
order_product.handed_out=True
order_product.handed_out = True
order_product.save()
self.save()
@ -210,8 +206,8 @@ class Order(CreatedUpdatedModel):
if not self.paid:
messages.error(request, "Order %s is not paid, so cannot mark it as refunded!" % self.pk)
else:
self.refunded=True
### delete any tickets related to this order
self.refunded = True
# delete any tickets related to this order
if self.tickets.all():
messages.success(request, "Order %s marked as refunded, deleting %s tickets..." % (self.pk, self.tickets.count()))
self.tickets.all().delete()
@ -259,7 +255,6 @@ class Order(CreatedUpdatedModel):
if not self.coinify_api_invoices.exists():
return False
coinifyinvoice = None
for tempinvoice in self.coinify_api_invoices.all():
# we already have a coinifyinvoice for this order, check if it expired
if not tempinvoice.expired:
@ -512,7 +507,7 @@ class CoinifyAPIInvoice(CreatedUpdatedModel):
@property
def expired(self):
return parse_datetime(self.invoicejson['expire_time']) < timezone.now()
return parse_datetime(self.invoicejson['expire_time']) < timezone.now()
class CoinifyAPICallback(CreatedUpdatedModel):

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,6 +1,5 @@
from django.conf.urls import url
from .views import *
from tickets.views import ShopTicketListView
urlpatterns = [
url(r'^$', ShopIndexView.as_view(), name='index'),

View file

@ -3,21 +3,23 @@ from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.urlresolvers import reverse, reverse_lazy
from django.db.models import Count, F
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest, Http404
from django.http import (
HttpResponse,
HttpResponseRedirect,
HttpResponseBadRequest,
Http404
)
from django.shortcuts import get_object_or_404
from django.views.generic import (
View,
TemplateView,
ListView,
DetailView,
FormView,
UpdateView,
)
from django.views.generic.base import RedirectView
from django.views.generic.detail import SingleObjectMixin
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.utils.dateparse import parse_datetime
from django.utils import timezone
from shop.models import (
@ -27,24 +29,22 @@ from shop.models import (
ProductCategory,
EpayCallback,
EpayPayment,
CoinifyAPIInvoice,
CoinifyAPICallback,
CreditNote,
)
from .forms import AddToOrderForm
from .epay import calculate_epay_hash, validate_epay_callback
from collections import OrderedDict
from vendor.coinify.coinify_api import CoinifyAPI
from vendor.coinify.coinify_callback import CoinifyCallback
from .coinify import create_coinify_invoice, save_coinify_callback, process_coinify_invoice_json
import json, time
from .coinify import (
create_coinify_invoice,
save_coinify_callback,
process_coinify_invoice_json
)
import logging
logger = logging.getLogger("bornhack.%s" % __name__)
#################################################################################
### Mixins
# Mixins
class EnsureCreditNoteHasPDFMixin(SingleObjectMixin):
model = CreditNote
@ -92,7 +92,9 @@ class EnsureUnpaidOrderMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if self.get_object().paid:
messages.error(request, "This order is already paid for!")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(EnsureUnpaidOrderMixin, self).dispatch(
request, *args, **kwargs
@ -105,7 +107,9 @@ class EnsurePaidOrderMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if not self.get_object().paid:
messages.error(request, "This order is not paid for!")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(EnsurePaidOrderMixin, self).dispatch(
request, *args, **kwargs
@ -118,7 +122,9 @@ class EnsureClosedOrderMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if self.get_object().open is not None:
messages.error(request, 'This order is still open!')
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(EnsureClosedOrderMixin, self).dispatch(
request, *args, **kwargs
@ -160,15 +166,16 @@ class EnsureOrderHasInvoicePDFMixin(SingleObjectMixin):
def dispatch(self, request, *args, **kwargs):
if not self.get_object().invoice.pdf:
messages.error(request, "This order has no invoice yet!")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(EnsureOrderHasInvoicePDFMixin, self).dispatch(
request, *args, **kwargs
)
#################################################################################
### Shop views
# Shop views
class ShopIndexView(ListView):
model = Product
template_name = "shop_index.html"
@ -215,7 +222,7 @@ class ProductDetailView(FormView, DetailView):
def dispatch(self, request, *args, **kwargs):
if not self.get_object().category.public:
### this product is not publicly available
# this product is not publicly available
raise Http404("Product not found")
return super(ProductDetailView, self).dispatch(
@ -264,7 +271,9 @@ class ProductDetailView(FormView, DetailView):
return super(ProductDetailView, self).form_valid(form)
def get_success_url(self):
return Order.objects.get(user=self.request.user, open__isnull=False).get_absolute_url()
return Order.objects.get(
user=self.request.user, open__isnull=False
).get_absolute_url()
class OrderListView(LoginRequiredMixin, ListView):
@ -289,7 +298,9 @@ class OrderDetailView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureOrderH
if payment_method in order.PAYMENT_METHODS:
if not request.POST.get('accept_terms'):
messages.error(request, "You need to accept the general terms and conditions before you can continue!")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': order.pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': order.pk})
)
# Set payment method and mark the order as closed
order.payment_method = payment_method
@ -389,9 +400,7 @@ class OrderMarkAsPaidView(LoginRequiredMixin, SingleObjectMixin, View):
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
#################################################################################
### Epay views
# Epay views
class EpayFormView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureClosedOrderMixin, EnsureOrderHasProductsMixin, DetailView):
model = Order
template_name = 'epay_form.html'
@ -435,18 +444,18 @@ class EpayCallbackView(SingleObjectMixin, View):
return HttpResponse(status=400)
if order.paid:
### this order is already paid, perhaps we are seeing a double callback?
# this order is already paid, perhaps we are seeing a double callback?
return HttpResponse('OK')
### epay callback is valid - has the order been paid in full?
# epay callback is valid - has the order been paid in full?
if int(query['amount']) == order.total * 100:
### create an EpayPayment object linking the callback to the order
# create an EpayPayment object linking the callback to the order
EpayPayment.objects.create(
order=order,
callback=callback,
txnid=query.get('txnid'),
)
### and mark order as paid (this will create tickets)
# and mark order as paid (this will create tickets)
order.mark_as_paid(request)
else:
logger.error("valid epay callback with wrong amount detected")
@ -464,15 +473,16 @@ class EpayThanksView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureClosedO
if request.GET:
# epay redirects the user back to our accepturl with a long
# and ugly querystring, redirect user to the clean url
return HttpResponseRedirect(reverse('shop:epay_thanks', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse('shop:epay_thanks', kwargs={'pk': self.get_object().pk})
)
return super(EpayThanksView, self).dispatch(
request, *args, **kwargs
)
#################################################################################
### Bank Transfer view
# Bank Transfer view
class BankTransferView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureOrderHasProductsMixin, DetailView):
model = Order
@ -489,16 +499,14 @@ class BankTransferView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpai
return context
#################################################################################
### Cash payment view
# Cash payment view
class CashView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureOrderHasProductsMixin, DetailView):
model = Order
template_name = 'cash.html'
#################################################################################
### Coinify views
# Coinify views
class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUnpaidOrderMixin, EnsureClosedOrderMixin, EnsureOrderHasProductsMixin, SingleObjectMixin, RedirectView):
model = Order
@ -511,7 +519,9 @@ class CoinifyRedirectView(LoginRequiredMixin, EnsureUserOwnsOrderMixin, EnsureUn
coinifyinvoice = create_coinify_invoice(order, request)
if not coinifyinvoice:
messages.error(request, "There was a problem with the payment provider. Please try again later")
return HttpResponseRedirect(reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk}))
return HttpResponseRedirect(
reverse_lazy('shop:order_detail', kwargs={'pk': self.get_object().pk})
)
return super(CoinifyRedirectView, self).dispatch(
request, *args, **kwargs
@ -544,14 +554,17 @@ class CoinifyCallbackView(SingleObjectMixin, View):
# attemt to validate the callbackc
if sdk.validate_callback(request.body, request.META['HTTP_X_COINIFY_CALLBACK_SIGNATURE']):
# mark callback as valid in db
callbackobject.valid=True
callbackobject.valid = True
callbackobject.save()
else:
logger.error("invalid coinify callback detected")
return HttpResponseBadRequest('something is fucky')
if callbackobject.payload['event'] == 'invoice_state_change' or callbackobject.payload['event'] == 'invoice_manual_resend':
coinifyinvoice = process_coinify_invoice_json(callbackobject.payload['data'], self.get_object())
process_coinify_invoice_json(
callbackobject.payload['data'],
self.get_object()
)
return HttpResponse('OK')
else:
logger.error("unsupported callback event %s" % callbackobject.payload['event'])

View file

@ -1,5 +1,3 @@
from django.apps import AppConfig

View file

@ -43,6 +43,7 @@ class Sponsor(CampRelatedModel):
def camp(self):
return self.tier.camp
class SponsorTier(CampRelatedModel):
name = models.CharField(
max_length=25,

View file

@ -1,5 +1,3 @@
from django.apps import AppConfig

View file

@ -9,9 +9,9 @@ class EnsureWritableCampMixin(SingleObjectMixin):
# do not permit view if camp is in readonly mode
if self.camp.read_only:
messages.error(request, "No thanks")
return redirect(reverse('village_list', kwargs={'camp_slug': self.camp.slug}))
return redirect(
reverse('village_list', kwargs={'camp_slug': self.camp.slug})
)
# alright, continue with the request
return super().dispatch(request, *args, **kwargs)