Merge branch 'master' into display-threading

Conflicts:
	client-barcode/freitagslib/network.py
This commit is contained in:
Sebastian Pipping 2011-10-17 20:01:43 +02:00
commit 028d03456f
25 changed files with 371 additions and 174 deletions

View File

@ -16,7 +16,7 @@
inkscape:version="0.48.2 r9819" inkscape:version="0.48.2 r9819"
sodipodi:docname="freitagskasse.svg"> sodipodi:docname="freitagskasse.svg">
<title <title
id="title3609">HOWTO Freitagskasse v3.1</title> id="title3609">HOWTO Freitagskasse v3.2</title>
<defs <defs
id="defs4"> id="defs4">
<marker <marker
@ -53,9 +53,9 @@
borderopacity="1.0" borderopacity="1.0"
inkscape:pageopacity="0.0" inkscape:pageopacity="0.0"
inkscape:pageshadow="2" inkscape:pageshadow="2"
inkscape:zoom="0.49497475" inkscape:zoom="0.7"
inkscape:cx="370.73312" inkscape:cx="67.266124"
inkscape:cy="362.70358" inkscape:cy="265.56241"
inkscape:document-units="px" inkscape:document-units="px"
inkscape:current-layer="layer1" inkscape:current-layer="layer1"
showgrid="false" showgrid="false"
@ -73,7 +73,7 @@
<dc:format>image/svg+xml</dc:format> <dc:format>image/svg+xml</dc:format>
<dc:type <dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>HOWTO Freitagskasse v3.1</dc:title> <dc:title>HOWTO Freitagskasse v3.2</dc:title>
<dc:creator> <dc:creator>
<cc:Agent> <cc:Agent>
<dc:title>Sebastian Pipping &lt;sebastian@pipping.org&gt;</dc:title> <dc:title>Sebastian Pipping &lt;sebastian@pipping.org&gt;</dc:title>
@ -1054,7 +1054,8 @@
id="rect3535-9" /></flowRegion><flowPara id="rect3535-9" /></flowRegion><flowPara
id="flowPara3537-0">1 Euro</flowPara></flowRoot> </g> id="flowPara3537-0">1 Euro</flowPara></flowRoot> </g>
<g <g
id="g6092"> id="g6092"
transform="translate(-1.09375e-6,0)">
<g <g
id="g4397" id="g4397"
inkscape:label="ink_ext_XXXXXX" inkscape:label="ink_ext_XXXXXX"
@ -1352,7 +1353,7 @@
id="flowPara3537-0-75">10 Euro</flowPara></flowRoot> </g> id="flowPara3537-0-75">10 Euro</flowPara></flowRoot> </g>
<g <g
id="g8994" id="g8994"
transform="translate(-4,0)"> transform="translate(-3.9999988,0)">
<g <g
id="g3261" id="g3261"
inkscape:label="ink_ext_XXXXXX" inkscape:label="ink_ext_XXXXXX"
@ -1545,7 +1546,7 @@
id="flowPara3537-0-75-8">COMMIT</flowPara></flowRoot> </g> id="flowPara3537-0-75-8">COMMIT</flowPara></flowRoot> </g>
<g <g
id="g8958" id="g8958"
transform="translate(-4,0)"> transform="translate(-19.933595,0)">
<g <g
id="g3163" id="g3163"
inkscape:label="ink_ext_XXXXXX" inkscape:label="ink_ext_XXXXXX"
@ -1705,7 +1706,7 @@
height="87.14286" height="87.14286"
width="178.57143" width="178.57143"
id="rect3535-9-1-9" /></flowRegion><flowPara id="rect3535-9-1-9" /></flowRegion><flowPara
id="flowPara3537-0-75-7">UNDO</flowPara></flowRoot> </g> id="flowPara3537-0-75-7">STORNO</flowPara></flowRoot> </g>
<path <path
sodipodi:type="arc" sodipodi:type="arc"
style="color:#000000;fill:#000000;stroke:#000000;stroke-width:5.4000001;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" style="color:#000000;fill:#000000;stroke:#000000;stroke-width:5.4000001;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"

Before

Width:  |  Height:  |  Size: 158 KiB

After

Width:  |  Height:  |  Size: 158 KiB

View File

@ -283,9 +283,15 @@ class Status:
% ('', '', color(balance), sign(balance, plus), % ('', '', color(balance), sign(balance, plus),
abs(balance), COLOR_RESET)) abs(balance), COLOR_RESET))
def shorten(text, length):
if len(text) <= length:
return text
else:
return text[:length - 3] + '...'
def show_item(position, diff, label, color): def show_item(position, diff, label, color):
print('%2d) %-40s %s%c %6.2f Euro%s' \ print('%2d) %-40s %s%c %6.2f Euro%s' \
% (position, label, color, sign(diff), % (position, shorten(label, 40), color, sign(diff),
abs(diff), COLOR_RESET)) abs(diff), COLOR_RESET))
def show_bar(): def show_bar():
@ -342,7 +348,7 @@ class Status:
print_display('\x0b\nKonto: %5.2f!' % (self.balance) ) print_display('\x0b\nKonto: %5.2f!' % (self.balance) )
print() print()
print(COLOR_SOME + 'Committen nicht vergessen.' + COLOR_RESET) print(COLOR_MUCH + 'Committen nicht vergessen.' + COLOR_RESET)
else: else:
print('Kontostand beträgt: %s%.2f Euro%s' % (COLOR_MUCH, self.balance, COLOR_RESET)) print('Kontostand beträgt: %s%.2f Euro%s' % (COLOR_MUCH, self.balance, COLOR_RESET))
display_screen("KONTOSTAND","%s: %.2f Euro" % (self.login_name,self.balance)) display_screen("KONTOSTAND","%s: %.2f Euro" % (self.login_name,self.balance))

View File

