proof that I did something during 33c3

This commit is contained in:
Thomas Steen Rasmussen 2016-12-29 00:15:13 +01:00
parent f8a513ec72
commit 9b089de165
40 changed files with 353 additions and 185 deletions

View file

@ -72,7 +72,7 @@ TEMPLATES = [
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'shop.context_processors.current_order', 'shop.context_processors.current_order',
'shop.context_processors.user_has_tickets', 'shop.context_processors.user_has_tickets',
'camps.context_processors.camps', 'camps.context_processors.camp',
], ],
}, },
}, },

View file

@ -11,8 +11,10 @@ from django.contrib import admin
from django.views.generic import TemplateView, RedirectView from django.views.generic import TemplateView, RedirectView
from django.core.urlresolvers import reverse_lazy from django.core.urlresolvers import reverse_lazy
from camps.views import * from camps.views import *
from info.views import CampInfoView from info.views import *
from villages.views import *
from program.views import *
from sponsors.views import *
urlpatterns = [ urlpatterns = [
url( url(
@ -27,24 +29,11 @@ urlpatterns = [
r'^news/', r'^news/',
include('news.urls', namespace='news') include('news.urls', namespace='news')
), ),
url(
r'^villages/',
include('villages.urls', namespace='villages')
),
url(
r'^schedule/',
include('program.urls', namespace='schedule')
),
url( url(
r'^$', r'^$',
TemplateView.as_view(template_name='frontpage.html'), TemplateView.as_view(template_name='frontpage.html'),
name='frontpage' name='frontpage'
), ),
url(
r'^info/',
TemplateView.as_view(template_name='info.html'),
name='info'
),
url( url(
r'^contact/', r'^contact/',
TemplateView.as_view(template_name='contact.html'), TemplateView.as_view(template_name='contact.html'),
@ -90,28 +79,63 @@ urlpatterns = [
# camp specific urls below here # camp specific urls below here
url(r'(?P<camp_slug>[-_\w+]+)/', include([ url(
r'(?P<camp_slug>[-_\w+]+)/', include([
url( url(
r'^$', r'^$',
CampDetailView.as_view(), CampDetailView.as_view(),
name='camp_detail' name='camp_detail'
), ),
url( url(
r'^info/$', r'^info/$',
CampInfoView.as_view(), CampInfoView.as_view(),
name='info' name='info'
), ),
url( url(
r'^schedule/$', r'^schedule/', include([
CampScheduleView.as_view(), url(
name='schedule' r'^(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/$',
ProgramDayView.as_view(),
name='schedule_day'
), ),
url(
r'^$',
ProgramOverviewView.as_view(),
name='schedule_index'
),
url(
r'^speakers/$',
SpeakerListView.as_view(),
name='speaker_index'
),
url(
r'^speakers/(?P<slug>[-_\w+]+)/$',
SpeakerDetailView.as_view(),
name='speaker_detail'
),
url(
r'^events/$',
EventListView.as_view(),
name='event_index'
),
url(
r'^(?P<slug>[-_\w+]+)/$',
EventDetailView.as_view(),
name='event'
),
])
),
url( url(
r'^sponsors/$', r'^sponsors/$',
CampSponsorView.as_view(), SponsorIndexView.as_view(),
name='camp_sponsors' name='sponsors'
), ),
url(r'^villages/$', include([
url(
r'^villages/', include([
url( url(
r'^$', r'^$',
VillageListView.as_view(), VillageListView.as_view(),
@ -137,7 +161,9 @@ urlpatterns = [
VillageDetailView.as_view(), VillageDetailView.as_view(),
name='village_detail' name='village_detail'
), ),
])), ])
])), ),
])
)
] ]

View file

@ -3,9 +3,16 @@ from .models import Camp
from django.utils import timezone from django.utils import timezone
def camps(request): def camp(request):
if 'camp_slug' in request.resolver_match.kwargs:
camp = Camp.objects.get(slug=request.resolver_match.kwargs['camp_slug'])
request.session['campslug'] = camp.slug
else:
request.session['campslug'] = None
camp = None
return { return {
'upcoming_camps': Camp.objects.filter(camp_start__gt=timezone.now()), 'camps': Camp.objects.all().order_by('-camp_start'),
'previous_camps': Camp.objects.filter(camp_start__lt=timezone.now()), 'camp': camp
} }

View file

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2016-12-28 17:50
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('camps', '0010_auto_20161220_1714'),
]
operations = [
migrations.AddField(
model_name='camp',
name='logo_large',
field=models.CharField(default='', help_text=b'The filename of the large logo to use on the frontpage of this camp', max_length=100, verbose_name=b'Large logo for this camp'),
preserve_default=False,
),
migrations.AddField(
model_name='camp',
name='logo_small',
field=models.CharField(default='', help_text=b'The filename of the small logo to use in the top of the page for this camp', max_length=100, verbose_name=b'Small logo for this camp'),
preserve_default=False,
),
]

View file

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2016-12-28 23:12
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('camps', '0011_auto_20161228_1750'),
]
operations = [
migrations.RemoveField(
model_name='camp',
name='logo_large',
),
migrations.RemoveField(
model_name='camp',
name='logo_small',
),
]

View file

@ -1,13 +1,14 @@
from django.views.generic.detail import SingleObjectMixin
from camps.models import Camp from camps.models import Camp
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
class CampViewMixin(Object): class CampViewMixin(object):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
self.camp = get_object_or_404(Camp, slug=self.kwargs.camp_slug) self.camp = get_object_or_404(Camp, slug=self.kwargs['camp_slug'])
return super(CampViewMixin, self).dispatch(request, *args, **kwargs) return super(CampViewMixin, self).dispatch(request, *args, **kwargs)
def get_queryset(self): def get_queryset(self):
return self.objects.filter(camp=self.camp) queryset = super(CampViewMixin, self).get_queryset()
return queryset.filter(camp=self.camp)

View file

@ -1,3 +1,6 @@
from django.contrib import admin from django.contrib import admin
from .models import *
admin.site.register(InfoCategory)
admin.site.register(InfoItem)
# Register your models here.

View file

@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2016-12-28 23:12
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('info', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='infocategory',
options={'ordering': ['-weight', 'headline'], 'verbose_name_plural': 'Info Categories'},
),
migrations.AlterField(
model_name='infocategory',
name='weight',
field=models.PositiveIntegerField(default=100, help_text='Determines sorting/ordering. Heavier categories sink to the bottom. Categories with the same weight are ordered alphabetically. Defaults to 100.'),
),
migrations.AlterField(
model_name='infoitem',
name='weight',
field=models.PositiveIntegerField(default=100, help_text='Determines sorting/ordering. Heavier items sink to the bottom. Items with the same weight are ordered alphabetically. Defaults to 100.'),
),
]

View file

@ -9,6 +9,7 @@ class InfoCategory(CreatedUpdatedModel):
class Meta: class Meta:
ordering = ['-weight', 'headline'] ordering = ['-weight', 'headline']
unique_together = (('anchor', 'camp'), ('headline', 'camp')) unique_together = (('anchor', 'camp'), ('headline', 'camp'))
verbose_name_plural = "Info Categories"
camp = models.ForeignKey( camp = models.ForeignKey(
'camps.Camp', 'camps.Camp',
@ -26,14 +27,18 @@ class InfoCategory(CreatedUpdatedModel):
) )
weight = models.PositiveIntegerField( weight = models.PositiveIntegerField(
help_text = 'Determines sorting/ordering. Heavier categories sink to the bottom. Categories with the same weight are ordered alphabetically.' 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): def clean(self):
if InfoItem.objects.filter(camp=self.camp, anchor=self.anchor).exists(): if InfoItem.objects.filter(category__camp=self.camp, anchor=self.anchor).exists():
# this anchor is already in use on an item, so it cannot be used (must be unique on the page) # this anchor is already in use on an item, so it cannot be used (must be unique on the page)
raise ValidationError({'anchor': 'Anchor is already in use on an info item for this camp'}) raise ValidationError({'anchor': 'Anchor is already in use on an info item for this camp'})
def __str__(self):
return '%s (%s)' % (self.headline, self.camp)
class InfoItem(CreatedUpdatedModel): class InfoItem(CreatedUpdatedModel):
class Meta: class Meta:
@ -60,11 +65,12 @@ class InfoItem(CreatedUpdatedModel):
) )
weight = models.PositiveIntegerField( weight = models.PositiveIntegerField(
help_text = 'Determines sorting/ordering. Heavier items sink to the bottom. Items with the same weight are ordered alphabetically.' help_text = 'Determines sorting/ordering. Heavier items sink to the bottom. Items with the same weight are ordered alphabetically. Defaults to 100.',
default = 100,
) )
def clean(self): def clean(self):
if InfoCategory.objects.filter(camp=self.camp, anchor=self.anchor).exists(): if InfoCategory.objects.filter(camp=self.category.camp, anchor=self.anchor).exists():
# this anchor is already in use on a category, so it cannot be used here (they must be unique on the entire page) # this anchor is already in use on a category, so it cannot be used here (they must be unique on the entire page)
raise ValidationError({'anchor': 'Anchor is already in use on an info category for this camp'}) raise ValidationError({'anchor': 'Anchor is already in use on an info category for this camp'})

View file

@ -26,9 +26,10 @@ Info | {{ block.super }}
} }
</style> </style>
{% if categories %}
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h2>Table of Contents</h2> <h3>Table of Contents</h3>
<p class="list-group"> <p class="list-group">
{% for category in categories %} {% for category in categories %}
<a href="#{{ category.anchor }}" class="list-group-item">{{ category.headline }}</a> <a href="#{{ category.anchor }}" class="list-group-item">{{ category.headline }}</a>
@ -41,14 +42,13 @@ Info | {{ block.super }}
<span class="anchor" id="{{ category.anchor }}"></span> <span class="anchor" id="{{ category.anchor }}"></span>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h2>When is BornHack happening?</h2> <h2>{{ category.title }}</h2>
<div class="panel-group"> <div class="panel-group">
{% for item in category.infoitems %} {% for item in category.infoitems.all %}
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<span class="sub-anchor" id="{{ item.anchor }}"></span> <span class="sub-anchor" id="{{ item.anchor }}"></span>
<h4 class="panel-title"> <h4 class="panel-title">{{ item.headline }}
{{ item.title }}
<a href="#{{ item.anchor }}"> <a href="#{{ item.anchor }}">
<i class="glyphicon glyphicon-link"></i> <i class="glyphicon glyphicon-link"></i>
</a> </a>
@ -63,23 +63,8 @@ Info | {{ block.super }}
</div> </div>
</div> </div>
{% endfor %} {% endfor %}
{% else %}
<script src="{% static 'js/leaflet.js' %}"></script> <h3>No info found for {{ camp.title }}</h3>
<script> {% endif %}
var map = L.map('map', {center: [55.131520, 14.903000], zoom: 10});
L.tileLayer(
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
{
attribution: '&copy; <a href="http://osm.org/copyright" target="_blank">OpenStreetMap</a> contributors',
}
).addTo(map);
var camp_latlong = [55.011520, 14.975360];
L.marker(camp_latlong).addTo(map);
L.marker(camp_latlong).addTo(map)
.bindPopup('<strong>Coordinates:</strong><br>55.011520, 14.975360<br><strong>Address:</strong><br>Baunevej 11, 3720 Aakirkeby')
.openPopup();
</script>
{% endblock %} {% endblock %}

