Compare commits
8 Commits
Author | SHA1 | Date |
---|---|---|
|
851c85f4be | |
|
a036e86b96 | |
|
8a728f1568 | |
|
729eab6cf9 | |
|
37897b6a12 | |
|
a4c308af6f | |
|
91f549b69e | |
|
63b3f71141 |
|
@ -8,6 +8,7 @@
|
||||||
k4ever/k4ever.db
|
k4ever/k4ever.db
|
||||||
k4ever/media/img/
|
k4ever/media/img/
|
||||||
k4ever/settings.py
|
k4ever/settings.py
|
||||||
|
k4ever/k4ever/settings.py
|
||||||
*.kdev4
|
*.kdev4
|
||||||
.kdev4
|
.kdev4
|
||||||
*.kate-swp
|
*.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 piston.utils import rc
|
||||||
from main.models import Plugin, PluginPermission
|
from main.models import Plugin, PluginPermission
|
||||||
|
|
||||||
from settings import PLUGIN_GROUP_ID
|
from k4ever.settings import PLUGIN_GROUP_ID
|
||||||
|
|
||||||
def manglePluginPerms(apiFunc):
|
def manglePluginPerms(apiFunc):
|
||||||
""" Changes to a given user when the authenticated user is an plugin.
|
""" Changes to a given user when the authenticated user is an plugin.
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
from easy_thumbnails.files import get_thumbnailer
|
from easy_thumbnails.files import get_thumbnailer
|
||||||
from piston.handler import BaseHandler
|
from piston.handler import BaseHandler
|
||||||
from piston.utils import rc
|
from piston.utils import rc
|
||||||
from k4ever.buyable.models import *
|
from buyable.models import *
|
||||||
from k4ever.transaction.models import *
|
from transaction.models import *
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
from django.core.exceptions import MultipleObjectsReturned
|
from django.core.exceptions import MultipleObjectsReturned
|
||||||
|
@ -116,7 +116,7 @@ class BuyableItemHandler(BaseHandler):
|
||||||
p.save(saveOrder=False)
|
p.save(saveOrder=False)
|
||||||
order.save()
|
order.save()
|
||||||
|
|
||||||
return {'success': True, 'balance': request.user.get_profile().balance}
|
return {'success': True, 'balance': request.user.userprofile.balance}
|
||||||
|
|
||||||
def bulkBuy(self, request):
|
def bulkBuy(self, request):
|
||||||
"""Buy a :class:`Buyable <buyable.models.Buyable>` item.
|
"""Buy a :class:`Buyable <buyable.models.Buyable>` item.
|
||||||
|
@ -179,7 +179,7 @@ class BuyableItemHandler(BaseHandler):
|
||||||
p.save(saveOrder=False)
|
p.save(saveOrder=False)
|
||||||
order.save()
|
order.save()
|
||||||
|
|
||||||
return {'success': True, 'balance': request.user.get_profile().balance}
|
return {'success': True, 'balance': request.user.userprofile.balance}
|
||||||
|
|
||||||
|
|
||||||
class BuyableTypeHandler(BaseHandler):
|
class BuyableTypeHandler(BaseHandler):
|
||||||
|
@ -290,7 +290,7 @@ class TransactionTransactHandler(BaseHandler):
|
||||||
return getError(rc.BAD_REQUEST, "Your TransactionType could not be found")
|
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 = Transaction(user=request.user, transactionType=tType, amount=amount, checked=not tType.needsCheck)
|
||||||
trans.save()
|
trans.save()
|
||||||
return {'success': True, 'balance': request.user.get_profile().balance}
|
return {'success': True, 'balance': request.user.userprofile.balance}
|
||||||
|
|
||||||
class TransactionTypeHandler(BaseHandler):
|
class TransactionTypeHandler(BaseHandler):
|
||||||
"""Handler for :class:`Transaction Types <transaction.models.TransactionType>`
|
"""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.")
|
return getError(rc.BAD_REQUEST, "The recipient user does not exist.")
|
||||||
trans = VirtualTransaction(user=request.user, recipient=recipient, amount=amount, comment=comment)
|
trans = VirtualTransaction(user=request.user, recipient=recipient, amount=amount, comment=comment)
|
||||||
trans.save()
|
trans.save()
|
||||||
return {'success': True, 'balance': request.user.get_profile().balance}
|
return {'success': True, 'balance': request.user.userprofile.balance}
|
||||||
|
|
||||||
class AccountBalanceHandler(BaseHandler):
|
class AccountBalanceHandler(BaseHandler):
|
||||||
"""Handler for the user's account balance"""
|
"""Handler for the user's account balance"""
|
||||||
|
@ -357,7 +357,7 @@ class AccountBalanceHandler(BaseHandler):
|
||||||
@manglePluginPerms
|
@manglePluginPerms
|
||||||
def read(self, request):
|
def read(self, request):
|
||||||
"""Returns the user's current account balance"""
|
"""Returns the user's current account balance"""
|
||||||
balance = request.user.get_profile().balance
|
balance = request.user.userprofile.balance
|
||||||
return {'balance': balance}
|
return {'balance': balance}
|
||||||
|
|
||||||
class AuthBlobHandler(BaseHandler):
|
class AuthBlobHandler(BaseHandler):
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#
|
#
|
||||||
# Licensed under GNU Affero General Public License v3 or later
|
# 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.resource import Resource
|
||||||
from piston.authentication import HttpBasicAuthentication
|
from piston.authentication import HttpBasicAuthentication
|
||||||
from api2.authentication import DjangoAuthentication, MultiAuthentication
|
from api2.authentication import DjangoAuthentication, MultiAuthentication
|
||||||
|
@ -47,7 +47,7 @@ authUserRes = CsrfExemptResource(handler=AuthUserHandler, **ad)
|
||||||
configRes = CsrfExemptResource(handler=ConfigHandler, **ad)
|
configRes = CsrfExemptResource(handler=ConfigHandler, **ad)
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = (
|
||||||
url(r'buyable/item/?$', buyableItemRes),
|
url(r'buyable/item/?$', buyableItemRes),
|
||||||
url(r'buyable/item/(?P<itemId>\d+)/?$', buyableItemRes),
|
url(r'buyable/item/(?P<itemId>\d+)/?$', buyableItemRes),
|
||||||
url(r'buyable/item/bulkbuy/?$', buyableItemRes, {'bulkBuy': True}),
|
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. """
|
""" Special BuyableAdminForm which checks the buyable image for an 1:1 aspect ratio. """
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Buyable
|
model = Buyable
|
||||||
|
exclude = []
|
||||||
|
|
||||||
def clean_image(self):
|
def clean_image(self):
|
||||||
img = self.cleaned_data['image']
|
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
|
from django.core.management import commands, call_command
|
||||||
import buyable.models
|
import buyable.models
|
||||||
|
|
||||||
|
@ -6,5 +6,5 @@ def createBuyableTypes(sender, app, created_models, **kwargs):
|
||||||
if buyable.models.BuyableType in created_models:
|
if buyable.models.BuyableType in created_models:
|
||||||
call_command("loaddata", "buyable_types")
|
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", ")
|
return l.rstrip(u", ")
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
profile = self.user.get_profile()
|
profile = self.user.userprofile
|
||||||
if self.id == None:
|
if self.id == None:
|
||||||
# new item, get it!
|
# new item, get it!
|
||||||
profile.balance -= self.price
|
profile.balance -= self.price
|
||||||
|
@ -88,12 +88,12 @@ class Order(models.Model):
|
||||||
# get old
|
# get old
|
||||||
oldobj = Order.objects.get(id=self.id)
|
oldobj = Order.objects.get(id=self.id)
|
||||||
if oldobj.user == self.user:
|
if oldobj.user == self.user:
|
||||||
profile = self.user.get_profile()
|
profile = self.user.userprofile
|
||||||
profile.balance -= (self.price - oldobj.price)
|
profile.balance -= (self.price - oldobj.price)
|
||||||
profile.save()
|
profile.save()
|
||||||
else:
|
else:
|
||||||
oldProfile = oldobj.user.get_profile()
|
oldProfile = oldobj.user.userprofile
|
||||||
newProfile = self.user.get_profile()
|
newProfile = self.user.userprofile
|
||||||
oldProfile.balance += oldobj.price
|
oldProfile.balance += oldobj.price
|
||||||
oldProfile.save()
|
oldProfile.save()
|
||||||
newprofile.balance -= self.price
|
newprofile.balance -= self.price
|
||||||
|
@ -111,7 +111,7 @@ class Order(models.Model):
|
||||||
# where all the buyables have not updated the price
|
# where all the buyables have not updated the price
|
||||||
updOrder = Order.objects.get(id=instance.id)
|
updOrder = Order.objects.get(id=instance.id)
|
||||||
if updOrder.price != Decimal("0"):
|
if updOrder.price != Decimal("0"):
|
||||||
profile = updOrder.user.get_profile()
|
profile = updOrder.user.userprofile
|
||||||
profile.balance += updOrder.price
|
profile.balance += updOrder.price
|
||||||
profile.save()
|
profile.save()
|
||||||
|
|
||||||
|
|
|
@ -15,21 +15,21 @@
|
||||||
{% for buyable in buyables %}
|
{% for buyable in buyables %}
|
||||||
<li class="span2" title="{{ buyable.name }}" rel="tooltip">
|
<li class="span2" title="{{ buyable.name }}" rel="tooltip">
|
||||||
<div class="thumbnail">
|
<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 }}" />
|
<img src="{% thumbnail buyable.image 128x128 %}" alt="{{ buyable.name }}" />
|
||||||
</a>
|
</a>
|
||||||
<div class="caption">
|
<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-toolbar">
|
||||||
<div class="btn-group" data-id="{{ buyable.id}}" data-name="{{ buyable.name }}" data-image="{% thumbnail buyable.image 48x48 %}">
|
<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>
|
<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">
|
<ul class="dropdown-menu" style="text-align: left">
|
||||||
{% if buyable.hasDeposit %}
|
{% 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" 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 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 onlyDeposit" href="{% url 'buyable_buy' buyable.id "only/deposit" %}"><i class="icon-retweet"></i> Kaufen (Nur Pfand) - {{ buyable.deposit|floatformat:2 }}</a></li>
|
||||||
{% else %}
|
{% 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 %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,14 +5,16 @@
|
||||||
#
|
#
|
||||||
# Licensed under GNU Affero General Public License v3 or later
|
# 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/
|
#/store/
|
||||||
urlpatterns = patterns('',
|
urlpatterns = (
|
||||||
(r'^$', 'buyable.views.showItems'),
|
url(r'^$', buyable.views.showItems, name='buyable_overview'),
|
||||||
url(r'^show/(\d+)/$', 'buyable.views.showItem', name='buyable_show'),
|
url(r'^show/(\d+)/$', buyable.views.showItem, name='buyable_show'),
|
||||||
url(r'^buy/(\d+)/$', 'buyable.views.buyItem', name='buyable_buy'),
|
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'^buy/(\d+)/(with/deposit|only/deposit)/$', buyable.views.buyItem, name='buyable_buy'),
|
||||||
(r'^bought/(\d+)/?$', 'buyable.views.boughtItem'),
|
url(r'^bought/(\d+)/?$', buyable.views.boughtItem),
|
||||||
(r'^history/?$', 'buyable.views.history'),
|
url(r'^history/?$', buyable.views.history, name='buyable_history'),
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#
|
#
|
||||||
# Licensed under GNU Affero General Public License v3 or later
|
# 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.template import RequestContext
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
@ -29,7 +29,7 @@ def showItems(request):
|
||||||
if order_by == 'price':
|
if order_by == 'price':
|
||||||
items = items.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
|
@login_required
|
||||||
def showItem(request, itemid):
|
def showItem(request, itemid):
|
||||||
|
@ -38,7 +38,7 @@ def showItem(request, itemid):
|
||||||
except Buyable.DoesNotExist:
|
except Buyable.DoesNotExist:
|
||||||
# baww, kein item mit der id :( (oder mutax trollt rum)
|
# baww, kein item mit der id :( (oder mutax trollt rum)
|
||||||
return HttpResponseRedirect("/buy/")
|
return HttpResponseRedirect("/buy/")
|
||||||
return render_to_response("buyables/showItem.html", {'item': item}, RequestContext(request))
|
return render(request, "buyables/showItem.html", {'item': item})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -76,7 +76,7 @@ def boughtItem(request, orderid):
|
||||||
if error == None and (item.user != request.user):
|
if error == None and (item.user != request.user):
|
||||||
item1 = None
|
item1 = None
|
||||||
error = u"Diese Items gehören dir nicht"
|
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
|
@login_required
|
||||||
def history(request):
|
def history(request):
|
||||||
|
@ -98,4 +98,4 @@ def history(request):
|
||||||
# If page is out of range, deliver last page
|
# If page is out of range, deliver last page
|
||||||
histpage = paginator.page(paginator.num_pages)
|
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.
|
# Django settings for k4ever project.
|
||||||
|
|
||||||
|
import os
|
||||||
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
TEMPLATE_DEBUG = DEBUG
|
|
||||||
PISTON_DISPLAY_ERRORS = DEBUG
|
PISTON_DISPLAY_ERRORS = DEBUG
|
||||||
DEBUG_PROPOGATE_EXCEPTIONS = DEBUG
|
DEBUG_PROPOGATE_EXCEPTIONS = DEBUG
|
||||||
|
|
||||||
|
@ -14,7 +17,7 @@ MANAGERS = ADMINS
|
||||||
# use sqlite by default
|
# use sqlite by default
|
||||||
DATABASES = {
|
DATABASES = {
|
||||||
'default': {
|
'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.
|
'NAME': 'k4ever.db', # Or path to database file if using sqlite3.
|
||||||
'USER': '', # Not used with sqlite3.
|
'USER': '', # Not used with sqlite3.
|
||||||
'PASSWORD': '', # 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).
|
# trailing slash if there is a path component (optional in other cases).
|
||||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||||
MEDIA_URL = '/media/'
|
MEDIA_URL = '/media/'
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
||||||
# trailing slash.
|
# trailing slash.
|
||||||
|
@ -77,18 +81,38 @@ AUTH_PROFILE_MODULE = 'main.UserProfile'
|
||||||
LOGIN_URL = '/user/login/'
|
LOGIN_URL = '/user/login/'
|
||||||
LOGIN_REDIRECT_URL = '/'
|
LOGIN_REDIRECT_URL = '/'
|
||||||
|
|
||||||
|
ALLOWED_HOSTS = ['*']
|
||||||
|
|
||||||
AUTHENTICATION_BACKENDS = (
|
AUTHENTICATION_BACKENDS = (
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
'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.middleware.common.CommonMiddleware',
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
@ -98,31 +122,28 @@ MIDDLEWARE_CLASSES = (
|
||||||
|
|
||||||
ROOT_URLCONF = 'k4ever.urls'
|
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 = (
|
INSTALLED_APPS = (
|
||||||
'django.contrib.auth',
|
'django.contrib.auth',
|
||||||
'django.contrib.contenttypes',
|
'django.contrib.contenttypes',
|
||||||
'django.contrib.sessions',
|
'django.contrib.sessions',
|
||||||
'django.contrib.sites',
|
'django.contrib.sites',
|
||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
'buyable',
|
'buyable',
|
||||||
'transaction',
|
'transaction',
|
||||||
'main',
|
'main',
|
||||||
'django.contrib.admin',
|
'django.contrib.admin',
|
||||||
'easy_thumbnails',
|
'easy_thumbnails',
|
||||||
|
'piston',
|
||||||
|
'rest_framework',
|
||||||
)
|
)
|
||||||
|
|
||||||
TEMPLATE_CONTEXT_PROCESSORS = (
|
|
||||||
"django.contrib.auth.context_processors.auth",
|
STATICFILES_DIRS = [
|
||||||
"django.core.context_processors.debug",
|
os.path.join(BASE_DIR, "media"),
|
||||||
"django.core.context_processors.i18n",
|
]
|
||||||
"django.core.context_processors.media",
|
STATIC_ROOT = os.path.join(BASE_DIR, "static")
|
||||||
"django.core.context_processors.static",
|
|
||||||
"django.contrib.messages.context_processors.messages",
|
REST_FRAMEWORK = {
|
||||||
"django.core.context_processors.request",
|
'DEFAULT_PREMISSION_CLASSES': 'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
|
||||||
)
|
}
|
|
@ -5,11 +5,14 @@
|
||||||
#
|
#
|
||||||
# Licensed under GNU Affero General Public License v3 or later
|
# 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
|
from django.contrib import admin
|
||||||
admin.autodiscover()
|
admin.autodiscover()
|
||||||
|
import django.views.static
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
import main.views
|
||||||
|
|
||||||
|
urlpatterns = (
|
||||||
# Example:
|
# Example:
|
||||||
# (r'^k4ever/', include('k4ever.foo.urls')),
|
# (r'^k4ever/', include('k4ever.foo.urls')),
|
||||||
|
|
||||||
|
@ -17,15 +20,16 @@ urlpatterns = patterns('',
|
||||||
# to INSTALLED_APPS to enable admin documentation:
|
# to INSTALLED_APPS to enable admin documentation:
|
||||||
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
# user stuff? go to main
|
# user stuff? go to main
|
||||||
(r'^$', 'main.views.startpage'),
|
url(r'^$', main.views.startpage, name='main.views.startpage'),
|
||||||
(r'^api2/', include('api2.urls')),
|
url(r'^api2/', include('api2.urls')),
|
||||||
(r'^user/', include('main.urls')),
|
url(r'^api3/', include('api3.urls')),
|
||||||
(r'^transaction/', include('transaction.urls')),
|
url(r'^user/', include('main.urls')),
|
||||||
(r'^store/', include('buyable.urls')),
|
url(r'^transaction/', include('transaction.urls')),
|
||||||
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': 'media'}),
|
url(r'^store/', include('buyable.urls')),
|
||||||
(r'^docs/(?P<path>.*)$', 'django.views.static.serve', {'document_root': 'docs'}),
|
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:
|
# 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 """
|
""" Form made to require that the user of a plugin is in the plugin group """
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Plugin
|
model = Plugin
|
||||||
|
exclude = []
|
||||||
|
|
||||||
def clean_user(self):
|
def clean_user(self):
|
||||||
user = self.cleaned_data['user']
|
user = self.cleaned_data['user']
|
||||||
|
|
|
@ -5,28 +5,32 @@
|
||||||
#
|
#
|
||||||
# Licensed under GNU Affero General Public License v3 or later
|
# 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):
|
#from django.contrib.admin.filterspecs import FilterSpec, BooleanFieldFilterSpec
|
||||||
""" Custom filter to display only users with negative balance """
|
#
|
||||||
def __init__(self, f, request, *args, **kwargs):
|
#class IsNegativeFilterSpec(FilterSpec):
|
||||||
super(IsNegativeFilterSpec, self).__init__(f, request, *args, **kwargs)
|
# """ Custom filter to display only users with negative balance """
|
||||||
self.lookup_kwarg = '%s__lt' % f.name
|
# def __init__(self, f, request, *args, **kwargs):
|
||||||
self.lookup_val = request.GET.get(self.lookup_kwarg, None) # Check if current request already has a filter
|
# super(IsNegativeFilterSpec, self).__init__(f, request, *args, **kwargs)
|
||||||
|
# self.lookup_kwarg = '%s__lt' % f.name
|
||||||
def title(self):
|
# self.lookup_val = request.GET.get(self.lookup_kwarg, None) # Check if current request already has a filter
|
||||||
return 'Kontostand'
|
#
|
||||||
|
# def title(self):
|
||||||
def choices(self, cl):
|
# return 'Kontostand'
|
||||||
yield {
|
#
|
||||||
'selected': self.lookup_val == None,
|
# def choices(self, cl):
|
||||||
'query_string': "?",
|
# yield {
|
||||||
'display': 'Alle'}
|
# 'selected': self.lookup_val == None,
|
||||||
yield {
|
# 'query_string': "?",
|
||||||
'selected': self.lookup_val == '0',
|
# 'display': 'Alle'}
|
||||||
'query_string': cl.get_query_string(
|
# yield {
|
||||||
{self.lookup_kwarg: 0},
|
# 'selected': self.lookup_val == '0',
|
||||||
['balance__isnull']),
|
# 'query_string': cl.get_query_string(
|
||||||
'display': 'Nur Negative'}
|
# {self.lookup_kwarg: 0},
|
||||||
|
# ['balance__isnull']),
|
||||||
FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'has_negative_filter', False), IsNegativeFilterSpec))
|
# '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
|
from django.core.management import commands, call_command
|
||||||
import django.contrib.auth
|
import django.contrib.auth
|
||||||
|
|
||||||
|
@ -6,5 +6,5 @@ def createPluginGroup(sender, app, created_models, **kwargs):
|
||||||
if django.contrib.auth.models.Group in created_models:
|
if django.contrib.auth.models.Group in created_models:
|
||||||
call_command("loaddata", "group_plugin")
|
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):
|
class UserProfile(models.Model):
|
||||||
""" Contains data for a user, especially the account balance. """
|
""" 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 = models.DecimalField(max_digits=9, decimal_places=2, default=Decimal(0))
|
||||||
balance.has_negative_filter = True
|
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
|
The other attributes are used for plugin/user read/write access to the
|
||||||
authblob.
|
authblob.
|
||||||
"""
|
"""
|
||||||
user = models.ForeignKey(User, unique=True)
|
user = models.OneToOneField(User)
|
||||||
|
|
||||||
# plugin info
|
# plugin info
|
||||||
name = models.CharField(max_length=40)
|
name = models.CharField(max_length=40)
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% comment %}
|
{% comment %}
|
||||||
# This file is part of k4ever, a point-of-sale system
|
# This file is part of k4ever, a point-of-sale system
|
||||||
|
@ -11,16 +12,16 @@
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<link rel="stylesheet" media="screen" type="text/css"
|
<link rel="stylesheet" media="screen" type="text/css"
|
||||||
href="/media/css/style.css" />
|
href="{% static "css/style.css" %}" />
|
||||||
{% block extrastyle %}{% endblock %}
|
{% block extrastyle %}{% endblock %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var MEDIA_URL = "/media/";
|
var MEDIA_URL = "/static/";
|
||||||
</script>
|
</script>
|
||||||
<script type='text/javascript' src="/media/js/jquery-1.5.1.js"></script>
|
<script type='text/javascript' src="{% static "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="{% static "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="{% static "js/jquery.ui.autocomplete.html.js" %}"></script>
|
||||||
<script type='text/javascript' src="/media/js/jquery.gritter.min.js"></script>
|
<script type='text/javascript' src="{% static "js/jquery.gritter.min.js" %}"></script>
|
||||||
<script type='text/javascript' src="/media/js/k4ever.js"></script>
|
<script type='text/javascript' src="{% static "js/k4ever.js" %}"></script>
|
||||||
{% endblock head %}
|
{% endblock head %}
|
||||||
|
|
||||||
{% block "content" %}
|
{% block "content" %}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% comment %}
|
{% comment %}
|
||||||
# This file is part of k4ever, a point-of-sale system
|
# This file is part of k4ever, a point-of-sale system
|
||||||
|
@ -12,13 +13,13 @@
|
||||||
{# load url from future #}
|
{# load url from future #}
|
||||||
|
|
||||||
{% block extrastyle %}
|
{% block extrastyle %}
|
||||||
<link rel="stylesheet" type="text/css" href="{% block stylesheet %}{{ MEDIA_URL }}css/admin.css{% endblock %}" />
|
<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 %}{% load adminmedia %}{% admin_media_prefix %}css/ie.css{% endblock %}" /><![endif]-->
|
<!--[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 %}{% admin_media_prefix %}css/rtl.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 %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block extrahead %}
|
{% 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 %}
|
{% block blockbots %}<meta name="robots" content="NONE,NOARCHIVE" />{% endblock %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#
|
#
|
||||||
# Licensed under GNU Affero General Public License v3 or later
|
# Licensed under GNU Affero General Public License v3 or later
|
||||||
{% endcomment %}
|
{% endcomment %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html {% if user.is_authenticated %}class="loggedIn"{% endif %}>
|
<html {% if user.is_authenticated %}class="loggedIn"{% endif %}>
|
||||||
|
@ -13,20 +14,20 @@
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
|
||||||
{% block head %}
|
{% block head %}
|
||||||
<link rel="stylesheet" media="screen" type="text/css"
|
<link rel="stylesheet" media="screen" type="text/css"
|
||||||
href="{{ MEDIA_URL }}css/style.css" />
|
href="{% static "css/style.css" %}" />
|
||||||
{% block extrastyle %}{% endblock %}
|
{% block extrastyle %}{% endblock %}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var MEDIA_URL = "{{ MEDIA_URL }}";
|
var MEDIA_URL = "/static/";
|
||||||
</script>
|
</script>
|
||||||
<script type='text/javascript' src="{{ MEDIA_URL }}js/jquery.min.js"></script>
|
<script type='text/javascript' src="{% static "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="{% static "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="{% static "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="{% static "js/jquery.gritter.min.js" %}"></script>
|
||||||
<script type="text/javascript" src="{{ MEDIA_URL }}bootstrap/js/bootstrap.min.js"></script>
|
<script type="text/javascript" src="{% static "bootstrap/js/bootstrap.min.js" %}"></script>
|
||||||
<script type='text/javascript' src="{{ MEDIA_URL }}js/k4ever.js"></script>
|
<script type='text/javascript' src="{% static "js/k4ever.js" %}"></script>
|
||||||
{% block extrahead %}{% endblock %}
|
{% block extrahead %}{% endblock %}
|
||||||
{% endblock head %}
|
{% endblock head %}
|
||||||
<title>Freitagsrundenkasse{% block "title" %}{% endblock %}</title>
|
<title>Unbranded K4Ever{% block "title" %}{% endblock %}</title>
|
||||||
</head>
|
</head>
|
||||||
<body{%block bodyargs %}{%endblock%}>
|
<body{%block bodyargs %}{%endblock%}>
|
||||||
<div class="navbar navbar-fixed-top">
|
<div class="navbar navbar-fixed-top">
|
||||||
|
|
|
@ -9,47 +9,47 @@
|
||||||
|
|
||||||
{% load navigation_extras %}
|
{% load navigation_extras %}
|
||||||
|
|
||||||
{% url transaction.views.overview as transactions %}
|
{% url 'transactions' as transactions %}
|
||||||
{% url main.views.startpage as home %}
|
{% url 'main.views.startpage' as home %}
|
||||||
{% url buyable.views.showItems as store %}
|
{% url 'buyable_overview' as store %}
|
||||||
{% url buyable.views.history as history %}
|
{% url 'buyable_history' as history %}
|
||||||
{% url main.views.settings as settings %}
|
{% url 'main_settings' as settings %}
|
||||||
{% url django.contrib.auth.views.logout as logout %}
|
{% url 'logout' as logout %}
|
||||||
{% url django.contrib.auth.views.login as login %}
|
{% url 'login' as login %}
|
||||||
{% url main.views.register as register %}
|
{% url 'register' as register %}
|
||||||
|
|
||||||
<ul role="navigation sitemap" class="nav">
|
<ul role="navigation sitemap" class="nav">
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<li class="{% active request home %}"><a href="{{ home }}">Home</a></li>
|
<li class="{% active home %}"><a href="{{ home }}">Home</a></li>
|
||||||
<li class="{% active request store %}"><a href="{{ store }}">Einkaufen</a></li>
|
<li class="{% active store %}"><a href="{{ store }}">Einkaufen</a></li>
|
||||||
<li class="{% active request transactions %}"><a href="{{ transactions }}">Konto</a></li>
|
<li class="{% active transactions %}"><a href="{{ transactions }}">Konto</a></li>
|
||||||
<li class="{% active request history %}"><a href="{{ history }}">Frühere Einkäufe</a></li>
|
<li class="{% active history %}"><a href="{{ history }}">Frühere Einkäufe</a></li>
|
||||||
<li class="divider-vertical" role="presentation"></li>
|
<li class="divider-vertical" role="presentation"></li>
|
||||||
<ul class="nav">
|
<ul class="nav">
|
||||||
<li class="dropdown">
|
<li class="dropdown">
|
||||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="icon user"></span></a>
|
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="icon user"></span></a>
|
||||||
<ul class="dropdown-menu">
|
<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 %}
|
{% if user.is_staff %}
|
||||||
<li class=""><a href="/admin/"><i class="icon-lock"></i> Administration</a></li>
|
<li class=""><a href="/admin/"><i class="icon-lock"></i> Administration</a></li>
|
||||||
{% endif %}
|
{% 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>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="{% active request login %}"><a href="{{ login }}">Anmelden</a></li>
|
<li class="{% active login %}"><a href="{{ login }}">Anmelden</a></li>
|
||||||
<li class="{% active request register %}"><a href="{{ register }}">Registrieren</a></li>
|
<li class="{% active register %}"><a href="{{ register }}">Registrieren</a></li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
<div class="pull-right">
|
<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">
|
<form class="navbar-search">
|
||||||
<input placeholder="Suche und kaufe..." class="search-query autocomplete"
|
<input placeholder="Suche und kaufe..." class="search-query autocomplete"
|
||||||
type="search" name="search_term" value="Lade Daten..."
|
type="search" name="search_term" value="Lade Daten..."
|
||||||
disabled="disabled" />
|
disabled="disabled" />
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
@ -15,18 +15,18 @@
|
||||||
{% for buyable in buyables %}
|
{% for buyable in buyables %}
|
||||||
<tr>
|
<tr>
|
||||||
<td class="productImage">
|
<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>
|
||||||
<td class="name"><span>{{ buyable.name }}</span> {% if buyable.num_buys %}({{ buyable.num_buys }} mal gekauft){% endif %}</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 }}">
|
<td class="actions btn-group" data-image="{% thumbnail buyable.image 48x48 %}" data-name="{{ buyable.name }}" data-id="{{ buyable.id }}">
|
||||||
{% if buyable.deposit > 0 %}
|
{% 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" 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 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 %}
|
{% 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 %}
|
{% endif %}
|
||||||
{% else %}
|
{% 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 %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -11,8 +11,9 @@ import re
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag(takes_context=True)
|
||||||
def active(request, pattern):
|
def active(context, pattern):
|
||||||
|
request = context['request']
|
||||||
if pattern == request.path:
|
if pattern == request.path:
|
||||||
return "active"
|
return "active"
|
||||||
return ""
|
return ""
|
||||||
|
|
|
@ -6,19 +6,23 @@
|
||||||
#
|
#
|
||||||
# Licensed under GNU Affero General Public License v3 or later
|
# Licensed under GNU Affero General Public License v3 or later
|
||||||
|
|
||||||
from django.conf.urls.defaults import *
|
|
||||||
from django.conf import settings
|
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('',
|
urlpatterns = (
|
||||||
(r'^$', 'django.views.generic.simple.redirect_to', {'url': 'login/'}),
|
#(r'^$', 'django.views.generic.simple.redirect_to', {'url': 'login/'}),
|
||||||
(r'^register/$', 'main.views.register'),
|
url(r'^$', RedirectView.as_view(url='login/')),
|
||||||
(r'^login/$', 'main.views.login'),
|
url(r'^register/$', main.views.register, name='register'),
|
||||||
(r'^logout/$', 'django.contrib.auth.views.logout',
|
url(r'^login/$', main.views.login, name='login'),
|
||||||
|
url(r'^logout/$', django.contrib.auth.views.logout,
|
||||||
{'template_name': 'registration/logout.html',
|
{'template_name': 'registration/logout.html',
|
||||||
'next_page': '/user/login/'}),
|
'next_page': '/user/login/'}, name='logout'),
|
||||||
(r'^settings/$', 'main.views.settings'),
|
url(r'^settings/$', main.views.settings, name='main_settings'),
|
||||||
#plugin stuff
|
#plugin stuff
|
||||||
(r'^settings/plugin/(?P<method>(?:allow|deny))/(?P<pluginId>\d+)/$', 'main.views.pluginPermission'),
|
url(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/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.contrib.auth.decorators import login_required
|
||||||
from django.db.models import Count, Max
|
from django.db.models import Count, Max
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
import django.contrib.auth.views
|
import django.contrib.auth.views
|
||||||
|
@ -18,7 +18,7 @@ import django.contrib.auth.views
|
||||||
from buyable.models import Purchase, Buyable, BuyableType
|
from buyable.models import Purchase, Buyable, BuyableType
|
||||||
from main.helper import getUserFromAuthblob
|
from main.helper import getUserFromAuthblob
|
||||||
from main.models import Plugin, PluginPermission
|
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
|
@login_required
|
||||||
def startpage(request):
|
def startpage(request):
|
||||||
|
@ -52,12 +52,12 @@ def startpage(request):
|
||||||
buyables = buyables.annotate(max_dateTime=Max('purchase__order__dateTime'))
|
buyables = buyables.annotate(max_dateTime=Max('purchase__order__dateTime'))
|
||||||
context[context_vars[2]] = buyables.order_by('-max_dateTime')[:5]
|
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):
|
def register(request):
|
||||||
""" The "no registration available" page... """
|
""" The "no registration available" page... """
|
||||||
return render_to_response("registration/register.html", RequestContext(request))
|
return render(request, "registration/register.html")
|
||||||
|
|
||||||
|
|
||||||
def getPluginDict(request):
|
def getPluginDict(request):
|
||||||
|
@ -83,7 +83,7 @@ def settings(request):
|
||||||
form.save()
|
form.save()
|
||||||
pdict['password_success'] = "Es wurde ein neues Passwort gesetzt."
|
pdict['password_success'] = "Es wurde ein neues Passwort gesetzt."
|
||||||
pdict['form'] = form
|
pdict['form'] = form
|
||||||
return render_to_response("settings/settings.html", pdict, RequestContext(request))
|
return render(request, "settings/settings.html", pdict)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def pluginPermission(request, method, pluginId):
|
def pluginPermission(request, method, pluginId):
|
||||||
|
@ -94,14 +94,14 @@ def pluginPermission(request, method, pluginId):
|
||||||
except Plugin.DoesNotExist:
|
except Plugin.DoesNotExist:
|
||||||
d = getPluginDict(request)
|
d = getPluginDict(request)
|
||||||
d['pluginerror'] = "Ein Plugin mit der angegebenen ID existiert nicht"
|
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":
|
if method == "allow":
|
||||||
try:
|
try:
|
||||||
p = PluginPermission.objects.get(user=request.user, plugin=plugin)
|
p = PluginPermission.objects.get(user=request.user, plugin=plugin)
|
||||||
d = getPluginDict(request)
|
d = getPluginDict(request)
|
||||||
d['pluginerror'] = "Dieses Plugin wurde bereits erlaubt"
|
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:
|
except PluginPermission.DoesNotExist:
|
||||||
p = PluginPermission(user=request.user, plugin=plugin)
|
p = PluginPermission(user=request.user, plugin=plugin)
|
||||||
p.save()
|
p.save()
|
||||||
|
@ -112,7 +112,7 @@ def pluginPermission(request, method, pluginId):
|
||||||
except PluginPermission.DoesNotExist:
|
except PluginPermission.DoesNotExist:
|
||||||
d = getPluginDict(request)
|
d = getPluginDict(request)
|
||||||
d['pluginerror'] = "Keine Berechtigungen für dieses Plugin gefunden - kann also auch nicht zurückgezogen werden"
|
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/")
|
return HttpResponseRedirect("/user/settings/")
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@ -128,7 +128,7 @@ def pluginAuthblob(request, pluginId):
|
||||||
except Plugin.DoesNotExist:
|
except Plugin.DoesNotExist:
|
||||||
d = getPluginDict(request)
|
d = getPluginDict(request)
|
||||||
d['pluginerror'] = "Ein Plugin mit der angegebenen ID existiert nicht"
|
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
|
# find plugin permission for user
|
||||||
p = None
|
p = None
|
||||||
|
@ -137,13 +137,13 @@ def pluginAuthblob(request, pluginId):
|
||||||
except PluginPermission.DoesNotExist:
|
except PluginPermission.DoesNotExist:
|
||||||
d = getPluginDict(request)
|
d = getPluginDict(request)
|
||||||
d['pluginerror'] = "Vor dem editieren vom Authblob muss das Plugin ersteinmal erlaubt werden"
|
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?
|
# has the user write access to the authblob?
|
||||||
if not p.plugin.userCanWriteAuthblob or not "authblob" in request.POST:
|
if not p.plugin.userCanWriteAuthblob or not "authblob" in request.POST:
|
||||||
d = getPluginDict(request)
|
d = getPluginDict(request)
|
||||||
d['pluginerror'] = "Der Authblob darf für dieses Plugin nicht vom User verändert werden (oder der Authblob war kaputt)"
|
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
|
# clean authblob \r\n ==> \n
|
||||||
authblob = request.POST["authblob"].replace("\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:
|
if p.plugin.maxLinesPerAuthblob > 0 and (authblob.rstrip().count("\n") + 1) > p.plugin.maxLinesPerAuthblob:
|
||||||
d = getPluginDict(request)
|
d = getPluginDict(request)
|
||||||
d['pluginerror'] = "Der Authblob darf maximal %d Zeilen haben" % (p.plugin.maxLinesPerAuthblob,)
|
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
|
# check, if this is equal to the old users plugin
|
||||||
pluginsWithAuthblob = PluginPermission.objects.filter(plugin=plugin, user=request.user, authblob__exact=authblob)
|
pluginsWithAuthblob = PluginPermission.objects.filter(plugin=plugin, user=request.user, authblob__exact=authblob)
|
||||||
if pluginsWithAuthblob.count() > 0:
|
if pluginsWithAuthblob.count() > 0:
|
||||||
d = getPluginDict(request)
|
d = getPluginDict(request)
|
||||||
d['pluginerror'] = "Das ist der gleiche Authblob, den du vorher auch hattest."
|
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)
|
# check for every authblob-line, if there is somebody who has it (if unique)
|
||||||
if p.plugin.uniqueAuthblob:
|
if p.plugin.uniqueAuthblob:
|
||||||
|
@ -173,13 +173,13 @@ def pluginAuthblob(request, pluginId):
|
||||||
else:
|
else:
|
||||||
d = getPluginDict(request)
|
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!"
|
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.authblob = authblob
|
||||||
p.save()
|
p.save()
|
||||||
d = getPluginDict(request)
|
d = getPluginDict(request)
|
||||||
d['pluginmsg'] = "Authblob erfolgreich geändert"
|
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):
|
def login(request):
|
||||||
|
|
|
@ -1,11 +1,22 @@
|
||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
from django.core.management import execute_manager
|
import os
|
||||||
try:
|
import sys
|
||||||
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)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
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 "))
|
(self.checked and " " or " not "))
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
profile = self.user.get_profile()
|
profile = self.user.userprofile
|
||||||
if self.id == None:
|
if self.id == None:
|
||||||
# insert
|
# insert
|
||||||
profile.balance += self.amount
|
profile.balance += self.amount
|
||||||
|
@ -51,11 +51,11 @@ class Transaction(models.Model):
|
||||||
# update
|
# update
|
||||||
oldobj = Transaction.objects.get(id=self.id)
|
oldobj = Transaction.objects.get(id=self.id)
|
||||||
if oldobj.user != self.user:
|
if oldobj.user != self.user:
|
||||||
oldprofile = oldobj.user.get_profile()
|
oldprofile = oldobj.user.userprofile
|
||||||
oldprofile.balance -= oldobj.amount
|
oldprofile.balance -= oldobj.amount
|
||||||
oldprofile.save()
|
oldprofile.save()
|
||||||
# just to be save, reget profile
|
# just to be save, reget profile
|
||||||
profile = self.user.get_profile()
|
profile = self.user.userprofile
|
||||||
profile.balance += self.amount
|
profile.balance += self.amount
|
||||||
else:
|
else:
|
||||||
profile.balance += (self.amount-oldobj.amount)
|
profile.balance += (self.amount-oldobj.amount)
|
||||||
|
@ -64,7 +64,7 @@ class Transaction(models.Model):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def pre_delete_signal(sender, instance, **kwargs):
|
def pre_delete_signal(sender, instance, **kwargs):
|
||||||
profile = instance.user.get_profile()
|
profile = instance.user.userprofile
|
||||||
profile.balance -= instance.amount
|
profile.balance -= instance.amount
|
||||||
profile.save()
|
profile.save()
|
||||||
|
|
||||||
|
@ -87,8 +87,8 @@ class VirtualTransaction(models.Model):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def moveMoney(fromUser, toUser, amount, commit=True):
|
def moveMoney(fromUser, toUser, amount, commit=True):
|
||||||
if not (fromUser == toUser):
|
if not (fromUser == toUser):
|
||||||
fromProfile = fromUser.get_profile()
|
fromProfile = fromUser.userprofile
|
||||||
toProfile = toUser.get_profile()
|
toProfile = toUser.userprofile
|
||||||
fromProfile.balance -= amount
|
fromProfile.balance -= amount
|
||||||
toProfile.balance += amount
|
toProfile.balance += amount
|
||||||
if commit:
|
if commit:
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
#
|
#
|
||||||
# Licensed under GNU Affero General Public License v3 or later
|
# 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('',
|
urlpatterns = (
|
||||||
(r'^$', 'transaction.views.overview'),
|
url(r'^$', transaction.views.overview, name='transactions'),
|
||||||
(r'^state/(success|error|vsuccess|verror)/(payin|payout)/$', 'transaction.views.state'),
|
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.contrib.auth.decorators import login_required
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
|
|
||||||
from transaction.forms import TransactionForm, VirtualTransactionForm
|
from transaction.forms import TransactionForm, VirtualTransactionForm
|
||||||
|
@ -50,7 +50,7 @@ def overview(request):
|
||||||
else:
|
else:
|
||||||
state = "verror"
|
state = "verror"
|
||||||
return HttpResponseRedirect("state/%s/%s/" % (state,payway))
|
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
|
@login_required
|
||||||
|
@ -77,4 +77,4 @@ def state(request, state="", payway=""):
|
||||||
|
|
||||||
if payway == "payout":
|
if payway == "payout":
|
||||||
payout = True
|
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