@ -55,7 +55,7 @@ class BuyCommand(object):
return self._item.name return self._item.name
def commodity_label(self): def commodity_label(self):
if self._deposit: if self._deposit or self.deposit_value() <= 0:
return self._item.name return self._item.name
else: else:
return "%s (exkl. Pfand)" % self._item.name return "%s (exkl. Pfand)" % self._item.name

View File

@ -23,7 +23,6 @@ DEPOSIT_CASH = 1
DEPOSIT_BANK = 2 DEPOSIT_BANK = 2
_BASE_URL = 'http://devcat.someserver.de:13805/api2/'
_BASE_URL = 'https://k4ever.freitagsrunde.org:443/api2/' _BASE_URL = 'https://k4ever.freitagsrunde.org:443/api2/'
_auth = base64.encodestring('%s:%s' % (os.environ['BARCODE_PLUGIN_USER'], os.environ['BARCODE_PLUGIN_PASS'])).rstrip() _auth = base64.encodestring('%s:%s' % (os.environ['BARCODE_PLUGIN_USER'], os.environ['BARCODE_PLUGIN_PASS'])).rstrip()

View File

@ -1,13 +1,55 @@
Kassensystem Kassensystem
############
Preamble
========
For ages there has been the discussion - Kassensystem!
So many attempts have been made, so many things have been discussed
and overengineered... But oh well, here is our attempt!
Mighty Kassensystem, finally!
Dependencies
============
- python-django >= 1.3
- python-django-auth-ldap
- python-django-piston
- easy-thumbnails
https://github.com/SmileyChris/easy-thumbnails.git
Installation Process Installation Process
==================== ====================
1. Webserver
Some sort of Webserver is needed to host the django part. All about deploying
django can be found at https://docs.djangoproject.com/en/dev/howto/deployment/
Mostly this will be apache2 + mod_wsgi.
k4ever has static files which should be served by the webserver directly, so
be sure to turn off python for the media/ directory.
For development there is also djangos builtin webserver. You can use it via
./manage.py runserver but THIS SHOULD NEVER BE USED IN A PRODOCTIVE
ENVIRONMENT.
2. The database
- edit settings.py for database - edit settings.py for database
- Add Usergroups: ('Normal User', 'Plugin') ( to be renamed) - Add Usergroups: ('Normal User', 'Plugin') ( to be renamed)
- ./manage.py syncdb - ./manage.py syncdb
- install script for needed data will be written.
API Documentation
=== =============
Yes, there is more documentation than this readme! It is present
at k4ever/docs/, but if you want (and have python-sphinx) installed,
you can compile it to nice html (or pdf, ...) pages. There is a
``Makefile`` present to your assistance.

View File

@ -11,25 +11,25 @@ Noch zu tun:
[x] doku [x] doku
[x] API(wget)-Beispiele [x] API(wget)-Beispiele
[ ] Authblob erlaubt momentan beliebige größe - beschrängen auf 10kb o.ä. [ ] Authblob erlaubt momentan beliebige größe - beschrängen auf 10kb o.ä.
[ ] API erlauben mehrere Items auf eine Order zu setzen (und damit auch deposit zu getränk zu kaufen) [x] API erlauben mehrere Items auf eine Order zu setzen (und damit auch deposit zu getränk zu kaufen)
Todo bis release: Todo bis release:
- artikel in datenbank (wir oder gemeinschaftlich am freitag?) [/] artikel in datenbank (wir oder gemeinschaftlich am freitag?)
- barcode client (sping) [ ] barcode client (sping)
- pfand fuer barcode client [x] pfand fuer barcode client
- guter erklärender plugintext [ ] guter erklärender plugintext
- startseite (konrad?) [x] startseite
- beliebte items mit kaufoption, eventuell sortiert nach drei gruppen wie (Getränke, Essen, [Anderes]) oder (Getränke, Süßes, Salziges, [Anderes]) [x] beliebte items mit kaufoption, eventuell sortiert nach drei gruppen wie (Getränke, Essen, [Anderes]) oder (Getränke, Süßes, Salziges, [Anderes])
- einkaufsseite [x] einkaufsseite
- alle items, sortierung nach preis/alphabet [x] alle items, sortierung nach preis/alphabet
- suchfeld fixen (konrad?) [x] suchfeld fixen (konrad?)
[x] image aspect ration checking und/oder irgendwo hinschreiben (seba) [x] image aspect ration checking und/oder irgendwo hinschreiben (seba)
- transaktionsseite schöner machen [x] transaktionsseite schöner machen
- pluginseite (einstellungen) schöner machen [x] pluginseite (einstellungen) schöner machen
- history: items durch bilder ersetzen, pfand drunterschreiben wenn pfand... [x] history: items durch bilder ersetzen, pfand drunterschreiben wenn pfand...
- apidocs probelesen - apidocs probelesen
- icons auf startseite unter loginfeld - icons auf startseite unter loginfeld
- blabla zum kassensystem fuer docs (tannek, seba) [ ] blabla zum kassensystem fuer docs
Nice-to-haf: Nice-to-haf:
@ -48,8 +48,6 @@ Open for discussion:
- 15, besser 20:Man sucht auf ja nach etwas und will sich nicht totklicken ~~~TKroenert - 15, besser 20:Man sucht auf ja nach etwas und will sich nicht totklicken ~~~TKroenert
Konrad: Konrad:
Abmeldebutton rechts oder rot?
- die liste der zu einkaufenden items ist doof :(
- /store/history/ ist noch kaputt + zeit unformatiert
- /transaction/ sehen die gemachten transactions noch nicht so cool aus
- in js verhindern, das wer durch doppelklick auf "KAUFEN" das ding 2x kauft(also 2x http request abgesetzt werden) - in js verhindern, das wer durch doppelklick auf "KAUFEN" das ding 2x kauft(also 2x http request abgesetzt werden)
- BUG: Auf der HOME-seite ist das Bild direkt neben "SNACKS" nicht als link anklickbar
- BUG: directBuy-anzeige ist z.B. auf der HOME-seite hinter den "Kauf"-Buttons

Binary file not shown.

View File

@ -1,15 +0,0 @@
django gibt tabellenstruktur vor
webinterface
mit django
fuer
adminsistration
user preferences
kaufen
undsoweiter
d.h. voller funktionsumfang
-- milestone 2
touchinterface am kuehlschrank
möglichst simpel

54
devel/map.html Normal file
View File

@ -0,0 +1,54 @@
<html><head><title>New Map</title><script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js" type="text/javascript"></script><script type="text/javascript">
jQuery.noConflict();
</script>
<script src="http://vue.tufts.edu/htmlexport-includes/jquery.maphilight.min.js" type="text/javascript"></script><script src="http://vue.tufts.edu/htmlexport-includes/v3/tooltip.min.js" type="text/javascript"></script><script type="text/javascript">jQuery(function() {jQuery.fn.maphilight.defaults = {
fill: false,
fillColor: '000000',
fillOpacity: 0.2,
stroke: true,
strokeColor: '282828',
strokeOpacity: 1,
strokeWidth: 4,
fade: true,
alwaysOn: false
}
jQuery('.example2 img').maphilight();
});
</script>
<style type="text/css">
#tooltip{
position:absolute;
border:1px solid #333;
background:#f7f5d1;
padding:2px 5px;
color:#333;
display:none;
}
</style>
</head><body>
<div class="example2"><img class="map" src="map.png" width="771.0" height="847.0" usemap="#vuemap"><map name="vuemap"> <area id="node0" shape="rect" coords="24,433,243,521"></area>
<area class="tooltip" title="deprecated (json-)
api from Konrad;
used by the
webinterface" id="node1" shape="rect" coords="429,26,515,66"></area>
<area class="tooltip" title="new all-in-one
REST-Api" id="node2" shape="rect" coords="424,113,521,152"></area>
<area class="tooltip" title="/App/ for buyables
like mate,kitkat" id="node3" shape="rect" coords="409,202,534,242"></area>
<area class="tooltip" title="/App/ for login,
register,settings" id="node4" shape="rect" coords="421,307,524,346"></area>
<area class="tooltip" title="/App/ for
moneytransfers" id="node5" shape="rect" coords="396,398,548,437"></area>
<area class="tooltip" title="stores webstuff
(images,css,js)" id="node6" shape="rect" coords="415,527,529,567"></area>
<area class="tooltip" title="django-default" id="node7" shape="rect" coords="401,621,545,661"></area>
<area class="tooltip" title="django-default
(empty)" id="node8" shape="rect" coords="401,784,545,824"></area>
<area class="tooltip" title="maps URLs to
python-(views.py)
functions " id="node9" shape="rect" coords="417,693,527,733"></area>
<area id="node10" shape="rect" coords="695,486,745,518"></area>
<area id="node11" shape="rect" coords="695,537,746,570"></area>
<area id="node12" shape="rect" coords="702,595,737,627"></area>
</map></div></body></html>

