Merge branch 'django-and-channels-upgrade'

This commit is contained in:
Thomas Steen Rasmussen 2018-04-14 15:42:39 +02:00
commit 870d1c9d67
26 changed files with 117 additions and 60 deletions

View file

@ -1,6 +1,9 @@
from django.conf.urls import url from django.conf.urls import url
from .views import * from .views import *
app_name = 'backoffice'
urlpatterns = [ urlpatterns = [
url(r'^$', BackofficeIndexView.as_view(), name='index'), url(r'^$', BackofficeIndexView.as_view(), name='index'),
url(r'product_handout/$', ProductHandoutView.as_view(), name='product_handout'), url(r'product_handout/$', ProductHandoutView.as_view(), name='product_handout'),

View file

@ -24,11 +24,12 @@ WKHTMLTOPDF_CMD="{{ wkhtmltopdf_path }}"
CHANNEL_LAYERS = { CHANNEL_LAYERS = {
"default": { "default": {
"BACKEND": "{{ django_channels_backend }}", "BACKEND": "{{ django_channels_backend }}",
"ROUTING": "bornhack.routing.channel_routing",
"CONFIG": {{ django_channels_config }} "CONFIG": {{ django_channels_config }}
}, },
} }
ASGI_APPLICATION = "bornhack.routing.application"
# start redirecting to the next camp instead of the previous camp after # start redirecting to the next camp instead of the previous camp after
# this much of the time between the camps has passed # this much of the time between the camps has passed
CAMP_REDIRECT_PERCENT=25 CAMP_REDIRECT_PERCENT=25

View file

@ -1,8 +1,14 @@
from django.conf.urls import url
from channels.routing import ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from program.consumers import ScheduleConsumer from program.consumers import ScheduleConsumer
channel_routing = [ application = ProtocolTypeRouter({
ScheduleConsumer.as_route(path=r"^/schedule/"), "websocket": AuthMiddlewareStack(
] URLRouter([
url(r"^schedule/", ScheduleConsumer)
])
)
})

View file

@ -62,7 +62,7 @@ urlpatterns = [
name='general-terms' name='general-terms'
), ),
url(r'^accounts/', include('allauth.urls')), url(r'^accounts/', include('allauth.urls')),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', admin.site.urls),
url( url(
r'^camps/$', r'^camps/$',

View file

@ -35,7 +35,7 @@ class Migration(migrations.Migration):
('updated', models.DateTimeField(auto_now=True)), ('updated', models.DateTimeField(auto_now=True)),
('uuid', models.UUIDField(default=uuid.uuid4, serialize=False, editable=False, primary_key=True)), ('uuid', models.UUIDField(default=uuid.uuid4, serialize=False, editable=False, primary_key=True)),
('date', models.DateField(help_text='What date?', verbose_name='Date')), ('date', models.DateField(help_text='What date?', verbose_name='Date')),
('camp', models.ForeignKey(to='camps.Camp', help_text='Which camp does this day belong to.', verbose_name='Camp')), ('camp', models.ForeignKey(on_delete=models.PROTECT, to='camps.Camp', help_text='Which camp does this day belong to.', verbose_name='Camp')),
], ],
options={ options={
'verbose_name_plural': 'Days', 'verbose_name_plural': 'Days',
@ -51,8 +51,8 @@ class Migration(migrations.Migration):
('description', models.CharField(max_length=255, help_text='What this expense covers.', verbose_name='Description')), ('description', models.CharField(max_length=255, help_text='What this expense covers.', verbose_name='Description')),
('amount', models.DecimalField(max_digits=7, help_text='The amount of the expense.', verbose_name='Amount', decimal_places=2)), ('amount', models.DecimalField(max_digits=7, help_text='The amount of the expense.', verbose_name='Amount', decimal_places=2)),
('currency', models.CharField(max_length=3, choices=[('btc', 'BTC'), ('dkk', 'DKK'), ('eur', 'EUR'), ('sek', 'SEK')], help_text='What currency the amount is in.', verbose_name='Currency')), ('currency', models.CharField(max_length=3, choices=[('btc', 'BTC'), ('dkk', 'DKK'), ('eur', 'EUR'), ('sek', 'SEK')], help_text='What currency the amount is in.', verbose_name='Currency')),
('camp', models.ForeignKey(to='camps.Camp', help_text='The camp to which this expense relates to.', verbose_name='Camp')), ('camp', models.ForeignKey(on_delete=models.PROTECT, to='camps.Camp', help_text='The camp to which this expense relates to.', verbose_name='Camp')),
('covered_by', models.ForeignKey(to=settings.AUTH_USER_MODEL, blank=True, help_text='Which user, if any, covered this expense.', verbose_name='Covered by', null=True)), ('covered_by', models.ForeignKey(on_delete=models.PROTECT, to=settings.AUTH_USER_MODEL, blank=True, help_text='Which user, if any, covered this expense.', verbose_name='Covered by', null=True)),
], ],
options={ options={
'verbose_name_plural': 'Expenses', 'verbose_name_plural': 'Expenses',
@ -67,8 +67,8 @@ class Migration(migrations.Migration):
('uuid', models.UUIDField(default=uuid.uuid4, serialize=False, editable=False, primary_key=True)), ('uuid', models.UUIDField(default=uuid.uuid4, serialize=False, editable=False, primary_key=True)),
('cost', models.DecimalField(default=1500.0, decimal_places=2, help_text='What the user should/is willing to pay for this signup.', verbose_name='Cost', max_digits=7)), ('cost', models.DecimalField(default=1500.0, decimal_places=2, help_text='What the user should/is willing to pay for this signup.', verbose_name='Cost', max_digits=7)),
('paid', models.BooleanField(help_text='Whether the user has paid.', verbose_name='Paid?', default=False)), ('paid', models.BooleanField(help_text='Whether the user has paid.', verbose_name='Paid?', default=False)),
('camp', models.ForeignKey(to='camps.Camp', help_text='The camp that has been signed up for.', verbose_name='Camp')), ('camp', models.ForeignKey(on_delete=models.PROTECT, to='camps.Camp', help_text='The camp that has been signed up for.', verbose_name='Camp')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, help_text='The user that has signed up.', verbose_name='User')), ('user', models.ForeignKey(on_delete=models.PROTECT, to=settings.AUTH_USER_MODEL, help_text='The user that has signed up.', verbose_name='User')),
], ],
options={ options={
'verbose_name_plural': 'Signups', 'verbose_name_plural': 'Signups',

View file

@ -1,7 +1,7 @@
from django.conf.urls import url from django.conf.urls import url
from . import views from . import views
app_name = 'news'
urlpatterns = [ urlpatterns = [
url(r'^$', views.NewsIndex.as_view(), kwargs={'archived': False}, name='index'), url(r'^$', views.NewsIndex.as_view(), kwargs={'archived': False}, name='index'),
url(r'^archive/$', views.NewsIndex.as_view(), kwargs={'archived': True}, name='archive'), url(r'^archive/$', views.NewsIndex.as_view(), kwargs={'archived': True}, name='archive'),

View file

@ -19,7 +19,7 @@ class Migration(migrations.Migration):
('created', models.DateTimeField(auto_now_add=True)), ('created', models.DateTimeField(auto_now_add=True)),
('updated', models.DateTimeField(auto_now=True)), ('updated', models.DateTimeField(auto_now=True)),
('uuid', models.UUIDField(serialize=False, editable=False, primary_key=True, default=uuid.uuid4)), ('uuid', models.UUIDField(serialize=False, editable=False, primary_key=True, default=uuid.uuid4)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, help_text='The django user this profile belongs to.', verbose_name='User')), ('user', models.OneToOneField(on_delete=models.PROTECT, to=settings.AUTH_USER_MODEL, help_text='The django user this profile belongs to.', verbose_name='User')),
], ],
options={ options={
'verbose_name_plural': 'Profiles', 'verbose_name_plural': 'Profiles',

View file

@ -19,6 +19,7 @@ class Profile(CreatedUpdatedModel, UUIDModel):
User, User,
verbose_name=_('User'), verbose_name=_('User'),
help_text=_('The django user this profile belongs to.'), help_text=_('The django user this profile belongs to.'),
on_delete=models.PROTECT
) )
name = models.CharField( name = models.CharField(

View file

@ -2,6 +2,8 @@ from django.conf.urls import url
from .views import ProfileDetail, ProfileUpdate from .views import ProfileDetail, ProfileUpdate
app_name = 'profiles'
urlpatterns = [ urlpatterns = [
url(r'^$', ProfileDetail.as_view(), name='detail'), url(r'^$', ProfileDetail.as_view(), name='detail'),
url(r'^edit$', ProfileUpdate.as_view(), name='update'), url(r'^edit$', ProfileUpdate.as_view(), name='update'),

View file

@ -1,6 +1,6 @@
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import DetailView, UpdateView from django.views.generic import DetailView, UpdateView
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from django.contrib import messages from django.contrib import messages
from . import models from . import models

View file

@ -1,4 +1,4 @@
from channels.generic.websockets import JsonWebsocketConsumer from channels.generic.websocket import JsonWebsocketConsumer
from camps.models import Camp from camps.models import Camp
from .models import ( from .models import (
@ -12,13 +12,11 @@ from .models import (
class ScheduleConsumer(JsonWebsocketConsumer): class ScheduleConsumer(JsonWebsocketConsumer):
http_user = True groups = ['schedule_users']
def connection_groups(self, **kwargs): def receive(self, text_data, **kwargs):
return ['schedule_users'] user = self.scope['user']
content = self.decode_json(text_data)
def raw_receive(self, message, **kwargs):
content = self.decode_json(message['text'])
action = content.get('action') action = content.get('action')
data = {} data = {}
@ -39,14 +37,27 @@ class ScheduleConsumer(JsonWebsocketConsumer):
events_query_set = Event.objects.filter(camp=camp) events_query_set = Event.objects.filter(camp=camp)
events = list([x.serialize() for x in events_query_set]) events = list([x.serialize() for x in events_query_set])
event_instances_query_set = EventInstance.objects.filter(event__camp=camp) event_instances_query_set = EventInstance.objects.filter(
event_instances = list([x.serialize(user=message.user) for x in event_instances_query_set]) event__camp=camp
)
event_instances = list([
x.serialize(user=user)
for x in event_instances_query_set
])
event_locations_query_set = EventLocation.objects.filter(camp=camp) event_locations_query_set = EventLocation.objects.filter(
event_locations = list([x.serialize() for x in event_locations_query_set]) camp=camp
)
event_locations = list([
x.serialize()
for x in event_locations_query_set
])
event_types_query_set = EventType.objects.filter() event_types_query_set = EventType.objects.filter()
event_types = list([x.serialize() for x in event_types_query_set]) event_types = list([
x.serialize()
for x in event_types_query_set
])
speakers_query_set = Speaker.objects.filter(camp=camp) speakers_query_set = Speaker.objects.filter(camp=camp)
speakers = list([x.serialize() for x in speakers_query_set]) speakers = list([x.serialize() for x in speakers_query_set])
@ -67,18 +78,21 @@ class ScheduleConsumer(JsonWebsocketConsumer):
event_instance_id = content.get('event_instance_id') event_instance_id = content.get('event_instance_id')
event_instance = EventInstance.objects.get(id=event_instance_id) event_instance = EventInstance.objects.get(id=event_instance_id)
Favorite.objects.create( Favorite.objects.create(
user=message.user, user=user,
event_instance=event_instance event_instance=event_instance
) )
if action == 'unfavorite': if action == 'unfavorite':
event_instance_id = content.get('event_instance_id') event_instance_id = content.get('event_instance_id')
event_instance = EventInstance.objects.get(id=event_instance_id) event_instance = EventInstance.objects.get(id=event_instance_id)
favorite = Favorite.objects.get(event_instance=event_instance, user=message.user) favorite = Favorite.objects.get(
event_instance=event_instance,
user=user
)
favorite.delete() favorite.delete()
if data: if data:
self.send(data) self.send_json(data)
def disconnect(self, message, **kwargs): def disconnect(self, message, **kwargs):
pass pass

View file

@ -11,7 +11,7 @@ from django.db import models
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.utils.text import slugify from django.utils.text import slugify
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from django.core.files.storage import FileSystemStorage from django.core.files.storage import FileSystemStorage
from django.urls import reverse from django.urls import reverse
from django.apps import apps from django.apps import apps
@ -75,6 +75,7 @@ class UserSubmittedModel(CampRelatedModel):
user = models.ForeignKey( user = models.ForeignKey(
'auth.User', 'auth.User',
on_delete=models.PROTECT
) )
PROPOSAL_DRAFT = 'draft' PROPOSAL_DRAFT = 'draft'
@ -148,7 +149,8 @@ class SpeakerProposal(UserSubmittedModel):
camp = models.ForeignKey( camp = models.ForeignKey(
'camps.Camp', 'camps.Camp',
related_name='speakerproposals' related_name='speakerproposals',
on_delete=models.PROTECT
) )
name = models.CharField( name = models.CharField(
@ -216,7 +218,8 @@ class EventProposal(UserSubmittedModel):
camp = models.ForeignKey( camp = models.ForeignKey(
'camps.Camp', 'camps.Camp',
related_name='eventproposals' related_name='eventproposals',
on_delete=models.PROTECT
) )
title = models.CharField( title = models.CharField(
@ -231,6 +234,7 @@ class EventProposal(UserSubmittedModel):
event_type = models.ForeignKey( event_type = models.ForeignKey(
'program.EventType', 'program.EventType',
help_text='The type of event', help_text='The type of event',
on_delete=models.PROTECT
) )
speakers = models.ManyToManyField( speakers = models.ManyToManyField(
@ -300,7 +304,8 @@ class EventLocation(CampRelatedModel):
camp = models.ForeignKey( camp = models.ForeignKey(
'camps.Camp', 'camps.Camp',
related_name='eventlocations' related_name='eventlocations',
on_delete=models.PROTECT
) )
def __str__(self): def __str__(self):
@ -379,6 +384,7 @@ class Event(CampRelatedModel):
event_type = models.ForeignKey( event_type = models.ForeignKey(
'program.EventType', 'program.EventType',
help_text='The type of this event', help_text='The type of this event',
on_delete=models.PROTECT
) )
slug = models.SlugField( slug = models.SlugField(
@ -391,6 +397,7 @@ class Event(CampRelatedModel):
'camps.Camp', 'camps.Camp',
related_name='events', related_name='events',
help_text='The camp this event belongs to', help_text='The camp this event belongs to',
on_delete=models.PROTECT
) )
video_url = models.URLField( video_url = models.URLField(
@ -410,6 +417,7 @@ class Event(CampRelatedModel):
null=True, null=True,
blank=True, blank=True,
help_text='The event proposal object this event was created from', help_text='The event proposal object this event was created from',
on_delete=models.PROTECT
) )
class Meta: class Meta:
@ -463,7 +471,8 @@ class EventInstance(CampRelatedModel):
event = models.ForeignKey( event = models.ForeignKey(
'program.event', 'program.event',
related_name='instances' related_name='instances',
on_delete=models.PROTECT
) )
when = DateTimeRangeField() when = DateTimeRangeField()
@ -474,7 +483,8 @@ class EventInstance(CampRelatedModel):
location = models.ForeignKey( location = models.ForeignKey(
'program.EventLocation', 'program.EventLocation',
related_name='eventinstances' related_name='eventinstances',
on_delete=models.PROTECT
) )
class Meta: class Meta:
@ -600,6 +610,7 @@ class Speaker(CampRelatedModel):
null=True, null=True,
related_name='speakers', related_name='speakers',
help_text='The camp this speaker belongs to', help_text='The camp this speaker belongs to',
on_delete=models.PROTECT
) )
events = models.ManyToManyField( events = models.ManyToManyField(
@ -614,6 +625,7 @@ class Speaker(CampRelatedModel):
null=True, null=True,
blank=True, blank=True,
help_text='The speaker proposal object this speaker was created from', help_text='The speaker proposal object this speaker was created from',
on_delete=models.PROTECT
) )
class Meta: class Meta:
@ -660,7 +672,10 @@ class Favorite(models.Model):
related_name='favorites', related_name='favorites',
on_delete=models.PROTECT on_delete=models.PROTECT
) )
event_instance = models.ForeignKey('program.EventInstance') event_instance = models.ForeignKey(
'program.EventInstance',
on_delete=models.PROTECT
)
class Meta: class Meta:
unique_together = ['user', 'event_instance'] unique_together = ['user', 'event_instance']

3
src/requirements/dev.txt Normal file
View file

@ -0,0 +1,3 @@
-r production.txt
django-debug-toolbar==1.9.1

View file

@ -1,26 +1,19 @@
Django==2.0.4
channels==2.0.2
channels_redis=2.1.1
CommonMark==0.7.3 CommonMark==0.7.3
Django==1.10.5
Pillow==4.0.0 Pillow==4.0.0
PyPDF2==1.26.0 PyPDF2==1.26.0
Unidecode==0.04.20 Unidecode==0.04.20
argparse==1.2.1 argparse==1.2.1
asgi-redis==1.3.0
asyncio==3.4.3 asyncio==3.4.3
bleach==1.5.0 bleach==1.5.0
# fix https://github.com/django/daphne/pull/107
git+https://github.com/tykling/daphne@ws-x-forwarded-for-bugfix
# fix https://github.com/django/channels/issues/622
#channels==1.1.3
git+https://github.com/tykling/channels@master
defusedxml==0.4.1 defusedxml==0.4.1
django-allauth==0.30.0 django-allauth==0.30.0
django-bleach==0.3.0 django-bleach==0.3.0
django-bootstrap3==8.2.2 django-bootstrap3==8.2.2
django-debug-toolbar==1.6
django-channels-panel==0.0.5
django-extensions==1.7.7 django-extensions==1.7.7
django-wkhtmltopdf==3.1.0 django-wkhtmltopdf==3.1.0
docopt==0.6.2 docopt==0.6.2

View file

@ -1,5 +1,5 @@
def current_order(request): def current_order(request):
if request.user.is_authenticated(): if request.user.is_authenticated:
order = None order = None
orders = request.user.orders.filter(open__isnull=False) orders = request.user.orders.filter(open__isnull=False)

View file

@ -8,7 +8,7 @@ from django.contrib.postgres.fields import DateTimeRangeField, JSONField
from django.utils.text import slugify from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.utils import timezone from django.utils import timezone
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from decimal import Decimal from decimal import Decimal
from datetime import timedelta from datetime import timedelta
@ -376,7 +376,7 @@ class EpayPayment(CreatedUpdatedModel, UUIDModel):
verbose_name = 'Epay Payment' verbose_name = 'Epay Payment'
verbose_name_plural = 'Epay Payments' verbose_name_plural = 'Epay Payments'
order = models.OneToOneField('shop.Order') order = models.OneToOneField('shop.Order', on_delete=models.PROTECT)
callback = models.ForeignKey('shop.EpayCallback', on_delete=models.PROTECT) callback = models.ForeignKey('shop.EpayCallback', on_delete=models.PROTECT)
txnid = models.IntegerField() txnid = models.IntegerField()
@ -469,8 +469,18 @@ class CreditNote(CreatedUpdatedModel):
class Invoice(CreatedUpdatedModel): class Invoice(CreatedUpdatedModel):
order = models.OneToOneField('shop.Order', null=True, blank=True) order = models.OneToOneField(
customorder = models.OneToOneField('shop.CustomOrder', null=True, blank=True) 'shop.Order',
null=True,
blank=True,
on_delete=models.PROTECT
)
customorder = models.OneToOneField(
'shop.CustomOrder',
null=True,
blank=True,
on_delete=models.PROTECT
)
pdf = models.FileField(null=True, blank=True, upload_to='invoices/') pdf = models.FileField(null=True, blank=True, upload_to='invoices/')
sent_to_customer = models.BooleanField(default=False) sent_to_customer = models.BooleanField(default=False)

View file

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

View file

@ -1,7 +1,7 @@
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.urlresolvers import reverse, reverse_lazy from django.urls import reverse, reverse_lazy
from django.db.models import Count, F from django.db.models import Count, F
from django.http import ( from django.http import (
HttpResponse, HttpResponse,

View file

@ -5,7 +5,7 @@ from django.utils.text import slugify
from utils.models import CampRelatedModel from utils.models import CampRelatedModel
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from django.conf import settings from django.conf import settings
import logging import logging
logger = logging.getLogger("bornhack.%s" % __name__) logger = logging.getLogger("bornhack.%s" % __name__)

View file

@ -1,6 +1,9 @@
from django.conf.urls import url, include from django.conf.urls import url, include
from .views import * from .views import *
app_name = 'teams'
urlpatterns = [ urlpatterns = [
url( url(
r'^$', r'^$',

View file

@ -8,9 +8,8 @@ from django.shortcuts import redirect
from django.contrib import messages from django.contrib import messages
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from django.conf import settings from django.conf import settings
from profiles.models import Profile from profiles.models import Profile
import logging import logging

View file

@ -3,7 +3,7 @@ import hashlib
import base64 import base64
import qrcode import qrcode
from django.conf import settings from django.conf import settings
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from utils.models import ( from utils.models import (
UUIDModel, UUIDModel,

View file

@ -6,6 +6,8 @@ from .views import (
ShopTicketDetailView ShopTicketDetailView
) )
app_name = 'tickets'
urlpatterns = [ urlpatterns = [
url( url(
r'^$', r'^$',

View file

@ -1,4 +1,4 @@
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from django.db import models from django.db import models
from django.utils.text import slugify from django.utils.text import slugify
from utils.models import UUIDModel, CampRelatedModel from utils.models import UUIDModel, CampRelatedModel

View file

@ -1,6 +1,9 @@
from django.conf.urls import url from django.conf.urls import url
from .views import * from .views import *
app_name = 'villages'
urlpatterns = [ urlpatterns = [
url(r'^$', VillageListView.as_view(), name='list'), url(r'^$', VillageListView.as_view(), name='list'),
url(r'create/$', VillageCreateView.as_view(), name='create'), url(r'create/$', VillageCreateView.as_view(), name='create'),

View file

@ -1,6 +1,6 @@
from django.http import Http404 from django.http import Http404
from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.urlresolvers import reverse_lazy from django.urls import reverse_lazy
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin