just a commit before we start the days work
|
@ -4,6 +4,11 @@ from django.utils import timezone
|
|||
|
||||
|
||||
def camp(request):
|
||||
"""
|
||||
if we have a camp_slug url component then get the "current" Camp object.
|
||||
Return it after adding the slug to request.session along with a "camps"
|
||||
queryset containing all camps (used to build the menu and such)
|
||||
"""
|
||||
if 'camp_slug' in request.resolver_match.kwargs:
|
||||
camp = Camp.objects.get(slug=request.resolver_match.kwargs['camp_slug'])
|
||||
request.session['campslug'] = camp.slug
|
||||
|
@ -12,7 +17,7 @@ def camp(request):
|
|||
camp = None
|
||||
|
||||
return {
|
||||
'camps': Camp.objects.all().order_by('-camp_start'),
|
||||
'camps': Camp.objects.all().order_by('-camp'),
|
||||
'camp': camp
|
||||
}
|
||||
|
||||
|
|
47
camps/migrations/0013_auto_20161229_2201.py
Normal file
|
@ -0,0 +1,47 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2016-12-29 22:01
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.contrib.postgres.fields.ranges
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('camps', '0012_auto_20161228_2312'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='camp',
|
||||
name='buildup_start',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='camp',
|
||||
name='camp_end',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='camp',
|
||||
name='camp_start',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='camp',
|
||||
name='teardown_end',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='camp',
|
||||
name='buildup',
|
||||
field=django.contrib.postgres.fields.ranges.DateTimeRangeField(help_text=b'The camp buildup period.', null=True, verbose_name=b'Buildup Period'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='camp',
|
||||
name='camp',
|
||||
field=django.contrib.postgres.fields.ranges.DateTimeRangeField(help_text=b'The camp period.', null=True, verbose_name=b'Camp Period'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='camp',
|
||||
name='teardown',
|
||||
field=django.contrib.postgres.fields.ranges.DateTimeRangeField(help_text=b'The camp teardown period.', null=True, verbose_name=b'Teardown period'),
|
||||
),
|
||||
]
|
31
camps/migrations/0014_auto_20161229_2202.py
Normal file
|
@ -0,0 +1,31 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2016-12-29 22:02
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.contrib.postgres.fields.ranges
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('camps', '0013_auto_20161229_2201'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='camp',
|
||||
name='buildup',
|
||||
field=django.contrib.postgres.fields.ranges.DateTimeRangeField(help_text=b'The camp buildup period.', verbose_name=b'Buildup Period'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='camp',
|
||||
name='camp',
|
||||
field=django.contrib.postgres.fields.ranges.DateTimeRangeField(help_text=b'The camp period.', verbose_name=b'Camp Period'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='camp',
|
||||
name='teardown',
|
||||
field=django.contrib.postgres.fields.ranges.DateTimeRangeField(help_text=b'The camp teardown period.', verbose_name=b'Teardown period'),
|
||||
),
|
||||
]
|
22
camps/migrations/0015_auto_20170116_1634.py
Normal file
|
@ -0,0 +1,22 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2017-01-16 16:34
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('camps', '0014_auto_20161229_2202'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='expense',
|
||||
name='refund_user',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Expense',
|
||||
),
|
||||
]
|
20
camps/migrations/0016_camp_description.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2017-01-16 16:37
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('camps', '0015_auto_20170116_1634'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='camp',
|
||||
name='description',
|
||||
field=models.TextField(default=b'', help_text=b'Description of the camp, shown on the camp frontpage. HTML and markdown supported.', verbose_name=b'Description'),
|
||||
),
|
||||
]
|
19
camps/migrations/0017_remove_camp_description.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2017-01-16 21:59
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('camps', '0016_camp_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='camp',
|
||||
name='description',
|
||||
),
|
||||
]
|
|
@ -1,6 +1,8 @@
|
|||
import datetime
|
||||
from django.db import models
|
||||
from utils.models import UUIDModel, CreatedUpdatedModel
|
||||
from program.models import EventType
|
||||
from django.contrib.postgres.fields import DateTimeRangeField
|
||||
|
||||
|
||||
class Camp(CreatedUpdatedModel, UUIDModel):
|
||||
|
@ -25,69 +27,34 @@ class Camp(CreatedUpdatedModel, UUIDModel):
|
|||
help_text='The url slug to use for this camp'
|
||||
)
|
||||
|
||||
buildup_start = models.DateTimeField(
|
||||
verbose_name='Buildup Start date',
|
||||
help_text='When the camp buildup starts.',
|
||||
buildup = DateTimeRangeField(
|
||||
verbose_name='Buildup Period',
|
||||
help_text='The camp buildup period.',
|
||||
)
|
||||
|
||||
camp_start = models.DateTimeField(
|
||||
verbose_name='Start date',
|
||||
help_text='When the camp starts.',
|
||||
camp = DateTimeRangeField(
|
||||
verbose_name='Camp Period',
|
||||
help_text='The camp period.',
|
||||
)
|
||||
|
||||
camp_end = models.DateTimeField(
|
||||
verbose_name='End date',
|
||||
help_text='When the camp ends.',
|
||||
)
|
||||
|
||||
teardown_end = models.DateTimeField(
|
||||
verbose_name='Start date',
|
||||
help_text='When the camp teardown ends.',
|
||||
teardown = DateTimeRangeField(
|
||||
verbose_name='Teardown period',
|
||||
help_text='The camp teardown period.',
|
||||
)
|
||||
|
||||
def __unicode__(self):
|
||||
return "%s - %s" % (self.title, self.tagline)
|
||||
|
||||
@property
|
||||
def event_types(self):
|
||||
# return all event types with at least one event in this camp
|
||||
return EventType.objects.filter(event__instances__isnull=False, event__camp=self).distinct()
|
||||
|
||||
class Expense(CreatedUpdatedModel, UUIDModel):
|
||||
class Meta:
|
||||
verbose_name = 'Expense'
|
||||
verbose_name_plural = 'Expenses'
|
||||
@property
|
||||
def logo_small(self):
|
||||
return 'img/%(slug)s/logo/%(slug)s-logo-small.png' % {'slug': self.slug}
|
||||
|
||||
payment_time = models.DateTimeField(
|
||||
verbose_name='Expense date/time',
|
||||
help_text='The date and time this expense was paid.',
|
||||
)
|
||||
|
||||
description = models.CharField(
|
||||
verbose_name='Description',
|
||||
help_text='What this expense covers.',
|
||||
max_length=255,
|
||||
)
|
||||
|
||||
dkk_amount = models.DecimalField(
|
||||
verbose_name='DKK Amount',
|
||||
help_text='The DKK amount of the expense.',
|
||||
max_digits=7,
|
||||
decimal_places=2,
|
||||
)
|
||||
|
||||
receipt = models.ImageField(
|
||||
verbose_name='Image of receipt',
|
||||
help_text='Upload a scan or image of the receipt',
|
||||
)
|
||||
|
||||
refund_user = models.ForeignKey(
|
||||
'auth.User',
|
||||
verbose_name='Refund user',
|
||||
help_text='Which user, if any, covered this expense and should be refunded.',
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
|
||||
refund_paid = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name='Refund paid?',
|
||||
help_text='Has this expense been refunded to the user?',
|
||||
)
|
||||
@property
|
||||
def logo_large(self):
|
||||
return 'img/%(slug)s/logo/%(slug)s-logo-large.png' % {'slug': self.slug}
|
||||
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load commonmark %}
|
||||
{% load static from staticfiles %}
|
||||
{% block content %}
|
||||
{{ camp.title }}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<img src="{% static camp.logo_large %}" class="img-responsive" id="front-logo" />
|
||||
<br />
|
||||
|
||||
{{ camp.description|commonmark }}
|
||||
{% endblock content %}
|
||||
|
||||
|
|
61
camps/templates/camp_detail_bornhack-2016.html
Normal file
|
@ -0,0 +1,61 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load commonmark %}
|
||||
{% load static from staticfiles %}
|
||||
{% load imageutils %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<img src="{% static camp.logo_large %}" class="img-responsive" id="front-logo" />
|
||||
|
||||
<br />
|
||||
|
||||
<div class="col-md-8 text-container">
|
||||
<div class="lead">
|
||||
<strong>Bornhack 2016</strong> was the first BornHack. It took place from <strong>August 27 to September 3rd 2016</strong> on the Danish island of Bornholm. The tagline of this event was <strong>Initial Commit</strong>.
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{% thumbnail 'img/bornhack-2016/esbjerg' '1600x988-B12A2612.jpg' 'A quiet moment in the chillout area by the bar' %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{% thumbnail 'img/bornhack-2016/fonsmark' 'FB1_5128.JPG' 'Emma Holten speaking at BornHack 2016' %}
|
||||
</div>
|
||||
<div class="col-md-8 text-container">
|
||||
<div class="lead">
|
||||
With <strong>3 keynotes, 38 talks, and 9 workshops</strong> we had an ambitious program which was well received by participants. We also had an <strong>amazing list of sponsors</strong> making the event financially possible.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-8 text-container">
|
||||
<p class="lead">Many of the speakers and keynotes were present for the <strong>full week</strong>, providing participants with <strong>ample opportunity to discuss projects and exchange ideas</strong>.</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
{% thumbnail 'img/bornhack-2016/fonsmark' 'FB1_5149.JPG' 'Danish politicians debating at BornHack 2016' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
{% thumbnail 'img/bornhack-2016/esbjerg' '1600x988-B12A2631.jpg' 'The BornHack 2016 organiser team' %}
|
||||
</div>
|
||||
<div class="col-md-8 text-container">
|
||||
<div class="lead">
|
||||
The team behind BornHack 2016 had <strong>a lot of help</strong> from volunteer participants when it was needed. We are <strong>very grateful</strong> and will repay the kindness by continuing to organise awesome events.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
|
@ -5,6 +5,8 @@ from .models import *
|
|||
|
||||
class CampDetailView(DetailView):
|
||||
model = Camp
|
||||
template_name = 'camp_detail.html'
|
||||
slug_url_kwarg = 'camp_slug'
|
||||
|
||||
def get_template_names(self):
|
||||
return 'camp_detail_%s.html' % self.get_object().slug
|
||||
|
||||
|
|
|
@ -74,4 +74,7 @@ class InfoItem(CreatedUpdatedModel):
|
|||
# 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'})
|
||||
|
||||
def __str__(self):
|
||||
return '%s (%s)' % (self.headline, self.category)
|
||||
|
||||
|
||||
|
|
|
@ -6,6 +6,9 @@ News | {{ block.super }}
|
|||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if request.resolver_match.kwargs.archived %}
|
||||
<i>Showing archived news items. <a href="{% url 'news:index' archived=False %}">Show regular news items</a></i>
|
||||
{% endif %}
|
||||
{% for item in news_items %}
|
||||
<div>
|
||||
<h3><a href="{% url 'news:detail' slug=item.slug %}">{{ item.title }}</a> <small>{{ item.published_at|date:"Y-m-d" }}</small></h3>
|
||||
|
@ -17,4 +20,9 @@ News | {{ block.super }}
|
|||
{% empty %}
|
||||
<h3>No news yet. Stay tuned!</h3>
|
||||
{% endfor %}
|
||||
{% if not request.resolver_match.kwargs.archived %}
|
||||
<hr />
|
||||
<i><a href="{% url 'news:archive' archived=True %}">Show archived news items</a></i>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ from . import views
|
|||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.NewsIndex.as_view(), 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'(?P<slug>[-_\w+]+)/$', views.NewsDetail.as_view(), name='detail'),
|
||||
]
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@ class NewsIndex(ListView):
|
|||
template_name = 'news_index.html'
|
||||
context_object_name = 'news_items'
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
def get_queryset(self):
|
||||
return NewsItem.objects.filter(
|
||||
published_at__isnull=False,
|
||||
published_at__lt=timezone.now(),
|
||||
archived=False
|
||||
archived=self.kwargs['archived']
|
||||
)
|
||||
|
||||
|
||||
|
|
33
program/migrations/0011_auto_20161229_2149.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2016-12-29 21:49
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.contrib.postgres.fields.ranges
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('program', '0010_auto_20161212_1809'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='eventinstance',
|
||||
options={'ordering': ['when']},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='eventinstance',
|
||||
name='end',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='eventinstance',
|
||||
name='start',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='eventinstance',
|
||||
name='when',
|
||||
field=django.contrib.postgres.fields.ranges.DateTimeRangeField(null=True),
|
||||
),
|
||||
]
|
21
program/migrations/0012_auto_20161229_2150.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2016-12-29 21:50
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.contrib.postgres.fields.ranges
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('program', '0011_auto_20161229_2149'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='eventinstance',
|
||||
name='when',
|
||||
field=django.contrib.postgres.fields.ranges.DateTimeRangeField(),
|
||||
),
|
||||
]
|
|
@ -1,5 +1,5 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.postgres.fields import DateTimeRangeField
|
||||
from django.db import models
|
||||
from django.utils.text import slugify
|
||||
|
||||
|
@ -18,7 +18,7 @@ class EventType(CreatedUpdatedModel):
|
|||
|
||||
|
||||
class Event(CreatedUpdatedModel):
|
||||
""" Something that is on the program. """
|
||||
""" Something that is on the program one or more times. """
|
||||
title = models.CharField(max_length=255)
|
||||
slug = models.SlugField(blank=True, max_length=255)
|
||||
abstract = models.TextField()
|
||||
|
@ -40,19 +40,17 @@ class Event(CreatedUpdatedModel):
|
|||
class EventInstance(CreatedUpdatedModel):
|
||||
""" An instance of an event """
|
||||
event = models.ForeignKey('program.event', related_name='instances')
|
||||
start = models.DateTimeField()
|
||||
end = models.DateTimeField()
|
||||
when = DateTimeRangeField()
|
||||
|
||||
class Meta:
|
||||
ordering = ['start']
|
||||
ordering = ['when']
|
||||
|
||||
def __unicode__(self):
|
||||
return '%s (%s to %s)' % (self.event, self.start, self.end)
|
||||
|
||||
return '%s (%s)' % (self.event, self.when)
|
||||
|
||||
|
||||
class Speaker(CreatedUpdatedModel):
|
||||
""" Person anchoring an event. """
|
||||
""" A Person anchoring an event. """
|
||||
name = models.CharField(max_length=150)
|
||||
biography = models.TextField()
|
||||
picture = models.ImageField(null=True, blank=True)
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
<a href="{% url 'schedule:index' %}" style="background-color: black; border: 0; color: white; display: inline-block; padding: 5px;">
|
||||
All
|
||||
</a>
|
||||
{% for event_type in event_types %}
|
||||
<a href="{% url 'schedule:index' %}?type={{ event_type.slug }}" style="background-color: {{ event_type.color }}; border: 0; color: {% if event_type.light_text %}white{% else %}black{% endif %}; display: inline-block; padding: 5px;">
|
||||
{% for event_type in camp.event_types %}
|
||||
<a href="{% url 'schedule_index' %}?type={{ event_type.slug }}" style="background-color: {{ event_type.color }}; border: 0; color: {% if event_type.light_text %}white{% else %}black{% endif %}; display: inline-block; padding: 5px;">
|
||||
{{ event_type.name }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
|
|
|
@ -26,62 +26,13 @@ class ProgramOverviewView(CampViewMixin, ListView):
|
|||
model = models.Event
|
||||
template_name = 'program_overview.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(
|
||||
ProgramOverviewView, self
|
||||
).get_context_data(**kwargs)
|
||||
|
||||
days = Day.objects.all()
|
||||
context['days'] = days
|
||||
|
||||
filter = {}
|
||||
if 'type' in self.request.GET:
|
||||
event_type = self.request.GET['type']
|
||||
filter["event_type__slug"] = event_type
|
||||
|
||||
context['day_events'] = OrderedDict([
|
||||
(
|
||||
day,
|
||||
self.get_queryset().filter(
|
||||
days__in=[day],
|
||||
**filter
|
||||
).order_by(
|
||||
'start'
|
||||
)
|
||||
)
|
||||
for day in days
|
||||
])
|
||||
|
||||
context['event_types'] = models.EventType.objects.all()
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class ProgramDayView(CampViewMixin, TemplateView):
|
||||
template_name = 'program_day.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ProgramDayView, self).get_context_data(**kwargs)
|
||||
year = int(kwargs['year'])
|
||||
month = int(kwargs['month'])
|
||||
day = int(kwargs['day'])
|
||||
date = datetime.date(year=year, month=month, day=day)
|
||||
day = Day.objects.filter(date=date)
|
||||
context['date'] = date
|
||||
context['events'] = models.Event.objects.filter(days=day).order_by('event_type', 'start')
|
||||
context['event_types'] = models.EventType.objects.all()
|
||||
context['days'] = Day.objects.filter(date__year=year)
|
||||
return context
|
||||
|
||||
|
||||
class EventDetailView(CampViewMixin, DetailView):
|
||||
model = models.Event
|
||||
template_name = 'program_event_detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EventDetailView, self).get_context_data(**kwargs)
|
||||
# TODO: date__year is hardcoded here - need fix for 2017 :P
|
||||
context['days'] = Day.objects.filter(date__year=2016)
|
||||
return context
|
||||
|
||||
|
||||
|
|
BIN
static_src/img/bornhack-2016/ahf/jarlsgaard.jpg
Normal file
After Width: | Height: | Size: 500 KiB |
BIN
static_src/img/bornhack-2016/ahf/thumbnail_jarlsgaard.jpg.png
Normal file
After Width: | Height: | Size: 67 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x1000-B12A2398.jpg
Normal file
After Width: | Height: | Size: 138 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x900-B12A2452.jpg
Normal file
After Width: | Height: | Size: 110 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x900-B12A2485.jpg
Normal file
After Width: | Height: | Size: 99 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x900-B12A2514.jpg
Normal file
After Width: | Height: | Size: 180 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x900-B12A2604.jpg
Normal file
After Width: | Height: | Size: 156 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x900-B12A2608.jpg
Normal file
After Width: | Height: | Size: 157 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x988-B12A2610.jpg
Normal file
After Width: | Height: | Size: 348 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x988-B12A2612.jpg
Normal file
After Width: | Height: | Size: 314 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x988-B12A2620.jpg
Normal file
After Width: | Height: | Size: 354 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x988-B12A2624.jpg
Normal file
After Width: | Height: | Size: 404 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x988-B12A2631.jpg
Normal file
After Width: | Height: | Size: 204 KiB |
BIN
static_src/img/bornhack-2016/esbjerg/1600x988-B12A2634.jpg
Normal file
After Width: | Height: | Size: 368 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 59 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 72 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 76 KiB |
After Width: | Height: | Size: 78 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 77 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/FA0_1961.JPG
Normal file
After Width: | Height: | Size: 3.6 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FA0_1983.JPG
Normal file
After Width: | Height: | Size: 8 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FA0_1986.JPG
Normal file
After Width: | Height: | Size: 6 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FB1_5090.JPG
Normal file
After Width: | Height: | Size: 3.4 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FB1_5111.JPG
Normal file
After Width: | Height: | Size: 3.7 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FB1_5126.JPG
Normal file
After Width: | Height: | Size: 5.4 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FB1_5128.JPG
Normal file
After Width: | Height: | Size: 1.7 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FB1_5149.JPG
Normal file
After Width: | Height: | Size: 3.3 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FB1_5168.JPG
Normal file
After Width: | Height: | Size: 7 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FB1_5265.JPG
Normal file
After Width: | Height: | Size: 4.2 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/FB1_5312.JPG
Normal file
After Width: | Height: | Size: 6.1 MiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FA0_1961.JPG.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FA0_1983.JPG.png
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FA0_1986.JPG.png
Normal file
After Width: | Height: | Size: 64 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FB1_5090.JPG.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FB1_5111.JPG.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FB1_5126.JPG.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FB1_5128.JPG.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FB1_5149.JPG.png
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FB1_5168.JPG.png
Normal file
After Width: | Height: | Size: 68 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FB1_5265.JPG.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
static_src/img/bornhack-2016/fonsmark/thumbnail_FB1_5312.JPG.png
Normal file
After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 34 KiB |
BIN
static_src/img/logo-large.png
Normal file
After Width: | Height: | Size: 24 KiB |
|
@ -33,7 +33,7 @@
|
|||
</button>
|
||||
<a class="navbar-brand" href="/">
|
||||
{% if request.resolver_match.kwargs.camp_slug %}
|
||||
<img src="{{ baseurl }}/img/{{ camp.slug }}/{{ camp.slug }}-logo-small.png" class="img-responsive" />
|
||||
<img src="{% static camp.logo_small %}" class="img-responsive" />
|
||||
{% else %}
|
||||
<img src="{% static 'img/logo-small.png' %}" class="img-responsive" />
|
||||
{% endif %}
|
||||
|
@ -44,13 +44,14 @@
|
|||
<li><a href="{% url 'news:index' %}">News</a></li>
|
||||
<li><a href="{% url 'shop:index' %}">Shop</a></li>
|
||||
<li class="dropdown">
|
||||
<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>
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Camps<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
{% for camp in camps %}
|
||||
<li><a href="{% url 'camp_detail' camp_slug=camp.slug %}">{{ camp.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="{% url 'contact' %}">Contact</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
{% if user.is_authenticated %}
|
||||
|
@ -83,7 +84,7 @@
|
|||
{% block footer %}
|
||||
<a href="{% url 'general-terms' %}">General Terms & Conditions</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 %}
|
||||
</div>
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static from staticfiles %}
|
||||
|
||||
{% load imageutils %}
|
||||
{% block content %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<img src="{% static 'img/logo.png' %}" class="img-responsive"
|
||||
id="front-logo" />
|
||||
<img src="{% static 'img/logo-large.png' %}" class="img-responsive" id="front-logo" />
|
||||
|
||||
<br />
|
||||
|
||||
|
@ -19,11 +18,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150812_162831.jpg">
|
||||
<img class="img-thumbnail"
|
||||
src="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150812_162831_tn.jpg"
|
||||
alt="Tents at CCCamp2015" title="Tents at CCCamp2015">
|
||||
</a>
|
||||
{% thumbnail 'img/bornhack-2016/fonsmark' 'FA0_1961.JPG' 'BornHack' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -31,11 +26,7 @@
|
|||
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/jarlsgaard.jpg">
|
||||
<img class="img-thumbnail"
|
||||
src="https://people.bornhack.org/tyk/ohm_cccamp_pics/jarlsgaard_tn.jpg"
|
||||
alt="Jarlsgaard from above" title="Jarlsgaard from above">
|
||||
</a>
|
||||
{% thumbnail 'img/bornhack-2016/ahf' 'jarlsgaard.jpg' 'Jarlsgård buildings from above' %}
|
||||
</div>
|
||||
<div class="col-md-8 text-container">
|
||||
<div class="lead">
|
||||
|
@ -57,11 +48,7 @@
|
|||
</p>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/_MG_5755.jpg">
|
||||
<img class="img-thumbnail"
|
||||
src="https://people.bornhack.org/tyk/ohm_cccamp_pics/_MG_5755_tn.jpg"
|
||||
alt="Hacking in Baconsvin village at OHM2013" title="Hacking in Baconsvin village at OHM2013">
|
||||
</a>
|
||||
{% thumbnail 'img/bornhack-2016/fonsmark' 'FB1_5090.JPG' 'Talk at BornHack 2016' %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -87,43 +74,15 @@
|
|||
</div>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150815_141706.jpg">
|
||||
<img class="img-thumbnail"
|
||||
src="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150815_141706_tn.jpg"
|
||||
alt="Hacking sign at CCCamp2015" title="Hacking sign at CCCamp2015">
|
||||
</a>
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150812_163606.jpg">
|
||||
<img class="img-thumbnail" src="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150812_163606_tn.jpg"
|
||||
alt="Entrance to Baconsvin village at CCCamp2015" title="Entrance to Baconsvin village at CCCamp2015">
|
||||
</a>
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150812_201635.jpg">
|
||||
<img class="img-thumbnail" src="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150812_201635_tn.jpg"
|
||||
alt="Dome being built at CCCamp2015" title="Dome being built at CCCamp2015">
|
||||
</a>
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/_MG_5746.jpg">
|
||||
<img class="img-thumbnail" src="https://people.bornhack.org/tyk/ohm_cccamp_pics/_MG_5746_tn.jpg"
|
||||
alt="Person swinging lights in the night at OHM2013" title="Person swinging lights in the night at OHM2013">
|
||||
</a>
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150814_145204.jpg">
|
||||
<img class="img-thumbnail" src="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150814_145204_tn.jpg"
|
||||
alt="Queer Feminist Geeks village at CCCamp2015" title="Queer Feminist Geeks village at CCCamp2015">
|
||||
</a>
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150815_154027.jpg">
|
||||
<img class="img-thumbnail" src="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150815_154027_tn.jpg"
|
||||
alt="Dome at CCCamp2015" title="Dome at CCCamp2015">
|
||||
</a>
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/_MG_5736.jpg">
|
||||
<img class="img-thumbnail" src="https://people.bornhack.org/tyk/ohm_cccamp_pics/_MG_5736_tn.jpg"
|
||||
alt="Lights at night at OHM2013" title="Lights at night at OHM2013">
|
||||
</a>
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150815_154119.jpg">
|
||||
<img class="img-thumbnail" src="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150815_154119_tn.jpg"
|
||||
alt="Free Chelsea Manning sign at CCCamp2015" title="Free Chelsea Manning sign at CCCamp2015">
|
||||
</a>
|
||||
<a href="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150816_153404.jpg">
|
||||
<img class="img-thumbnail" src="https://people.bornhack.org/tyk/ohm_cccamp_pics/IMG_20150816_153404_tn.jpg"
|
||||
alt="Swedish Embassy sign at CCCamp2015" title="Swedish Embassy sign at CCCamp2015">
|
||||
</a>
|
||||
{% thumbnail 'img/bornhack-2016/fonsmark' 'FA0_1983.JPG' 'Happy organisers welcoming people at the entrance to BornHack 2016' %}
|
||||
{% thumbnail 'img/bornhack-2016/fonsmark' 'FA0_1986.JPG' 'A bus full of hackers arrive at BornHack 2016' %}
|
||||
{% thumbnail 'img/bornhack-2016/fonsmark' 'FB1_5126.JPG' 'Late night hacking at Baconsvin village at BornHack 2016' %}
|
||||
{% thumbnail 'img/bornhack-2016/fonsmark' 'FB1_5168.JPG' '#irl_bar by night at BornHack 2016' %}
|
||||
{% thumbnail 'img/bornhack-2016/fonsmark' 'FB1_5265.JPG' 'Happy organisers welcoming people to BornHack 2016' %}
|
||||
{% thumbnail 'img/bornhack-2016/esbjerg' '1600x900-B12A2452.jpg' 'Soldering the BornHack 2016 badge' %}
|
||||
{% thumbnail 'img/bornhack-2016/esbjerg' '1600x900-B12A2485.jpg' 'Colored light in the grass' %}
|
||||
{% thumbnail 'img/bornhack-2016/esbjerg' '1600x988-B12A2624.jpg' 'Working on decorations' %}
|
||||
{% thumbnail 'img/bornhack-2016/esbjerg' '1600x900-B12A2604.jpg' 'Sitting around the campfire at BornHack 2016' %}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -18,16 +18,57 @@ class Command(BaseCommand):
|
|||
def handle(self, *args, **options):
|
||||
self.output('Creating camps...')
|
||||
camp1 = Camp.objects.create(
|
||||
name='BornHack 2016',
|
||||
title='BornHack 2016',
|
||||
tagline='Initial Commit',
|
||||
slug='bornhack-2016',
|
||||
start=timezone.datetime(2016, 8, 27, 12, 0, tzinfo=timezone.utc),
|
||||
end=timezone.datetime(2016, 9, 4, 12, 0, tzinfo=timezone.utc)
|
||||
buildup = (
|
||||
timezone.datetime(2016, 8, 25, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2016, 8, 27, 12, 0, tzinfo=timezone.utc),
|
||||
),
|
||||
camp = (
|
||||
timezone.datetime(2016, 8, 27, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2016, 9, 04, 12, 0, tzinfo=timezone.utc),
|
||||
),
|
||||
teardown = (
|
||||
timezone.datetime(2016, 9, 04, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2016, 9, 06, 12, 0, tzinfo=timezone.utc),
|
||||
),
|
||||
)
|
||||
|
||||
camp2 = Camp.objects.create(
|
||||
name='BornHack 2015',
|
||||
slug='bornhack-2015',
|
||||
start=timezone.datetime(2015, 8, 27, 12, 0, tzinfo=timezone.utc),
|
||||
end=timezone.datetime(2015, 9, 4, 12, 0, tzinfo=timezone.utc)
|
||||
title='BornHack 2017',
|
||||
tagline='Make Tradition',
|
||||
slug='bornhack-2017',
|
||||
buildup = (
|
||||
timezone.datetime(2017, 8, 20, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2017, 8, 22, 12, 0, tzinfo=timezone.utc),
|
||||
),
|
||||
camp = (
|
||||
timezone.datetime(2017, 8, 22, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2017, 8, 29, 12, 0, tzinfo=timezone.utc),
|
||||
),
|
||||
teardown = (
|
||||
timezone.datetime(2015, 8, 29, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2015, 8, 31, 12, 0, tzinfo=timezone.utc),
|
||||
),
|
||||
)
|
||||
|
||||
camp3 = Camp.objects.create(
|
||||
title='BornHack 2018',
|
||||
tagline='Undecided',
|
||||
slug='bornhack-2018',
|
||||
buildup = (
|
||||
timezone.datetime(2018, 8, 13, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2018, 8, 16, 12, 0, tzinfo=timezone.utc),
|
||||
),
|
||||
camp = (
|
||||
timezone.datetime(2018, 8, 16, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2018, 8, 23, 12, 0, tzinfo=timezone.utc),
|
||||
),
|
||||
teardown = (
|
||||
timezone.datetime(2018, 8, 23, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2018, 8, 26, 12, 0, tzinfo=timezone.utc),
|
||||
),
|
||||
)
|
||||
|
||||
self.output('Creating news...')
|
||||
|
@ -46,15 +87,15 @@ class Command(BaseCommand):
|
|||
content='unpublished news body here',
|
||||
)
|
||||
news4 = NewsItem.objects.create(
|
||||
title='welcome to bornhack 2015',
|
||||
title='welcome to bornhack 2017',
|
||||
content='news body here',
|
||||
published_at=timezone.datetime(2015, 8, 22, 12, 0, tzinfo=timezone.utc),
|
||||
published_at=timezone.datetime(2017, 8, 22, 12, 0, tzinfo=timezone.utc),
|
||||
archived=True
|
||||
)
|
||||
news5 = NewsItem.objects.create(
|
||||
title='bornhack 2015 is over',
|
||||
title='bornhack 2017 is over',
|
||||
content='news body here',
|
||||
published_at=timezone.datetime(2015, 8, 27, 12, 0, tzinfo=timezone.utc),
|
||||
published_at=timezone.datetime(2017, 8, 29, 12, 0, tzinfo=timezone.utc),
|
||||
archived=True
|
||||
)
|
||||
|
||||
|
@ -190,8 +231,10 @@ class Command(BaseCommand):
|
|||
self.output("creating eventinstances...")
|
||||
ei1 = EventInstance.objects.create(
|
||||
event=ev3,
|
||||
start=timezone.datetime(2016, 8, 27, 12, 0, tzinfo=timezone.utc),
|
||||
end=timezone.datetime(2016, 8, 27, 13, 0, tzinfo=timezone.utc),
|
||||
when=(
|
||||
timezone.datetime(2016, 8, 27, 12, 0, tzinfo=timezone.utc),
|
||||
timezone.datetime(2016, 8, 27, 13, 0, tzinfo=timezone.utc)
|
||||
)
|
||||
)
|
||||
ei2 = EventInstance.objects.create(
|
||||
event=ev1,
|
||||
|
|
2
utils/templates/thumbnail.html
Normal file
|
@ -0,0 +1,2 @@
|
|||
<a href="{{ path }}/{{ filename }}"><img class="img-thumbnail" src="{{ path }}/thumbnail_{{ filename }}.png" alt="{{ description }}" title="{{ description }}"></a>
|
||||
|
18
utils/templatetags/imageutils.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
from django import template
|
||||
from django.contrib.staticfiles.templatetags.staticfiles import static
|
||||
|
||||
register = template.Library()
|
||||
@register.inclusion_tag('thumbnail.html')
|
||||
def thumbnail(path, filename, description):
|
||||
"""
|
||||
Returns the HTML to show an image including thumbnail.
|
||||
Assumes the thumbnail is called 'thumbnail_foo.jpg.png' if the image is called 'foo.jpg'.
|
||||
Path should be relative inside static root.
|
||||
Description is used for alt-text and mouseover.
|
||||
"""
|
||||
return {
|
||||
'path': static('') + path,
|
||||
'filename': filename,
|
||||
'description': description,
|
||||
}
|
||||
|
20
villages/migrations/0009_auto_20161229_2143.py
Normal file
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10.4 on 2016-12-29 21:43
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('villages', '0008_auto_20161228_2209'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='village',
|
||||
name='private',
|
||||
field=models.BooleanField(default=False, help_text='Check if your village is invite only. Leave unchecked to welcome strangers.'),
|
||||
),
|
||||
]
|
|
@ -24,7 +24,7 @@ class Village(CreatedUpdatedModel, UUIDModel):
|
|||
|
||||
private = models.BooleanField(
|
||||
default=False,
|
||||
help_text='Check if your village is privately organized'
|
||||
help_text='Check if your village is invite only. Leave unchecked to welcome strangers.'
|
||||
)
|
||||
|
||||
deleted = models.BooleanField(
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
{% load bootstrap3 %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h3>Create {{ camp.title }} Village</h3>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
|
|
|
@ -12,15 +12,12 @@ Villages | {{ block.super }}
|
|||
is fairly simple: a village is just a spot on the campsite where you and a
|
||||
bunch of your friends/likeminded people camp together. Apart from peoples
|
||||
individual tents which they sleep in, many villages bring a large common tent
|
||||
where you can hack and hang out during the day.
|
||||
</p>
|
||||
|
||||
<p class="lead">
|
||||
It is also possible to rent a tent, chairs and tables in the shop!
|
||||
where you can hack and hang out during the day. It is also possible to rent a
|
||||
tent, chairs and tables in the shop!
|
||||
</p>
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'village_create' camp_slug=camp.slug %}" class="btn btn-primary">Create a village</a>
|
||||
<a href="{% url 'village_create' camp_slug=camp.slug %}" class="btn btn-primary">Create a new {{ camp.title }} village</a>
|
||||
{% endif %}
|
||||
|
||||
<hr />
|
||||
|
|