BIN
devel/map.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

View File

@ -92,6 +92,10 @@ class BuyableItemHandler(BaseHandler):
amount = getInt(request.data, 'amount', 1) amount = getInt(request.data, 'amount', 1)
if amount < 1: if amount < 1:
return rc.BAD_REQUEST return rc.BAD_REQUEST
if amount > 30:
ret = rc.BAD_REQUEST
ret.write("\nYou are trying to buy more than 30 items at once. This is not permitted. If you think it should, mail the admins / fix this in the handlers.py\n");
return ret
if (not item.hasDeposit() and deposit != self.BUY_ITEM) or \ if (not item.hasDeposit() and deposit != self.BUY_ITEM) or \
deposit not in (self.BUY_ITEM, self.BUY_DEPOSIT, self.BUY_ITEM_AND_DEPOSIT): deposit not in (self.BUY_ITEM, self.BUY_DEPOSIT, self.BUY_ITEM_AND_DEPOSIT):
return rc.BAD_REQUEST return rc.BAD_REQUEST
@ -145,6 +149,11 @@ class BuyableItemHandler(BaseHandler):
ret.write("\nThe items/deposists parameter have to be a list.\n") ret.write("\nThe items/deposists parameter have to be a list.\n")
return ret return ret
if len(itemList) > 30:
ret = rc.BAD_REQUEST
ret.write("\nYou are trying to buy more than 30 items at once. This is not permitted. If you think it should, mail the admins / fix this in the handlers.py\n");
return ret
if len(itemList) == 0: if len(itemList) == 0:
ret = rc.BAD_REQUEST ret = rc.BAD_REQUEST
ret.write("\nYour request contains no items/deposits.\n") ret.write("\nYour request contains no items/deposits.\n")
@ -251,9 +260,9 @@ class TransactionTransactHandler(BaseHandler):
amount = getDecimal(request.POST, 'amount', Decimal(0)) amount = getDecimal(request.POST, 'amount', Decimal(0))
tTypeId = getInt(request.POST, 'type', -1) tTypeId = getInt(request.POST, 'type', -1)
if amount <= 0: if amount < Decimal("0.01"):
ret = rc.BAD_REQUEST ret = rc.BAD_REQUEST
rc.write("\nA negative amount is not supported right now (there has not been put enough thought into the 'lending money' process\n") ret.write("\nA negative amount (or zeroed) is not supported right now (there has not been put enough thought into the 'lending money' process\n")
return ret return ret
tType = None tType = None
try: try:

View File

