Initial villages feature

This commit is contained in:
Víðir Valberg Guðmundsson 2016-07-05 23:43:18 +02:00
parent fe0bc14ac1
commit 8786b5af88
16 changed files with 254 additions and 13 deletions

View file

@ -29,6 +29,7 @@ INSTALLED_APPS = [
'shop', 'shop',
'news', 'news',
'utils', 'utils',
'villages',
'allauth', 'allauth',
'allauth.account', 'allauth.account',

View file

@ -42,19 +42,8 @@
{% if current_camp.shop_open %} {% if current_camp.shop_open %}
<li><a href="{% url 'shop:index' %}">Shop</a></li> <li><a href="{% url 'shop:index' %}">Shop</a></li>
{% if current_order and current_order.get_number_of_items %}
<li>
<a href="{% url 'shop:order_detail' pk=current_order.pk %}">
<i class="glyphicon glyphicon-shopping-cart"></i>
<span class="badge">
{{ current_order.get_number_of_items }}
</span>
</a>
</li>
{% endif %}
{% endif %} {% endif %}
<li><a href="{% url 'villages:list' %}">Villages</a></li>
<li><a href="{% url 'call-for-speakers' %}">Speakers</a></li> <li><a href="{% url 'call-for-speakers' %}">Speakers</a></li>
<li><a href="{% url 'call-for-sponsors' %}">Sponsors</a></li> <li><a href="{% url 'call-for-sponsors' %}">Sponsors</a></li>
<li><a href="{% url 'contact' %}">Contact</a></li> <li><a href="{% url 'contact' %}">Contact</a></li>

View file

@ -74,6 +74,10 @@ 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'^accounts/', include('allauth.urls')), url(r'^accounts/', include('allauth.urls')),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
] ]

View file

@ -19,7 +19,21 @@
{% if has_tickets %} {% if has_tickets %}
<li class="pull-right"><a href="{% url 'shop:ticket_list' %}">Tickets</a></li> <li class="pull-right"><a href="{% url 'shop:ticket_list' %}">Tickets</a></li>
{% endif %} {% endif %}
<li class="pull-right no-before"><a href="{% url 'shop:order_list' %}">Orders</a></li> <li class="pull-right"><a href="{% url 'shop:order_list' %}">Orders</a></li>
<li class="pull-right no-before">
{% if current_order and current_order.get_number_of_items %}
<a href="{% url 'shop:order_detail' pk=current_order.pk %}">
{% endif %}
<i class="glyphicon glyphicon-shopping-cart"></i>
<span class="badge">
{{ current_order.get_number_of_items|default:0 }}
</span>
{% if current_order and current_order.get_number_of_items %}
</a>
{% endif %}
</li>
{% endif %} {% endif %}
</ol> </ol>
</div> </div>

0
villages/__init__.py Normal file
View file

8
villages/admin.py Normal file
View file

@ -0,0 +1,8 @@
from django.contrib import admin
from .models import Village
@admin.register(Village)
class VillageAdmin(admin.ModelAdmin):
pass

7
villages/apps.py Normal file
View file

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

View file

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.6 on 2016-07-05 21:38
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
('camps', '0005_auto_20160510_2011'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Village',
fields=[
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('created', models.DateTimeField(auto_now_add=True)),
('updated', models.DateTimeField(auto_now=True)),
('name', models.CharField(max_length=255)),
('slug', models.SlugField(blank=True, max_length=255)),
('description', models.TextField()),
('open', models.BooleanField(default=False, help_text='Is this village open for others to join?')),
('camp', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='camps.Camp')),
('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
options={
'ordering': ['name'],
},
),
]

View file

58
villages/models.py Normal file
View file

