Merge branch 'master' into production

This commit is contained in:
Andreas Zweili 2018-01-28 12:57:56 +01:00
commit 33261ecdb2
18 changed files with 1012 additions and 367 deletions

View File

@ -13,7 +13,7 @@ WSGIPythonPath /vagrant/django/didgeridoo/
ServerAdmin webmaster@localhost
Alias /media/ /vagrant/django/didgeridoo/media/
Alias /media/ /srv/media/
Alias /static/ /vagrant/django/didgeridoo/static/
<Directory /vagrant/django/didgeridoo/didgeridoo>
@ -23,7 +23,7 @@ WSGIPythonPath /vagrant/django/didgeridoo/
</Directory>
<Directory /vagrant/django/didgeridoo/media>
<Directory /srv/media>
Require all granted
</Directory>

View File

@ -11,134 +11,99 @@ Key:Value pairs of new currencys.
"""
def get_exchange_rate():
# zweitweise kann die resource nicht geladen werden.
# https://stackoverflow.com/a/43523497/4061870
# During weekends there are no updates.
# To develop i need a testresource.
# In that case i comment the Online Resource block and uncomment the
# development Block...
# ~~~~~~~~~~~~~~~~~~~~~
# Online Resource block:
# ~~~~~~~~~~~~~~~~~~~~~
today = datetime.now().strftime("%Y-%m-%d")
SNB_URL = 'https://www.snb.ch/selector/de/mmr/exfeed/rss'
def get_rss(url):
urlsocket = ''
try:
urlsocket = urllib.request.urlopen(SNB_URL)
urlsocket = urllib.request.urlopen(url)
return(urlsocket)
except urllib.error.URLError as e:
print('err: urllib.request.urlopen: ', e.reason)
def parse_rss(urlsocket):
if urlsocket:
root = ET.parse(urlsocket)
root = ET.ElementTree(root)
# ~~~~~~~~~~~~~~~~~~~~~
# development block:
# ~~~~~~~~~~~~~~~~~~~~~
# today = "2018-01-08"
# try:
# root = ET.ElementTree(file='rss')
# except Exception as e:
# print('exchange_rates.py_urlsocket failed %s (
# %s) on date: %s for %s'
# % (e, type(e), root))
# ~~~~~~~~~~~~~~~~~~~~~
rss_tree = ET.ElementTree(root)
return(rss_tree)
# Namespaces
ns = {'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'none': 'http://purl.org/rss/1.0/',
'dc': 'http://purl.org/dc/elements/1.1/',
'dcterms': 'http://purl.org/dc/terms/',
'cb': 'http://www.cbwiki.net/wiki/index.php/Specification_1.2/'
}
# Pathvariables to XML Namespaces
rate_path = 'cb:statistics/cb:exchangeRate/'
observation_path = 'cb:statistics/cb:exchangeRate/cb:observation/'
exchange_rates = {}
for item in root.findall('none:item', ns):
# for eatch item n the list we grab the release date
# to evaluate if its fresh data or old:
# THE CURRENCY DATE:
datetime_str = item.find('dc:date', ns).text
# convert string to date object:
# https://stackoverflow.com/a/12282040/4061870
# seams like snb striked the microsecond somewhere
# between Nov. and Dez. 2017 so maybe first check
# time type is with milliseconds:
def get_exchange_rate(rss_tree, ns):
# Pathvariables to XML Namespaces with
rate_path = 'cb:statistics/cb:exchangeRate/'
observation_path = 'cb:statistics/cb:exchangeRate/cb:observation/'
exchange_rates = []
for item in rss_tree.findall('none:item', ns):
datetime_str = item.find('dc:date', ns).text
try:
date = datetime.strptime(''.join(
datetime_str.rsplit(':', 1)),
"%Y-%m-%dT%H:%M:%S%z").strftime(
"%Y-%m-%d")
except Exception as e:
print('%s (%s)' % (e, type(e)))
try:
date = datetime.strptime(''.join(
datetime_str.rsplit(':', 1)),
"%Y-%m-%dT%H:%M:%S%z").strftime(
"%Y-%m-%dT%H:%M:%S.%f%z").strftime(
"%Y-%m-%d")
continue
except Exception as e:
print('%s (%s)' % (e, type(e)))
try:
date = datetime.strptime(''.join(
datetime_str.rsplit(':', 1)),
"%Y-%m-%dT%H:%M:%S.%f%z").strftime(
"%Y-%m-%d")
continue
except Exception as e:
print('%s (%s)' % (e, type(e)))
continue
# Print dates for development:
# print("date:", date, "today:", today)
# only the values of today are used so check for date in XML:
if date == today:
# now search for the currency exchange rate:
target_currency = item.find(rate_path +
'cb:targetCurrency', ns).text
value = float(item.find(observation_path +
'cb:value', ns).text)
value = float(value) # convert to float
foreign_value = value # copy to new value to have both.
if item.find(observation_path + 'cb:unit_mult', ns) is None:
# because it's dangerous to check for present,
# i check for none here and have to set the target
# to 1. as im multiplying it later.
unit_mult = float("1.0")
else:
# shift left by 2 digits with "/"
# https://stackoverflow.com/questions/8362792/
# because some currencys differ widly from CHF
unit_mult = item.find(observation_path +
'cb:unit_mult', ns).text
# unit_mult defaults to '0' so we check for 8 decimal
# values (2..-6) they represent the fracton value to
# calculate the correct decimalpoint.
if unit_mult == '2': # thinking of Bitcoins
unit_mult = '0.01'
if unit_mult == '1':
unit_mult = '0.10'
if unit_mult == '-1':
unit_mult = '10'
if unit_mult == '-2': # Japan Yen
unit_mult = '100'
if unit_mult == '-3':
unit_mult = '1000'
if unit_mult == '-4':
unit_mult = '10000'
if unit_mult == '-5':
unit_mult = '100000'
if unit_mult == '-6': # indian rupies
unit_mult = '1000000'
unit_mult = float(unit_mult) # convert to float
# calculate the Currency to CHF:
foreign_value = 1 / value
foreign_value *= unit_mult
value = value / unit_mult
# truncate it to decimal values provided by the xml:
foreign_value_round = round(foreign_value, 5)
# Print nice setup of all calculated currencys for development:
# print("date:", date, " 1 ", target_currency, " costs: ",
# CHFvalue, "CHF and 1 ", base_currency, " costs: ",
# FOREIGNvalue_round, target_currency)
exchange_rates.update(
{target_currency: foreign_value_round})
# Print the Dictionary:
# print(exchange_rates)
else:
continue
return(exchange_rates, today)
# now search for the currency exchange rate:
target_currency = item.find(rate_path +
'cb:targetCurrency', ns).text
value = float(item.find(observation_path +
'cb:value', ns).text)
value = float(value) # convert to float
foreign_value = value # copy to new value to have both.
if item.find(observation_path + 'cb:unit_mult', ns) is None:
# because it's dangerous to check for present,
# i check for none here and have to set the target
# to 1. as im multiplying it later.
unit_mult = float("1.0")
else:
# shift left by 2 digits with "/"
# https://stackoverflow.com/questions/8362792/
# because some currencys differ widly from CHF
unit_mult = item.find(observation_path +
'cb:unit_mult', ns).text
# unit_mult defaults to '0' so we check for 8 decimal
# values (2..-6) they represent the fracton value to
# calculate the correct decimalpoint.
if unit_mult == '2': # thinking of Bitcoins
unit_mult = '0.01'
if unit_mult == '1':
unit_mult = '0.10'
if unit_mult == '-1':
unit_mult = '10'
if unit_mult == '-2': # Japan Yen
unit_mult = '100'
if unit_mult == '-3':
unit_mult = '1000'
if unit_mult == '-4':
unit_mult = '10000'
if unit_mult == '-5':
unit_mult = '100000'
if unit_mult == '-6': # indian rupies
unit_mult = '1000000'
unit_mult = float(unit_mult) # convert to float
# calculate the Currency to CHF:
foreign_value = 1 / value
foreign_value *= unit_mult
value = value / unit_mult
# truncate it to decimal values provided by the xml:
foreign_value_round = round(foreign_value, 5)
# Print nice setup of all calculated currencys for development:
# print("date:", date, " 1 ", target_currency, " costs: ",
# CHFvalue, "CHF and 1 ", base_currency, " costs: ",
# FOREIGNvalue_round, target_currency)
data = [{'date': date,
'currency': target_currency,
'exchangerate': foreign_value_round}]
exchange_rates.append(data)
# Print the Dictionary:
print(exchange_rates)
return(exchange_rates)

View File

@ -20,7 +20,8 @@ class ExchangeRate_date(models.Model):
class ExchangeRate(models.Model):
name = models.ForeignKey(ExchangeRate_name)
date = models.ForeignKey(ExchangeRate_date)
exchange_rate_to_chf = models.DecimalField(max_digits=12, decimal_places=5)
exchange_rate_to_chf = models.DecimalField(max_digits=12,
decimal_places=5)
def __str__(self):
return str(self.name)

View File

@ -1,14 +1,9 @@
<!DOCTYPE html>
<head>
<link rel="stylesheet" href="{{ STATIC_URL }}/static/admin/css/base.css" />
</head>
<body>
<div id="content" class="flex">
<h1>Currencies in CHF</h1>
<p> {{ message }} </p>
<h2> Frühere Daten: </h2>
<br>
<h3> US Dollars: </h3>
{% extends "webshop/base.html" %}
{% block section_title %}Currencies in CHF{% endblock %}
{% block content %}
<h2> {{ message }} </h2>
<h3> Frühere Daten: </h3>
<h4> US Dollars: </h4>
{% if currency_USD_list %}
<table>
<tr>
@ -28,7 +23,7 @@
</p>
{% endif %}
<br>
<h3> EURO: </h3>
<h4> EURO: </h4>
{% if currency_EUR_list %}
<table>
<tr>
@ -48,7 +43,7 @@
</p>
{% endif %}
<br>
<h3> Japanese Yenn: </h3>
<h4> Japanese Yenn: </h4>
{% if currency_JPY_list %}
<table>
<tr>
@ -69,7 +64,7 @@
</p>
{% endif %}
<br>
<h3> Great Britain Pounds: </h3>
<h4> Great Britain Pounds: </h4>
{% if currency_GBP_list %}
<table>
<tr>
@ -90,5 +85,4 @@
</p>
{% endif %}
</div>
</body>
</html>
{% endblock %}

View File

@ -0,0 +1,12 @@
from django import template
register = template.Library()
@register.filter()
def boldcoffee(value):
# currency_of_customer = request.session['currency']
return '%s !!gefiltert!!' % value
# excample filter: {{ article.price_in_chf|boldcoffee }}

View File

@ -1,7 +1,9 @@
from django.conf.urls import url
from currencies.views import currencies
from currencies.views import currencies, currency_update
urlpatterns = [
url(r'^currencies/$', currencies),
url(r'^ajax/currency_update/$',
currency_update,
name='currency_update'),
]

View File

@ -1,82 +1,133 @@
from django.shortcuts import render
import datetime
from datetime import datetime
from django.views.generic.edit import UpdateView
from currencies.models import (ExchangeRate,
ExchangeRate_date,
ExchangeRate_name)
from currencies import exchange_rates
from django.http import JsonResponse
def currency_update(request):
# https://simpleisbetterthancomplex.com/tutorial/2016/08/29/how-to-work-with-ajax-request-with-django.html
if request.GET.get('currency_update', None) == 'CHF':
data = {}
else:
currency = request.GET.get('currency_update', None)
data = ExchangeRate.objects.filter(
name__name=currency).values(
'exchange_rate_to_chf').latest(
'date__date')
print('currency:', currency, 'data: ', data)
return JsonResponse(data)
def currencies(request):
# this function fetches the data from exchange_rates.py
# evaluates if the values are already stored and
# prepares the view all dynamicaly.
# It can grow in terms of more Currencies over time automaticaly.
today = ''
raw_data = []
try:
raw_data, today = exchange_rates.get_exchange_rate()
except Exception as e:
print('views raw_data: ', raw_data, 'error:', e) # assert False
message_no = "Already querried today: "
message_yes = " Updated successfully: "
if raw_data:
print(raw_data)
for currency, rate in raw_data.items():
if ExchangeRate.objects.filter(
date__date=today,
name__name=currency):
message_no += currency + ", "
# A: https://stackoverflow.com/a/27802801/4061870
else:
if ExchangeRate_date.objects.filter(date=today)[:1]:
try:
# lustigerweise gibt .values() den value und die id
# zurück. Ohne .values() gibts nur den "value"
date_dict = ExchangeRate_date.objects.filter(
date=today).values()
except Exception as e:
print('exdate_exists %s (%s) on %s'
% (e, type(e), today))
else:
try:
exdate = ExchangeRate_date.objects.create(
date=today)
exdate.save()
except Exception as e:
print('exdate_not_exists %s (%s) for %s'
% (e, type(e), today))
if ExchangeRate_name.objects.filter(
name=currency)[:1]:
try:
name_dict = ExchangeRate_name.objects.filter(
name=currency).values()
except Exception as e:
print('exname_exists %s (%s) on %s'
% (e, type(e), currency))
else:
try:
exname = ExchangeRate_name.objects.create(
name=currency)
exname.save()
except Exception as e:
print('exname_not_exists %s (%s) on %s'
% (e, type(e), currency))
try:
exrate = ExchangeRate.objects.create(
# name_id=name_id,
name_id=ExchangeRate_name.objects.get(
name=currency).id,
# date_id=date_id,
date_id=ExchangeRate_date.objects.get(
date=today).id,
exchange_rate_to_chf=rate,
)
exrate.save()
message_yes += currency + ", "
except Exception as e:
print('exrate_create %s (%s) on %s for %s'
% (e, type(e), currency, today))
"""this function fetches the data from swiss national bank
evaluates if the values are already stored and
prepares a view all dynamicaly.
It can grow in terms of more Currencies over time automaticaly."""
# Namespaces
ns = {'rdf': 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
'none': 'http://purl.org/rss/1.0/',
'dc': 'http://purl.org/dc/elements/1.1/',
'dcterms': 'http://purl.org/dc/terms/',
'cb': 'http://www.cbwiki.net/wiki/index.php/Specification_1.2/'
}
SNB_URL = 'https://www.snb.ch/selector/de/mmr/exfeed/rss'
try:
urlsocket = exchange_rates.get_rss(SNB_URL)
except Exception as e:
print('currencies/views get_rss(): ', urlsocket, 'error:', e)
try:
rss_tree = exchange_rates.parse_rss(urlsocket)
except Exception as e:
print('currencies/views parse_rss(): ', rss_tree, 'error:', e)
try:
raw_data = exchange_rates.get_exchange_rate(rss_tree, ns)
except Exception as e:
print('currencies/views get_exchange_rate(): ', raw_data, 'error:', e)
today = datetime.now().strftime("%Y-%m-%d")
message_no = "Already querried: "
length_of_message_no = len(message_no)
message_yes = " Updated successfully: "
length_of_message_yes = len(message_yes)
# raw_data can be empty. In this case skip:
if raw_data:
for one_obj_of_list in raw_data:
for exchange_rate_of_one_day in one_obj_of_list:
date = exchange_rate_of_one_day['date']
currency = exchange_rate_of_one_day['currency']
exchangerate = exchange_rate_of_one_day['exchangerate']
# check for already existing exrates per day and add
# to message that its already been saved.
if ExchangeRate.objects.filter(
date__date=date,
name__name=currency):
message_no += currency + ' on ' + date + ", "
else:
if ExchangeRate_date.objects.filter(date=date)[:1]:
# if data and currency is not yet present, save it.
try:
# A: https://stackoverflow.com/a/27802801/4061870
# lustigerweise gibt .values() den value und die id
# zurück. Ohne .values() gibts nur den "value"
date_dict = ExchangeRate_date.objects.filter(
date=date).values()
except Exception as e:
print('currencies/views/exdate_exists \
%s (%s) on %s'
% (e, type(e), today))
else:
try:
exdate = ExchangeRate_date.objects.create(
date=date)
exdate.save()
except Exception as e:
print('currencies/views/exdate_not_exists \
%s (%s) for %s'
% (e, type(e), date))
if ExchangeRate_name.objects.filter(
name=currency)[:1]:
# if data and currency is not yet present, save it.
try:
name_dict = ExchangeRate_name.objects.filter(
name=currency).values()
except Exception as e:
print('currencies/views/exname_exists \
%s (%s) on %s'
% (e, type(e), currency))
else:
try:
exname = ExchangeRate_name.objects.create(
name=currency)
exname.save()
except Exception as e:
print('currencies/views/exname_not_exists \
%s (%s) on %s'
% (e, type(e), currency))
try:
# save item to where id's match.
exrate = ExchangeRate.objects.create(
# name_id=name_id,
name_id=ExchangeRate_name.objects.get(
name=currency).id,
# date_id=date_id,
date_id=ExchangeRate_date.objects.get(
date=date).id,
exchange_rate_to_chf=exchangerate,
)
exrate.save()
message_yes += currency + ' on ' + date + ", "
except Exception as e:
print('currencies/views/exrate_create \
%s (%s) on %s for %s'
% (e, type(e), currency, date))
# prepare messages:
# python can not swap a char insinde a sting so i have
@ -87,12 +138,13 @@ def currencies(request):
message_yes = message_yes[::-1] # invert the string
message_yes = message_yes.replace(",", "!", 1) # replace f. , with !
message_yes = message_yes[::-1] # invert the string back
if len(message_no) > 24 and len(message_yes) > 23:
# here we evaluate what kind of message is valid:
if len(message_no) > length_of_message_no\
and len(message_yes) > length_of_message_yes:
message = message_no + message_yes
elif len(message_no) > 24:
message = message_no
elif len(message_yes) > 23:
elif len(message_yes) > 18:
message = message_yes
elif datetime.datetime.today().isoweekday() == 6:
message = """Die Abfrage wurde ohne ergebniss beendet.
@ -106,61 +158,18 @@ def currencies(request):
"""
else:
message = """Die Abfrage wurde ohne ergebniss beendet.
Kann es sein dass die SNB aufgrund eines Feiertages
geschlossen ist?
"""
# know we can query our data for presentaton:
currency_list = ExchangeRate.objects.all()
currency_USD_list = ExchangeRate.objects.filter(name__name='USD')
currency_EUR_list = ExchangeRate.objects.filter(name__name='EUR')
currency_JPY_list = ExchangeRate.objects.filter(name__name='JPY')
currency_GBP_list = ExchangeRate.objects.filter(name__name='GBP')
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# I leave this part in the document as history.
# Problem is that i get the expected List with dictionaries like:
# view_currencies_list[
# {'date': '2017-12-29, 'USD':'1.00', 'EUR':'1.00', 'GBP':'1.00', 'JPY':'1.00'},
# {'date': '2017-12-30, 'USD':'1.00', 'EUR':'1.00', 'GBP':'1.00', 'JPY':'1.00'},
# ]
# but the dict of 'date:' does not seam to deliver the same values as
# the dict's of key name:'USD' im not able to fix this in moment.
# nor am i able to generate a HTML table with date | USD | EUR | ...
# -------------------------------------------------------------------
# -------------------------------------------------------------------
# prepare data to be displayed in a html table:
# https://stackoverflow.com/questions/8749158/removing-duplicates-from-dictionary#8749473
# A: https://stackoverflow.com/questions/37205793/django-values-list-vs-values#37205928
# B: https://stackoverflow.com/questions/6521892/how-to-access-a-dictionary-key-value-present-inside-a-list
# # search for currencies in a date and apend them to the list
# view_currency_list = []
# view_currencies_list = ExchangeRate_name.objects.all()
# view_dates_list = ExchangeRate_date.objects.all()
# count_date = 0
# count_currencies = 0
# for view_date in view_dates_list:
# count_date += 1
# view_currency_dict = {view_date}
# # view_currency_dict.update({})
# for view_currency in view_currencies_list:
# count_currencies += 1
# try:
# x = ExchangeRate.objects.filter(date__date=str(
# view_date),
# name__name=str(
# view_currency
# )).values() # A
# view_exchange_rate_to_chf = x[0]['exchange_rate_to_chf']
# except Exception as e:
# print('prepare_view %s (%s) for %s on %s is %s'
# % (e, type(e), view_currency, view_date,
# view_exchange_rate_to_chf))
# view_exchange_rate_to_chf = " "
#
# view_currency_dict.update({view_currency:
# view_exchange_rate_to_chf}) # B
#
# view_currency_list.append(view_currency_dict)
# assert False
currency_USD_list = ExchangeRate.objects.filter(
name__name='USD').order_by('date__date')
currency_EUR_list = ExchangeRate.objects.filter(
name__name='EUR').order_by('date__date')
currency_JPY_list = ExchangeRate.objects.filter(
name__name='JPY').order_by('date__date')
currency_GBP_list = ExchangeRate.objects.filter(
name__name='GBP').order_by('date__date')
# and publish it on template:
return render(request,
'currencies/index.html',
{'currency_list': currency_list,

View File

@ -44,7 +44,6 @@ INSTALLED_APPS = [
'django.contrib.messages',
'django.contrib.staticfiles',
'currencies',
'bootstrap3',
]
MIDDLEWARE = [
@ -132,9 +131,34 @@ USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.10/howto/static-files/
# seams like it changed with 1.13+ (14.1.18|IH)
# https://stackoverflow.com/a/14800489/4061870
# Absolute path to the directory static files should be collected to.
# Don't put anything in this directory yourself; store your static files
# in apps' "static/" subdirectories and in STATICFILES_DIRS.
# Example: "/home/media/media.lawrence.com/static/"
STATIC_ROOT = ''
# URL prefix for static files.
# Example: "http://media.lawrence.com/static/"
STATIC_URL = '/static/'
STATIC_ROOT = '/vagrant/django/didgeridoo/static/'
# Additional locations of static files
STATICFILES_DIRS = (
# Put strings here, like "/home/html/static" or "C:/www/django/static".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
'/vagrant/django/didgeridoo/static',
)
# List of finder classes that know how to find static files in
# various locations.
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
)
MEDIA_URL = '/media/'
MEDIA_ROOT = '/srv/media/'

View File

@ -0,0 +1,30 @@
$("#id_currency_update").change(function () {
var currency_update = $(this).val();
$("#id_currency_update").val(currency_update);
$.ajax({
url: '/ajax/currency_update/',
data: {
'currency_update': currency_update
},
dataType: 'json',
success: function (data) {
var foo = jQuery.parseJSON(data);
alert("es pop auf! --dies kommt von: static/js/app.js--." + foo.currency_update);
}
});
});
//document.getElementById('id_currency_update').getElementsByTagName('currency_update')
//$("#id_currency_update").val('USD').selected = 'selected';
//https://stackoverflow.com/a/30489067/4061870
// var obj = document.getElementById("id_currency_update");
// for(i=0; i<obj.options.length; i++){
// if(obj.options[i].value == "USD"){
// obj.selectedIndex = i;
// }
// }
// var e document.getElementById("id_currency_update");
//e.value = currency_update;

View File

@ -28,28 +28,10 @@
</div>
</div>
</div>
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="{% url 'index' %}">
HOME
</a>
</div>
<ul class="nav navbar-nav">
<li><a href="#">CART</a></li>
{% if user.is_authenticated %}
<li><a href="{% url 'profile' %}">PROFILE</a></li>
<li><a href="{% url 'logout' %}">LOGOUT</a></li>
{% else %}
<li><a href="{% url 'login' %}">LOGIN</a></li>
{% endif %}
<li><a href="#">CURRENCY</a></li>
</ul>
</div>
</nav>
{% block nav %}{% include "webshop/nav.html" %}{% endblock %}
<div class="container-fluid">
<div class="row">
<div class="col-sm-2">
<div class="col-md-2">
{% block sidebar %}
{% if category_list %}
<ul>
@ -67,13 +49,15 @@
{% endif %}
{% endblock %}
</div>
<div class="col-sm-10 ">
<div class="col-md-8 panel panel-default">
<div class="panel-heading">
<h1>
{% block section_title %}{% endblock %}
</h1>
</div>
<div class="col-sm-10 ">
{% block content %}{% endblock %}
</div>
<div class="panel-body">
{% block content %}{% endblock %}
</div>
</div>
</div>
</div>
@ -82,12 +66,37 @@
<div class="row">
<div class="col-sm-12">
{% block footer %}
This is a case study project of Ivan Hörler and Andreas Zweili. </br>
It is a school project/excercise and has no commercial intent.
<div class="container text-center">
<hr>
<div class="row">
<div class="col-lg-12">
<ul class="nav nav-pills nav-justified">
<li>
<a id='school'
target='_blank'
href='http://www.ibz.ch'
>This is a case study project of Ivan Hörler and Andreas Zweili.
</br>
It is a school project/excercise and has no commercial intent.
</a>
</li>
<li>
<a href="/currencies">Currencies</a>
</li>
<li>
<a href="#">How to use</a>
</li>
</ul>
</div>
</div>
</div>
{% endblock %}
</div>
</div>
</div>
</footer>
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>
<script src="{% static 'js/app.js' %}"></script>
<script>{% block javascript %}{% endblock %}</script>
</body>
</html>

View File

@ -1,5 +1,7 @@
{% extends "webshop/base.html" %}
{% load customfilters %}
{% block section_title %}Articles{% endblock %}
{% block content %}
{% if articles_list %}
<table class="table">

View File

@ -0,0 +1,42 @@
{% block nav %}
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="{% url 'index' %}">
HOME
</a>
<ul class="nav navbar-nav">
<li><a href="#">CART</a></li>
{% if user.is_authenticated %}
<li>
<a href="{% url 'profile' %}">PROFILE</a>
</li>
<li>
<a href="{% url 'logout' %}">LOGOUT</a>
</li>
{% else %}
<li>
<a href="{% url 'login' %}">LOGIN</a>
</li>
{% endif %}
<!-- https://pypi.python.org/pypi/django-select-multiple-field -->
<form method="POST" novalidate>
<select name="currency_update" id="id_currency_update">
<option value="CHF">CHF</option>
<option value="USD">USD</option>
<option value="GBP">GBP</option>
<option value="JPY">JPY</option>
</select>
{% csrf_token %}
</form>
</ul>
</div>
<!--
Es wird auf id im app.js file gemached.
die URL wird im app.js gesetzt
und mit urls.py weitergereicht.
dann auf name im views.py gemached und ausgeführt.
-->
</div>
</nav>
{% endblock %}

View File

@ -11,6 +11,10 @@ urlpatterns = [
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'),
url(r'^profile/$',
views.profile,
name='profile'),
url(r'^registration/$',
views.registration,
name='registration'),
]

View File

@ -11,6 +11,7 @@ from webshop.models import (Article,
Picture)
from webshop.forms import RegistrationForm
# Create your views here.

View File

@ -1,4 +1,4 @@
@misc{django_extensions,
@misc{djangoextensions,
month = {{01}},
note = {{\url{https://github.com/django-extensions/django-extensions}}},
Urldate = {{2018-01-05}},
@ -16,3 +16,93 @@
year = {2016},
}
@misc{removeadd,
month = {{01}},
note = {{\url{https://stackoverflow.com/a/21454467/7723859}}},
Urldate = {{2018-01-15}},
author = {Avinash Garg},
title = {{How to remove Add button in Django admin, for specific Model?}},
year = {2014},
}
@misc{removedelete,
month = {{08}},
note = {{\url{https://stackoverflow.com/a/7031093/7723859}}},
Urldate = {{2018-01-15}},
author = {Jonathan R.},
title = {{In Django Admin how do I disable the Delete link}},
year = {2011},
}
@misc{readonly,
month = {{09}},
note = {{\url{https://stackoverflow.com/a/46124159/7723859}}},
Urldate = {{2018-01-15}},
author = {gdlmx},
title = {{Display a model field as readonly in Django admin}},
year = {2017},
}
@misc{timezone,
month = {{07}},
note = {{\url{https://stackoverflow.com/a/38239673}}},
Urldate = {{2018-01-15}},
author = {Antoine Pinsard},
title = {{Django: timezone.now vs timezone.now()}},
year = {2016},
}
@misc{usermodel,
month = {{07}},
note = {{\url{https://simpleisbetterthancomplex.com/tutorial/2016/07/22/how-to-extend-django-user-model.html}}},
Urldate = {{2018-01-15}},
author = {Vitor Freitas},
title = {{How to Extend Django User Model}},
year = {2016},
}
@misc{djangogirls,
month = {{10}},
note = {{\url{https://tutorial.djangogirls.org/en/}}},
Urldate = {{2018-01-15}},
author = {DjangoGirls},
title = {{Django Girls Tutorial}},
year = {2017},
}
@misc{images,
month = {{08}},
note = {{\url{https://stackoverflow.com/a/1235542}}},
Urldate = {{2018-01-15}},
author = {steve},
title = {{How do I include image files in Django templates?}},
year = {2009},
}
@misc{djangodoc,
month = {{01}},
note = {{\url{https://docs.djangoproject.com/en/1.11/}}},
Urldate = {{2018-01-15}},
author = {Django Foundation},
title = {{Django documentation}},
year = {2018},
}
@misc{upload,
month = {{12}},
note = {{\url{https://stackoverflow.com/a/8542030}}},
Urldate = {{2018-01-15}},
author = {Akseli Pal{\'{e}}n},
title = {{Need a minimal Django file upload example [closed]}},
year = {2011},
}
@misc{tree,
month = {{09}},
note = {{\url{https://stackoverflow.com/a/39729832}}},
Urldate = {{2018-01-15}},
author = {ht\_},
title = {{Tree view in django template}},
year = {2016},
}

View File

@ -5,6 +5,7 @@
#+LATEX_CLASS_OPTIONS: [a4paper,11pt]
#+LaTeX_HEADER: \input{style}
#+OPTIONS: H:5 todo:t
#+LANGUAGE: de
#+STARTUP: align
@ -390,7 +391,7 @@ Abbildung: ([[fig:umweltgrafik]]) grafisch dargestellt.
*** NEXT Risikobewertung
#+CAPTION: Risikobewertung Wahrscheinlichkeit
#+ATTR_LATEX: :align l|l
#+ATTR_LATEX: :align l|l :placement [H]
#+NAME: tab:wahrscheinlichkeit
| *Bewertung* | *Beschreibung: Warscheinlichkeit (W)* |
|-------------+---------------------------------------|
@ -399,7 +400,7 @@ Abbildung: ([[fig:umweltgrafik]]) grafisch dargestellt.
| 3 = hoch | Hohe warscheinlichkeit > 50% |
#+CAPTION: Risikobewertung Auswirkung
#+ATTR_LATEX: :align l|l
#+ATTR_LATEX: :align l|l :placement [H]
#+NAME: tab:auswirkung
| *Bewertung* | *Beschreibung: Auswirkung (A)* |
|-------------+-------------------------------------------------|
@ -408,7 +409,7 @@ Abbildung: ([[fig:umweltgrafik]]) grafisch dargestellt.
| 3 = hoch | Projekt erfüllt nicht alle Anforderungen |
#+CAPTION: Grafische Darstellung der Risikoanalyse
#+ATTR_LATEX: :width 9cm
#+ATTR_LATEX: :width 9cm :placement [H]
#+NAME: fig:risk
[[file:diagrammes/risk_analysis.eps]]
@ -475,7 +476,7 @@ Als Interessent möchte ich...
- die Preise in einer anderen Währung anzeigen können um die
Preise in einer mir bekannten Währung vergleichen zu können.
*** TODO Use Cases
*** Use Cases
Ein Use Case sammelt alle möglichen Szenarien, die eintreten können,
wenn ein Akteur versucht, mit Hilfe des betrachteten Systems ein
@ -506,158 +507,617 @@ Webshops beschränkt.
#+LATEX:\end{landscape}
#+LATEX:\newpage
**** NEXT Use Case Detailbeschreibung
**** Use Case Detailbeschreibung
#+CAPTION: Use Case
#+ATTR_LATEX: :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}|
Use Cases werden in der Regel mit Hilfe einer sogenannten Use Case
Schablone im Detail beschrieben damit klar ist wie der Ablauf jeweils
genau aussieht. Die von uns verwendete Schablone wurde von Alistair
Cockburn definiert.
Da ein Web-Shop eine sehr umfangreiche Applikation ist gibt es sehr
viele Use Cases welche beschrieben und umgesetzt werden müssen. Aus
zeitlichen Gründen haben wir nur einen kleinen Teil der Use Cases im
Detail ausgearbeitet. Insbesondere diese welche wir selber
ausprogrammiert haben. Die gesamte Liste an Use Cases sieht wie folgt
aus, die Use Cases mit den Nummern wurden dabei im Detail ausgearbeitet:
#+LATEX: {\footnotesize
| - [[*Artikel durchst%C3%B6bern][1.0 Artikel durchstöbern]] | - Kategorie erfassen (Admin Funktion) |
| - [[Registration][2.0 Registration]] | - Kategorie ändern (Admin Funktion) |
| - [[User Login][2.1 User Login]] | - Kategorie löschen (Admin Funktion) |
| - User Profil ansehen | - Bild hochladen (Admin Funktion) |
| - [[Artikel in Warenkorb legen][3.0 Artikel in Warenkorb legen]] | - Bild ändern (Admin Funktion) |
| - [[W%C3%A4hrung %C3%A4ndern][3.1 Währung ändern]] | - Bild löschen (Admin Funktion) |
| - Währung aktualisieren (Admin Funktion) | - Bestellung erfassen (Admin Funktion) |
| - [[Checkout][3.2 Checkout]] | - [[Bestellung %C3%A4ndern/korrigieren][7.0 Bestellung ändern/korrigieren (Admin Funktion)]] |
| - [[User Passwort %C3%A4ndern][4.0 User Passwort ändern (Admin Funktion)]] | - Bestellung löschen (Admin Funktion) |
| - [[Artikel erfassen][5.0 Artikel erfassen (Admin Funktion)]] | - [[max_pictures Option anpassen][6.0 max_pictures Option anpassen (Admin Funktion)]] |
| - Artikel ändern (Admin Funktion) | - max_pictures Option deaktivieren (Admin Funktion) |
| - Artikel löschen (Admin Funktion) | - User erfassen (Admin Funktion) |
| - Materialbestellung erfassen (Admin Funktion) | - User/Personen Daten ändern (Admin Funktion) |
| - Materialbestellung ändern/korrigieren (Admin Funktion) | - User löschen (Admin Funktion) |
| - Materialbestellung löschen (Admin Funktion) | - User Berechtigungen anpassen (Admin Funktion) |
| - Stadt hinzufügen (Admin Funktion) | |
| - Stadt ändern (Admin Funktion) | |
| - Stadt löschen (Admin Funktion) | |
#+LATEX:}
***** Artikel durchstöbern
#+LATEX:{\footnotesize
#+CAPTION: Use 1.0 Artikel durchstöbern
#+ATTR_LATEX::environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:browse_article
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 1.0 Artikel durchstöbern |
|---------------------+--------------------------------|
| *Description* | Durchklicken der verschiedenen Kategorieren und ansehen der Artikel Details und Bilder. |
|---------------------+--------------------------------|
| *Actors* | Kunden, Interessenten |
|---------------------+--------------------------------|
| *Status* | Freigegeben |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | User möchte Artikel einsehen |
|---------------------+--------------------------------|
| *Preconditions* | Website aufgerufen |
|---------------------+--------------------------------|
| *Postconditions* | - |
|---------------------+--------------------------------|
| *Normal Flow* | 1. Website aufrufen |
| | 2. Kategorienen durchsehen |
| | 3. Artikel anklicken |
|---------------------+--------------------------------|
| *Alternative Flow* | - |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
***** Registration
#+LATEX:{\footnotesize
#+CAPTION: Use Case 2.0 Registration
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:registration
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 2.0 Registration |
|---------------------+--------------------------------|
| *Description* | Ein User registriert sich einen Account. |
|---------------------+--------------------------------|
| *Actors* | Interessent |
|---------------------+--------------------------------|
| *Status* | Freigebgen |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | User möchte einen Account erstellen. |
|---------------------+--------------------------------|
| *Preconditions* | Email Adresse vorhanden |
|---------------------+--------------------------------|
| *Postconditions* | Account wurde erfolgreich erstellt. |
|---------------------+--------------------------------|
| *Normal Flow* | 1. User klickt auf den Link "Go to registration.". |
| | 2. User füllt das Registrations Formular aus. |
| | 3. User schliesst die Registrierung mit Klick auf "Register" ab. |
| | 4. Die Website leitet ihn in den Login Bereich um. |
|---------------------+--------------------------------|
| *Alternative Flow* | 1. User klickt auf den Link "Go to registration.". |
| | 2. User füllt das Registrations Formular mir falschen Daten aus. |
| | 3. Die Website gibt die entsprechenden Fehler aus. |
| | 4. Der User korrigiert die Angaben. |
| | 5. User schliesst die Registrierung mit Klick auf "Register" ab. |
| | 6. Die Website leitet ihn in den Login Bereich um. |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
***** User Login
#+LATEX:{\footnotesize
#+CAPTION: Use Case 2.1 User Login
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:login
|---------------------+-----------------------------|
| *Identifier + Name* | |
|---------------------+-----------------------------|
| *Description* | |
|---------------------+-----------------------------|
| *Actors* | |
|---------------------+-----------------------------|
| *Status* | Freigegeben |
|---------------------+-----------------------------|
| *Includes* | - |
|---------------------+-----------------------------|
| *Trigger* | |
|---------------------+-----------------------------|
| *Preconditions* | |
|---------------------+-----------------------------|
| *Postconditions* | |
|---------------------+-----------------------------|
| *Normal Flow* | |
|---------------------+-----------------------------|
| *Alternative Flow* | - |
|---------------------+-----------------------------|
| *Notes* | - |
|---------------------+-----------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+-----------------------------|
| *Author* | A. Zweili & I. |
|---------------------+-----------------------------|
| *Date* | |
|---------------------+-----------------------------|
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 2.1 User Login |
|---------------------+--------------------------------|
| *Description* | Ein Kunde logt sich auf der Website ein. |
|---------------------+--------------------------------|
| *Actors* | Kunde |
|---------------------+--------------------------------|
| *Status* | Freigeben |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | Ein Kunde möchte sich einloggen. |
|---------------------+--------------------------------|
| *Preconditions* | UC 2.0 erfolgreich abgeschlossen. |
|---------------------+--------------------------------|
| *Postconditions* | User hat sich erfolgreich eingeloggt. |
|---------------------+--------------------------------|
| *Normal Flow* | 1. User klickt in der Navigation auf "Login". |
| | 2. User gibt Zugangsdaten ein. |
| | 3. User beendet Login mit Klick auf "Login". |
| | 4. Die Website leitet ihn auf die Index Seite um und zeigt neu eine "Profil" und "Logout" Schaltfläche. |
|---------------------+--------------------------------|
| *Alternative Flow* | 1. User klickt in der Navigation auf "Login". |
| | 2. User gibt falsche Zugangsdaten ein. |
| | 3. User beendet Login mit Klick auf "Login". |
| | 4. Die Website gibt entsprechende Fehlermeldungen aus. |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
***** Artikel in Warenkorb legen
#+LATEX:{\footnotesize
#+CAPTION: Use Case 3.0 Artikel in Warenkorb legen
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:cart
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 3.0 Artikel in Warenkorb legen |
|---------------------+--------------------------------|
| *Description* | Ein Kunde legt einen Artikel in den Warenkorb. |
|---------------------+--------------------------------|
| *Actors* | Kunde |
|---------------------+--------------------------------|
| *Status* | Freigeben |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | Ein Kunde möchte einen Artikel kaufen. |
|---------------------+--------------------------------|
| *Preconditions* | UC2.1 erfolgreich abgeschlossen. |
|---------------------+--------------------------------|
| *Postconditions* | Artikel wurde im Warenkorb gespeichert. |
|---------------------+--------------------------------|
| *Normal Flow* | 1. User klickt einen Artikel an. |
| | 2. User klickt auf "Add to cart". |
| | 3. Die Website speichert den Artikel im Warenkorb. |
|---------------------+--------------------------------|
| *Alternative Flow* | 1. User klickt einen Artikel mit Stock "0.0" an. |
| | 2. User klickt auf "Add to cart". |
| | 3. Die Website meldet "We are sorry but this item is out of stock.". |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
***** Währung ändern
#+LATEX:{\footnotesize
#+CAPTION: Use Case 3.1 Währung ändern
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:currency
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 3.1 Währung ändern |
|---------------------+--------------------------------|
| *Description* | Ein User ändert die Währung für die Preise. |
|---------------------+--------------------------------|
| *Actors* | Kunde, Interessent |
|---------------------+--------------------------------|
| *Status* | Freigeben |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | Ein User möchte sich die Preise in einer anderen Währung anzeigen lassen. |
|---------------------+--------------------------------|
| *Preconditions* | - |
|---------------------+--------------------------------|
| *Postconditions* | Die Preise werden in der gewünschten Währung angezeigt. |
|---------------------+--------------------------------|
| *Normal Flow* | 1. Der User wählt im Drop-Down die gewünschte Währung aus. |
| | 2. Die Website aktualisiert und zeigt die neu berechneten Preise an. |
|---------------------+--------------------------------|
| *Alternative Flow* | - |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
***** Checkout
#+LATEX:{\footnotesize
#+CAPTION: Use Case 3.2 Checkout
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:checkout
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 3.2 Checkout |
|---------------------+--------------------------------|
| *Description* | User gibt seinen Warenkorb als Bestellung auf. |
|---------------------+--------------------------------|
| *Actors* | Kunde |
|---------------------+--------------------------------|
| *Status* | Freigeben |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | Ein Kunde möchte seine Artikel im Warenkorb bestellen. |
|---------------------+--------------------------------|
| *Preconditions* | UC2.1 und UC3.0 erfolgreich abgeschlossen. |
|---------------------+--------------------------------|
| *Postconditions* | Die Bestellung wurde von der Website gespeichert. |
|---------------------+--------------------------------|
| *Normal Flow* | 1. Der User klickt in der Navigation auf "Cart". |
| | 2. Die Website leitet ihn zum Warenkorb um. |
| | 3. Der User klickt dort auf "Checkout". |
| | 4. Die Website gibt ihm eine komplette Übersicht der Bestellung sowie der Empfängeradresse. |
| | 5. User klickt auf "Send order". |
|---------------------+--------------------------------|
| *Alternative Flow* | 1. Der User klickt in der Navigation auf "Cart". |
| | 2. Die Website leitet ihn zum Warenkorb um. |
| | 3. Der User klickt dort auf "Checkout". |
| | 4. Die Website gibt ihm eine komplette Übersicht der Bestellung sowie der Empfängeradresse. |
| | 5. Der User bricht die Bestellung mit Klick auf "Cancel" ab. |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
***** User Passwort ändern
#+LATEX:{\footnotesize
#+CAPTION: 4.0 User Passwort ändern
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:password
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 4.0 User Passwort ändern |
|---------------------+--------------------------------|
| *Description* | Ein Administrator ändert ein User Kennwort. |
|---------------------+--------------------------------|
| *Actors* | Verwaltung |
|---------------------+--------------------------------|
| *Status* | Freigeben |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | Ein Administrator möchte ein Passwort zurücksetzen weil es vergessen wurde. |
|---------------------+--------------------------------|
| *Preconditions* | Account mit Administrationsrechten vorhanden. |
|---------------------+--------------------------------|
| *Postconditions* | Auf dem User Account wurde ein neues Passwort gesetzt. |
|---------------------+--------------------------------|
| *Normal Flow* | 1. Der Administrator loggt sich unter https://didgeridoo.ml/admin ein. |
| | 2. Admin klickt auf "Users". |
| | 3. Admin wählt den passenden Account aus. |
| | 4. Klickt unterhalb des Passwort Hashes auf "this form". |
| | 5. Gibt zweimal das neue Passwort ein und klickt "Change password". |
| | 6. Die Website leitet den Admin zurück zu den User Details. |
|---------------------+--------------------------------|
| *Alternative Flow* | 1. Der Administrator loggt sich unter https://didgeridoo.ml/admin ein. |
| | 2. Admin klicht auf "Users". |
| | 3. Admin wählt den passenden Account aus. |
| | 4. Klickt unterhalb des Passwort Hashes auf "this form". |
| | 5. Gibt zweimal ein invalides Passwort ein und klickt "Change password". |
| | 6. Die Website gibt eine entsprechende Fehlermeldung aus. |
| | 7. Der Admin korrigiert die Passwörter und klickt auf "Change password". |
| | 8. Die Website leitet den Admin zurück zu den User Details. |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
***** Artikel erfassen
#+LATEX:{\footnotesize
#+CAPTION: 5.0 Artikel erfassen
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:create_article
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 5.0 Artikel erfassen |
|---------------------+--------------------------------|
| *Description* | Ein Administrator erfasst einen neuen Artikel mit Bildern. |
|---------------------+--------------------------------|
| *Actors* | Verwaltung |
|---------------------+--------------------------------|
| *Status* | Freigeben |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | Um das Sortiment zu erweitern möchte der Administrator einen neuen Artikel erfassen. |
|---------------------+--------------------------------|
| *Preconditions* | Account mit Administrationsrechten vorhanden. |
|---------------------+--------------------------------|
| *Postconditions* | Der Artikel wir im Webshop angezeigt. |
|---------------------+--------------------------------|
| *Normal Flow* | 1. Der Administrator loggt sich unter https://didgeridoo.ml/admin ein. |
| | 2. Admin klickt neben "Articles" auf "+ Add". |
| | 3. Admin füllt das Formular aus und lädt ein Bild hoch. |
| | 4. Klickt unten rechts auf "Save". |
| | 5. Die Website speichert den Artikel in der Datenbank. |
|---------------------+--------------------------------|
| *Alternative Flow* | 1. Der Administrator loggt sich unter https://didgeridoo.ml/admin ein. |
| | 2. Admin klickt neben "Articles" auf "+ Add". |
| | 3. Admin füllt das Formular aus und lädt zuviele Bilder hoch. |
| | 4. Klickt unten rechts auf "Save". |
| | 5. Die Website gibt eine entsprechende Fehlermeldung aus. |
| | 6. Der Admin entfernt die überzähligen Bilder. |
| | 7. Die Website speichert den Artikel in der Datenbank. |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
***** max_pictures Option anpassen
#+LATEX:{\footnotesize
#+CAPTION: Use Case 6.0 max_pictures Option anpassen
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:max_pictures
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 6.0 max_pictures Option anpassen |
|---------------------+--------------------------------|
| *Description* | Ein Administrator ändert die max_pictures Option. |
|---------------------+--------------------------------|
| *Actors* | Verwaltung |
|---------------------+--------------------------------|
| *Status* | Freigeben |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | Ein Administrator möchte die maximale Anzahl Bilder pro Artikel anpassen. |
|---------------------+--------------------------------|
| *Preconditions* | Account mit Administrationsrechten vorhanden. |
|---------------------+--------------------------------|
| *Postconditions* | Der neue Wert wurde von der Website gespeichert. |
|---------------------+--------------------------------|
| *Normal Flow* | 1. Der Administrator loggt sich unter https://didgeridoo.ml/admin ein. |
| | 2. Admin klickt auf "Options" und anschliessend auf "max_pictures". |
| | 3. Admin ändert den Wert "Value" zu einer Ganzzahl seiner Wahl. |
| | 4. Klickt unten rechts auf "Save". |
| | 5. Die Website speichert den Wert in der Datenbank. |
|---------------------+--------------------------------|
| *Alternative Flow* | 1. Der Administrator loggt sich unter https://didgeridoo.ml/admin ein. |
| | 2. Admin klickt auf "Options" und anschliessend auf "max_pictures". |
| | 3. Admin ändert den Wert "Value" zu einer Gleitzahl seiner Wahl. |
| | 4. Klickt unten rechts auf "Save". |
| | 5. Die Website gibt eine entsprechende Fehlermeldung aus. |
| | 6. Der Admin korrigiert den Wert und klickt "Save". |
| | 7. Die Website speichert den Wert in der Datenbank. |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
***** Bestellung ändern/korrigieren
#+LATEX:{\footnotesize
#+CAPTION: Use Case 7.0 Bestellung ändern/korrigieren
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{.25\textwidth}|p{.7\textwidth}| :placement [H]
#+NAME: tab:change_order
|---------------------+--------------------------------|
| | <30> |
| *Identifier + Name* | 7.0 Bestellung ändern/korrigieren |
|---------------------+--------------------------------|
| *Description* | Ein Administrator korrigiert eine Bestellung. |
|---------------------+--------------------------------|
| *Actors* | Verwaltung |
|---------------------+--------------------------------|
| *Status* | Freigeben |
|---------------------+--------------------------------|
| *Includes* | - |
|---------------------+--------------------------------|
| *Trigger* | Administrator ändert auf Wunsch eines Kunden eine Bestellung. |
|---------------------+--------------------------------|
| *Preconditions* | Account mit Administrationsrechten vorhanden. |
|---------------------+--------------------------------|
| *Postconditions* | Die Bestellung hat eine angepasste Artikel Menge. |
|---------------------+--------------------------------|
| *Normal Flow* | 1. Der Administrator loggt sich unter https://didgeridoo.ml/admin ein. |
| | 2. Admin klickt auf "Orders" und anschliessend auf die passende Order ID. |
| | 3. Admin ändert den Wert "Amount" des ersten Artikels zu 0. |
| | 4. Klickt unten rechts auf "Save". |
| | 5. Die Website speichert die Bestellung in der Datenbank. |
|---------------------+--------------------------------|
| *Alternative Flow* | - |
|---------------------+--------------------------------|
| *Notes* | - |
|---------------------+--------------------------------|
| *UC History* | 1.0 Darft erstellt durch AZ |
|---------------------+--------------------------------|
| *Author* | A. Zweili & I. Hörler |
|---------------------+--------------------------------|
| *Date* | 16.01.2018 |
|---------------------+--------------------------------|
#+LATEX:}
*** NEXT Mockup
#+CAPTION: Ein frühes Mockup des Shop
#+ATTR_LATEX: :width \textwidth
#+NAME: mockup
[[file:pictures/mockup-full-snipet.png][file:pictures/mockup-full-snipet.png]]
[[./pictures/mockup-full-snipet.png]]
*** TODO Models
\footcite{djangoextensions}
*** TODO Klassendiagramme der Models
**** NEXT Category
#+ATTR_LATEX: :width 9cm
\footcite{tree}
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Kategorien
#+NAME: fig:category
[[file:pictures/class_category.png]]
[[./pictures/class_category.png]]
**** NEXT Option
#+ATTR_LATEX: :width 9cm
\footcite{readonly}
\footcite{removeadd}
\footcite{removedelete}
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Optionen
#+NAME: fig:option
[[file:pictures/class_option.png][file:pictures/class_option.png]]
**** NEXT Setting
#+ATTR_LATEX: :width 9cm
#+CAPTION: Klassenmodel für Einstellungen
#+NAME: fig:umweltgrafik
[[file:pictures/class_setting.png][file:pictures/class_setting.png]]
[[./pictures/class_option.png]]
**** NEXT ArticleStatus
#+ATTR_LATEX: :width 9cm
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Artikelstatus
#+NAME: fig:articlestatus
[[file:pictures/class_articlestatus.png][file:pictures/class_articlestatus.png]]
[[./pictures/class_articlestatus.png]]
**** TODO ExchangeRate
#+ATTR_LATEX: :width 9cm
\footcite{timezone}
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Wechselkurse
#+NAME: fig:exchangerate
[[file:pictures/class_exchangerate.png][file:pictures/class_exchangerate.png]]
[[./pictures/class_exchangerate.png]]
**** NEXT Article
#+ATTR_LATEX: :width 9cm
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Artikel
#+NAME: fig:article
[[file:pictures/class_article.png][file:pictures/class_article.png]]
[[./pictures/class_article.png]]
**** NEXT OrderStatus
#+ATTR_LATEX: :width 9cm
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Bestellstatus
#+NAME: fig:orderstatus
[[file:pictures/class_orderstatus.png][file:pictures/class_orderstatus.png]]
[[./pictures/class_orderstatus.png]]
**** NEXT OrderOfGoods
#+ATTR_LATEX: :width 9cm
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Warenbestellungen
#+NAME: fig:orderofgoods
[[file:pictures/class_orderofgoods.png][file:pictures/class_orderofgoods.png]]
[[./pictures/class_orderofgoods.png]]
**** NEXT Picture
#+ATTR_LATEX: :width 9cm
\footcite{upload}
\footcite{images}
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Bilder
#+NAME: fig:picture
[[file:pictures/class_picture.png][file:pictures/class_picture.png]]
[[./pictures/class_picture.png]]
**** NEXT Order
#+ATTR_LATEX: :width 9cm
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Bestellungen
#+NAME: fig:order
[[file:pictures/class_order.png][file:pictures/class_order.png]]
[[./pictures/class_order.png]]
**** NEXT ShoppingCart
#+ATTR_LATEX: :width 9cm
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Warenkörbe
#+NAME: fig:shoppingcart
[[file:pictures/class_shoppingcart.png][file:pictures/class_shoppingcart.png]]
[[./pictures/class_shoppingcart.png]]
**** NEXT City
#+ATTR_LATEX: :width 9cm
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Städte
#+NAME: fig:city
[[file:pictures/class_city.png][file:pictures/class_city.png]]
[[./pictures/class_city.png]]
**** NEXT Salutation
#+ATTR_LATEX: :width 9cm
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Anreden
#+NAME: fig:salutation
[[file:pictures/class_salutation.png][file:pictures/class_salutation.png]]
[[./pictures/class_salutation.png]]
**** NEXT Person
#+ATTR_LATEX: :width 9cm
\footcite{usermodel}
#+ATTR_LATEX: :width 9cm :placement [H]
#+CAPTION: Klassenmodel für Personen
#+NAME: fig:person
[[file:pictures/class_person.png][file:pictures/class_person.png]]
[[./pictures/class_person.png]]
** Benutzerinterface
*** Mockup skizzieren
*** Frontend Umsetzung
*** Backend Umsetzung
** Testfälle
** Testing
*** Fixtures
#+LATEX:\newpage
#+LATEX:\begin{landscape}
*** Testfälle
#+CAPTION: Testfälle
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{1.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|
#+ATTR_LATEX: :environment longtable :align |>{\columncolor[HTML]{EFEFEF}}p{1.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}|p{2.5cm}| :placement [H]
#+NAME: tab:testcases
|----------------------+----------------------+----------------------+----------------------+----------------------+----------------------+----------------------+----------------------|
| <20> | <20> | <20> | <20> | <20> | <20> | <20> | <20> |