@ -1,8 +1,12 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load thumbnail %}
{% block "content" %} {% block "content" %}
{% if history %} {% if history %}
<h1>Fr&uuml;here Eink&auml;ufe von {{ user }}</h1> <div style="width:800px">
<h1>Fr&uuml;here Eink&auml;ufe von {{ user }}</h1>
</div>
<div class="pagination" style="width:800px; text-align:center; margin-top:25px"> <div class="pagination" style="width:800px; text-align:center; margin-top:25px">
<table width="100%"> <table width="100%">
<tr> <tr>
@ -51,7 +55,7 @@
{% for item in order.purchase_set.all %} {% for item in order.purchase_set.all %}
<td width="80px"> <td width="80px">
{% if not item.isDeposit %} {% if not item.isDeposit %}
<img src="{{ MEDIA_URL }}{{ item.buyable.image }}" width=64 height=64> <img src="{% thumbnail item.buyable.image 64x64 %}" width=64 height=64>
{% else %} {% else %}
<b>{{ item.buyable.name }} Pfand</b> <b>{{ item.buyable.name }} Pfand</b>
{% endif %} {% endif %}

View File

@ -0,0 +1,42 @@
{% load thumbnail %}
{% if buyables %}
<table class="showitem">
<tbody>
{% for buyable in buyables %}
<tr>
<td class="productImage">
<a href="/store/show/{{ buyable.id }}"><img src="{% thumbnail buyable.image 64x64 %}"/></a>
</td>
<td class="name"><a href="/store/show/{{ buyable.id }}">{{ buyable.name }}</a></td>
<td class="actions">
{% if buyable.hasDeposit %}
<a class="buyButton includingPrice" href="/store/buy/{{ buyable.id }}"
title="Kaufen (Ohne Pfand)">
<span><span>{{ buyable.price|floatformat:2 }} €</span></span>
</a>
<a class="buyButton includingDeposit includingPrice"
href="/store/buy/{{ buyable.id }}/with/deposit" title="Kaufen (Mit Pfand)">
<span><span>{{ buyable.price|floatformat:2 }} € / {{ buyable.deposit|floatformat:2 }} €</span></span>
</a>
<a class="buyButton onlyDeposit includingPrice"
href="/store/buy/{{ buyable.id }}/only/deposit" title="Kaufen (Nur Pfand)">
<span><span>{{ buyable.deposit|floatformat:2 }} €</span></span>
</a>
{% else %}
<a class="buyButton includingPrice" href="/store/buy/{{ buyable.id }}"
title="Kaufen">
<span><span>{{ buyable.price|floatformat:2 }} €</span></span>
</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>{{ default|default_if_none:"Noch keine gekauft" }}</p>
{% endif %}

View File

@ -1,4 +1,6 @@
{% extends "base.html" %} {% extends "base.html" %}
{% load thumbnail %}
{% block "content" %} {% block "content" %}
<p><a href="/store/">Zur Liste aller Items</a></p> <p><a href="/store/">Zur Liste aller Items</a></p>
@ -10,7 +12,7 @@
<tr> <tr>
<td colspan="2" align="center"> <td colspan="2" align="center">
<div style="font-size:large">{{ item.name }}</div> <div style="font-size:large">{{ item.name }}</div>
<img src="{{ MEDIA_URL }}{{ item.image }}"> <img src="{% thumbnail item.image 400x400 %}">
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@ -1,46 +1,8 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block "content" %} {% block "content" %}
<div style="float:left; width=200;"> Sortieren nach <a href="/store/">Letzte Änderung</a> | <a href="?order=alphabet">Alphabet</a> | <a href="?order=price">Preis</a><br/>
<table class="showitem" width="864px" style="border-width:0px"> <div style="width:800px">
{% for item in items %} {% include "buyables/product_list.html" with buyables=items %}
<tr> </div>
<td width="64px">
<a href="/store/show/{{ item.id }}"><img WIDTH=64 HEIGHT=64 src="{{ MEDIA_URL }}{{ item.image }}"></a>
</td>
<th width="200px" align="center">
<span style="font-size: large">{{ item.name }}</span><br/>
<a href="/store/show/{{ item.id }}">Details</a>
</th>
<td width="200px">
<a class="button" href="/store/buy/{{ item.id }}/">Kaufen f&uuml;r {{ item.price|floatformat:2 }} €<br/>{% if item.hasDeposit %} (Ohne Pfand){% endif %}</a>
</td>
<td width="200px">
{% if item.hasDeposit %}
<a class="button" href="/store/buy/{{ item.id }}/with/deposit/">Kaufen f&uuml;r {{ item.price|floatformat:2 }} € <br/>+ {{ item.deposit|floatformat:2 }} € Pfand</a>
{% else %}
&nbsp;
{% endif %}
</td>
<td width="200px">
{% if item.hasDeposit %}
<a class="button" href="/store/buy/{{ item.id }}/only/deposit/">Kaufen <br/>nur {{ item.deposit|floatformat:2 }} € Pfand</a>
{% else %}
&nbsp;
{% endif %}
</td>
</tr>
{% comment %}
Buy <a href="/store/buy/{{ item.id }}/">it!</a>
{% if item.hasDeposit %}
<a href="/store/buy/{{ item.id }}/with/deposit/">it+deposit!</a>
<a href="/store/buy/{{ item.id }}/only/deposit/"> only deposit!</a>
{% endif %}
</br> (
{% for type in item.buyableType.all %}
{{ type }}
{% endfor %} )
</div>{% endcomment %}
{% endfor %}
</table>
{% endblock %} {% endblock %}

View File

@ -11,6 +11,17 @@ from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger, Invali
def showItems(request): def showItems(request):
# FIXME: Implement pagination here # FIXME: Implement pagination here
items = Buyable.objects.all() items = Buyable.objects.all()
try:
order_by = request.GET.get('order', 'date')
except ValueError:
order_by = 'date'
if order_by == 'alphabet':
items = items.order_by('name')
if order_by == 'price':
items = items.order_by('price')
return render_to_response("buyables/showItems.html", {'items': items}, RequestContext(request)) return render_to_response("buyables/showItems.html", {'items': items}, RequestContext(request))
@login_required @login_required

View File