@ -0,0 +1,58 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse_lazy
from django.db import models
from django.utils.text import slugify
from camps.models import Camp
from utils.models import CreatedUpdatedModel, UUIDModel
class Village(CreatedUpdatedModel, UUIDModel):
class Meta:
ordering = ['name']
camp = models.ForeignKey('camps.Camp')
contact = models.ForeignKey('auth.User')
name = models.CharField(max_length=255)
slug = models.SlugField(max_length=255, blank=True)
description = models.TextField()
open = models.BooleanField(
default=False,
help_text='Is this village open for others to join?'
)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse_lazy('villages:detail', kwargs={'slug': self.slug})
def save(self, **kwargs):
if (
not self.pk or
not self.slug or
Village.objects.filter(slug=self.slug).count() > 1
):
slug = slugify(self.name)
incrementer = 1
# We have to make sure that the slug won't clash with current slugs
while Village.objects.filter(slug=slug).exists():
if incrementer == 1:
slug = '{}-1'.format(slug)
else:
slug = '{}-{}'.format(
'-'.join(slug.split('-')[:-1]),
incrementer
)
incrementer += 1
self.slug = slug
if not hasattr(self, 'camp'):
self.camp = Camp.objects.current()
super(Village, self).save(**kwargs)

View file

@ -0,0 +1,16 @@
{% extends 'base.html' %}
{% load commonmark %}
{% block content %}
<h3>{{ village.name }}</h3>
{{ village.description|commonmark }}
<hr />
{% if user in village.users.all %}
<a href="{% url 'villages:update' slug=village.slug %}">Edit</a>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,16 @@
{% extends 'base.html' %}
{% load bootstrap3 %}
{% block content %}
<form method="post">
{% csrf_token %}
{% bootstrap_form form %}
<hr />
<button class="btn btn-primary pull-right" type="submit">Save</button>
</form>
{% endblock %}

View file

@ -0,0 +1,38 @@
{% extends 'base.html' %}
{% block content %}
<p>
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 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>
{% if user.is_authenticated %}
<a href="{% url 'villages:create' %}" class="btn btn-primary">Create a village</a>
{% endif %}
<hr />
<table class="table table-hover table-condensed table-striped">
<thead>
<tr>
<th>Name</th>
<th>Price</th>
</tr>
</thead>
<tbody>
{% for village in villages %}
<tr>
<td>
<a href="{% url 'villages:detail' slug=village.slug %}">
{{ village.name }}
</a>
</td>
<td>
{{ village.description|truncatewords:15 }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

3
villages/tests.py Normal file
View file

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

9
villages/urls.py Normal file
View file

@ -0,0 +1,9 @@
from django.conf.urls import url
from views import *
urlpatterns = [
url(r'^$', VillageListView.as_view(), name='list'),
url(r'create/$', VillageCreateView.as_view(), name='create'),
url(r'(?P<slug>[-_\w+]+)/edit/$', VillageUpdateView.as_view(), name='update'),
url(r'(?P<slug>[-_\w+]+)/$', VillageDetailView.as_view(), name='detail'),
]

40
villages/views.py Normal file
View file

@ -0,0 +1,40 @@
from django.core.urlresolvers import reverse_lazy
from django.http import HttpResponseRedirect
from django.views.generic import ListView, DetailView, CreateView, UpdateView
from .models import (
Village,
)
class VillageListView(ListView):
model = Village
template_name = 'village_list.html'
context_object_name = 'villages'
class VillageDetailView(DetailView):
model = Village
template_name = 'village_detail.html'
context_object_name = 'village'
class VillageCreateView(CreateView):
model = Village
template_name = 'village_form.html'
fields = ['name', 'description', 'open']
success_url = reverse_lazy('villages:list')
def form_valid(self, form):
village = form.save(commit=False)
village.contact = self.request.user
village.save()
return HttpResponseRedirect(village.get_absolute_url())
class VillageUpdateView(UpdateView):
model = Village
template_name = 'village_form.html'
fields = ['name', 'description', 'open']
def get_success_url(self):
return self.get_object().get_absolute_url()