Merge commit 'ee7232cd502afbf15f36769da0835b4a1e1358df' into currency
* commit 'ee7232cd502afbf15f36769da0835b4a1e1358df': checkout the production branch on the production server add a registration disable debugging for production add a user profile extend the base template with login, profile and logout links add templates to support user authentication add url patterns to support user authentication remove an unnecessary shebang remove unnecessary attributes from the Person model redirect logins back to the index make imports more explicit remove an unnecessary configuration remove an old file change the article status to active change the content include because the org-mode file is called doku add a python package to the ansible role add fixtures with test data fix the admin view of order of goods added sketch of Siteview to docs
This commit is contained in:
commit
487c96710a
|
@ -30,7 +30,7 @@ Vagrant.configure("2") do |config|
|
|||
#zu installierende Pakete
|
||||
apt-get install -y apache2 python3-django mariadb-server avahi-daemon \
|
||||
libnss-mdns libapache2-mod-wsgi-py3 python3-mysqldb python3-pip
|
||||
pip3 install django-extensions Pillow
|
||||
pip3 install django-extensions Pillow pyaml
|
||||
|
||||
/vagrant/ansible/roles/web_AI-5/tasks/setup_script.sh
|
||||
SHELL
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
git: repo=https://git.2li.ch/ibz/web_AI-5.git
|
||||
dest="/vagrant"
|
||||
force=yes
|
||||
version=production
|
||||
|
||||
- name: Set Permissions on the repository
|
||||
file:
|
||||
|
@ -27,6 +28,7 @@
|
|||
name:
|
||||
- django-extensions
|
||||
- Pillow
|
||||
- pyaml
|
||||
executable: pip3
|
||||
|
||||
- name: Run the setup script to add some final touches
|
||||
|
|
|
@ -17,3 +17,5 @@ echo "from django.contrib.auth.models import User; \
|
|||
User.objects.filter(email='admin@example.com').delete(); \
|
||||
User.objects.create_superuser('admin', 'admin@example.com', 'password')" |
|
||||
python3 /vagrant/django/didgeridoo/manage.py shell
|
||||
|
||||
python3 /vagrant/django/didgeridoo/manage.py loaddata webshop
|
||||
|
|
|
@ -23,9 +23,13 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||
SECRET_KEY = '(#4#-$$&mx7(%q+6&&@-c&g%i0dc4)zfks1%sy8b%lsxspou&%'
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
DEBUG = False
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
ALLOWED_HOSTS = [
|
||||
'localhost',
|
||||
'127.0.0.1',
|
||||
'didgeridoo.ml'
|
||||
]
|
||||
|
||||
|
||||
# Application definition
|
||||
|
@ -131,9 +135,4 @@ STATIC_URL = '/static/'
|
|||
STATIC_ROOT = '/vagrant/django/didgeridoo/static/'
|
||||
MEDIA_ROOT = '/vagrant/django/didgeridoo/media/'
|
||||
|
||||
|
||||
ALLOWED_HOSTS = [
|
||||
'localhost',
|
||||
'127.0.0.1',
|
||||
'didgeridoo.ml'
|
||||
]
|
||||
LOGIN_REDIRECT_URL = '/'
|
||||
|
|
|
@ -3,8 +3,9 @@ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
|||
from django.contrib.auth.models import User
|
||||
|
||||
# Register your models here.
|
||||
from .models import (Article, Order, OrderPosition, Person, City, Picture,
|
||||
OrderOfGoods, Category, Option, Setting)
|
||||
from webshop.models import (Article, Order, OrderPosition,
|
||||
Person, City, Picture, OrderOfGoods,
|
||||
Category, Option, Setting)
|
||||
|
||||
|
||||
class PersonInline(admin.StackedInline):
|
||||
|
@ -31,6 +32,13 @@ class OrderAdmin(admin.ModelAdmin):
|
|||
inlines = (OrderPositionInline,)
|
||||
|
||||
|
||||
class OrderOfGoodsAdmin(admin.ModelAdmin):
|
||||
list_display = ('id', 'article', 'order_status', 'order_date')
|
||||
list_filter = ('order_date',)
|
||||
date_hierarchy = 'order_date'
|
||||
ordering = ('-order_date',)
|
||||
|
||||
|
||||
admin.site.unregister(User)
|
||||
admin.site.register(User, UserAdmin)
|
||||
|
||||
|
@ -38,7 +46,7 @@ admin.site.register(Article)
|
|||
admin.site.register(Order, OrderAdmin)
|
||||
admin.site.register(City)
|
||||
admin.site.register(Picture)
|
||||
admin.site.register(OrderOfGoods)
|
||||
admin.site.register(OrderOfGoods, OrderOfGoodsAdmin)
|
||||
admin.site.register(Category)
|
||||
admin.site.register(Option)
|
||||
admin.site.register(Setting)
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
- model: webshop.Category
|
||||
fields:
|
||||
name: "First Parent Category"
|
||||
parent_category:
|
||||
- model: webshop.Category
|
||||
fields:
|
||||
name: "Second Parent Category"
|
||||
parent_category:
|
||||
- model: webshop.Category
|
||||
fields:
|
||||
name: "Third Parent Category"
|
||||
parent_category:
|
||||
- model: webshop.Category
|
||||
fields:
|
||||
name: "Fourth Parent Category"
|
||||
parent_category:
|
||||
- model: webshop.Category
|
||||
fields:
|
||||
name: "Child Category 1"
|
||||
parent_category: 1
|
||||
- model: webshop.Category
|
||||
fields:
|
||||
name: "Child Category 2"
|
||||
parent_category: 2
|
||||
- model: webshop.Category
|
||||
fields:
|
||||
name: "Child Category 3"
|
||||
parent_category: 3
|
||||
- model: webshop.Category
|
||||
fields:
|
||||
name: "Child Category 4"
|
||||
parent_category: 4
|
||||
|
||||
- model: webshop.Article
|
||||
fields:
|
||||
name: "Article of First Parent Category"
|
||||
category: 1
|
||||
description: "An article sorted under the First Parent Category."
|
||||
stock: 10
|
||||
status: 3
|
||||
price_in_chf: 10.1
|
||||
- model: webshop.Article
|
||||
fields:
|
||||
name: "Article of Second Parent Category"
|
||||
category: 2
|
||||
description: "An article sorted under the Second Parent Category."
|
||||
stock: 20
|
||||
status: 3
|
||||
price_in_chf: 20.2
|
||||
- model: webshop.Article
|
||||
fields:
|
||||
name: "Article of Third Parent Category"
|
||||
category: 3
|
||||
description: "An article sorted under the Third Parent Category."
|
||||
stock: 30
|
||||
status: 3
|
||||
price_in_chf: 30.3
|
||||
- model: webshop.Article
|
||||
fields:
|
||||
name: "Article of Fourth Parent Category"
|
||||
category: 4
|
||||
description: "An article sorted under the Fourth Parent Category."
|
||||
stock: 40
|
||||
status: 3
|
||||
price_in_chf: 40.4
|
||||
- model: webshop.Article
|
||||
fields:
|
||||
name: "Article of Child Category 1"
|
||||
category: 5
|
||||
description: "An article sorted under the Child Category 1."
|
||||
stock: 11
|
||||
status: 3
|
||||
price_in_chf: 11.1
|
||||
- model: webshop.Article
|
||||
fields:
|
||||
name: "Article of Child Category 2"
|
||||
category: 6
|
||||
description: "An article sorted under the Child Category 2."
|
||||
stock: 22
|
||||
status: 3
|
||||
price_in_chf: 21.2
|
||||
- model: webshop.Article
|
||||
fields:
|
||||
name: "Article of Child Category 3"
|
||||
category: 7
|
||||
description: "An article sorted under the Child Category 3."
|
||||
stock: 33
|
||||
status: 3
|
||||
price_in_chf: 31.3
|
||||
- model: webshop.Article
|
||||
fields:
|
||||
name: "Article of Child Category 4"
|
||||
category: 8
|
||||
description: "An article sorted under the Child Category 4."
|
||||
stock: 44
|
||||
status: 3
|
||||
price_in_chf: 41.4
|
|
@ -0,0 +1,24 @@
|
|||
from django import forms
|
||||
from webshop.models import Salutation, City
|
||||
|
||||
|
||||
class RegistrationForm(forms.Form):
|
||||
email = forms.EmailField()
|
||||
salutation = forms.ModelChoiceField(queryset=Salutation.objects.all())
|
||||
first_name = forms.CharField()
|
||||
last_name = forms.CharField()
|
||||
street_name = forms.CharField()
|
||||
street_number = forms.CharField()
|
||||
zip_code = forms.IntegerField(min_value=1000, max_value=9999)
|
||||
city = forms.CharField()
|
||||
|
||||
def clean_city(self):
|
||||
# Check that the two password entries match
|
||||
city = self.cleaned_data['city']
|
||||
zip_code = self.cleaned_data['zip_code']
|
||||
try:
|
||||
City.objects.get(name=city, zip_code=zip_code)
|
||||
except City.DoesNotExist:
|
||||
raise forms.ValidationError(
|
||||
"The zip code and the city don't match.")
|
||||
return city
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from decimal import Decimal
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.db import models
|
||||
|
@ -130,8 +128,6 @@ class Salutation(models.Model):
|
|||
|
||||
|
||||
class Person(models.Model):
|
||||
first_name = models.CharField(max_length=200)
|
||||
last_name = models.CharField(max_length=200)
|
||||
salutation = models.ForeignKey(Salutation)
|
||||
city = models.ForeignKey(City)
|
||||
street_name = models.CharField(max_length=200)
|
||||
|
@ -139,4 +135,4 @@ class Person(models.Model):
|
|||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
|
||||
def __str__(self):
|
||||
return self.last_name
|
||||
return self.user.username
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{% extends 'webshop/base.html' %}
|
||||
|
||||
{% block section_title %}You have been successfully logged out.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
|||
{% extends 'webshop/base.html' %}
|
||||
|
||||
{% block section_title %}Login{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<button type="submit">Login</button>
|
||||
<p><a href="{% url 'registration' %}">Go to registration.</a></p>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,17 @@
|
|||
{% extends 'webshop/base.html' %}
|
||||
|
||||
{% block section_title %}User Profile{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<p><b>Username: </b>{{ request.user.username }}</p>
|
||||
<p><b>Salutation: </b>{{ person.salutation }}</p>
|
||||
<p><b>Firstname: </b>{{ request.user.first_name }}</p>
|
||||
<p><b>Lastname: </b>{{ request.user.last_name }}</p>
|
||||
<p><b>City: </b>{{ person.city }}</p>
|
||||
<p><b>Street: </b>{{ person.street_name }}</p>
|
||||
<p><b>Streetnumber: </b>{{ person.street_number }}</p>
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -0,0 +1,19 @@
|
|||
{% extends 'webshop/base.html' %}
|
||||
|
||||
{% block section_title %}Registration{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if profile_form.errors %}
|
||||
<p style="color: red;">
|
||||
Please correct the error{{ form.errors|pluralize }} below.
|
||||
</p>
|
||||
{% endif %}
|
||||
<form action="" method="post" novalidate>
|
||||
<table>
|
||||
{{ user_form.as_table }}
|
||||
{{ profile_form.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<button type="submit">Register</button>
|
||||
</form>
|
||||
{% endblock %}
|
|
@ -4,6 +4,12 @@
|
|||
</head>
|
||||
<body>
|
||||
<div id="content" class="flex">
|
||||
<a href="{% url 'index' %}">Home</a> |
|
||||
{% if user.is_authenticated %}
|
||||
<a href="{% url 'profile' %}">Profile</a> | <a href="{% url 'logout' %}">Logout</a>
|
||||
{% else %}
|
||||
<a href="{% url 'login' %}">Login</a>
|
||||
{% endif %}
|
||||
<h1>{% block section_title %}Music Instrument Shop{% endblock %}</h1>
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from django.conf.urls import url
|
||||
from django.conf.urls import url, include
|
||||
|
||||
from . import views
|
||||
from webshop import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.index, name='index'),
|
||||
|
@ -10,4 +10,7 @@ urlpatterns = [
|
|||
url(r'^category/(?P<category_id>[0-9]+)/$',
|
||||
views.articles_in_category,
|
||||
name='category'),
|
||||
url('^', include('django.contrib.auth.urls')),
|
||||
url(r'^profile/$', views.profile, name='profile'),
|
||||
url(r'^registration/$', views.registration, name='registration'),
|
||||
]
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404, render
|
||||
from .models import Article, Category, ArticleStatus
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from webshop.models import Article, Category, ArticleStatus, Person, City
|
||||
from webshop.forms import RegistrationForm
|
||||
|
||||
# Create your views here.
|
||||
|
||||
|
@ -33,3 +38,39 @@ def article_details(request, article_id):
|
|||
article = get_object_or_404(Article, pk=article_id)
|
||||
return render(request, 'webshop/article_details.html',
|
||||
{'article': article})
|
||||
|
||||
|
||||
@login_required
|
||||
def profile(request):
|
||||
person = Person.objects.get(user=request.user)
|
||||
return render(request, 'registration/profile.html',
|
||||
{'person': person})
|
||||
|
||||
|
||||
def registration(request):
|
||||
if request.method == 'POST':
|
||||
profile_form = RegistrationForm(request.POST)
|
||||
user_form = UserCreationForm(request.POST)
|
||||
if (profile_form.is_valid() and user_form.is_valid()):
|
||||
pf = profile_form.cleaned_data
|
||||
uf = user_form.cleaned_data
|
||||
user = User.objects.create_user(uf['username'],
|
||||
pf['email'],
|
||||
uf['password2'])
|
||||
user.last_name = pf['last_name']
|
||||
user.first_name = pf['first_name']
|
||||
user.save()
|
||||
person = Person.objects.create(
|
||||
salutation=pf['salutation'],
|
||||
city=City.objects.get(zip_code=pf['zip_code'],
|
||||
name=pf['city']),
|
||||
street_name=pf['street_name'],
|
||||
street_number=pf['street_number'],
|
||||
user=user)
|
||||
return HttpResponseRedirect('/login/')
|
||||
else:
|
||||
profile_form = RegistrationForm
|
||||
user_form = UserCreationForm
|
||||
return render(request, 'registration/register.html',
|
||||
{'profile_form': profile_form,
|
||||
'user_form': user_form})
|
||||
|
|
|
@ -201,6 +201,10 @@ Am ende des Projekts die nicht lauffähigen teile ausgrenzen. :-)
|
|||
|
||||
* Umsetzung
|
||||
** Spezifikation
|
||||
*** Mockup
|
||||
#+ATTR_LATEX: :width 18cm
|
||||
#+CAPTION: a early Mockup of the shop
|
||||
[[file:pictures/mockup-full-snipet.png][file:pictures/mockup-full-snipet.png]
|
||||
*** Anwendungsfälle
|
||||
*** Klassendiagramme der Models
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
\microtypesetup{protrusion=true} % enables protrusion
|
||||
\newpage
|
||||
|
||||
\include{content}
|
||||
\include{doku}
|
||||
|
||||
\newpage
|
||||
\nocite{*}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 320 KiB |
|
@ -1,20 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<meta charset="UTF-8">
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>audioguide</h1>
|
||||
<h3>a mobile offline audioguide</h3>
|
||||
noop
|
||||
noop
|
||||
noop
|
||||
noop
|
||||
noop
|
||||
noop
|
||||
<p>the audioguide that makes a offline usage possible.</p>
|
||||
</header>
|
||||
<nav>
|
||||
</nav>
|
||||
</body>
|
||||
</html>
|
|
@ -24,7 +24,7 @@ use webshopdb;
|
|||
insert into webshop_articlestatus (name)
|
||||
values ('out of stock'),
|
||||
('hidden'),
|
||||
('on sale');
|
||||
('active');
|
||||
|
||||
use webshopdb;
|
||||
insert into webshop_city (zip_code, name)
|
||||
|
|
Loading…
Reference in New Issue