from cashonly.models import * from django.http import HttpResponse from django.contrib.auth import authenticate from django.views.decorators.csrf import csrf_exempt from django.contrib.sessions.backends.db import SessionStore import json import hashlib API_VERSION = 2 err_msgs = {} #Global errors ERR_DATABASE = 1 ERR_PARSE_REQUEST = 2 ERR_UNKNOWN_ACTION = 3 ERR_PARAM = 4 ERR_INVALID_SESSION = 5 err_msgs[ERR_DATABASE] = 'Can\'t connect to database' err_msgs[ERR_PARSE_REQUEST] = 'Error while parsing request' err_msgs[ERR_UNKNOWN_ACTION] = 'Unknown action specified' err_msgs[ERR_PARAM] = 'Given parameters don\'t match the actions requirements' err_msgs[ERR_INVALID_SESSION] = 'The session key is invalid' #Auth key errors ERR_INVALID_AUTH_KEY = 6 ERR_AUTH_KEY_LOCKED = 7 ERR_AUTH_KEY_NOT_PERMITTED = 8 err_msgs[ERR_INVALID_AUTH_KEY] = 'The given authentication key is invalid' err_msgs[ERR_AUTH_KEY_LOCKED] = 'The given authentication key is locked' err_msgs[ERR_AUTH_KEY_NOT_PERMITTED] = 'The given authentication key \ has insufficient permissions for this action' #Errors for get_user_info ERR_USER_NOT_FOUND = 11 ERR_INCORRECT_PIN = 12 err_msgs[ERR_USER_NOT_FOUND] = 'Unknown user' err_msgs[ERR_INCORRECT_PIN] = 'Pin/Password is not valid' #Errors for get_item_infos ERR_ITEM_NOT_FOUND = 31 err_msgs[ERR_ITEM_NOT_FOUND] = 'Can\'t find the given item' #Errors for buy_items ERR_ITEM_NOT_FOUND_ = 41 ERR_INSUFFICIENT_CREDIT = 42 err_msgs[ERR_ITEM_NOT_FOUND_] = 'At least one of the items to buy could \ not be found' err_msgs[ERR_INSUFFICIENT_CREDIT] = 'The user has not enough money left to \ buy the specified items' #Errors for cash_prepaid_card ERR_CASH_CODE_NOT_VALID = 51 err_msgs[ERR_CASH_CODE_NOT_VALID] = 'Given code can\'t be found or has \ already been used' #Errors for cash_[gs]et_config_key ERR_CONFIG_TYPE_MISMATCH = 61 ERR_CONFIG_UNKNOWN_TYPE = 62 err_msgs[ERR_CONFIG_TYPE_MISMATCH] = 'Value in database doesn\'t match the \ datatype for that key' err_msgs[ERR_CONFIG_UNKNOWN_TYPE] = 'Given value is neither int, bool, string \ nor float' #Errors for cash_modify_credit ERR_USER_NOT_FOUND__ = 71 ERR_USER_NOT_AUTHORIZED = 72 err_msgs[ERR_USER_NOT_FOUND] = 'User not found' err_msgs[ERR_USER_NOT_AUTHORIZED] = 'User not authorized to change another \ user\'s credit' class ApiError(Exception): def __init__(self, code): self.code = code def check_session(data): try: key = data['session_key'] except KeyError: raise ApiError(ERR_PARAM) s = SessionStore(session_key = key) if not s.exists(key): raise ApiError(ERR_INVALID_SESSION) if not s.has_key('userid'): raise ApiError(ERR_INVALID_SESSION) return s def start_session(credentials): try: user = authenticate(**credentials) except KeyError: raise ApiError(ERR_PARAM) if user is not None: # Credentials are valid, so save user id in session s = SessionStore() s['userid'] = user.id s.save() return s.session_key else: raise ApiError(ERR_INCORRECT_PIN) # Disable CSRF, because clients don't do cookies @csrf_exempt def cashapi(request): retval = {} error = {'code': 0, 'msg': None} try: try: req = json.loads(request.body) except: raise ApiError(ERR_PARSE_REQUEST) print req action = req['action'] data = req['data'] if action == 'start_session_password': creds = {'username': data['user'], 'password': data['password']} retval['session_key'] = start_session(creds) elif action == 'start_session_pin': creds = {'card_number': data['card_number'], 'pin': data['pin']} retval['session_key'] = start_session(creds) elif action == 'close_session': s = check_session(data) s.delete elif action == 'get_user_info': s = check_session(data) user = User.objects.get(pk = s['userid']) retval['id'] = user.id retval['name'] = user.first_name + ' ' + user.last_name retval['nick'] = user.username retval['mail'] = user.email retval['card_number'] = user.account.card_number retval['credit'] = int(user.account.credit * 100) elif action == 'get_item_info': try: try: item = Product.objects.get(pk = data['id']) except KeyError: try: item = Product.objects.get(productbarcode__barcode = data['ean']) except KeyError: raise ApiError(ERR_PARAM) except Product.DoesNotExist: raise ApiError(ERR_ITEM_NOT_FOUND) if not item.active: raise ApiError(ERR_ITEM_NOT_FOUND) retval['id'] = item.id retval['name'] = item.name retval['ean'] = str(item.productbarcode_set.all()[0]) retval['price'] = int(item.price * 100) elif action == 'buy_items': s = check_session(data) shopping_list = {} try: for item in data['items']: try: p = Product.objects.get(pk = item[0]) shopping_list[p] = int(item[1]) except Product.DoesNotExist: raise ApiError(ERR_ITEM_NOT_FOUND_) except ValueError: raise ApiError(ERR_PARAM) except KeyError: raise ApiError(ERR_PARAM) user = User.objects.get(pk = s['userid']) try: if user.account.buy_products(shopping_list): retval['new_credit'] = int(user.account.credit * 100) else: raise ApiError(ERR_INSUFFICIENT_CREDIT) except ValueError: raise ApiError(ERR_PARAM) elif action == 'modify_credit': s = check_session(data) treasurer = User.objects.get(pk=s['userid']) if not treasurer.has_perm('cashonly.change_account'): raise ApiError(ERR_USER_NOT_AUTHORIZED) try: user = User.objects.get(pk=data['user_id']) except User.DoesNotExist: raise ApiError(ERR_USER_NOT_FOUND__) except KeyError: raise ApiError(ERR_PARAM) try: amount = int(data['amount']) except (KeyError, ValueError): raise ApiError(ERR_PARAM) # TODO: Auslagern PAYOUT_SUBJECT = ugettext_noop('Payout') DEPOSIT_SUBJECT = ugettext_noop('Deposit') DESCRIPTION = ugettext_noop('Authorized by %(first)s %(last)s') if amount > 0: subject = DEPOSIT_SUBJECT else: subject = PAYOUT_SUBJECT desc = DESCRIPTION % {'first': treasurer.first_name, 'last': treasurer.last_name} user.account.change_credit(amount/100, subject, desc) retval['new_credit'] = int(user.account.credit*100) except ApiError as e: error = {'code': e.code, 'msg': err_msgs[e.code]} # Generate return object ret = {'err_code': error['code'], 'err_msg': error['msg'], 'return_values': retval, 'api_version': API_VERSION} print ret return HttpResponse(json.dumps(ret))