Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
Sebastian Lohff | 851c85f4be | |
Sebastian Lohff | a036e86b96 | |
Sebastian Lohff | 8a728f1568 | |
Sebastian Lohff | 729eab6cf9 | |
Sebastian Lohff | 37897b6a12 | |
Sebastian Lohff | a4c308af6f | |
Sebastian Lohff | 91f549b69e | |
Sebastian Lohff | 63b3f71141 |
|
@ -8,6 +8,7 @@
|
|||
k4ever/k4ever.db
|
||||
k4ever/media/img/
|
||||
k4ever/settings.py
|
||||
k4ever/k4ever/settings.py
|
||||
*.kdev4
|
||||
.kdev4
|
||||
*.kate-swp
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
Django piston is pretty old and does not work with django1.11 out of the box.
|
||||
For the transition these are the changes required to get piston working
|
||||
|
||||
Start out by creating a new virtualenv, install the requirements, then change the following lines:
|
||||
|
||||
In piston/emitters.py:
|
||||
# instead of the original simplejson import
|
||||
import json as simplejson
|
||||
|
||||
# instead of the DateTimeAwareJsonEncoder import
|
||||
from django.core.serializers.json import DjangoJSONEncoder as DateTimeAwareJSONEncoder
|
||||
|
||||
# in ~186 replace the following line
|
||||
for f in data._meta.fields + data._meta.virtual_fields])
|
||||
# with this line
|
||||
for f in data._meta.fields + tuple(data._meta.virtual_fields)])
|
||||
|
||||
In piston/resource.py
|
||||
# in ~207 replace
|
||||
resp = HttpResponse(stream, mimetype=ct, status=status_code)
|
||||
# with this line
|
||||
resp = HttpResponse(stream, content_type=ct, status=status_code)
|
|
@ -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.
|
||||
|
|
|
@ -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.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.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.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.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.balance
|
||||
return {'balance': balance}
|
||||
|
||||
class AuthBlobHandler(BaseHandler):
|
||||
|
|
|
@ -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}),
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
|
@ -0,0 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class Api3Config(AppConfig):
|
||||
name = 'api3'
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
|
@ -0,0 +1,60 @@
|
|||
from django.contrib.auth.models import User
|
||||
from rest_framework import serializers
|
||||
|
||||
from buyable.models import BuyableType, Buyable, Order, Purchase
|
||||
from transaction.models import TransactionType, Transaction, VirtualTransaction
|
||||
|
||||
|
||||
class UserSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('id', 'username',)
|
||||
|
||||
|
||||
class BuyableTypeSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = BuyableType
|
||||
fields = ['url', 'id', 'name']
|
||||
|
||||
|
||||
class BuyableSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Buyable
|
||||
fields = ['url', 'id', 'name', 'description', 'price', 'barcode', 'deposit', 'image', 'buyableType']
|
||||
|
||||
|
||||
class PurchaseSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = Purchase
|
||||
fields = ['id', 'price', 'isDeposit', 'buyable']
|
||||
|
||||
|
||||
class OrderSerializer(serializers.HyperlinkedModelSerializer):
|
||||
purchases = PurchaseSerializer(source='purchase_set', many=True)
|
||||
|
||||
class Meta:
|
||||
model = Order
|
||||
fields = ['url', 'id', 'price', 'dateTime', 'purchases']
|
||||
|
||||
|
||||
class TransactionTypeSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = TransactionType
|
||||
fields = ('url', 'id', 'name')
|
||||
|
||||
|
||||
class TransactionSerializer(serializers.HyperlinkedModelSerializer):
|
||||
transactionType = TransactionTypeSerializer()
|
||||
|
||||
class Meta:
|
||||
model = Transaction
|
||||
fields = ('url', 'id', 'amount', 'dateTime', 'checked', 'transactionType')
|
||||
|
||||
|
||||
class VirtualTransactionSerializer(serializers.HyperlinkedModelSerializer):
|
||||
user = UserSerializer()
|
||||
recipient = UserSerializer()
|
||||
|
||||
class Meta:
|
||||
model = VirtualTransaction
|
||||
fields = ('url', 'id', 'amount', 'dateTime', 'comment', 'user', 'recipient')
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
|
@ -0,0 +1,20 @@
|
|||
from django.conf.urls import include, url
|
||||
from rest_framework import routers
|
||||
|
||||
from .views import BuyableTypeViewSet, BuyableViewSet, OrderViewSet
|
||||
from .views import TransactionTypeViewSet, TransactionViewSet, VirtualTransactionViewSet
|
||||
|
||||
router = routers.DefaultRouter()
|
||||
router.register('buyabletypes', BuyableTypeViewSet)
|
||||
router.register('buyables', BuyableViewSet)
|
||||
router.register('orders', OrderViewSet, basename='order')
|
||||
|
||||
router.register('transactiontypes', TransactionTypeViewSet)
|
||||
router.register('transactions', TransactionViewSet, 'transaction')
|
||||
router.register('virtualtransactions', VirtualTransactionViewSet, 'virtualtransaction')
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^', include(router.urls)),
|
||||
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))
|
||||
]
|
|
@ -0,0 +1,55 @@
|
|||
from django.db.models import Q
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from .serializers import BuyableTypeSerializer, BuyableSerializer, OrderSerializer
|
||||
from .serializers import TransactionTypeSerializer, TransactionSerializer, VirtualTransactionSerializer
|
||||
from buyable.models import BuyableType, Buyable, Order
|
||||
from transaction.models import TransactionType, Transaction, VirtualTransaction
|
||||
|
||||
|
||||
class BuyableTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = BuyableType.objects.all()
|
||||
serializer_class = BuyableTypeSerializer
|
||||
|
||||
|
||||
class BuyableViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = Buyable.objects.all()
|
||||
serializer_class = BuyableSerializer
|
||||
|
||||
|
||||
class OrderViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = OrderSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return Order.objects.filter(user=self.request.user)
|
||||
|
||||
|
||||
class TransactionTypeViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
queryset = TransactionType.objects.all()
|
||||
serializer_class = TransactionTypeSerializer
|
||||
|
||||
|
||||
class TransactionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = TransactionSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return Transaction.objects.filter(user=self.request.user).order_by("-dateTime")
|
||||
|
||||
|
||||
class VirtualTransactionViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = VirtualTransactionSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return (VirtualTransaction.objects.filter(Q(user=self.request.user) | Q(recipient=self.request.user))
|
||||
.order_by("-dateTime"))
|
||||
|
||||
|
||||
# class BalanceView(APIView):
|
||||
# def get(self, request):
|
||||
# return Response({'balance': request.user.userprofile.balance}
|
||||
class BalanceViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
pass
|
|
@ -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']
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10 on 2018-10-24 01:07
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from decimal import Decimal
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Buyable',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('price', models.DecimalField(decimal_places=2, max_digits=8)),
|
||||
('image', models.ImageField(help_text=b'<strong>The Image needs to have a 1:1 aspect ratio.</strong>', upload_to=b'img/buyable/')),
|
||||
('deposit', models.DecimalField(decimal_places=2, max_digits=8)),
|
||||
('description', models.TextField()),
|
||||
('barcode', models.CharField(blank=True, default=b'', max_length=100)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='BuyableType',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Order',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('price', models.DecimalField(decimal_places=2, default=Decimal('0'), max_digits=8)),
|
||||
('dateTime', models.DateTimeField(auto_now_add=True)),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Purchase',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('price', models.DecimalField(decimal_places=2, default=None, max_digits=8)),
|
||||
('isDeposit', models.BooleanField()),
|
||||
('buyable', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='buyable.Buyable')),
|
||||
('order', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='buyable.Order')),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='buyable',
|
||||
name='buyableType',
|
||||
field=models.ManyToManyField(to='buyable.BuyableType'),
|
||||
),
|
||||
]
|
|
@ -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
|
||||
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
|
||||
profile.balance -= (self.price - oldobj.price)
|
||||
profile.save()
|
||||
else:
|
||||
oldProfile = oldobj.user.get_profile()
|
||||
newProfile = self.user.get_profile()
|
||||
oldProfile = oldobj.user.userprofile
|
||||
newProfile = self.user.userprofile
|
||||
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
|
||||
profile.balance += updOrder.price
|
||||
profile.save()
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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'),
|
||||
)
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -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,18 +81,38 @@ 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',
|
||||
)
|
||||
|
||||
MIDDLEWARE_CLASSES = (
|
||||
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 = (
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
|
@ -98,31 +122,28 @@ 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',
|
||||
'rest_framework',
|
||||
)
|
||||
|
||||
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")
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_PREMISSION_CLASSES': 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
|
||||
}
|
|
@ -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,16 @@ 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'^api3/', include('api3.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)),
|
||||
)
|
|
@ -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']
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10 on 2018-10-24 01:07
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from decimal import Decimal
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Plugin',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=40)),
|
||||
('author', models.CharField(max_length=40)),
|
||||
('version', models.CharField(max_length=40)),
|
||||
('descr', models.TextField(default=b'')),
|
||||
('uniqueAuthblob', models.BooleanField(default=False)),
|
||||
('userCanWriteAuthblob', models.BooleanField(default=True)),
|
||||
('maxLinesPerAuthblob', models.IntegerField(default=0)),
|
||||
('userCanReadAuthblob', models.BooleanField(default=True)),
|
||||
('pluginCanWriteAuthblob', models.BooleanField(default=False)),
|
||||
('pluginCanReadAuthblob', models.BooleanField(default=False)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PluginPermission',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('authblob', models.TextField(default=b'')),
|
||||
('plugin', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='main.Plugin')),
|
||||
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='UserProfile',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('balance', models.DecimalField(decimal_places=2, default=Decimal('0'), max_digits=9)),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
]
|
|
@ -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)
|
||||
|
|
|
@ -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" %}
|
||||
|
|
|
@ -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 %}
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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.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..."
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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 ""
|
|
@ -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),
|
||||
)
|
||||
|
|
|
@ -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ür dieses Plugin gefunden - kann also auch nicht zurü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ür dieses Plugin nicht vom User verä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ä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ändert"
|
||||
return render_to_response("settings/settings.html", d, RequestContext(request))
|
||||
return render(request, "settings/settings.html", d)
|
||||
|
||||
|
||||
def login(request):
|
||||
|
|
|
@ -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 os
|
||||
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)
|
||||
|
||||
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)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
django==1.11
|
||||
easy_thumbnails
|
||||
oauth
|
||||
django-auth-ldap
|
||||
djangorestframework
|
||||
django-piston
|
|
@ -0,0 +1,60 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.10 on 2018-10-24 01:07
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from decimal import Decimal
|
||||
from django.conf import settings
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import transaction.validator
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Transaction',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('dateTime', models.DateTimeField(auto_now_add=True)),
|
||||
('amount', models.DecimalField(decimal_places=2, max_digits=8, validators=[transaction.validator.validate_notZero])),
|
||||
('checked', models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='TransactionType',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('needsCheck', models.BooleanField(default=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='VirtualTransaction',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('dateTime', models.DateTimeField(auto_now_add=True)),
|
||||
('amount', models.DecimalField(decimal_places=2, max_digits=8, validators=[django.core.validators.MinValueValidator(Decimal('0.01'))], verbose_name=b'Betrag')),
|
||||
('comment', models.CharField(max_length=100, verbose_name=b'Verwendungszweck')),
|
||||
('recipient', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='receivedtransaction', to=settings.AUTH_USER_MODEL, verbose_name='Empf\xe4nger')),
|
||||
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transaction',
|
||||
name='transactionType',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='transaction.TransactionType', verbose_name=b'Typ'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='transaction',
|
||||
name='user',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
]
|
|
@ -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
|
||||
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
|
||||
oldprofile.balance -= oldobj.amount
|
||||
oldprofile.save()
|
||||
# just to be save, reget profile
|
||||
profile = self.user.get_profile()
|
||||
profile = self.user.userprofile
|
||||
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
|
||||
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
|
||||
toProfile = toUser.userprofile
|
||||
fromProfile.balance -= amount
|
||||
toProfile.balance += amount
|
||||
if commit:
|
||||
|
|
|
@ -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),
|
||||
)
|
||||
|
|
|
@ -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})
|
||||
|
|
|
@ -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()
|
||||
|
Loading…
Reference in New Issue