@ -1,31 +1,29 @@
{% load thumbnail %}
{% if buyables %} {% if buyables %}
{% if removeWrapper == None %} <table width=100% class="showitem">
<table width=100%>
<tbody> <tbody>
{% endif %}
{% for buyable in buyables %} {% for buyable in buyables %}
<tr> <tr>
<td class="productImage"> <td class="productImage">
<a href="/store/show/{{ buyable.buyable__id }}"><img src="{{ MEDIA_URL }}{{ buyable.buyable__image }}" /></a> <a href="/store/show/{{ buyable.buyable__id }}"><img src="{% thumbnail buyable.buyable__image 64x64 %}" /></a>
</td> </td>
<td class="name"><span>{{ buyable.buyable__name }}</span> ({{ buyable.num_buys }} mal gekauft)</td> <td class="name"><span>{{ buyable.buyable__name }}</span> {% if buyable.num_buys %}({{ buyable.num_buys }} mal gekauft){% endif %}</td>
<td> <td class="actions">
{% if buyable.buyable__deposit > 0 %} {% if buyable.buyable__deposit > 0 %}
<a class="buyButton" href="/store/buy/{{ buyable.buyable__id }}" title="Kaufen (Ohne Pfand)"><span>Kaufen (Ohne Pfand)</span></a> <a class="buyButton includingPrice" href="/store/buy/{{ buyable.buyable__id }}" title="Kaufen (Ohne Pfand)"><span><span>{{ buyable.buyable__price|floatformat:2 }}€</span></span></a>
<a class="buyButton includingDeposit" href="/store/buy/{{ buyable.buyable__id }}/with/deposit" title="Kaufen (Mit Pfand)"><span>Kaufen (Mit Pfand)</span></a> <a class="buyButton includingDeposit includingPrice" href="/store/buy/{{ buyable.buyable__id }}/with/deposit" title="Kaufen (Mit Pfand)"><span><span>{{ buyable.buyable__price|floatformat:2 }} € / {{ buyable.buyable__deposit|floatformat:2 }}€</span></span></a>
{% if includeDeposit %} {% if includeDeposit %}
<a class="buyButton onlyDeposit" href="/store/buy/{{ buyable.buyable__id }}/only/deposit" title="Kaufen (Nur Pfand)"><span>Kaufen (Nur Pfand)</span></a> <a class="buyButton onlyDeposit" href="/store/buy/{{ buyable.buyable__id }}/only/deposit" title="Kaufen (Nur Pfand)"><span><span>{{ buyable.buyable__deposit|floatformat:2 }}€</span></span></a>
{% endif %} {% endif %}
{% else %} {% else %}
<a class="buyButton" href="/store/buy/{{ buyable.buyable__id }}" title="Kaufen"><span>Kaufen</span></a> <a class="buyButton" href="/store/buy/{{ buyable.buyable__id }}" title="Kaufen"><span><span>{{ buyable.buyable__price|floatformat:2 }}€</span></span></a>
{% endif %} {% endif %}
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
{% if removeWrapper == None %}
</tbody> </tbody>
</table> </table>
{% endif %}
{% else %} {% else %}
<p>{{ default|default_if_none:"Noch keine gekauft" }}</p> <p>{{ default|default_if_none:"Noch keine gekauft" }}</p>
{% endif %} {% endif %}

View File

@ -1,6 +1,6 @@
<form method="post" action="/what/do/i/know"> <form method="get" action="#">
<input placeholder="Suche und kaufe..." class="autocomplete" <input placeholder="Suche und kaufe..." class="autocomplete"
type="search" name="search_term" value="Lade Daten..." type="search" name="search_term" value="Lade Daten..."
disabled="disabled" /> disabled="disabled" />
<input type="submit" value="Suchen" /> <input type="submit" value="Suchen" />
</form> </form>

View File

@ -2,7 +2,7 @@
{% block "content" %} {% block "content" %}
{% if allMostDrinks or allMostSnacks %} {% if allMostDrinks or allMostSnacks %}
<table class="showitem"> <table style="border: 0 none; width:100%">
<thead> <thead>
<tr> <tr>
<td role="presentation">&nbsp;</td> <td role="presentation">&nbsp;</td>
@ -14,25 +14,25 @@
<tbody> <tbody>
<tr> <tr>
<th scope="row">Getränke</th> <th scope="row">Getränke</th>
<td> <td style="vertical-align:top">
{% include "main/product_list.html" with buyables=allMostDrinks %} {% include "main/product_list.html" with buyables=allMostDrinks %}
</td> </td>
<td> <td style="vertical-align:top">
{% include "main/product_list.html" with buyables=usersMostDrinks %} {% include "main/product_list.html" with buyables=usersMostDrinks %}
</td> </td>
<td> <td style="vertical-align:top">
{% include "main/product_list.html" with buyables=usersLastDrinks %} {% include "main/product_list.html" with buyables=usersLastDrinks %}
</td> </td>
</tr> </tr>
<tr> <tr style="border-top: 2px solid #ECECEC">
<th scope="row">Snacks</th> <th scope="row">Snacks</th>
<td> <td style="vertical-align.top">
{% include "main/product_list.html" with buyables=allMostSnacks %} {% include "main/product_list.html" with buyables=allMostSnacks %}
</td> </td>
<td> <td style="vertical-align:top">
{% include "main/product_list.html" with buyables=usersMostSnacks %} {% include "main/product_list.html" with buyables=usersMostSnacks %}
</td> </td>
<td> <td style="vertical-align:top">
{% include "main/product_list.html" with buyables=usersLastSnacks %} {% include "main/product_list.html" with buyables=usersLastSnacks %}
</td> </td>
</tr> </tr>

View File

@ -18,4 +18,10 @@
<input type="submit" value="Anmelden" /> <input type="submit" value="Anmelden" />
<input type="hidden" name="next" value="{{ next }}" /> <input type="hidden" name="next" value="{{ next }}" />
</form> </form>
<div class="notice">
<h2>Das Kassensystem ist 'Aktiv' - nutzt euren Frunden-Account</h2>
</div>

View File

