Add first version of a wishlist app - create wishes in the admin for now. Fix a few unrelated things while here: update our date and time formats to be more internationally unambigous, and always show timezone. Also fix an old bug which meant that bornhack.dk/program redirect never worked. (#445)
This commit is contained in:
parent
575324f3cc
commit
95b41bdd44
|
@ -50,6 +50,7 @@ INSTALLED_APPS = [
|
|||
"tokens",
|
||||
"feedback",
|
||||
"economy",
|
||||
"wishlist",
|
||||
"allauth",
|
||||
"allauth.account",
|
||||
"allauth_2fa",
|
||||
|
@ -69,10 +70,10 @@ LANGUAGE_CODE = "en-us"
|
|||
# USE_I18N = True
|
||||
# USE_L10N = True
|
||||
USE_TZ = True
|
||||
SHORT_DATE_FORMAT = "d/m-Y"
|
||||
DATE_FORMAT = "d/m-Y"
|
||||
DATETIME_FORMAT = "d/m-Y H:i"
|
||||
TIME_FORMAT = "H:i"
|
||||
SHORT_DATE_FORMAT = "Ymd"
|
||||
DATE_FORMAT = "l, M jS, Y"
|
||||
DATETIME_FORMAT = "l, M jS, Y, H:i (e)"
|
||||
TIME_FORMAT = "H:i (e)"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
|
|
|
@ -63,7 +63,7 @@ urlpatterns = [
|
|||
path(
|
||||
"program/",
|
||||
CampRedirectView.as_view(),
|
||||
kwargs={"page": "schedule_index"},
|
||||
kwargs={"page": "program:schedule_index"},
|
||||
name="schedule_index_redirect",
|
||||
),
|
||||
path(
|
||||
|
@ -84,6 +84,12 @@ urlpatterns = [
|
|||
kwargs={"page": "village_list"},
|
||||
name="village_list_redirect",
|
||||
),
|
||||
path(
|
||||
"wishlist/",
|
||||
CampRedirectView.as_view(),
|
||||
kwargs={"page": "wishlist:list"},
|
||||
name="wish_list_redirect",
|
||||
),
|
||||
path("people/", PeopleView.as_view(), name="people"),
|
||||
# camp specific urls below here
|
||||
path(
|
||||
|
@ -129,6 +135,7 @@ urlpatterns = [
|
|||
path("backoffice/", include("backoffice.urls", namespace="backoffice")),
|
||||
path("feedback/", FeedbackCreate.as_view(), name="feedback"),
|
||||
path("economy/", include("economy.urls", namespace="economy")),
|
||||
path("wishlist/", include("wishlist.urls", namespace="wishlist")),
|
||||
]
|
||||
),
|
||||
),
|
||||
|
|
|
@ -18,7 +18,7 @@ News | {{ block.super }}
|
|||
{% 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>
|
||||
<h3><a href="{% url 'news:detail' slug=item.slug %}">{{ item.title }}</a> <small>{{ item.published_at }}</small></h3>
|
||||
</div>
|
||||
{{ item.content|trustedcommonmark }}
|
||||
{% if not forloop.last %}
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
</li>
|
||||
<li><a href="{% url 'contact' %}">Contact</a></li>
|
||||
<li><a href="{% url 'people' %}">People</a></li>
|
||||
<li><a href="{% url 'wish_list_redirect' %}">Wishlist</a></li>
|
||||
{% if request.user.is_staff %}
|
||||
<li><a href="{% url 'admin:index' %}">Django Admin</a></li>
|
||||
{% endif %}
|
||||
|
|
0
src/wishlist/__init__.py
Normal file
0
src/wishlist/__init__.py
Normal file
8
src/wishlist/admin.py
Normal file
8
src/wishlist/admin.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django.contrib import admin
|
||||
|
||||
from .models import Wish
|
||||
|
||||
@admin.register(Wish)
|
||||
class WishAdmin(admin.ModelAdmin):
|
||||
pass
|
||||
|
5
src/wishlist/apps.py
Normal file
5
src/wishlist/apps.py
Normal file
|
@ -0,0 +1,5 @@
|
|||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class WishlistConfig(AppConfig):
|
||||
name = 'wishlist'
|
33
src/wishlist/migrations/0001_initial.py
Normal file
33
src/wishlist/migrations/0001_initial.py
Normal file
|
@ -0,0 +1,33 @@
|
|||
# Generated by Django 3.0.3 on 2020-02-09 18:24
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('teams', '0051_auto_20190312_1129'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Wish',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', models.DateTimeField(auto_now_add=True)),
|
||||
('updated', models.DateTimeField(auto_now=True)),
|
||||
('name', models.CharField(help_text='Short description of the wish', max_length=100)),
|
||||
('slug', models.SlugField(help_text='The url slug for this wish')),
|
||||
('description', models.TextField(help_text='Description of the needed item. Markdown is supported!')),
|
||||
('count', models.IntegerField(default=1, help_text='How many do we need?')),
|
||||
('fulfilled', models.BooleanField(default=False, help_text='A Wish is marked as fulfilled when we no longer need the thing.')),
|
||||
('team', models.ForeignKey(help_text='The team that needs this thing. When in doubt pick Orga :)', on_delete=django.db.models.deletion.PROTECT, related_name='wishes', to='teams.Team')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
0
src/wishlist/migrations/__init__.py
Normal file
0
src/wishlist/migrations/__init__.py
Normal file
66
src/wishlist/models.py
Normal file
66
src/wishlist/models.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.text import slugify
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from utils.models import CampRelatedModel
|
||||
|
||||
|
||||
class Wish(CampRelatedModel):
|
||||
"""
|
||||
This model contains the stuff BornHack needs. This can be anything from kitchen equipment
|
||||
to network cables, or anything really.
|
||||
"""
|
||||
name = models.CharField(
|
||||
max_length=100,
|
||||
help_text="Short description of the wish",
|
||||
)
|
||||
|
||||
slug = models.SlugField(
|
||||
blank=True,
|
||||
help_text="The url slug for this wish. Leave blank to autogenerate one.",
|
||||
)
|
||||
|
||||
description = models.TextField(
|
||||
help_text="Description of the needed item. Markdown is supported!"
|
||||
)
|
||||
|
||||
count = models.IntegerField(
|
||||
default=1,
|
||||
help_text="How many do we need?",
|
||||
)
|
||||
|
||||
fulfilled = models.BooleanField(
|
||||
default=False,
|
||||
help_text="A Wish is marked as fulfilled when we no longer need the thing.",
|
||||
)
|
||||
|
||||
team = models.ForeignKey(
|
||||
"teams.Team",
|
||||
help_text="The team that needs this thing. When in doubt pick Orga :)",
|
||||
on_delete=models.PROTECT,
|
||||
related_name="wishes",
|
||||
)
|
||||
|
||||
@property
|
||||
def camp(self):
|
||||
return self.team.camp
|
||||
|
||||
camp_filter = "team__camp"
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def save(self, **kwargs):
|
||||
print("inside save()")
|
||||
if not self.slug:
|
||||
self.slug = slugify(self.name)
|
||||
if not self.slug:
|
||||
raise ValidationError("Unable to slugify")
|
||||
super().save(**kwargs)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("wishlist:detail", kwargs={
|
||||
"camp_slug": self.camp.slug,
|
||||
"wish_slug": self.slug,
|
||||
})
|
19
src/wishlist/templates/wish_detail.html
Normal file
19
src/wishlist/templates/wish_detail.html
Normal file
|
@ -0,0 +1,19 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load commonmark %}
|
||||
|
||||
{% block title %}
|
||||
Wish List | {{ block.super }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>BornHack Wish: {{ wish.name }}</h2>
|
||||
|
||||
<p class="lead">{{ wish.description }}</p>
|
||||
|
||||
<p class="lead">Number needed: {{ wish.count }}</p>
|
||||
|
||||
<p class="lead"><i>This wish was created by the <a href="{% url 'teams:general' camp_slug=wish.team.camp.slug team_slug=wish.team.slug %}">{{ wish.team.name }} Team</a> for {{ wish.team.camp.title }} on {{ wish.created }}. If you can help please visit their <a href="{% url 'teams:general' camp_slug=wish.camp.slug team_slug=wish.team.slug %}">team page</a> for contact info!</i></p>
|
||||
|
||||
<a class="btn btn-primary" href="{% url 'wish_list_redirect' %}"><i class="fas fa-undo"></i> Back to Wish List</a>
|
||||
{% endblock %}
|
43
src/wishlist/templates/wish_list.html
Normal file
43
src/wishlist/templates/wish_list.html
Normal file
|
@ -0,0 +1,43 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
{% load commonmark %}
|
||||
|
||||
{% block title %}
|
||||
Wish List | {{ block.super }}
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
<h2>BornHack Wishlist</h2>
|
||||
|
||||
<p class="lead">
|
||||
This is a list of things the different BornHack teams need. If you own
|
||||
something on the list and you would like to donate it to BornHack then please
|
||||
don't hesitate to contact the team in question. Partial donations are also welcome,
|
||||
so if a team needs 10 of something and you have 5 then we still want to hear from you.
|
||||
When we no longer need something it will be removed from this list.
|
||||
</p>
|
||||
|
||||
<table class="table table-hover table-striped">
|
||||
<tr>
|
||||
<th>Wish</th>
|
||||
<th>Team</th>
|
||||
<th>Description</th>
|
||||
<th>Number</th>
|
||||
<th>Created</th>
|
||||
</tr>
|
||||
{% for wish in wish_list %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{% url 'wishlist:detail' camp_slug=camp.slug wish_slug=wish.slug %}">{{ wish.name }}</a>
|
||||
</td>
|
||||
<td>{{ wish.team.name }} Team</td>
|
||||
<td>{{ wish.description|trustedcommonmark }}</td>
|
||||
<td>{{ wish.count }}</td>
|
||||
<td>{{ wish.created }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
3
src/wishlist/tests.py
Normal file
3
src/wishlist/tests.py
Normal file
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
9
src/wishlist/urls.py
Normal file
9
src/wishlist/urls.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from django.urls import path
|
||||
from .views import WishListView, WishDetailView
|
||||
|
||||
|
||||
app_name = "wishlist"
|
||||
urlpatterns = [
|
||||
path("", WishListView.as_view(), name="list"),
|
||||
path("<slug:wish_slug>/", WishDetailView.as_view(), name="detail"),
|
||||
]
|
16
src/wishlist/views.py
Normal file
16
src/wishlist/views.py
Normal file
|
@ -0,0 +1,16 @@
|
|||
from django.shortcuts import render
|
||||
from django.views.generic import ListView, DetailView
|
||||
|
||||
from .models import Wish
|
||||
|
||||
|
||||
class WishListView(ListView):
|
||||
model = Wish
|
||||
template_name = "wish_list.html"
|
||||
|
||||
|
||||
class WishDetailView(DetailView):
|
||||
model = Wish
|
||||
template_name = "wish_detail.html"
|
||||
slug_url_kwarg = "wish_slug"
|
||||
|
Loading…
Reference in a new issue