View file

@ -2,16 +2,15 @@ from django.shortcuts import render
from django.views.generic import ListView, DetailView from django.views.generic import ListView, DetailView
from django.utils import timezone from django.utils import timezone
from .models import * from .models import *
from camps.mixins import CampViewMixin
class CampInfoView(CampViewMixin, ListView):
class CampInfoView(ListView):
model = InfoCategory model = InfoCategory
template_name = 'info.html' template_name = 'info.html'
context_object_name = 'categories' context_object_name = 'categories'
def get_queryset(self, **kwargs): def get_queryset(self):
return InfoCategory.objects.filter( queryset = super(CampInfoView, self).get_queryset()
camp__slug=self.kwargs['camp_slug'] # do not show categories with 0 items
) return queryset.exclude(infoitems__isnull=True)

View file

@ -2,7 +2,7 @@ from collections import OrderedDict
import datetime import datetime
from django.views.generic import ListView, TemplateView, DetailView from django.views.generic import ListView, TemplateView, DetailView
from camp.mixins import CampViewMixin from camps.mixins import CampViewMixin
from . import models from . import models

0
sponsors/__init__.py Normal file
View file

3
sponsors/admin.py Normal file
View file

@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

7
sponsors/apps.py Normal file
View file

@ -0,0 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class SponsorsConfig(AppConfig):
name = 'sponsors'