@ -1,13 +1,12 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block "content" %} {% block "content" %}
<h2>Passwort</h2> <div style="width:800px">
<hr /> <h1>Passwort</h1>
Da die meisten der Nutzer dieses Systems &uuml;ber den LDAP der Freitagsrunde laufen, kann man hier sein Passwort nicht &auml;ndern. Wenn du dein Passwort trotzdem &auml;ndern m&ouml;chstest (und dieses System nicht &uuml;ber einen Freitagsrundenaccount benutzt), wende dich bitte an einen der Freitagsrunden-Admins. (lies: not implemented) Da die meisten der Nutzer dieses Systems &uuml;ber den LDAP der Freitagsrunde laufen, kann man hier sein Passwort nicht &auml;ndern. Wenn du dein Passwort trotzdem &auml;ndern m&ouml;chstest (und dieses System nicht &uuml;ber einen Freitagsrundenaccount benutzt), wende dich bitte an einen der Freitagsrunden-Admins. (lies: not implemented)
<br /> </div>
<br /> <div style="width:800px; margin-top: 25px">
<h2>Plugin Berechtigungen</h2> <h1>Pluginberechtigungen</h1>
<hr />
{% if pluginerror %} {% if pluginerror %}
<font color="red">{{ pluginerror|safe }}</font> <font color="red">{{ pluginerror|safe }}</font>
{% endif %} {% endif %}
@ -15,28 +14,33 @@
<font color="green">{{ pluginmsg|safe }}</font> <font color="green">{{ pluginmsg|safe }}</font>
{% endif %} {% endif %}
<p> <p>
<table> <table style="border: 2px solid #BBBBBB; -moz-border-radius: 3px; -webkit-border-radius: 3px; -khtml-border-radius: 3px; border-radius: 3px">
<tr> <tr style="height: 40px">
<th>Name</th> {% if permissions %}
<th>Author</th> <th rowspan={{ permissions|length|add:"1"}} style="vertical-align:middle; text-align:center; color:#0cb31c; -moz-transform: rotate(270deg); -webkit-transform: rotate(270deg); -ms-transform: rotate(270deg); -o-transform: rotate(270deg); transform: rotate(270deg)">Erlaubt</th>
<th>Version</th> {% else %}
<th>Beschreibung</th> <th>&nbsp;</th>
<th>AuthBlob</th> {% endif %}
<th>Erlauben/Verbieten</th> <th width="100px" style="vertical-align:middle">Name</th>
<th width="100px" style="vertical-align:middle">Author</th>
<th style="vertical-align:middle">Beschreibung</th>
<th width="100px" style="vertical-align:middle">AuthBlob</th>
<th width="150px" style="vertical-align:middle">Erlauben/Verbieten</th>
</tr> </tr>
{% for p in permissions %} {% for p in permissions %}
<tr style="background: green"> <tr>
<td style="vertical-align:middle">{{ p.plugin.name }}</td> <td style="vertical-align:middle; text-align:center">{{ p.plugin.name }}<br/>{{ p.plugin.version }}</td>
<td style="vertical-align:middle">{{ p.plugin.author }}</td> <td style="vertical-align:middle; text-align:center">{{ p.plugin.author }}</td>
<td style="vertical-align:middle">{{ p.plugin.version }}</td> <td style="vertical-align:middle; text-align:center"><div style="margin: 5px">{{ p.plugin.descr }}</div></td>
<td style="vertical-align:top">{{ p.plugin.descr }}</td> <td style="text-align:center">
<td>
{% if p.plugin.userCanWriteAuthblob %} {% if p.plugin.userCanWriteAuthblob %}
<form method="post" action="/user/settings/plugin/authblob/{{ p.plugin.id }}/"> <div style="margin:5px">
{% csrf_token %} <form method="post" action="/user/settings/plugin/authblob/{{ p.plugin.id }}/">
<textarea name="authblob">{{ p.authblob }}</textarea> {% csrf_token %}
<input type="submit" value="Speichern"> <textarea name="authblob">{{ p.authblob }}</textarea>
</form> <input type="submit" value="Speichern">
</form>
</div>
{% else %} {% else %}
{% if p.plugin.userCanReadAuthblob %} {% if p.plugin.userCanReadAuthblob %}
{{ p.authblob }} {{ p.authblob }}
@ -45,20 +49,22 @@
{% endif %} {% endif %}
{% endif %} {% endif %}
</td> </td>
<td style="vertical-align:middle"><a href="/user/settings/plugin/deny/{{ p.plugin.id }}/">Plugin verbieten</a></td> <td style="vertical-align:middle; text-align:center"><a href="/user/settings/plugin/deny/{{ p.plugin.id }}/" class="button" style="color: #e61e1e; margin-bottom: 35px">Plugin verbieten</a></td>
</tr> </tr>
{% endfor %} {% endfor %}
{% for plugin in unallowed %} {% if unallowed %}
<tr style="background: red"> <tr style="border-top: 1px solid #BBBBBB">
<td style="vertical-align:middle">{{ plugin.name }}</td> <th rowspan={{ unallowed|length}} style="vertical-align:middle; text-align:center; color:#e61e1e; -moz-transform: rotate(270deg); -webkit-transform: rotate(270deg); -ms-transform: rotate(270deg); -o-transform: rotate(270deg); transform: rotate(270deg)">Verboten</th>
<td style="vertical-align:middle">{{ plugin.author }}</td> {% for plugin in unallowed %}
<td style="vertical-align:middle">{{ plugin.version }}</td> <td style="vertical-align:middle; text-align:center">{{ plugin.name }}<br/>{{ plugin.version }}</td>
<td style="vertical-align:top">{{ plugin.descr }}</td> <td style="vertical-align:middle; text-align:center">{{ plugin.author }}</td>
<td>&nbsp;</td> <td style="vertical-align:middle; text-align:center"><div style="margin:5px">{{ plugin.descr }}</div></td>
<td style="vertical-align:middle"><a href="/user/settings/plugin/allow/{{ plugin.id }}/">Plugin erlauben</a></td> <td>&nbsp;</td>
</tr> <td style="vertical-align:middle; text-align:center"><a class="button" href="/user/settings/plugin/allow/{{ plugin.id }}/" style="color: #0cb31c; margin-buttom: 35px">Plugin erlauben</a></td>
{% endfor %} </tr>
<tr>
{% endfor %}
{% endif %}
</table> </table>
</p> </p>
{% endblock %} {% endblock %}

