Compare commits

..

1 Commits

Author SHA1 Message Date
Sebastian Lohff 63b3f71141 Migration to Django 1.10 2018-10-24 01:03:53 +02:00
31 changed files with 258 additions and 189 deletions

1
.gitignore vendored
View File

@ -8,6 +8,7 @@
k4ever/k4ever.db
k4ever/media/img/
k4ever/settings.py
k4ever/k4ever/settings.py
*.kdev4
.kdev4
*.kate-swp

View File

@ -10,7 +10,7 @@ from django.contrib.auth.models import User, Group
from piston.utils import rc
from main.models import Plugin, PluginPermission
from settings import PLUGIN_GROUP_ID
from k4ever.settings import PLUGIN_GROUP_ID
def manglePluginPerms(apiFunc):
""" Changes to a given user when the authenticated user is an plugin.

View File

@ -8,8 +8,8 @@
from easy_thumbnails.files import get_thumbnailer
from piston.handler import BaseHandler
from piston.utils import rc
from k4ever.buyable.models import *
from k4ever.transaction.models import *
from buyable.models import *
from transaction.models import *
from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth.models import Group
from django.core.exceptions import MultipleObjectsReturned
@ -116,7 +116,7 @@ class BuyableItemHandler(BaseHandler):
p.save(saveOrder=False)
order.save()
return {'success': True, 'balance': request.user.get_profile().balance}
return {'success': True, 'balance': request.user.userprofile_set.get().balance}
def bulkBuy(self, request):
"""Buy a :class:`Buyable <buyable.models.Buyable>` item.
@ -179,7 +179,7 @@ class BuyableItemHandler(BaseHandler):
p.save(saveOrder=False)
order.save()
return {'success': True, 'balance': request.user.get_profile().balance}
return {'success': True, 'balance': request.user.userprofile_set.get().balance}
class BuyableTypeHandler(BaseHandler):
@ -290,7 +290,7 @@ class TransactionTransactHandler(BaseHandler):
return getError(rc.BAD_REQUEST, "Your TransactionType could not be found")
trans = Transaction(user=request.user, transactionType=tType, amount=amount, checked=not tType.needsCheck)
trans.save()
return {'success': True, 'balance': request.user.get_profile().balance}
return {'success': True, 'balance': request.user.userprofile_set.get().balance}
class TransactionTypeHandler(BaseHandler):
"""Handler for :class:`Transaction Types <transaction.models.TransactionType>`
@ -348,7 +348,7 @@ class TransactionVirtualHandler(BaseHandler):
return getError(rc.BAD_REQUEST, "The recipient user does not exist.")
trans = VirtualTransaction(user=request.user, recipient=recipient, amount=amount, comment=comment)
trans.save()
return {'success': True, 'balance': request.user.get_profile().balance}
return {'success': True, 'balance': request.user.userprofile_set.get().balance}
class AccountBalanceHandler(BaseHandler):
"""Handler for the user's account balance"""
@ -357,7 +357,7 @@ class AccountBalanceHandler(BaseHandler):
@manglePluginPerms
def read(self, request):
"""Returns the user's current account balance"""
balance = request.user.get_profile().balance
balance = request.user.userprofile_set.get().balance
return {'balance': balance}
class AuthBlobHandler(BaseHandler):

View File

