2011-09-28 10:51:32 +02:00
from piston . handler import BaseHandler
2011-09-28 14:31:21 +02:00
from piston . utils import rc
2011-09-28 10:51:32 +02:00
from k4ever . buyable . models import *
from k4ever . transaction . models import *
2011-09-30 17:22:26 +02:00
from django . contrib . auth . decorators import user_passes_test
from django . contrib . auth . models import Group
2011-10-06 02:10:16 +02:00
from django . core . exceptions import MultipleObjectsReturned
2011-09-30 17:22:26 +02:00
from decorators import *
2011-10-10 23:59:45 +02:00
from collections import Iterable
2011-09-29 23:38:25 +02:00
from decimal import Decimal , InvalidOperation
2011-10-04 19:36:16 +02:00
from helper import *
2011-09-29 23:38:25 +02:00
import datetime
2011-09-28 10:51:32 +02:00
class BuyableItemHandler ( BaseHandler ) :
2011-10-04 19:36:16 +02:00
""" Handler responsible for getting and buying items. """
2011-09-28 10:51:32 +02:00
allowed_methods = ( ' GET ' , ' POST ' )
#fields = ('id', 'description')
model = Buyable
2011-09-29 14:14:29 +02:00
exclude = ( ' _* ' , )
2011-10-10 21:14:07 +02:00
BUY_ITEM , BUY_DEPOSIT , BUY_ITEM_AND_DEPOSIT = range ( 3 )
2011-09-28 10:51:32 +02:00
2011-10-10 23:59:45 +02:00
def read ( self , request , itemId = None , bulkBuy = False ) :
2011-10-04 19:36:16 +02:00
""" Get one or multiple items.
2011-10-06 02:10:16 +02:00
- type : Only get items belonging to this type
- barcode : Return only item ( s ) with this barcode
Note that neither type nor barcode is used if an item id
is specified .
2011-10-04 19:36:16 +02:00
"""
2011-10-10 23:59:45 +02:00
if bulkBuy :
ret = rc . NOT_IMPLEMENTED
ret . write ( " \n Bulk buying does not support GET \n " )
return ret
2011-10-06 02:10:16 +02:00
barcode = request . GET . get ( ' barcode ' , None )
2011-09-28 14:31:21 +02:00
if itemId == None :
2011-10-06 02:10:16 +02:00
obj = Buyable . objects . all ( )
if barcode and barcode != ' ' :
# try to get specific object or return 404
try :
return Buyable . objects . get ( barcode = barcode )
except MultipleObjectsReturned :
ret = rc . DUPLICATE_ENTRY
ret . write ( " \n We found more than one entry with this barcode. Bad. \n " )
return ret
except Buyable . DoesNotExist :
return rc . NOT_FOUND
2011-09-29 00:26:39 +02:00
else :
2011-10-06 02:10:16 +02:00
if request . GET . has_key ( ' type ' ) :
obj = Buyable . objects . filter ( buyableType__name = request . GET [ ' type ' ] )
return obj
2011-09-28 14:31:21 +02:00
try :
return Buyable . objects . get ( id = itemId )
except Buyable . DoesNotExist :
error = rc . NOT_FOUND
error . write ( " This buyable does not exist in our database " )
return error
2011-09-29 00:26:39 +02:00
2011-09-30 17:22:26 +02:00
@manglePluginPerms
2011-10-10 23:59:45 +02:00
def create ( self , request , itemId = None , bulkBuy = False ) :
""" Buy one or multiple :class:`Buyable <buyable.models.Buyable>` items.
"""
if not request . content_type :
request . data = request . POST
if bulkBuy :
return self . bulkBuy ( request )
else :
return self . buyItem ( request , itemId )
def buyItem ( self , request , itemId ) :
2011-10-04 19:36:16 +02:00
""" Buy a :class:`Buyable <buyable.models.Buyable>` item.
2011-10-10 21:14:07 +02:00
- deposit : Set to 0 for no deposit , 1 for item + deposit and 2 for deposit only ( default 0 )
- amount : amount of items to buy ( default 1 )
2011-10-04 19:36:16 +02:00
"""
2011-09-29 00:26:39 +02:00
if not itemId :
return rc . BAD_REQUEST
2011-09-29 14:14:29 +02:00
item = None
2011-09-29 00:26:39 +02:00
try :
2011-09-29 14:14:29 +02:00
item = Buyable . objects . get ( id = itemId )
2011-09-29 00:26:39 +02:00
except Buyable . DoesNotExist :
return rc . NOT_FOUND
2011-09-30 01:24:41 +02:00
# parse post data
2011-10-10 21:14:07 +02:00
deposit = getInt ( request . data , ' deposit ' , self . BUY_ITEM )
2011-09-30 01:24:41 +02:00
amount = getInt ( request . data , ' amount ' , 1 )
2011-09-29 14:14:29 +02:00
if amount < 1 :
return rc . BAD_REQUEST
2011-10-15 04:06:01 +02:00
if amount > 30 :
ret = rc . BAD_REQUEST
ret . write ( " \n You are trying to buy more than 30 items at once. This is not permitted. If you think it should, mail the admins / fix this in the handlers.py \n " ) ;
return ret
2011-10-10 21:14:07 +02:00
if ( not item . hasDeposit ( ) and deposit != self . BUY_ITEM ) or \
deposit not in ( self . BUY_ITEM , self . BUY_DEPOSIT , self . BUY_ITEM_AND_DEPOSIT ) :
return rc . BAD_REQUEST
2011-09-29 14:14:29 +02:00
order = Order ( )
order . create ( request . user )
2011-09-29 19:17:11 +02:00
order . save ( )
2011-09-29 14:14:29 +02:00
for i in range ( amount ) :
2011-10-10 21:14:07 +02:00
if deposit == self . BUY_ITEM or deposit == self . BUY_ITEM_AND_DEPOSIT :
p = Purchase . create ( order , item , isDeposit = False )
p . save ( )
if deposit == self . BUY_DEPOSIT or deposit == self . BUY_ITEM_AND_DEPOSIT :
2011-09-29 14:14:29 +02:00
p = Purchase . create ( order , item , isDeposit = True )
p . save ( )
order . updatePrice ( commit = True )
order . save ( )
2011-10-10 23:59:45 +02:00
return rc . CREATED
def bulkBuy ( self , request ) :
""" Buy a :class:`Buyable <buyable.models.Buyable>` item.
To buy multiple items , the body of the POST - request has to
be either JSON or YAML .
- items : List of items to buy .
- deposits : List of items to buy deposit for .
"""
if not request . content_type :
ret = rc . BAD_REQUEST
ret . write ( " \n The content-type of the request must not be empty/urlencoded \n " )
return ret
if not request . data . has_key ( " items " ) and not request . data . has_key ( " deposits " ) :
ret = rc . BAD_REQUEST
ret . write ( " \n You need to specify either items or deposits (or both). \n " )
return ret
2011-10-18 02:56:29 +02:00
if not request . data . has_key ( " items " ) :
request . data [ ' items ' ] = [ ]
if not request . data . has_key ( " deposits " ) :
request . data [ ' deposits ' ] = [ ]
2011-10-10 23:59:45 +02:00
itemList = [ ]
try :
2011-10-18 02:56:29 +02:00
if not isinstance ( request . data [ ' items ' ] , Iterable ) :
raise TypeError ( )
itemList + = request . data [ ' items ' ]
2011-10-10 23:59:45 +02:00
if request . data . has_key ( ' items ' ) :
2011-10-18 02:56:29 +02:00
if not isinstance ( request . data [ ' deposits ' ] , Iterable ) :
2011-10-10 23:59:45 +02:00
raise TypeError ( )
2011-10-18 02:56:29 +02:00
itemList + = request . data [ ' deposits ' ]
2011-10-10 23:59:45 +02:00
except TypeError :
ret = rc . BAD_REQUEST
ret . write ( " \n The items/deposists parameter have to be a list. \n " )
return ret
2011-10-15 04:06:01 +02:00
if len ( itemList ) > 30 :
ret = rc . BAD_REQUEST
ret . write ( " \n You are trying to buy more than 30 items at once. This is not permitted. If you think it should, mail the admins / fix this in the handlers.py \n " ) ;
return ret
2011-10-11 01:34:07 +02:00
if len ( itemList ) == 0 :
ret = rc . BAD_REQUEST
ret . write ( " \n Your request contains no items/deposits. \n " )
return ret
2011-10-10 23:59:45 +02:00
ids = { }
for item in itemList :
if not ids . has_key ( item ) :
try :
ids [ item ] = Buyable . objects . get ( id = item )
except Buyable . DoesNotExist :
ret = rc . NOT_FOUND
ret . write ( " \n The item with the id ' %s ' could not be found \n " % ( item , ) )
return ret
except ValueError :
ret = rc . NOT_FOUND
ret . write ( " \n Item ids should be numeric (and preferably integers) \n " )
return ret
if item in request . data [ ' deposits ' ] and not ids [ item ] . hasDeposit ( ) :
ret = rc . BAD_REQUEST
ret . write ( " \n Item ' %s ' cant be bought with deposit \n " % ( item , ) )
return ret
order = Order ( )
order . create ( request . user )
order . save ( )
purchases = [ ]
2011-10-18 02:56:29 +02:00
# buy items
for item in request . data [ ' items ' ] :
p = Purchase . create ( order , ids [ item ] , isDeposit = False )
p . save ( )
# buy deposits
for item in request . data [ ' deposits ' ] :
p = Purchase . create ( order , ids [ item ] , isDeposit = True )
p . save ( )
2011-10-10 23:59:45 +02:00
order . updatePrice ( commit = True )
order . save ( )
2011-10-04 00:43:11 +02:00
return rc . CREATED
2011-09-28 10:51:32 +02:00
class BuyableTypeHandler ( BaseHandler ) :
2011-10-04 19:36:16 +02:00
""" Handler for listing all :class:`BuyableType <buyable.models.BuyableType>`.
This class only supports read requests which won ' t accept
any arguments . It will give you a list of buyable - types .
Nothing more , nothing less .
"""
2011-09-28 10:51:32 +02:00
allowed_methods = ( ' GET ' , )
model = BuyableType
2011-10-02 17:58:54 +02:00
class HistoryHandler ( BaseHandler ) :
2011-10-10 21:14:07 +02:00
""" Handler providing access to the user ' s history """
2011-10-02 17:58:54 +02:00
allowed_methods = ( ' GET ' , )
fields = ( ' id ' , ' price ' , ' dateTime ' , ( ' purchase_set ' , ( ( ' buyable ' , ( ' id ' , ) ) , ' price ' , ' name ' ) ) )
@manglePluginPerms
def read ( self , request ) :
2011-10-10 21:14:07 +02:00
""" Get the user ' s history
2011-10-04 19:36:16 +02:00
- num : Number of entries to return
"""
2011-10-02 17:58:54 +02:00
num = getInt ( request . GET , ' num ' , 0 )
qset = Order . objects . filter ( user = request . user )
if num > 0 :
return qset [ : num ]
return qset
2011-09-28 10:51:32 +02:00
class TransactionTransactHandler ( BaseHandler ) :
2011-10-04 19:36:16 +02:00
""" Handler for transaction.
2011-10-10 21:14:07 +02:00
This handler takes care of adding money to accounts and returning
previous money transfers
2011-10-04 19:36:16 +02:00
"""
2011-09-28 10:51:32 +02:00
allowed_methods = ( ' GET ' , ' POST ' )
model = Transaction
2011-09-29 23:38:25 +02:00
fields = ( ' amount ' , ' dateTime ' , ' checked ' , ( ' transactionType ' , ( ' id ' , ' name ' ) ) )
2011-09-30 17:22:26 +02:00
@manglePluginPerms
2011-09-29 23:38:25 +02:00
def read ( self , request ) :
2011-10-10 21:14:07 +02:00
""" Return the user ' s last transactions
2011-10-04 19:36:16 +02:00
- num : Number of entries to return
"""
2011-09-29 23:38:25 +02:00
num = getInt ( request . GET , ' num ' , 0 )
if num < 0 :
return rc . BAD_REQUEST
userTrans = Transaction . objects . filter ( user = request . user )
if num > 0 :
return userTrans [ : num ]
return userTrans
2011-09-30 17:22:26 +02:00
@manglePluginPerms
2011-09-29 23:38:25 +02:00
def create ( self , request ) :
2011-10-04 19:36:16 +02:00
""" Transact money to an account
2011-10-10 21:14:07 +02:00
- amount : [ req ] Amount to add to the user ' s account
- type : [ req ] Type of transaction ( id )
2011-10-04 19:36:16 +02:00
"""
2011-09-29 23:38:25 +02:00
amount = getDecimal ( request . POST , ' amount ' , Decimal ( 0 ) )
tTypeId = getInt ( request . POST , ' type ' , - 1 )
2011-10-15 04:06:01 +02:00
if amount < Decimal ( " 0.01 " ) :
2011-09-29 23:38:25 +02:00
ret = rc . BAD_REQUEST
2011-10-15 04:06:01 +02:00
ret . write ( " \n A negative amount (or zeroed) is not supported right now (there has not been put enough thought into the ' lending money ' process \n " )
2011-09-29 23:38:25 +02:00
return ret
tType = None
try :
tType = TransactionType . objects . get ( id = tTypeId )
except TransactionType . DoesNotExist :
ret = rc . BAD_REQUEST
ret . write ( " \n Your TransactionType could not be found \n " )
return ret
trans = Transaction ( )
trans . user = request . user
trans . transactionType = tType
trans . dateTime = datetime . datetime . now ( )
trans . amount = amount
trans . save ( )
return rc . ALL_OK
2011-09-28 10:51:32 +02:00
class TransactionTypeHandler ( BaseHandler ) :
2011-10-04 19:36:16 +02:00
""" Handler for :class:`Transaction Types <transaction.models.TransactionType>`
Supplies a list of Transaction Types
"""
2011-09-28 10:51:32 +02:00
allowed_methods = ( ' GET ' , )
model = TransactionType
2011-09-29 23:38:25 +02:00
class AccountBalanceHandler ( BaseHandler ) :
2011-10-10 21:14:07 +02:00
""" Handler for the user ' s account balance """
2011-09-29 02:37:46 +02:00
allowed_methods = ( ' GET ' , )
2011-09-30 17:22:26 +02:00
@manglePluginPerms
2011-09-29 02:37:46 +02:00
def read ( self , request ) :
2011-10-10 21:14:07 +02:00
""" Returns the user ' s current account balance """
2011-09-29 23:41:48 +02:00
balance = request . user . get_profile ( ) . balance
return { ' balance ' : balance }
2011-09-29 02:37:46 +02:00
2011-09-28 10:51:32 +02:00
class AuthBlobHandler ( BaseHandler ) :
2011-10-10 21:14:07 +02:00
""" Handler to read and write a user ' s authblob
2011-10-04 19:36:16 +02:00
Currently these functions are only available for a plugin user .
2011-10-10 21:14:07 +02:00
Other users will get a rc . FORBIDDEN . Keep in mind that to use
these functions , a plugin needs the permissions to do this in its
2011-10-04 19:36:16 +02:00
configuration .
"""
2011-10-01 18:48:40 +02:00
allowed_methods = ( ' GET ' , ' POST ' )
@requirePlugin
@manglePluginPerms
def read ( self , request ) :
2011-10-10 21:14:07 +02:00
""" Read the user ' s authblob
2011-10-04 19:36:16 +02:00
To use this function the plugin needs
: attr : ` main . models . Plugin . pluginCanReadAuthblob ` to be true .
"""
2011-10-01 18:48:40 +02:00
if not request . plugin . pluginCanReadAuthblob :
ret = rc . FORBIDDEN
2011-10-10 21:14:07 +02:00
ret . write ( " \n This plugin is not allowed to read the user ' s authblob \n " )
2011-10-01 18:48:40 +02:00
return ret
2011-10-10 21:14:07 +02:00
return { ' authblob ' : request . pluginperms . authblob }
2011-10-01 18:48:40 +02:00
@requirePlugin
@manglePluginPerms
def create ( self , request ) :
2011-10-10 21:14:07 +02:00
""" Write the user ' s authblob.
2011-10-04 19:36:16 +02:00
To use this function the plugin needs
: attr : ` main . models . Plugin . pluginCanWriteAuthblob ` to be true .
. . Note : : In fact this method * should * be an update method , but for
compability reasons ( wget usage ) it was decided to make
this accessible as a create ( POST ) hook .
"""
2011-10-01 18:48:40 +02:00
if not request . plugin . pluginCanWriteAuthblob :
ret = rc . FORBIDDEN
2011-10-10 21:14:07 +02:00
ret . write ( " \n This plugin is not allowed to write the user ' s authblob \n " )
2011-10-01 18:48:40 +02:00
return ret
if not request . data . has_key ( ' authblob ' ) :
ret = rc . BAD_REQUEST
2011-10-10 21:14:07 +02:00
ret . write ( " \n To change the user ' s auth blob you actually need to provide one \n " )
2011-10-01 18:48:40 +02:00
request . pluginperms . authblob = request . data [ ' authblob ' ]
request . pluginperms . authblob . save ( )
return rc . ALL_OK
2011-09-29 00:26:39 +02:00
2011-09-30 22:29:02 +02:00
class AuthUserHandler ( BaseHandler ) :
2011-10-04 19:36:16 +02:00
""" Handler for mapping an authblob to a user
This handler is only available to plugins and only if
: attr : ` unique authblob < main . models . Plugin . uniqueAuthblob > `
is set for this plugin . Then it will provide a mapping from
2011-10-10 21:14:07 +02:00
an authblob to a specific user .
2011-10-04 19:36:16 +02:00
"""
2011-09-30 22:29:02 +02:00
allowed_methods = ( ' GET ' )
fields = ( ' id ' , ' username ' )
@requirePlugin
def read ( self , request ) :
2011-10-10 21:14:07 +02:00
""" Returns an user if one can be found, else rc.NOT_FOUND
2011-10-04 19:36:16 +02:00
- authblob : [ required ] Authblob to search
"""
2011-09-30 22:29:02 +02:00
if not request . plugin . uniqueAuthblob :
ret = rc . BAD_REQUEST
2011-10-10 21:14:07 +02:00
ret . write ( " \n This plugin does not support unique auth blobs, therefore we can ' t identify a user uniquely by their authblob \n " )
2011-09-30 22:29:02 +02:00
return ret
if not request . GET . has_key ( ' authblob ' ) :
return rc . BAD_REQUEST
try :
perm = PluginPermission . objects . get ( plugin = request . plugin , authblob = request . GET [ ' authblob ' ] )
return perm . user
except PluginPermission . DoesNotExist :
return rc . NOT_FOUND
2011-09-29 00:26:39 +02:00
class ConfigHandler ( BaseHandler ) :
2011-10-04 19:36:16 +02:00
""" Handler for API configuration values
This handler provides some API related configuration values """
2011-09-29 00:26:39 +02:00
allowed_methods = ( ' GET ' , )
def read ( self , request ) :
2011-10-04 19:36:16 +02:00
""" Get API configuration values
Currently returns the API version and mediaurl ( where to
find images etc . )
"""
2011-09-29 00:26:39 +02:00
return {
' version ' : ' 0.1 ' ,
' mediaurl ' : ' http://devcat.someserver.de:13805/media ' ,
}
2011-10-04 19:36:16 +02:00