View File

@ -20,18 +20,20 @@ def startpage(request):
allMostDrinks = allMost.filter(buyable__in=drinks).annotate(num_buys=Count('buyable')).order_by('-num_buys') allMostDrinks = allMost.filter(buyable__in=drinks).annotate(num_buys=Count('buyable')).order_by('-num_buys')
allMostSnacks = allMost.filter(buyable__in=snacks).annotate(num_buys=Count('buyable')).order_by('-num_buys') allMostSnacks = allMost.filter(buyable__in=snacks).annotate(num_buys=Count('buyable')).order_by('-num_buys')
usersMostDrinks = allMost.filter(buyable__in=drinks).filter(order__user=request.user.id).annotate(num_buys=Count('buyable')).order_by('-num_buys') usersMostDrinks = allMost.filter(buyable__in=drinks).filter(order__user=request.user.id).annotate(num_buys=Count('buyable')).order_by('-num_buys')
usersMostSnacks = allMost.filter(buyable__in=snacks).filter(order__user=request.user.id).annotate(num_buys=Count('buyable')).order_by('-num_buys') usersMostSnacks = allMost.filter(buyable__in=snacks).filter(order__user=request.user.id).annotate(num_buys=Count('buyable')).order_by('-num_buys')
# usersLastDrinks = allMost.filter(buyable__in=drinks).filter(order__user=request.user.id).annotate(num_buys=Count('buyable')).order_by('-order__dateTime') usersLastDrinks = allMost.filter(buyable__in=drinks).filter(order__user=request.user.id).annotate(num_buys=Count('buyable')).order_by('-order__dateTime')
# usersLastSnacks = allMost.filter(buyable__in=snacks).filter(order__user=request.user.id).annotate(num_buys=Count('buyable')).order_by('-order__dateTime') usersLastSnacks = allMost.filter(buyable__in=snacks).filter(order__user=request.user.id).annotate(num_buys=Count('buyable')).order_by('-order__dateTime')
usersLastDrinks = allMost.distinct().filter(buyable__in=drinks).filter(order__user=request.user.id).order_by('-order__dateTime')
usersLastSnacks = allMost.distinct().filter(buyable__in=snacks).filter(order__user=request.user.id).order_by('-order__dateTime')
usersLastDrinks = allMost.filter(buyable__in=drinks).filter(order__user=request.user.id).order_by('-order__dateTime')
usersLastSnacks = allMost.filter(buyable__in=snacks).filter(order__user=request.user.id).order_by('-order__dateTime')
#if someone knows a better way to do this, just replace this code #if someone knows a better way to do this, just replace this code
#purpose: filter usersLast so that it only contains unique items #purpose: filter usersLast so that it only contains unique items
#hint: distinct() does not work because dateTime is included due to order_by(), so all items appear distinct
usersLastDrinks_unique = [] usersLastDrinks_unique = []
for x in usersLastDrinks: for x in usersLastDrinks:
if not x in usersLastDrinks_unique: if not x in usersLastDrinks_unique:
@ -43,9 +45,10 @@ def startpage(request):
for x in usersLastSnacks: for x in usersLastSnacks:
if not x in usersLastSnacks_unique: if not x in usersLastSnacks_unique:
usersLastSnacks_unique.append(x) usersLastSnacks_unique.append(x)
#usersLastSnacks_unique = usersLastSnacks.distinct()
usersLastSnacks = usersLastSnacks_unique usersLastSnacks = usersLastSnacks_unique
return render_to_response("main/startpage.html", {'allMostDrinks' : allMostDrinks[:5], 'allMostSnacks' : allMostSnacks[:5], 'usersMostDrinks': usersMostDrinks[:5], 'usersMostSnacks': usersMostSnacks[:5], 'usersLastDrinks' : usersLastDrinks[:10], 'usersLastSnacks' : usersLastSnacks[:10]}, RequestContext(request)) return render_to_response("main/startpage.html", {'allMostDrinks' : allMostDrinks[:5], 'allMostSnacks' : allMostSnacks[:5], 'usersMostDrinks': usersMostDrinks[:5], 'usersMostSnacks': usersMostSnacks[:5], 'usersLastDrinks' : usersLastDrinks[:5], 'usersLastSnacks' : usersLastSnacks[:5]}, RequestContext(request))
def register(request): def register(request):
""" The "no registration available" page... """ """ The "no registration available" page... """
@ -122,9 +125,13 @@ def pluginAuthblob(request, pluginId):
d['pluginerror'] = "Der Authblob darf f&uuml;r dieses Plugin nicht vom User ver&auml;ndert werden (oder der Authblob war kaputt)" d['pluginerror'] = "Der Authblob darf f&uuml;r dieses Plugin nicht vom User ver&auml;ndert werden (oder der Authblob war kaputt)"
return render_to_response("settings/settings.html", d, RequestContext(request)) return render_to_response("settings/settings.html", d, RequestContext(request))
if p.plugin.uniqueAuthblob and PluginPermission.objects.filter(plugin=plugin, authblob=request.POST["authblob"]).count() > 0: pluginsWithAuthblob = PluginPermission.objects.filter(plugin=plugin, authblob=request.POST["authblob"])
if p.plugin.uniqueAuthblob and pluginsWithAuthblob.count() > 0:
d = getPluginDict(request) d = getPluginDict(request)
d['pluginerror'] = "Achtung! Dein Authblob wird bereits von einer anderen Person benutzt. Bitte w&auml;hle einen anderen (eindeutigen) Authblob!" if pluginsWithAuthblob[0].user == request.user:
d['pluginerror'] = "Das ist der gleiche Authblob, den du vorher auch hattest."
else:
d['pluginerror'] = "Achtung! Dein Authblob wird bereits von einer anderen Person benutzt. Bitte w&auml;hle einen anderen (eindeutigen) Authblob!"
return render_to_response("settings/settings.html", d, RequestContext(request)) return render_to_response("settings/settings.html", d, RequestContext(request))
p.authblob = request.POST['authblob'] p.authblob = request.POST['authblob']