@ -5,7 +5,7 @@
#
# Licensed under GNU Affero General Public License v3 or later
from django.conf.urls.defaults import *
from django.conf.urls import url, include
from piston.resource import Resource
from piston.authentication import HttpBasicAuthentication
from api2.authentication import DjangoAuthentication, MultiAuthentication
@ -47,7 +47,7 @@ authUserRes = CsrfExemptResource(handler=AuthUserHandler, **ad)
configRes = CsrfExemptResource(handler=ConfigHandler, **ad)
urlpatterns = patterns('',
urlpatterns = (
url(r'buyable/item/?$', buyableItemRes),
url(r'buyable/item/(?P<itemId>\d+)/?$', buyableItemRes),
url(r'buyable/item/bulkbuy/?$', buyableItemRes, {'bulkBuy': True}),

View File

@ -15,6 +15,7 @@ class BuyableAdminForm(forms.ModelForm):
""" Special BuyableAdminForm which checks the buyable image for an 1:1 aspect ratio. """
class Meta:
model = Buyable
exclude = []
def clean_image(self):
img = self.cleaned_data['image']

View File

@ -1,4 +1,4 @@
from django.db.models.signals import post_syncdb
from django.db.models.signals import post_migrate
from django.core.management import commands, call_command
import buyable.models
@ -6,5 +6,5 @@ def createBuyableTypes(sender, app, created_models, **kwargs):
if buyable.models.BuyableType in created_models:
call_command("loaddata", "buyable_types")
post_syncdb.connect(createBuyableTypes, sender=buyable.models)
post_migrate.connect(createBuyableTypes, sender=buyable.models)

View File

@ -79,7 +79,7 @@ class Order(models.Model):
return l.rstrip(u", ")
def save(self, *args, **kwargs):
profile = self.user.get_profile()
profile = self.user.userprofile_set.get()
if self.id == None:
# new item, get it!
profile.balance -= self.price
@ -88,12 +88,12 @@ class Order(models.Model):
# get old
oldobj = Order.objects.get(id=self.id)
if oldobj.user == self.user:
profile = self.user.get_profile()
profile = self.user.userprofile_set.get()
profile.balance -= (self.price - oldobj.price)
profile.save()
else:
oldProfile = oldobj.user.get_profile()
newProfile = self.user.get_profile()
oldProfile = oldobj.user.userprofile_set.get()
newProfile = self.user.userprofile_set.get()
oldProfile.balance += oldobj.price
oldProfile.save()
newprofile.balance -= self.price
@ -111,7 +111,7 @@ class Order(models.Model):
# where all the buyables have not updated the price
updOrder = Order.objects.get(id=instance.id)
if updOrder.price != Decimal("0"):
profile = updOrder.user.get_profile()
profile = updOrder.user.userprofile_set.get()
profile.balance += updOrder.price
profile.save()

View File

@ -15,21 +15,21 @@
{% for buyable in buyables %}
<li class="span2" title="{{ buyable.name }}" rel="tooltip">
<div class="thumbnail">
<a class="image" href="{% url buyable_show buyable.id %}">
<a class="image" href="{% url 'buyable_show' buyable.id %}">
<img src="{% thumbnail buyable.image 128x128 %}" alt="{{ buyable.name }}" />
</a>
<div class="caption">
<h4><a href="{% url buyable_show buyable.id %}">{{ buyable.name }}</a></h4>
<h4><a href="{% url 'buyable_show' buyable.id %}">{{ buyable.name }}</a></h4>
<div class="btn-toolbar">
<div class="btn-group" data-id="{{ buyable.id}}" data-name="{{ buyable.name }}" data-image="{% thumbnail buyable.image 48x48 %}">
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" href="#">Kaufen<span class="caret"></span></a>
<ul class="dropdown-menu" style="text-align: left">
{% if buyable.hasDeposit %}
<li><a class="buy" href="{% url buyable_buy buyable.id %}"><i class="icon-tag"></i> Kaufen (Ohne Pfand) - {{ buyable.price|floatformat:2 }}</a></li>
<li><a class="buy inclDeposit" href="{% url buyable_buy buyable.id "with/deposit" %}"><i class="icon-tags"></i> Kaufen (Mit Pfand) - {{ buyable.price|floatformat:2 }} / {{ buyable.deposit|floatformat:2 }}</a></li>
<li><a class="buy onlyDeposit" href="{% url buyable_buy buyable.id "only/deposit" %}"><i class="icon-retweet"></i> Kaufen (Nur Pfand) - {{ buyable.deposit|floatformat:2 }}</a></li>
<li><a class="buy" href="{% url 'buyable_buy' buyable.id %}"><i class="icon-tag"></i> Kaufen (Ohne Pfand) - {{ buyable.price|floatformat:2 }}</a></li>
<li><a class="buy inclDeposit" href="{% url 'buyable_buy' buyable.id "with/deposit" %}"><i class="icon-tags"></i> Kaufen (Mit Pfand) - {{ buyable.price|floatformat:2 }} / {{ buyable.deposit|floatformat:2 }}</a></li>
<li><a class="buy onlyDeposit" href="{% url 'buyable_buy' buyable.id "only/deposit" %}"><i class="icon-retweet"></i> Kaufen (Nur Pfand) - {{ buyable.deposit|floatformat:2 }}</a></li>
{% else %}
<li><a class="buy" href="{% url buyable_buy buyable.id %}"><i class="icon-tag"></i> Kaufen (Ohne Pfand) - {{ buyable.price|floatformat:2 }}</a></li>
<li><a class="buy" href="{% url 'buyable_buy' buyable.id %}"><i class="icon-tag"></i> Kaufen (Ohne Pfand) - {{ buyable.price|floatformat:2 }}</a></li>
{% endif %}
</ul>
</div>

View File

@ -5,14 +5,16 @@
#
# Licensed under GNU Affero General Public License v3 or later
from django.conf.urls.defaults import *
from django.conf.urls import url
import buyable.views
#/store/
urlpatterns = patterns('',
(r'^$', 'buyable.views.showItems'),
url(r'^show/(\d+)/$', 'buyable.views.showItem', name='buyable_show'),
url(r'^buy/(\d+)/$', 'buyable.views.buyItem', name='buyable_buy'),
url(r'^buy/(\d+)/(with/deposit|only/deposit)/$', 'buyable.views.buyItem', name='buyable_buy'),
(r'^bought/(\d+)/?$', 'buyable.views.boughtItem'),
(r'^history/?$', 'buyable.views.history'),
urlpatterns = (
url(r'^$', buyable.views.showItems, name='buyable_overview'),
url(r'^show/(\d+)/$', buyable.views.showItem, name='buyable_show'),
url(r'^buy/(\d+)/$', buyable.views.buyItem, name='buyable_buy'),
url(r'^buy/(\d+)/(with/deposit|only/deposit)/$', buyable.views.buyItem, name='buyable_buy'),
url(r'^bought/(\d+)/?$', buyable.views.boughtItem),
url(r'^history/?$', buyable.views.history, name='buyable_history'),
)

View File

@ -6,7 +6,7 @@
#
# Licensed under GNU Affero General Public License v3 or later
from django.shortcuts import render_to_response
from django.shortcuts import render
from django.template import RequestContext
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect
@ -29,7 +29,7 @@ def showItems(request):
if order_by == 'price':
items = items.order_by('price')
return render_to_response("buyables/showItems.html", {'items': items}, RequestContext(request))
return render(request, "buyables/showItems.html", {'items': items})
@login_required
def showItem(request, itemid):
@ -38,7 +38,7 @@ def showItem(request, itemid):
except Buyable.DoesNotExist:
# baww, kein item mit der id :( (oder mutax trollt rum)
return HttpResponseRedirect("/buy/")
return render_to_response("buyables/showItem.html", {'item': item}, RequestContext(request))
return render(request, "buyables/showItem.html", {'item': item})
@login_required
@ -76,7 +76,7 @@ def boughtItem(request, orderid):
if error == None and (item.user != request.user):
item1 = None
error = u"Diese Items gehören dir nicht"
return render_to_response("buyables/itemBought.html", {'order': item, 'error': error}, RequestContext(request))
return render(request, "buyables/itemBought.html", {'order': item, 'error': error})
@login_required
def history(request):
@ -98,4 +98,4 @@ def history(request):
# If page is out of range, deliver last page
histpage = paginator.page(paginator.num_pages)
return render_to_response("buyables/history.html", {'history': histpage}, RequestContext(request))
return render(request, "buyables/history.html", {'history': histpage})

View File

View File

@ -1,7 +1,10 @@
# Django settings for k4ever project.
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DEBUG = False
TEMPLATE_DEBUG = DEBUG
PISTON_DISPLAY_ERRORS = DEBUG
DEBUG_PROPOGATE_EXCEPTIONS = DEBUG
@ -14,7 +17,7 @@ MANAGERS = ADMINS
# use sqlite by default
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'k4ever.db', # Or path to database file if using sqlite3.
'USER': '', # Not used with sqlite3.
'PASSWORD': '', # Not used with sqlite3.
@ -59,6 +62,7 @@ MEDIA_ROOT = 'media/'
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
MEDIA_URL = '/media/'
STATIC_URL = '/static/'
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
@ -77,16 +81,36 @@ AUTH_PROFILE_MODULE = 'main.UserProfile'
LOGIN_URL = '/user/login/'
LOGIN_REDIRECT_URL = '/'
ALLOWED_HOSTS = ['*']
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
)
# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
'django.template.loaders.app_directories.load_template_source',
)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, "templates/")],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
#TEMPLATE_CONTEXT_PROCESSORS = (
# "django.contrib.auth.context_processors.auth",
# "django.core.context_processors.debug",
# "django.core.context_processors.i18n",
# "django.core.context_processors.media",
# "django.core.context_processors.static",
#)
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
@ -98,31 +122,24 @@ MIDDLEWARE_CLASSES = (
ROOT_URLCONF = 'k4ever.urls'
TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
)
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'buyable',
'transaction',
'main',
'django.contrib.admin',
'easy_thumbnails',
'piston',
)
TEMPLATE_CONTEXT_PROCESSORS = (
"django.contrib.auth.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.contrib.messages.context_processors.messages",
"django.core.context_processors.request",
)
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "media"),
]
STATIC_ROOT = os.path.join(BASE_DIR, "static")

