Compare commits

...

42 commits

Author SHA1 Message Date
Benjamin bc440dfa2a Add restrictions for editing recipe title 2023-03-11 18:20:22 +01:00
Benjamin 8f79bf5dd2 Limit version editing to creator and superusers 2023-03-11 17:52:44 +01:00
Benjamin f38fb8d410 refactor 2023-03-07 19:09:53 +01:00
Benjamin 45b5d9d0eb versions need a user 2023-03-06 18:19:47 +01:00
Benjamin 13c0670d0d refactor edit_version view fun 2023-03-06 18:16:22 +01:00
Benjamin 21413af8d4 anybody can read versions 2023-03-06 17:58:34 +01:00
Benjamin c61f69b26a always enforce version URI 2023-03-06 17:58:25 +01:00
Benjamin 3d2f97b50f remove explicit permission checks 2023-03-06 17:53:01 +01:00
Benjamin ebd397f351 minor 2023-03-06 17:49:57 +01:00
Benjamin a78be3378b refactor 2023-03-06 17:48:51 +01:00
Benjamin b2244e6deb Add color-scheme meta tag 2023-03-05 19:59:29 +01:00
Benjamin 61c206be3d Add missing file 2023-03-05 19:55:06 +01:00
Benjamin de2fb7dc9c add edit-recipe-name 2023-03-05 19:53:56 +01:00
Benjamin 41d8a54132 fixup! refactor author placeholder function 2023-03-05 19:33:05 +01:00
Benjamin 0071f4aac7 small refactor 2023-03-05 19:30:43 +01:00
Benjamin 65052ed6e7 refactor author placeholder function 2023-03-05 19:24:58 +01:00
Benjamin b6af65e915 Implement add recipe with version 2023-03-05 19:20:07 +01:00
Benjamin 11a8698a6f Fix version author placeholder 2023-03-05 19:00:48 +01:00
Benjamin b3ef2853b6 Fix bug: initial version data in view 2023-03-05 18:52:32 +01:00
Benjamin fff2d0b345 Delete unnecessary initial data 2023-03-05 18:42:05 +01:00
Benjamin 818df6f263 add TODOs 2023-03-04 13:13:08 +01:00
Benjamin bb01945c6c fixup! Add forms for adding recipes and versions
fix slug bug
2023-03-03 22:21:53 +01:00
Benjamin deb8d339d6 fixup! Add forms for adding recipes and versions
implement edit version with bug where editing and saving yields existing
slug error
2023-03-02 22:01:32 +01:00
Benjamin c0a8ba031f fixup! Add forms for adding recipes and versions
rename to author
2023-03-02 19:43:04 +01:00
Benjamin 38b7d20f29 fixup! Add forms for adding recipes and versions
simple alternative author input
2023-03-02 19:05:34 +01:00
Benjamin 99594a7e14 fixup! Add forms for adding recipes and versions
rename to alternative author
2023-03-02 18:58:21 +01:00
Benjamin 8705473454 fixup! Add forms for adding recipes and versions
rename to user
2023-03-02 18:54:26 +01:00
Benjamin adb67386af fixup! Add forms for adding recipes and versions
Add author name option
2023-02-26 23:23:01 +01:00
Benjamin 37f69e7364 fixup! Add forms for adding recipes and versions
No initial fields on second version
2023-02-26 22:15:39 +01:00
Benjamin bfb5e36d03 fixup! Add forms for adding recipes and versions
Add ingredients with text only
2023-02-26 22:06:05 +01:00
Benjamin b8000c6ce4 fixup! Add forms for adding recipes and versions
Add ingredients to version
2023-02-19 20:51:17 +01:00
Benjamin d9b1837f66 fixup! Add forms for adding recipes and versions
fix slug uniqueness testing
2023-02-19 14:23:04 +01:00
Benjamin 312c02cd51 fixup! Add forms for adding recipes and versions
Check for slug uniqueness
2023-02-19 11:22:41 +01:00
Benjamin acbcf3f606 fixup! Add forms for adding recipes and versions
Basic form for adding a version. Still needs:

