From 95b41bdd44a9115e773b525ee0be7f2045fd553a Mon Sep 17 00:00:00 2001 From: Thomas Steen Rasmussen Date: Thu, 13 Feb 2020 22:07:28 +0100 Subject: [PATCH] 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) --- src/bornhack/settings.py | 9 ++-- src/bornhack/urls.py | 9 +++- src/news/templates/news_index.html | 2 +- src/templates/base.html | 1 + src/wishlist/__init__.py | 0 src/wishlist/admin.py | 8 +++ src/wishlist/apps.py | 5 ++ src/wishlist/migrations/0001_initial.py | 33 +++++++++++++ src/wishlist/migrations/__init__.py | 0 src/wishlist/models.py | 66 +++++++++++++++++++++++++ src/wishlist/templates/wish_detail.html | 19 +++++++ src/wishlist/templates/wish_list.html | 43 ++++++++++++++++ src/wishlist/tests.py | 3 ++ src/wishlist/urls.py | 9 ++++ src/wishlist/views.py | 16 ++++++ 15 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 src/wishlist/__init__.py create mode 100644 src/wishlist/admin.py create mode 100644 src/wishlist/apps.py create mode 100644 src/wishlist/migrations/0001_initial.py create mode 100644 src/wishlist/migrations/__init__.py create mode 100644 src/wishlist/models.py create mode 100644 src/wishlist/templates/wish_detail.html create mode 100644 src/wishlist/templates/wish_list.html create mode 100644 src/wishlist/tests.py create mode 100644 src/wishlist/urls.py create mode 100644 src/wishlist/views.py diff --git a/src/bornhack/settings.py b/src/bornhack/settings.py index 9892513c..fe5df780 100644 --- a/src/bornhack/settings.py +++ b/src/bornhack/settings.py @@ -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 = [ { diff --git a/src/bornhack/urls.py b/src/bornhack/urls.py index 3cc9b032..e715cc32 100644 --- a/src/bornhack/urls.py +++ b/src/bornhack/urls.py @@ -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")), ] ), ), diff --git a/src/news/templates/news_index.html b/src/news/templates/news_index.html index 382af7c0..fd1c2435 100644 --- a/src/news/templates/news_index.html +++ b/src/news/templates/news_index.html @@ -18,7 +18,7 @@ News | {{ block.super }} {% endif %} {% for item in news_items %}
-

{{ item.title }} {{ item.published_at|date:"Y-m-d" }}

+

{{ item.title }} {{ item.published_at }}

{{ item.content|trustedcommonmark }} {% if not forloop.last %} diff --git a/src/templates/base.html b/src/templates/base.html index 8a1e19e1..1bb10e6f 100644 --- a/src/templates/base.html +++ b/src/templates/base.html @@ -75,6 +75,7 @@
  • Contact
  • People
  • +
  • Wishlist
  • {% if request.user.is_staff %}
  • Django Admin
  • {% endif %} diff --git a/src/wishlist/__init__.py b/src/wishlist/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/wishlist/admin.py b/src/wishlist/admin.py new file mode 100644 index 00000000..01a50130 --- /dev/null +++ b/src/wishlist/admin.py @@ -0,0 +1,8 @@ +from django.contrib import admin + +from .models import Wish + +@admin.register(Wish) +class WishAdmin(admin.ModelAdmin): + pass + diff --git a/src/wishlist/apps.py b/src/wishlist/apps.py new file mode 100644 index 00000000..6c0d16f1 --- /dev/null +++ b/src/wishlist/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class WishlistConfig(AppConfig): + name = 'wishlist' diff --git a/src/wishlist/migrations/0001_initial.py b/src/wishlist/migrations/0001_initial.py new file mode 100644 index 00000000..227c421e --- /dev/null +++ b/src/wishlist/migrations/0001_initial.py @@ -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, + }, + ), + ] diff --git a/src/wishlist/migrations/__init__.py b/src/wishlist/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/src/wishlist/models.py b/src/wishlist/models.py new file mode 100644 index 00000000..bbf0dd5b --- /dev/null +++ b/src/wishlist/models.py @@ -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, + }) diff --git a/src/wishlist/templates/wish_detail.html b/src/wishlist/templates/wish_detail.html new file mode 100644 index 00000000..4cfb6f2a --- /dev/null +++ b/src/wishlist/templates/wish_detail.html @@ -0,0 +1,19 @@ +{% extends 'base.html' %} +{% load static %} +{% load commonmark %} + +{% block title %} +Wish List | {{ block.super }} +{% endblock %} + +{% block content %} +

    BornHack Wish: {{ wish.name }}

    + +

    {{ wish.description }}

    + +

    Number needed: {{ wish.count }}

    + +

    This wish was created by the {{ wish.team.name }} Team for {{ wish.team.camp.title }} on {{ wish.created }}. If you can help please visit their team page for contact info!

    + + Back to Wish List +{% endblock %} diff --git a/src/wishlist/templates/wish_list.html b/src/wishlist/templates/wish_list.html new file mode 100644 index 00000000..52696ac8 --- /dev/null +++ b/src/wishlist/templates/wish_list.html @@ -0,0 +1,43 @@ +{% extends 'base.html' %} +{% load static %} +{% load commonmark %} + +{% block title %} +Wish List | {{ block.super }} +{% endblock %} + + +{% block content %} + +

    BornHack Wishlist

    + +

    + 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. +

    + + + + + + + + + + {% for wish in wish_list %} + + + + + + + + {% endfor %} +
    WishTeamDescriptionNumberCreated
    + {{ wish.name }} + {{ wish.team.name }} Team{{ wish.description|trustedcommonmark }}{{ wish.count }}{{ wish.created }}
    + +{% endblock %} diff --git a/src/wishlist/tests.py b/src/wishlist/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/src/wishlist/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/src/wishlist/urls.py b/src/wishlist/urls.py new file mode 100644 index 00000000..db3db135 --- /dev/null +++ b/src/wishlist/urls.py @@ -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("/", WishDetailView.as_view(), name="detail"), +] diff --git a/src/wishlist/views.py b/src/wishlist/views.py new file mode 100644 index 00000000..6c4c9ce1 --- /dev/null +++ b/src/wishlist/views.py @@ -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" +