View File

@ -5,11 +5,14 @@
#
# Licensed under GNU Affero General Public License v3 or later
from django.conf.urls.defaults import *
from django.conf.urls import url, include
from django.contrib import admin
admin.autodiscover()
import django.views.static
urlpatterns = patterns('',
import main.views
urlpatterns = (
# Example:
# (r'^k4ever/', include('k4ever.foo.urls')),
@ -17,15 +20,15 @@ urlpatterns = patterns('',
# to INSTALLED_APPS to enable admin documentation:
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# user stuff? go to main
(r'^$', 'main.views.startpage'),
(r'^api2/', include('api2.urls')),
(r'^user/', include('main.urls')),
(r'^transaction/', include('transaction.urls')),
(r'^store/', include('buyable.urls')),
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': 'media'}),
(r'^docs/(?P<path>.*)$', 'django.views.static.serve', {'document_root': 'docs'}),
url(r'^$', main.views.startpage, name='main.views.startpage'),
url(r'^api2/', include('api2.urls')),
url(r'^user/', include('main.urls')),
url(r'^transaction/', include('transaction.urls')),
url(r'^store/', include('buyable.urls')),
url(r'^media/(?P<path>.*)$', django.views.static.serve, {'document_root': 'media'}),
url(r'^docs/(?P<path>.*)$', django.views.static.serve, {'document_root': 'docs'}),
# Uncomment the next line to enable the admin:
(r'^admin/', include(admin.site.urls)),
url(r'^admin/', include(admin.site.urls)),
)

View File

@ -15,6 +15,7 @@ class PluginAdminForm(forms.ModelForm):
""" Form made to require that the user of a plugin is in the plugin group """
class Meta:
model = Plugin
exclude = []
def clean_user(self):
user = self.cleaned_data['user']

View File

@ -5,28 +5,32 @@
#
# Licensed under GNU Affero General Public License v3 or later
from django.contrib.admin.filterspecs import FilterSpec, BooleanFieldFilterSpec
# FIXME: this needs to be reimplemented (not compatible with django 1.10+)
# https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter
# http://stackoverflow.com/a/10644089
class IsNegativeFilterSpec(FilterSpec):
""" Custom filter to display only users with negative balance """
def __init__(self, f, request, *args, **kwargs):
super(IsNegativeFilterSpec, self).__init__(f, request, *args, **kwargs)
self.lookup_kwarg = '%s__lt' % f.name
self.lookup_val = request.GET.get(self.lookup_kwarg, None) # Check if current request already has a filter
def title(self):
return 'Kontostand'
def choices(self, cl):
yield {
'selected': self.lookup_val == None,
'query_string': "?",
'display': 'Alle'}
yield {
'selected': self.lookup_val == '0',
'query_string': cl.get_query_string(
{self.lookup_kwarg: 0},
['balance__isnull']),
'display': 'Nur Negative'}
FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'has_negative_filter', False), IsNegativeFilterSpec))
#from django.contrib.admin.filterspecs import FilterSpec, BooleanFieldFilterSpec
#
#class IsNegativeFilterSpec(FilterSpec):
# """ Custom filter to display only users with negative balance """
# def __init__(self, f, request, *args, **kwargs):
# super(IsNegativeFilterSpec, self).__init__(f, request, *args, **kwargs)
# self.lookup_kwarg = '%s__lt' % f.name
# self.lookup_val = request.GET.get(self.lookup_kwarg, None) # Check if current request already has a filter
#
# def title(self):
# return 'Kontostand'
#
# def choices(self, cl):
# yield {
# 'selected': self.lookup_val == None,
# 'query_string': "?",
# 'display': 'Alle'}
# yield {
# 'selected': self.lookup_val == '0',
# 'query_string': cl.get_query_string(
# {self.lookup_kwarg: 0},
# ['balance__isnull']),
# 'display': 'Nur Negative'}
#
#FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'has_negative_filter', False), IsNegativeFilterSpec))