* Check of slug uniqueness
* Choose between author user or author name
* slug auto-creation
* ingredients

TODO:

* Add recipe
2023-02-17 16:41:22 +01:00
Benjamin 6853be4ed5 Add forms for adding recipes and versions 2023-02-17 16:37:42 +01:00
Benjamin b898bc3ba5 Add recipe and version HTMLs for viewing 2023-02-17 16:37:13 +01:00
Benjamin e8eb37a558 Start App Recipes 2023-02-17 16:37:03 +01:00
Benjamin 2a93408179 Change not authorized message 2023-01-04 15:03:27 +01:00
Benjamin cf63cc2344 Add index.html as home 2022-12-28 10:58:23 +01:00
Benjamin 3e726644ac Very basic profile view 2022-12-26 17:30:26 +01:00
Benjamin 2acfcb29e9 Introduce base_main.html for <main> 2022-12-21 20:57:45 +01:00
Benjamin 1cc8f602a8 Implement new-user and login 2022-12-20 21:31:22 +01:00
26 changed files with 623 additions and 2 deletions

0
recipes/__init__.py Normal file
View file

6
recipes/admin.py Normal file
View file

@ -0,0 +1,6 @@
from django.contrib import admin
from .models import Recipe, Version, Ingredient
admin.site.register(Recipe)
admin.site.register(Version)
admin.site.register(Ingredient)

6
recipes/apps.py Normal file
View file

@ -0,0 +1,6 @@
from django.apps import AppConfig
class RecipesConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'recipes'

37
recipes/forms.py Normal file
View file

@ -0,0 +1,37 @@
from django.forms import ModelForm, ValidationError, modelformset_factory, BooleanField
from .models import Recipe, Version, Ingredient
class RecipeForm(ModelForm):
class Meta:
model = Recipe
fields = ['title', 'slug']
class VersionForm(ModelForm):
recipe_id: int
def __init__(self, *args, **kwargs):
placeholder = None
if 'author_placeholder' in kwargs:
placeholder = kwargs.pop('author_placeholder')
super().__init__(*args, **kwargs)
if placeholder:
self.fields['author'].widget.attrs.update({'placeholder': placeholder})
class Meta:
model = Version
fields = ['label', 'slug', 'body', 'author']
def clean_slug(self):
slug = self.cleaned_data['slug']
if 'slug' in self.changed_data:
recipe = Recipe.objects.get(id=self.recipe_id)
if recipe.versions.filter(slug=slug).count() > 0: # type: ignore
raise ValidationError('A recipe version with this slug already exists.')
return slug
class IngredientForm(ModelForm):
class Meta:
model = Ingredient
fields = ['text']
IngredientFormSet = modelformset_factory(Ingredient, fields=('text',), extra=1)

View file

34
recipes/models.py Normal file
View file

@ -0,0 +1,34 @@
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
class Recipe(models.Model):
title = models.CharField(max_length=100, null=False, blank=False)
slug = models.SlugField(unique=True)
def __str__(self) -> str:
return self.title
def get_absolute_url(self):
return reverse('recipe', kwargs={'slug': self.slug})
class Version(models.Model):
label = models.CharField(max_length=20, default='Original')
slug = models.SlugField(max_length=20, default='original')
body = models.TextField(null=True, blank=True)
user = models.ForeignKey(User, on_delete=models.PROTECT, null=False, blank=False)
author = models.CharField(max_length=30, blank=True)
recipe = models.ForeignKey(Recipe, on_delete=models.PROTECT, null=False, blank=False, related_name='versions')
def __str__(self) -> str:
return self.recipe.title + ' - ' + self.label
def get_absolute_url(self):
return reverse('version', kwargs={'slug_recipe': self.recipe.slug, 'slug_version': self.slug})
class Ingredient(models.Model):
text = models.CharField(max_length=50, null=False, blank=False)
version = models.ForeignKey(Version, on_delete=models.CASCADE, null=False, blank=False, related_name='ingredients')
def __str__(self) -> str:
return self.text + ' for ' + str(self.version)