View file

5
sponsors/models.py Normal file
View file

@ -0,0 +1,5 @@
from __future__ import unicode_literals
from django.db import models
# Create your models here.

3
sponsors/tests.py Normal file
View file

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

9
sponsors/views.py Normal file
View file

@ -0,0 +1,9 @@
from django.views.generic import TemplateView
from camps.mixins import CampViewMixin
class SponsorIndexView(CampViewMixin, TemplateView):
def get_template_name(self):
return '%s-sponsors.html' % self.camp.slug

View file

@ -1,5 +1,5 @@
body { body {
margin-top: 90px; margin-top: 85px;
margin-bottom: 35px; margin-bottom: 35px;
} }
@ -42,23 +42,7 @@ a, a:active, a:focus {
} }
.navbar-fixed-top { .navbar-fixed-top {
min-height: 80px; min-height: 70px;
}
@media (min-width: 768px) {
.nav li a {
padding: 30px 15px;
}
.nav {
float: right!important;
}
}
@media (max-width: 767px) {
.nav li {
text-align: center;
font-size: 20px;
}
} }
.navbar-toggle .icon-bar { .navbar-toggle .icon-bar {

View file

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View file

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View file

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

View file

@ -1,5 +1,7 @@
{% load static from staticfiles %} {% load static from staticfiles %}
{% load bootstrap3 %} {% load bootstrap3 %}
{% static "" as baseurl %}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
@ -20,7 +22,6 @@
</head> </head>
<body> <body>
<nav class="navbar navbar-fixed-top"> <nav class="navbar navbar-fixed-top">
<div class="container-fluid"> <div class="container-fluid">
<div class="navbar-header"> <div class="navbar-header">
@ -31,36 +32,29 @@
<span class="icon-bar"></span> <span class="icon-bar"></span>
</button> </button>
<a class="navbar-brand" href="/"> <a class="navbar-brand" href="/">
<img src="{% static 'img/logo-new.png' %}" class="img-responsive" /> {% if request.resolver_match.kwargs.camp_slug %}
<img src="{{ baseurl }}/img/{{ camp.slug }}/{{ camp.slug }}-logo-small.png" class="img-responsive" />
{% else %}
<img src="{% static 'img/logo-small.png' %}" class="img-responsive" />
{% endif %}
</a> </a>
</div> </div>
<div id="navbar" class="navbar-collapse collapse"> <div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav"> <ul class="nav navbar-nav">
<li><a href="{% url 'news:index' %}">News</a></li> <li><a href="{% url 'news:index' %}">News</a></li>
<li><a href="{% url 'shop:index' %}">Shop</a></li> <li><a href="{% url 'shop:index' %}">Shop</a></li>
<li class="dropdown"> <li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Camps <span class="caret"></span></a> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ camp.title|default:"Camps" }}<span class="caret"></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
{% for camp in upcoming_camps %} {% for camp in camps %}
<li><a href="{% url 'camp_detail' camp_slug=camp.slug %}">{{ camp.title }}</a></li>
{% endfor %}
<li role="separator" class="divider"></li>
{% for camp in previous_camps %}
<li><a href="{% url 'camp_detail' camp_slug=camp.slug %}">{{ camp.title }}</a></li> <li><a href="{% url 'camp_detail' camp_slug=camp.slug %}">{{ camp.title }}</a></li>
{% endfor %} {% endfor %}
</ul> </ul>
</li> </li>
{# only include camp specific menu items when relevant #} </ul>
{% if request.resolver_match.kwargs.camp_slug %} <ul class="nav navbar-nav navbar-right">
<li><a href="{% url 'camp_info' camp_slug=camp.slug %}">Info</a></li>
<li><a href="{% url 'camp_villages' camp_slug=camp.slug %}">Villages</a></li>
<li><a href="{% url 'camp_schedule' camp_slug=camp.slug %}">Schedule</a></li>
<li><a href="{% url 'camp_sponsors' camp_slug=camp.slug %}">Sponsors</a></li>
{% endif %}
<li><a href="{% url 'contact' %}">Contact</a></li>
{% if user.is_authenticated %} {% if user.is_authenticated %}
<li><a href="{% url 'profiles:detail' %}">Profile</a></li> <li><a href="{% url 'profiles:detail' %}">Account</a></li>
{% else %} {% else %}
<li><a href="{% url 'account_login' %}">Login</a></li> <li><a href="{% url 'account_login' %}">Login</a></li>
{% endif %} {% endif %}
@ -70,6 +64,18 @@
</nav> </nav>
<div id="main" class="container container-fluid"> <div id="main" class="container container-fluid">
{% if camp %}
<div class="row">
<div class="btn-group btn-group-justified">
<a class="btn {% if request.resolver_match.url_name == "camp_detail" %}btn-primary{% else %}btn-default{% endif %}" href="{% url 'camp_detail' camp_slug=camp.slug %}">{{ camp.title }}</a>
<a class="btn {% if request.resolver_match.url_name == "info" %}btn-primary{% else %}btn-default{% endif %}" href="{% url 'info' camp_slug=camp.slug %}">Info</a></li>
<a class="btn {% if request.resolver_match.url_name == "village_list" %}btn-primary{% else %}btn-default{% endif %}" href="{% url 'village_list' camp_slug=camp.slug %}">Villages</a>
<a class="btn {% if request.resolver_match.url_name == "schedule_index" %}btn-primary{% else %}btn-default{% endif %}" href="{% url 'schedule_index' camp_slug=camp.slug %}">Schedule</a>
<a class="btn {% if request.resolver_match.url_name == "sponsors" %}btn-primary{% else %}btn-default{% endif %}" href="{% url 'sponsors' camp_slug=camp.slug %}">Sponsors</a>
</div>
<p>
</div>
{% endif %}
{% bootstrap_messages %} {% bootstrap_messages %}
{% block content %}{% endblock %} {% block content %}{% endblock %}
<footer class="row"> <footer class="row">
@ -78,6 +84,7 @@
<a href="{% url 'general-terms' %}">General Terms &amp; Conditions</a> | <a href="{% url 'general-terms' %}">General Terms &amp; Conditions</a> |
<a href="{% url 'conduct' %}">Code of Conduct</a> | <a href="{% url 'conduct' %}">Code of Conduct</a> |
<a href="{% url 'privacy-policy' %}">Privacy Policy</a> <a href="{% url 'privacy-policy' %}">Privacy Policy</a>
<a href="{% url 'contact' %}">Contact</a>
{% endblock %} {% endblock %}
</div> </div>
</footer> </footer>

View file

@ -1,5 +1,5 @@
import uuid import uuid
from django.core.exceptions import ValidationError
from django.db import models from django.db import models
@ -19,7 +19,7 @@ class CleanedModel(models.Model):
print(message) print(message)
# dont save, just return # dont save, just return
return return
super(CreatedUpdatedModel, self).save(**kwargs) super(CleanedModel, self).save(**kwargs)
class UUIDModel(CleanedModel): class UUIDModel(CleanedModel):

View file

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2016-12-28 22:08
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('camps', '0011_auto_20161228_1750'),
('villages', '0006_remove_village_camp'),
]
operations = [
migrations.AddField(
model_name='village',
name='camp',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='camps.Camp'),
),
]