View File

@ -1,4 +1,4 @@
from django.db.models.signals import post_syncdb
from django.db.models.signals import post_migrate
from django.core.management import commands, call_command
import django.contrib.auth
@ -6,5 +6,5 @@ def createPluginGroup(sender, app, created_models, **kwargs):
if django.contrib.auth.models.Group in created_models:
call_command("loaddata", "group_plugin")
post_syncdb.connect(createPluginGroup, sender=django.contrib.auth.models)
post_migrate.connect(createPluginGroup, sender=django.contrib.auth.models)

View File

@ -12,7 +12,7 @@ from decimal import Decimal
class UserProfile(models.Model):
""" Contains data for a user, especially the account balance. """
user = models.ForeignKey(User, unique=True)
user = models.OneToOneField(User)
balance = models.DecimalField(max_digits=9, decimal_places=2, default=Decimal(0))
balance.has_negative_filter = True
@ -45,7 +45,7 @@ class Plugin(models.Model):
The other attributes are used for plugin/user read/write access to the
authblob.
"""
user = models.ForeignKey(User, unique=True)
user = models.OneToOneField(User)
# plugin info
name = models.CharField(max_length=40)

View File

@ -1,4 +1,5 @@
{% extends "base.html" %}
{% load static %}
{% comment %}
# This file is part of k4ever, a point-of-sale system
@ -11,16 +12,16 @@
{% block head %}
<link rel="stylesheet" media="screen" type="text/css"
href="/media/css/style.css" />
href="{% static "css/style.css" %}" />
{% block extrastyle %}{% endblock %}
<script type="text/javascript">
var MEDIA_URL = "/media/";
var MEDIA_URL = "/static/";
</script>
<script type='text/javascript' src="/media/js/jquery-1.5.1.js"></script>
<script type='text/javascript' src="/media/js/jquery-ui-1.8.10.custom.min.js"></script>
<script type='text/javascript' src="/media/js/jquery.ui.autocomplete.html.js"></script>
<script type='text/javascript' src="/media/js/jquery.gritter.min.js"></script>
<script type='text/javascript' src="/media/js/k4ever.js"></script>
<script type='text/javascript' src="{% static "js/jquery-1.5.1.js" %}"></script>
<script type='text/javascript' src="{% static "js/jquery-ui-1.8.10.custom.min.js" %}"></script>
<script type='text/javascript' src="{% static "js/jquery.ui.autocomplete.html.js" %}"></script>
<script type='text/javascript' src="{% static "js/jquery.gritter.min.js" %}"></script>
<script type='text/javascript' src="{% static "js/k4ever.js" %}"></script>
{% endblock head %}
{% block "content" %}

View File

@ -1,4 +1,5 @@
{% extends "base.html" %}
{% load static %}
{% comment %}
# This file is part of k4ever, a point-of-sale system
@ -12,13 +13,13 @@
{# load url from future #}
{% block extrastyle %}
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{{ MEDIA_URL }}css/admin.css{% endblock %}" />
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="{% block stylesheet_ie %}{% load adminmedia %}{% admin_media_prefix %}css/ie.css{% endblock %}" /><![endif]-->
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{% admin_media_prefix %}css/rtl.css{% endblock %}" />{% endif %}
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{% static "css/admin.css" %}{% endblock %}" />
<!--[if lte IE 7]><link rel="stylesheet" type="text/css" href="{% block stylesheet_ie %}{{ MEDIA_URL }}admin/css/ie.css{% endblock %}" /><![endif]-->
{% if LANGUAGE_BIDI %}<link rel="stylesheet" type="text/css" href="{% block stylesheet_rtl %}{{ MEDIA_URL }}admin/css/rtl.css{% endblock %}" />{% endif %}
{% endblock %}
{% block extrahead %}
<script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{% admin_media_prefix %}{% endfilter %}";</script>
<script type="text/javascript">window.__admin_media_prefix__ = "{% filter escapejs %}{{ MEDIA_URL }}admin{% endfilter %}";</script>
{% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %}
{% endblock %}

View File

@ -6,6 +6,7 @@
#
# Licensed under GNU Affero General Public License v3 or later
{% endcomment %}
{% load static %}
<!DOCTYPE html>
<html {% if user.is_authenticated %}class="loggedIn"{% endif %}>
@ -13,20 +14,20 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
{% block head %}
<link rel="stylesheet" media="screen" type="text/css"
href="{{ MEDIA_URL }}css/style.css" />
href="{% static "css/style.css" %}" />
{% block extrastyle %}{% endblock %}
<script type="text/javascript">
var MEDIA_URL = "{{ MEDIA_URL }}";
var MEDIA_URL = "/static/";
</script>
<script type='text/javascript' src="{{ MEDIA_URL }}js/jquery.min.js"></script>
<script type='text/javascript' src="{{ MEDIA_URL }}js/jquery-ui-1.8.10.custom.min.js"></script>
<script type='text/javascript' src="{{ MEDIA_URL }}js/jquery.ui.autocomplete.html.js"></script>
<script type='text/javascript' src="{{ MEDIA_URL }}js/jquery.gritter.min.js"></script>
<script type="text/javascript" src="{{ MEDIA_URL }}bootstrap/js/bootstrap.min.js"></script>
<script type='text/javascript' src="{{ MEDIA_URL }}js/k4ever.js"></script>
<script type='text/javascript' src="{% static "js/jquery.min.js" %}"></script>
<script type='text/javascript' src="{% static "js/jquery-ui-1.8.10.custom.min.js" %}"></script>
<script type='text/javascript' src="{% static "js/jquery.ui.autocomplete.html.js" %}"></script>
<script type='text/javascript' src="{% static "js/jquery.gritter.min.js" %}"></script>
<script type="text/javascript" src="{% static "bootstrap/js/bootstrap.min.js" %}"></script>
<script type='text/javascript' src="{% static "js/k4ever.js" %}"></script>
{% block extrahead %}{% endblock %}
{% endblock head %}
<title>Freitagsrundenkasse{% block "title" %}{% endblock %}</title>
<title>Unbranded K4Ever{% block "title" %}{% endblock %}</title>
</head>
<body{%block bodyargs %}{%endblock%}>
<div class="navbar navbar-fixed-top">

View File

@ -9,43 +9,43 @@
{% load navigation_extras %}
{% url transaction.views.overview as transactions %}
{% url main.views.startpage as home %}
{% url buyable.views.showItems as store %}
{% url buyable.views.history as history %}
{% url main.views.settings as settings %}
{% url django.contrib.auth.views.logout as logout %}
{% url django.contrib.auth.views.login as login %}
{% url main.views.register as register %}
{% url 'transactions' as transactions %}
{% url 'main.views.startpage' as home %}
{% url 'buyable_overview' as store %}
{% url 'buyable_history' as history %}
{% url 'main_settings' as settings %}
{% url 'logout' as logout %}
{% url 'login' as login %}
{% url 'register' as register %}
<ul role="navigation sitemap" class="nav">
{% if user.is_authenticated %}
<li class="{% active request home %}"><a href="{{ home }}">Home</a></li>
<li class="{% active request store %}"><a href="{{ store }}">Einkaufen</a></li>
<li class="{% active request transactions %}"><a href="{{ transactions }}">Konto</a></li>
<li class="{% active request history %}"><a href="{{ history }}">Frühere Einkäufe</a></li>
<li class="{% active home %}"><a href="{{ home }}">Home</a></li>
<li class="{% active store %}"><a href="{{ store }}">Einkaufen</a></li>
<li class="{% active transactions %}"><a href="{{ transactions }}">Konto</a></li>
<li class="{% active history %}"><a href="{{ history }}">Frühere Einkäufe</a></li>
<li class="divider-vertical" role="presentation"></li>
<ul class="nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="icon user"></span></a>
<ul class="dropdown-menu">
<li class="{% active request settings %}"><a href="{{ settings }}"><i class="icon-cog"></i> Einstellungen</a></li>
<li class="{% active settings %}"><a href="{{ settings }}"><i class="icon-cog"></i> Einstellungen</a></li>
{% if user.is_staff %}
<li class=""><a href="/admin/"><i class="icon-lock"></i> Administration</a></li>
{% endif %}
<li class="{% active request logout %}"><a href="{{ logout }}"><i class="icon-off"></i> Abmelden</a></li>
<li class="{% active logout %}"><a href="{{ logout }}"><i class="icon-off"></i> Abmelden</a></li>
</ul>
</li>
</ul>
{% else %}
<li class="{% active request login %}"><a href="{{ login }}">Anmelden</a></li>
<li class="{% active request register %}"><a href="{{ register }}">Registrieren</a></li>
<li class="{% active login %}"><a href="{{ login }}">Anmelden</a></li>
<li class="{% active register %}"><a href="{{ register }}">Registrieren</a></li>
{% endif %}
</ul>
{% if user.is_authenticated %}
<div class="pull-right">
<span class="brand balance">Kontostand: {{ user.get_profile.balance|floatformat:2 }} €</span>
<span class="brand balance">Kontostand: {{ user.userprofile_set.get.balance|floatformat:2 }} €</span>
<form class="navbar-search">
<input placeholder="Suche und kaufe..." class="search-query autocomplete"
type="search" name="search_term" value="Lade Daten..."

View File

@ -15,18 +15,18 @@
{% for buyable in buyables %}
<tr>
<td class="productImage">
<a href="{% url buyable_show buyable.id %}"><img src="{% thumbnail buyable.image 64x64 %}" /></a>
<a href="{% url 'buyable_show' buyable.id %}"><img src="{% thumbnail buyable.image 64x64 %}" /></a>
</td>
<td class="name"><span>{{ buyable.name }}</span> {% if buyable.num_buys %}({{ buyable.num_buys }} mal gekauft){% endif %}</td>
<td class="actions btn-group" data-image="{% thumbnail buyable.image 48x48 %}" data-name="{{ buyable.name }}" data-id="{{ buyable.id }}">
{% if buyable.deposit > 0 %}
<a class="button buy" href="{% url buyable_buy buyable.id %}" title="Kaufen (Ohne Pfand)"><span><span>{{ buyable.price|floatformat:2 }}€</span></span></a>
<a class="button buy inclDeposit" href="{% url buyable_buy buyable.id "with/deposit" %}" title="Kaufen (Mit Pfand)"><span><span>{{ buyable.price|floatformat:2 }}€ / {{ buyable.deposit|floatformat:2 }}€</span></span></a>
<a class="button buy" href="{% url 'buyable_buy' buyable.id %}" title="Kaufen (Ohne Pfand)"><span><span>{{ buyable.price|floatformat:2 }}€</span></span></a>
<a class="button buy inclDeposit" href="{% url 'buyable_buy' buyable.id "with/deposit" %}" title="Kaufen (Mit Pfand)"><span><span>{{ buyable.price|floatformat:2 }}€ / {{ buyable.deposit|floatformat:2 }}€</span></span></a>
{% if includeDeposit %}
<a class="button buy onlyDeposit" href="{% url buyable_buy buyable.id "only/deposit" %}" title="Kaufen (Nur Pfand)"><span><span>{{ buyable.deposit|floatformat:2 }}€</span></span></a>
<a class="button buy onlyDeposit" href="{% url 'buyable_buy' buyable.id "only/deposit" %}" title="Kaufen (Nur Pfand)"><span><span>{{ buyable.deposit|floatformat:2 }}€</span></span></a>
{% endif %}
{% else %}
<a class="button buy" href="{% url buyable_buy buyable.id %}" title="Kaufen"><span><span>{{ buyable.price|floatformat:2 }}€</span></span></a>
<a class="button buy" href="{% url 'buyable_buy' buyable.id %}" title="Kaufen"><span><span>{{ buyable.price|floatformat:2 }}€</span></span></a>
{% endif %}
</td>
</tr>

View File

@ -11,8 +11,9 @@ import re
register = Library()
@register.simple_tag
def active(request, pattern):
@register.simple_tag(takes_context=True)
def active(context, pattern):
request = context['request']
if pattern == request.path:
return "active"
return ""

View File

@ -6,19 +6,23 @@
#
# Licensed under GNU Affero General Public License v3 or later
from django.conf.urls.defaults import *
from django.conf import settings
from django.conf.urls import url
from django.views.generic import RedirectView
import main.views
import django.contrib.auth.views
urlpatterns = patterns('',
(r'^$', 'django.views.generic.simple.redirect_to', {'url': 'login/'}),
(r'^register/$', 'main.views.register'),
(r'^login/$', 'main.views.login'),
(r'^logout/$', 'django.contrib.auth.views.logout',
urlpatterns = (
#(r'^$', 'django.views.generic.simple.redirect_to', {'url': 'login/'}),
url(r'^$', RedirectView.as_view(url='login/')),
url(r'^register/$', main.views.register, name='register'),
url(r'^login/$', main.views.login, name='login'),
url(r'^logout/$', django.contrib.auth.views.logout,
{'template_name': 'registration/logout.html',
'next_page': '/user/login/'}),
(r'^settings/$', 'main.views.settings'),
'next_page': '/user/login/'}, name='logout'),
url(r'^settings/$', main.views.settings, name='main_settings'),
#plugin stuff
(r'^settings/plugin/(?P<method>(?:allow|deny))/(?P<pluginId>\d+)/$', 'main.views.pluginPermission'),
(r'^settings/plugin/authblob/(?P<pluginId>\d+)/$', 'main.views.pluginAuthblob'),
url(r'^settings/plugin/(?P<method>(?:allow|deny))/(?P<pluginId>\d+)/$', main.views.pluginPermission),
url(r'^settings/plugin/authblob/(?P<pluginId>\d+)/$', main.views.pluginAuthblob),
)

View File

@ -10,7 +10,7 @@ from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth.decorators import login_required
from django.db.models import Count, Max
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.shortcuts import render
from django.template import RequestContext
from django.core.urlresolvers import reverse
import django.contrib.auth.views
@ -18,7 +18,7 @@ import django.contrib.auth.views
from buyable.models import Purchase, Buyable, BuyableType
from main.helper import getUserFromAuthblob
from main.models import Plugin, PluginPermission
from settings import SNACK_TYPE_ID, DRINK_TYPE_ID
from k4ever.settings import SNACK_TYPE_ID, DRINK_TYPE_ID
@login_required
def startpage(request):
@ -52,12 +52,12 @@ def startpage(request):
buyables = buyables.annotate(max_dateTime=Max('purchase__order__dateTime'))
context[context_vars[2]] = buyables.order_by('-max_dateTime')[:5]
return render_to_response("main/startpage.html", context, RequestContext(request))
return render(request, "main/startpage.html", context)
def register(request):
""" The "no registration available" page... """
return render_to_response("registration/register.html", RequestContext(request))
return render(request, "registration/register.html")
def getPluginDict(request):
@ -83,7 +83,7 @@ def settings(request):
form.save()
pdict['password_success'] = "Es wurde ein neues Passwort gesetzt."
pdict['form'] = form
return render_to_response("settings/settings.html", pdict, RequestContext(request))
return render(request, "settings/settings.html", pdict)
@login_required
def pluginPermission(request, method, pluginId):
@ -94,14 +94,14 @@ def pluginPermission(request, method, pluginId):
except Plugin.DoesNotExist:
d = getPluginDict(request)
d['pluginerror'] = "Ein Plugin mit der angegebenen ID existiert nicht"
return render_to_response("settings/settings.html", d, RequestContext(request))
return render(request, "settings/settings.html", d)
if method == "allow":
try:
p = PluginPermission.objects.get(user=request.user, plugin=plugin)
d = getPluginDict(request)
d['pluginerror'] = "Dieses Plugin wurde bereits erlaubt"
return render_to_response("settings/settings.html", d, RequestContext(request))
return render(request, "settings/settings.html", d)
except PluginPermission.DoesNotExist:
p = PluginPermission(user=request.user, plugin=plugin)
p.save()
@ -112,7 +112,7 @@ def pluginPermission(request, method, pluginId):
except PluginPermission.DoesNotExist:
d = getPluginDict(request)
d['pluginerror'] = "Keine Berechtigungen f&uuml;r dieses Plugin gefunden - kann also auch nicht zur&uuml;ckgezogen werden"
return render_to_response("settings/settings.html", d, RequestContext(request))
return render(request, "settings/settings.html", d)
return HttpResponseRedirect("/user/settings/")
@login_required
@ -128,7 +128,7 @@ def pluginAuthblob(request, pluginId):
except Plugin.DoesNotExist:
d = getPluginDict(request)
d['pluginerror'] = "Ein Plugin mit der angegebenen ID existiert nicht"
return render_to_response("settings/settings.html", d, RequestContext(request))
return render(request, "settings/settings.html", d)
# find plugin permission for user
p = None
@ -137,13 +137,13 @@ def pluginAuthblob(request, pluginId):
except PluginPermission.DoesNotExist:
d = getPluginDict(request)
d['pluginerror'] = "Vor dem editieren vom Authblob muss das Plugin ersteinmal erlaubt werden"
return render_to_response("settings/settings.html", d, RequestContext(request))
return render(request, "settings/settings.html", d)
# has the user write access to the authblob?
if not p.plugin.userCanWriteAuthblob or not "authblob" in request.POST:
d = getPluginDict(request)
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(request, "settings/settings.html", d)
# clean authblob \r\n ==> \n
authblob = request.POST["authblob"].replace("\r\n", "\n")
@ -152,14 +152,14 @@ def pluginAuthblob(request, pluginId):
if p.plugin.maxLinesPerAuthblob > 0 and (authblob.rstrip().count("\n") + 1) > p.plugin.maxLinesPerAuthblob:
d = getPluginDict(request)
d['pluginerror'] = "Der Authblob darf maximal %d Zeilen haben" % (p.plugin.maxLinesPerAuthblob,)
return render_to_response("settings/settings.html", d, RequestContext(request))
return render(request, "settings/settings.html", d)
# check, if this is equal to the old users plugin
pluginsWithAuthblob = PluginPermission.objects.filter(plugin=plugin, user=request.user, authblob__exact=authblob)
if pluginsWithAuthblob.count() > 0:
d = getPluginDict(request)
d['pluginerror'] = "Das ist der gleiche Authblob, den du vorher auch hattest."
return render_to_response("settings/settings.html", d, RequestContext(request))
return render(request, "settings/settings.html", d)
# check for every authblob-line, if there is somebody who has it (if unique)
if p.plugin.uniqueAuthblob:
@ -173,13 +173,13 @@ def pluginAuthblob(request, pluginId):
else:
d = getPluginDict(request)
d['pluginerror'] = "Achtung! Dein Authblob (bzw. eine der Zeile davon) 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(request, "settings/settings.html", d)
p.authblob = authblob
p.save()
d = getPluginDict(request)
d['pluginmsg'] = "Authblob erfolgreich ge&auml;ndert"
return render_to_response("settings/settings.html", d, RequestContext(request))
return render(request, "settings/settings.html", d)
def login(request):

View File

@ -1,11 +1,22 @@
#!/usr/bin/env python
from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
import os
import sys
if __name__ == "__main__":
execute_manager(settings)
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "k4ever.settings")
try:
from django.core.management import execute_from_command_line
except ImportError:
# The above import may fail for some other reason. Ensure that the
# issue is really that Django is missing to avoid masking other
# exceptions on Python 2.
try:
import django
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
)
raise
execute_from_command_line(sys.argv)

View File

@ -43,7 +43,7 @@ class Transaction(models.Model):
(self.checked and " " or " not "))
def save(self, *args, **kwargs):
profile = self.user.get_profile()
profile = self.user.userprofile_set.get()
if self.id == None:
# insert
profile.balance += self.amount
@ -51,11 +51,11 @@ class Transaction(models.Model):
# update
oldobj = Transaction.objects.get(id=self.id)
if oldobj.user != self.user:
oldprofile = oldobj.user.get_profile()
oldprofile = oldobj.user.userprofile_set.get()
oldprofile.balance -= oldobj.amount
oldprofile.save()
# just to be save, reget profile
profile = self.user.get_profile()
profile = self.user.userprofile_set.get()
profile.balance += self.amount
else:
profile.balance += (self.amount-oldobj.amount)
@ -64,7 +64,7 @@ class Transaction(models.Model):
@staticmethod
def pre_delete_signal(sender, instance, **kwargs):
profile = instance.user.get_profile()
profile = instance.user.userprofile_set.get()
profile.balance -= instance.amount
profile.save()
@ -87,8 +87,8 @@ class VirtualTransaction(models.Model):
@staticmethod
def moveMoney(fromUser, toUser, amount, commit=True):
if not (fromUser == toUser):
fromProfile = fromUser.get_profile()
toProfile = toUser.get_profile()
fromProfile = fromUser.userprofile_set.get()
toProfile = toUser.userprofile_set.get()
fromProfile.balance -= amount
toProfile.balance += amount
if commit:

View File

@ -5,10 +5,11 @@
#
# Licensed under GNU Affero General Public License v3 or later
from django.conf.urls.defaults import patterns
from django.conf.urls import url
import transaction.views
urlpatterns = patterns('',
(r'^$', 'transaction.views.overview'),
(r'^state/(success|error|vsuccess|verror)/(payin|payout)/$', 'transaction.views.state'),
urlpatterns = (
url(r'^$', transaction.views.overview, name='transactions'),
url(r'^state/(success|error|vsuccess|verror)/(payin|payout)/$', transaction.views.state),
)

View File

@ -8,7 +8,7 @@
from django.contrib.auth.decorators import login_required
from django.db.models import Q
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.shortcuts import render
from django.template import RequestContext
from transaction.forms import TransactionForm, VirtualTransactionForm
@ -50,7 +50,7 @@ def overview(request):
else:
state = "verror"
return HttpResponseRedirect("state/%s/%s/" % (state,payway))
return render_to_response("transaction/overview.html", {'history': history, 'vhistory': vhistory, 'form': form, 'transacted': False, 'payout': None, 'error': False, 'vform': vform, 'vtransacted': False, 'verror': False}, RequestContext(request))
return render(request, "transaction/overview.html", {'history': history, 'vhistory': vhistory, 'form': form, 'transacted': False, 'payout': None, 'error': False, 'vform': vform, 'vtransacted': False, 'verror': False})
@login_required
@ -77,4 +77,4 @@ def state(request, state="", payway=""):
if payway == "payout":
payout = True
return render_to_response("transaction/overview.html", {'history': history, 'vhistory': vhistory, 'form': form, 'transacted': transacted, 'payout': payout, 'error': error, 'vform': vform, 'vtransacted': vtransacted, 'verror': verror}, RequestContext(request))
return render(request, "transaction/overview.html", {'history': history, 'vhistory': vhistory, 'form': form, 'transacted': transacted, 'payout': payout, 'error': error, 'vform': vform, 'vtransacted': vtransacted, 'verror': verror})

20
k4ever/wsgi.py Normal file
View File

@ -0,0 +1,20 @@
"""
WSGI config for cqtu project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.10/howto/deployment/wsgi/
"""
import os
import sys
from django.core.wsgi import get_wsgi_application
sys.path.append("/home/k4ever/k4ever")
sys.path.append("/home/k4ever/k4ever/k4ever")
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "k4ever.settings")
application = get_wsgi_application()