View File

@ -38,10 +38,15 @@ body {
line-height: 1; line-height: 1;
} }
h1, h2, h3, h4, h5, h6, th { h1, h2, h3, h4, h5, h6, th {
clear: both; clear: both;
font-weight: bold; font-weight: bold;
font-family: "Istok Web", inherit; text-align: center;
margin-bottom: 10px;
/* Sans-Serif? Srsly???
font-family: "Istok Web", inherit; */
} }
ol, ul, li { ol, ul, li {
@ -396,7 +401,7 @@ table.showitem td.productImage img {
table.showitem th { table.showitem th {
font-size: 20px; font-size: 20px;
text-align:center; text-align:center;
} }*/
table.showitem td.name { table.showitem td.name {
padding: 0 10px; padding: 0 10px;
@ -407,6 +412,19 @@ table.showitem td.name span {
font-weight: bold; font-weight: bold;
} }
table.showitem td.name a {
display: block;
font: 20px "Istok Web", inherit;
text-decoration: none;
color: inherit;
font-weight: bold;
}
table.showitem tbody tr:nth-child(even) td.name,
table.showitem tbody tr:nth-child(even) td.actions {
background-color: #ececec;
}
table.showitem td, table.showitem th { table.showitem td, table.showitem th {
vertical-align: middle; vertical-align: middle;
} }
@ -429,11 +447,14 @@ table.showitem th[scope="row"] {
a.buyButton { a.buyButton {
display: block; display: block;
padding: 5px 10px; padding: 5px 10px;
margin: 10px 10px 15px 0;
position: relative;
height: 32px; height: 32px;
text-align: center; text-align: center;
border-radius: 6px; border-radius: 6px;
float: left; float: left;
margin-right: 10px; z-index: 2;
text-decoration: none;
background-image: -webkit-gradient(linear, left top, left bottom, from(#666666), to(#111111)); background-image: -webkit-gradient(linear, left top, left bottom, from(#666666), to(#111111));
background-image: -webkit-linear-gradient(top, #666666, #111111); background-image: -webkit-linear-gradient(top, #666666, #111111);
@ -448,7 +469,12 @@ a.buyButton {
box-shadow: 0 1px 3px 0 black; box-shadow: 0 1px 3px 0 black;
} }
a.buyButton:hover { a.buyButton.includingPrice {
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.content a.buyButton:hover {
background-image: -webkit-gradient(linear, left top, left bottom, from(#555555), to(#000000)); background-image: -webkit-gradient(linear, left top, left bottom, from(#555555), to(#000000));
background-image: -webkit-linear-gradient(top, #555555, #000000); background-image: -webkit-linear-gradient(top, #555555, #000000);
background-image: -moz-linear-gradient(top, #555555, #000000); background-image: -moz-linear-gradient(top, #555555, #000000);
@ -465,15 +491,52 @@ a.buyButton:active {
box-shadow: 0 1px 3px 0 black, 0 1px 3px 0 black inset; box-shadow: 0 1px 3px 0 black, 0 1px 3px 0 black inset;
} }
a.buyButton.includingDeposit span { a.buyButton.includingDeposit > span {
background-image: url("img/payment_deposit.png"); background-image: url("img/payment_deposit.png");
min-width: 65px; min-width: 65px;
} }
a.buyButton span { a.buyButton.onlyDeposit > span {
background-image: url("img/deposit.png");
}
a.buyButton > span {
display: block; display: block;
height: 100%; height: 100%;
min-width: 32px; min-width: 32px;
background: url("img/payment.png") no-repeat center center transparent; background: url("img/payment.png") no-repeat center center transparent;
text-indent: -10000px; }
.content a {
color: #3398CC;
text-decoration: none;
}
.content a:hover {
color: white;
background: #3398CC;
}
.content a.button {
display: block;
margin-top: 7px;
padding: 0 10px;
text-align: center;
}
a.buyButton > span > span {
position: absolute;
bottom: -15px;
left: 0;
display: block;
width: 100%;
z-index: 1;
border-bottom-left-radius: 6px;
border-bottom-right-radius: 6px;
background-color: #3398cc;
color: white;
-moz-box-shadow: 0 1px 3px 0 black, 0 1px 1px 0 black inset;
-webkit-box-shadow: 0 1px 3px 0 black, 0 1px 1px 0 black inset;
box-shadow: 0 1px 3px 0 black, 0 1px 1px 0 black inset;
} }

1
k4ever/media/docs Symbolic link
View File

@ -0,0 +1 @@
../docs/_build/html/

View File

@ -74,7 +74,7 @@ LOGIN_REDIRECT_URL = '/'
AUTHENTICATION_BACKENDS = ( AUTHENTICATION_BACKENDS = (
# 'main.backend.CustomLDAPBackend', # 'main.backend.CustomLDAPBackend',
# 'django_auth_ldap.backend.LDAPBackend', 'django_auth_ldap.backend.LDAPBackend',
'django.contrib.auth.backends.ModelBackend', 'django.contrib.auth.backends.ModelBackend',
) )
@ -129,4 +129,5 @@ INSTALLED_APPS = (
'main', 'main',
# Uncomment the next line to enable the admin: # Uncomment the next line to enable the admin:
'django.contrib.admin', 'django.contrib.admin',
'easy_thumbnails',
) )