View file

@ -0,0 +1,41 @@
{% extends "base_main.html" %}
{% block title %}{{ recipe.title }}{% endblock %}
{% block main %}
<form action="" method="post" id="add-version-form">
{%csrf_token %}
{{ recipe_form.as_div }}
<table>
{{ version_form.as_table }}
</table>
{{ ingredients_formset.management_form }}
{% for ingredient_form in ingredients_formset %}
{{ ingredient_form.as_div }}
{% endfor %}
<button id="add-ingredient" type="button">Add Ingredient</button>
<input type="submit" value="Submit">
</form>
<script>
let firstIngredientDiv = document.querySelector("input[id^=id_ingredient][id$=text]").parentElement;
let addIngredientButton = document.querySelector("#add-ingredient");
let form = document.querySelector("#add-version-form");
let totalIngredientFormsInput = document.querySelector("#id_ingredient-TOTAL_FORMS");
addIngredientButton.addEventListener('click', addIngredient);
function addIngredient(e) {
let nextIngredientIndex = document.querySelectorAll("input[id^=id_ingredient][id$=text]").length
e.preventDefault();
let newIngredientDiv = firstIngredientDiv.cloneNode(true);
let formRegex = new RegExp('ingredient-(\\d){1}-', 'g');
newIngredientDiv.innerHTML = newIngredientDiv.innerHTML.replace(formRegex, `ingredient-${nextIngredientIndex}-`);
form.insertBefore(newIngredientDiv, addIngredientButton);
totalIngredientFormsInput.setAttribute('value', `${nextIngredientIndex + 1}`);
}
</script>
{% endblock %}

View file

@ -0,0 +1,40 @@
{% extends "base_main.html" %}
{% block title %}{{ recipe.title }}{% endblock %}
{% block main %}
<form action="" method="post" id="add-version-form">
{%csrf_token %}
<table>
{{ version_form.as_table }}
</table>
{{ ingredients_formset.management_form }}
{% for ingredient_form in ingredients_formset %}
{{ ingredient_form.as_div }}
{% endfor %}
<button id="add-ingredient" type="button">Add Ingredient</button>
<input type="submit" value="Submit">
</form>
<script>
let firstIngredientDiv = document.querySelector("input[id^=id_ingredient][id$=text]").parentElement;
let addIngredientButton = document.querySelector("#add-ingredient");
let form = document.querySelector("#add-version-form");
let totalIngredientFormsInput = document.querySelector("#id_ingredient-TOTAL_FORMS");
addIngredientButton.addEventListener('click', addIngredient);
function addIngredient(e) {
let nextIngredientIndex = document.querySelectorAll("input[id^=id_ingredient][id$=text]").length
e.preventDefault();
let newIngredientDiv = firstIngredientDiv.cloneNode(true);
let formRegex = new RegExp('ingredient-(\\d){1}-', 'g');
newIngredientDiv.innerHTML = newIngredientDiv.innerHTML.replace(formRegex, `ingredient-${nextIngredientIndex}-`);
form.insertBefore(newIngredientDiv, addIngredientButton);
totalIngredientFormsInput.setAttribute('value', `${nextIngredientIndex + 1}`);
}
</script>
{% endblock %}

View file

@ -0,0 +1,10 @@
{% extends "base_main.html" %}
{% block title %}{{ recipe.title }}{% endblock %}
{% block main %}
<form action="" method="post">
{%csrf_token %}
{{ form.as_div }}
<input type="submit" value="Submit">
</form>
{% endblock %}

View file