View file

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.4 on 2016-12-28 22:09
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('villages', '0007_village_camp'),
]
operations = [
migrations.AlterField(
model_name='village',
name='camp',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='camps.Camp'),
),
]

View file

@ -15,7 +15,7 @@ class Village(CreatedUpdatedModel, UUIDModel):
ordering = ['name'] ordering = ['name']
contact = models.ForeignKey('auth.User') contact = models.ForeignKey('auth.User')
camp = models.ForeignKey('camps.Camp')
name = models.CharField(max_length=255) name = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, blank=True) slug = models.SlugField(max_length=255, blank=True)
description = models.TextField( description = models.TextField(
@ -37,7 +37,7 @@ class Village(CreatedUpdatedModel, UUIDModel):
return self.name return self.name
def get_absolute_url(self): def get_absolute_url(self):
return reverse_lazy('villages:detail', kwargs={'slug': self.slug}) return reverse_lazy('village_detail', kwargs={'camp_slug': self.camp.slug, 'slug': self.slug})
def save(self, **kwargs): def save(self, **kwargs):
if ( if (

View file

@ -8,6 +8,6 @@
<button type="submit" class="btn btn-danger form-control">Confirm</button> <button type="submit" class="btn btn-danger form-control">Confirm</button>
<br /> <br />
<br /> <br />
<a href="{% url 'villages:detail' slug=village.slug %}" class="btn btn-default form-control">Cancel</a> <a href="{% url 'village_detail' slug=village.slug %}" class="btn btn-default form-control">Cancel</a>
</form> </form>
{% endblock %} {% endblock %}

View file

@ -13,8 +13,8 @@ Village: {{ village.name }} | {{ block.super }}
{% if user == village.contact %} {% if user == village.contact %}
<hr /> <hr />
<a href="{% url 'villages:update' slug=village.slug %}" class="btn btn-primary">Edit</a> <a href="{% url 'village_update' camp_slug=village.camp.slug slug=village.slug %}" class="btn btn-primary">Edit</a>
<a href="{% url 'villages:delete' slug=village.slug %}" class="btn btn-danger">Delete</a> <a href="{% url 'village_delete' camp_slug=village.camp.slug slug=village.slug %}" class="btn btn-danger">Delete</a>
{% endif %} {% endif %}
{% endblock %} {% endblock %}

View file

@ -6,7 +6,7 @@ Villages | {{ block.super }}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<h2>Villages</h2>
<p> <p>
If this is your first hackercamp the term 'Village' might be confusing but it If this is your first hackercamp the term 'Village' might be confusing but it
is fairly simple: a village is just a spot on the campsite where you and a is fairly simple: a village is just a spot on the campsite where you and a
@ -16,17 +16,15 @@ Villages | {{ block.super }}
</p> </p>
<p class="lead"> <p class="lead">
<a href="https://bornhack.dk/shop/?category=villages"> It is also possible to rent a tent, chairs and tables in the shop!
It is also possible to rent a tent, chairs and tables for villages here.
</a>
</p> </p>
{% if user.is_authenticated %} {% if user.is_authenticated %}
<a href="{% url 'villages:create' %}" class="btn btn-primary">Create a village</a> <a href="{% url 'village_create' camp_slug=camp.slug %}" class="btn btn-primary">Create a village</a>
{% endif %} {% endif %}
<hr /> <hr />
{% if villages %}
<table class="table table-hover table-condensed table-striped"> <table class="table table-hover table-condensed table-striped">
<thead> <thead>
<tr> <tr>
@ -39,7 +37,7 @@ Villages | {{ block.super }}
{% for village in villages %} {% for village in villages %}
<tr> <tr>
<td> <td>
<a href="{% url 'villages:detail' slug=village.slug %}"> <a href="{% url 'village_detail' camp_slug=camp.slug slug=village.slug %}">
{{ village.name }} {{ village.name }}
</a> </a>
</td> </td>
@ -53,5 +51,7 @@ Villages | {{ block.super }}
{% endfor %} {% endfor %}
</tbody> </tbody>
</table> </table>
{% else %}
<h4>No villages for <b>{{ camp.title }}</b> yet!</h4>
{% endif %}
{% endblock %} {% endblock %}

View file

@ -2,21 +2,20 @@ 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.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect from django.http import HttpResponseRedirect
from django.views.generic import ( from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
ListView, DetailView, CreateView, UpdateView, DeleteView
)
from django.views.generic.detail import SingleObjectMixin from django.views.generic.detail import SingleObjectMixin
from .models import Village from .models import Village
from camps.models import Camp
from camps.mixins import CampViewMixin
class VillageListView(ListView): class VillageListView(CampViewMixin, ListView):
queryset = Village.objects.not_deleted() queryset = Village.objects.not_deleted()
template_name = 'village_list.html' template_name = 'village_list.html'
context_object_name = 'villages' context_object_name = 'villages'
class VillageDetailView(DetailView): class VillageDetailView(CampViewMixin, DetailView):
queryset = Village.objects.not_deleted() queryset = Village.objects.not_deleted()
template_name = 'village_detail.html' template_name = 'village_detail.html'
context_object_name = 'village' context_object_name = 'village'
@ -31,6 +30,7 @@ class VillageCreateView(LoginRequiredMixin, CreateView):
def form_valid(self, form): def form_valid(self, form):
village = form.save(commit=False) village = form.save(commit=False)
village.contact = self.request.user village.contact = self.request.user
village.camp = Camp.objects.get(slug=self.request.session['campslug'])
village.save() village.save()
return HttpResponseRedirect(village.get_absolute_url()) return HttpResponseRedirect(village.get_absolute_url())
@ -64,3 +64,4 @@ class VillageDeleteView(EnsureUserOwnsVillageMixin, LoginRequiredMixin, DeleteVi
success_url = reverse_lazy('villages:list') success_url = reverse_lazy('villages:list')
template_name = 'village_confirm_delete.html' template_name = 'village_confirm_delete.html'
context_object_name = 'village' context_object_name = 'village'