@ -0,0 +1,40 @@
{% extends "base_main.html" %}
{% block title %}{{ recipe.title }}{% endblock %}
{% block main %}
<form action="" method="post" id="edit-version-form"> <!-- TODO refactor with add-version.html-->
{%csrf_token %}
<table>
{{ version_form.as_table }}
</table>
{{ ingredients_formset.management_form }}
{% for ingredient_form in ingredients_formset %}
{{ ingredient_form.as_div }}
{% endfor %}
<button id="add-ingredient" type="button">Add Ingredient</button>
<input type="submit" value="Submit">
</form>
<script>
let firstIngredientDiv = document.querySelector("input[id^=id_ingredient][id$=text]").parentElement;
let addIngredientButton = document.querySelector("#add-ingredient");
let form = document.querySelector("#edit-version-form");
let totalIngredientFormsInput = document.querySelector("#id_ingredient-TOTAL_FORMS");
addIngredientButton.addEventListener('click', addIngredient);
function addIngredient(e) {
let nextIngredientIndex = document.querySelectorAll("input[id^=id_ingredient][id$=text]").length
e.preventDefault();
let newIngredientDiv = firstIngredientDiv.cloneNode(true);
let formRegex = new RegExp('ingredient-(\\d){1}-', 'g');
newIngredientDiv.innerHTML = newIngredientDiv.innerHTML.replace(formRegex, `ingredient-${nextIngredientIndex}-`);
form.insertBefore(newIngredientDiv, addIngredientButton);
totalIngredientFormsInput.setAttribute('value', `${nextIngredientIndex + 1}`);
}
</script>
{% endblock %}

View file

@ -0,0 +1,12 @@
{% extends "base_main.html" %}
{% block title %}{{ recipe.title }}{% endblock %}
{% block main %}
<h1>{{ recipe.title }}</h1>
<p><a href="{% url 'edit-recipe' recipe.slug %}">Edit recipe name</a></p>
<p><a href="{% url 'add-version' recipe.slug %}">Add version</a></p>
<ul>
{% for v in versions %}
<li><a href="{{ v.get_absolute_url }}">{{ v.label }}</a></li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -0,0 +1,11 @@
{% extends "base_main.html" %}
{% block title %}Recipes{% endblock %}
{% block main %}
<h1>Recipes</h1>
<p><a href="{% url 'add-recipe' %}">Add recipe</a></p>
<ul>
{% for recipe in recipes %}
<li><a href="{{ recipe.get_absolute_url }}">{{ recipe.title }}</a></li>
{% endfor %}
</ul>
{% endblock %}

View file

@ -0,0 +1,17 @@
{% extends "base_main.html" %}
{% block title %}{{ recipe.title }}{% endblock %}
{% block main %}
<h1>{{ version.recipe.title }}{% if has_multiple_versions %} ({{ version.label }}){% endif %}</h1>
{% if has_multiple_versions %}
<p><a href="{{ recipe.get_absolute_url }}">Show all versions</a></p>
{% endif %}
<p><a href="{% url 'edit-recipe' recipe.slug %}">Edit recipe name</a></p>
<p><a href="{% url 'add-version' recipe.slug %}">Add version</a></p>
<p><a href="{% url 'edit-version' recipe.slug version.slug %}">Edit Version</a></p>
<ul>
{% for i in ingredients %}
<li>{{ i.text }}</li>
{% endfor %}
</ul>
<p>{{ version.body }}</p>
{% endblock %}

3
recipes/tests.py Normal file
View file

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

12
recipes/urls.py Normal file
View file

@ -0,0 +1,12 @@
from django.urls import path
from . import views
urlpatterns = [
path('', views.recipes, name='recipes'),
path('add-recipe/', views.add_recipe, name='add-recipe'),
path('<slug:slug>/add-version/', views.add_version, name='add-version'),
path('<slug:slug>/edit-recipe/', views.edit_recipe, name='edit-recipe'),
path('<slug:slug_recipe>/<slug:slug_version>/edit-version/', views.edit_version, name='edit-version'),
path('<slug:slug_recipe>/<slug:slug_version>/', views.version, name='version'),
path('<slug:slug>/', views.recipe, name='recipe'),
]

148
recipes/views.py Normal file
View file

@ -0,0 +1,148 @@
from django.shortcuts import render, get_object_or_404, redirect
from .models import Recipe, Version, Ingredient
from .forms import RecipeForm, VersionForm, IngredientFormSet
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from django.http.response import HttpResponseRedirect
from django.conf import settings
RECIPE_FORM_PREFIX = 'recipe'
VERSION_FORM_PREFIX = 'version'
INGREDIENTS_FORMSET_PREFIX = 'ingredient'
def get_name_of_user(user):
return user.first_name if user.first_name else user.username
@login_required
def recipes(request):
recipes = Recipe.objects.all()
return render(request, 'recipes.html', context={'recipes': recipes})
def version(request, slug_recipe, slug_version):
recipe = get_object_or_404(Recipe, slug=slug_recipe)
has_multiple_versions = recipe.versions.all().count() > 1 # type: ignore
version = get_object_or_404(Version, recipe=recipe, slug=slug_version)
ingredients = version.ingredients.all() # type: ignore
return render(request, 'version.html', context={'recipe': recipe, 'has_multiple_versions': has_multiple_versions, 'version': version, 'ingredients': ingredients})
@login_required
def recipe(request, slug):
recipe = get_object_or_404(Recipe, slug=slug)
versions = recipe.versions.all() # type: ignore
if (1 == versions.count()):
return HttpResponseRedirect(reverse('version', kwargs={'slug_recipe': slug, 'slug_version': versions.get().slug}))
else:
return render(request, 'recipe.html', context={'recipe': recipe, 'versions': versions})
def create_version(request, recipe: Recipe, version_form: VersionForm) -> Version:
version = version_form.save(commit=False)
version.user = request.user
version.recipe = recipe
version.save()
return version
def save_ingredients(version: Version, ingredients_formset: IngredientFormSet): # type: ignore
for ingredient in ingredients_formset.save(commit=False):
ingredient.version = version
ingredient.save()
@login_required
def add_recipe(request):
if request.method == 'POST':
recipe_form = RecipeForm(request.POST, prefix=RECIPE_FORM_PREFIX)
version_form = VersionForm(request.POST, prefix=VERSION_FORM_PREFIX, author_placeholder=get_name_of_user(request.user))
ingredients_formset = IngredientFormSet(request.POST, queryset=Ingredient.objects.none(), prefix=INGREDIENTS_FORMSET_PREFIX)
if recipe_form.is_valid() and version_form.is_valid() and ingredients_formset.is_valid():
recipe = recipe_form.save(commit=True)
version = create_version(request, recipe, version_form)
save_ingredients(version, ingredients_formset)
return HttpResponseRedirect(reverse('recipe', kwargs={'slug': recipe.slug}))
else:
recipe_form = RecipeForm(prefix=RECIPE_FORM_PREFIX)
version_form = VersionForm(prefix=VERSION_FORM_PREFIX, author_placeholder=get_name_of_user(request.user))
ingredients_formset = IngredientFormSet(queryset=Ingredient.objects.none(), prefix=INGREDIENTS_FORMSET_PREFIX)
return render(request, 'add-recipe.html', {'recipe_form': recipe_form, 'version_form': version_form, 'ingredients_formset': ingredients_formset})
@login_required
def edit_recipe(request, slug):
recipe = get_object_or_404(Recipe, slug=slug)
# It is assumed every recipe has at least one version
if not request.user.is_superuser:
users = set()
for version in recipe.versions.all(): # type: ignore
users.add(version.user)
if len(users) > 1 or (len(users) == 1 and next(iter(users)) != request.user):
return redirect(f"/accounts/login/?next={request.path}")
if request.method == 'POST':
form = RecipeForm(request.POST, instance=recipe, prefix=RECIPE_FORM_PREFIX)
if form.is_valid():
if form.has_changed():
form.save()
return HttpResponseRedirect(reverse('recipe', kwargs={'slug': recipe.slug}))
else:
form = RecipeForm(instance=recipe, prefix=RECIPE_FORM_PREFIX)
return render(request, 'edit-recipe.html', {'form': form})
@login_required
def add_version(request, slug):
recipe = get_object_or_404(Recipe, slug=slug)
if (recipe.versions.all().count() > 0): # type: ignore
version_initial = {'label': '', 'slug': ''}
else:
version_initial = {}
if request.method == 'POST':
version_form = VersionForm(request.POST, prefix=VERSION_FORM_PREFIX, initial=version_initial, author_placeholder=get_name_of_user(request.user))
ingredients_formset = IngredientFormSet(request.POST, queryset=Ingredient.objects.none(), prefix=INGREDIENTS_FORMSET_PREFIX)
version_form.recipe_id = recipe.id # type: ignore
if version_form.is_valid() and ingredients_formset.is_valid():
version = create_version(request, recipe, version_form)
save_ingredients(version, ingredients_formset)
return HttpResponseRedirect(reverse('version', kwargs={'slug_recipe': version.recipe.slug, 'slug_version': version.slug}))
else:
version_form = VersionForm(prefix=VERSION_FORM_PREFIX, initial=version_initial, author_placeholder=get_name_of_user(request.user))
ingredients_formset = IngredientFormSet(queryset=Ingredient.objects.none(), prefix=INGREDIENTS_FORMSET_PREFIX)
return render(request, 'add-version.html', {'version_form': version_form, 'ingredients_formset': ingredients_formset})
@login_required
def edit_version(request, slug_recipe, slug_version):
recipe = get_object_or_404(Recipe, slug=slug_recipe)
version = get_object_or_404(Version, recipe=recipe, slug=slug_version)
if version.user != request.user and not request.user.is_superuser:
return redirect(f"/accounts/login/?next={request.path}")
if request.method == 'POST':
version_form = VersionForm(request.POST, prefix=VERSION_FORM_PREFIX, instance=version, author_placeholder=get_name_of_user(request.user))
ingredients_formset = IngredientFormSet(request.POST, queryset=version.ingredients.all(), prefix=INGREDIENTS_FORMSET_PREFIX) # type: ignore
version_form.recipe_id = recipe.id # type: ignore
if version_form.is_valid() and ingredients_formset.is_valid():
if version_form.has_changed():
version = version_form.save()
if ingredients_formset.has_changed():
for ingredient in ingredients_formset.save(commit=False):
ingredient.version = version
ingredient.save()
return HttpResponseRedirect(reverse('version', kwargs={'slug_recipe': version.recipe.slug, 'slug_version': version.slug}))
else:
version_form = VersionForm(instance=version, prefix=VERSION_FORM_PREFIX, author_placeholder=get_name_of_user(request.user))
ingredients_formset = IngredientFormSet(queryset=version.ingredients.all(), prefix=INGREDIENTS_FORMSET_PREFIX) # type: ignore
return render(request, 'edit-version.html', {'version_form': version_form, 'ingredients_formset': ingredients_formset})

7
stadlbauer/forms.py Normal file
View file

@ -0,0 +1,7 @@
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class SignupForm(UserCreationForm):
class Meta:
model = User
fields = ('username', 'password1', 'password2', 'first_name', 'last_name')

View file

@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/4.1/ref/settings/
"""
from pathlib import Path
import os
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@ -31,6 +32,7 @@ ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'recipes.apps.RecipesConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
@ -54,7 +56,7 @@ ROOT_URLCONF = 'stadlbauer.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
@ -99,6 +101,10 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
# Project specific
LOGIN_REDIRECT_URL = '/'
LOGOUT_REDIRECT_URL = '/'
# Internationalization
# https://docs.djangoproject.com/en/4.1/topics/i18n/

View file

@ -14,8 +14,14 @@ Including another URLconf
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from django.urls import path, include
from . import views
urlpatterns = [
path('', views.index, name='index'),
path('recipes/', include('recipes.urls')),
path('admin/', admin.site.urls),
path('accounts/new-user/', views.new_user, name='new-user'),
path('accounts/profile/', views.profile, name='profile'),
path('accounts/', include('django.contrib.auth.urls')),
]

24
stadlbauer/views.py Normal file
View file

@ -0,0 +1,24 @@
from .forms import SignupForm
from django.shortcuts import render
from django.urls import reverse
from django.http.response import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
def new_user(request):
if request.method == 'POST':
form = SignupForm(request.POST)
if form.is_valid():
form.save(commit=True)
return HttpResponseRedirect(reverse('login'))
else:
form = SignupForm()
return render(request, 'registration/new-user.html', {'form': form})
@login_required
def profile(request):
return render(request, 'registration/profile.html')
def index(request):
return render(request, 'index.html')

24
templates/base.html Normal file
View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="color-scheme" content="dark light">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
max-width: 80ch;
margin: 0 auto;
}
</style>
{% load static %}
{% block head %}{% endblock %}
<title>{% block title %}Barn{% endblock %}</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>

29
templates/base_main.html Normal file
View file

@ -0,0 +1,29 @@
{% extends "base.html" %}
{% block head %}
{% load static %}
{% endblock %}
{% block body %}
<nav>
<ul>
<li><a href="{% url 'index' %}">Home</a></li>
{% if user.is_authenticated %}
<li><a href="{% url 'profile' %}">Profile {{ user.username }}</a></li>
<li><a href="{% url 'logout' %}">Logout</a></li>
{% else %}
<li><a href="{% url 'login' %}">Login</a></li>
<li><a href="{% url 'new-user' %}">Create account</a></li>
{% endif %}
</ul>
<ul>
<li><a href="{% url 'recipes' %}">Recipes</a></li>
</ul>
</nav>
<main>
{% block main %}
{% endblock %}
</main>
{% endblock %}

8
templates/index.html Normal file
View file

@ -0,0 +1,8 @@
{% extends "base_main.html" %}
{% block title %}Barn{% endblock %}
{% block main %}
<h1>Barn</h1>
<ul>
<li><h2><a href="{% url 'recipes' %}">Recipes</a></h2></li>
</ul>
{% endblock %}

View file

@ -0,0 +1,38 @@
{% extends "base_main.html" %}
{% block main %}
{% if form.errors %}
<section>
<p>Username and password do not match. Please try again.</p>
</section>
{% endif %}
{% if next %}
<section>
{% if user.is_authenticated %}
<p>You are not authorized to access this site. Please log in with an account with the necessary permissions.</p>
{% else %}
<p>Please log in to view this site.</p>
{% endif %}
</section>
{% endif %}
<form action="{% url 'login' %}" method="post">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</tr>
</table>
<input type="submit" value="Login">
<input type="hidden" name="next" value="{{ next }}">
</form>
{% endblock %}

View file

@ -0,0 +1,43 @@
{% extends "base_main.html" %}
{% block main %}
{% if form.errors %}
<section>
<h2>Error:</h2>
<ul>
{% for field in form %}
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
{% endfor %}
</ul>
</section>
{% endif %}
<form method="post" action="{% url 'new-user' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.first_name.label_tag }}</td>
<td>{{ form.first_name }}</td>
</tr>
<tr>
<td>{{ form.last_name.label_tag }}</td>
<td>{{ form.last_name }}</td>
</tr>
<tr>
<td>{{ form.password1.label_tag }}</td>
<td>{{ form.password1 }}</td>
</tr>
<tr>
<td>{{ form.password2.label_tag }}</td>
<td>{{ form.password2 }}</td>
</tr>
</table>
<input type="submit" value="Create account">
</form>
{% endblock %}

View file

@ -0,0 +1,19 @@
{% extends "base_main.html" %}
{% block title %}Profile {{ user.username }}{% endblock %}
{% block main %}
<h1>Profile {{ user.username }}</h1>
<table>
<tr>
<td>Username</td>
<td>{{ user.username }}</td>
</tr>
<tr>
<td>First name</td>
<td>{{ user.first_name }}</td>
</tr>
<tr>
<td>Last name</td>
<td>{{ user.last_name }}</td>
</tr>
</table>
{% endblock %}