forked from zap-me/premio_stage
-
Notifications
You must be signed in to change notification settings - Fork 0
/
paydb_core.py
156 lines (142 loc) · 6.24 KB
/
paydb_core.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import logging
import threading
from types import SimpleNamespace
from models import Role, User, Permission, PayDbTransaction
logger = logging.getLogger(__name__)
user_balances = SimpleNamespace(lock=threading.Lock(), kvstore=None)
def __balance(user):
## assumes lock is held
if not user.token in user_balances.kvstore:
return 0
return user_balances.kvstore[user.token]
def __balance_total():
## assumes lock is held
balance = 0
for val in user_balances.kvstore.values():
balance += val
return balance
def __tx_play(txn):
## assumes lock is held
if not txn.sender.token in user_balances.kvstore:
user_balances.kvstore[txn.sender.token] = 0
if txn.recipient and not txn.recipient.token in user_balances.kvstore:
user_balances.kvstore[txn.recipient.token] = 0
if txn.action == txn.ACTION_ISSUE:
user_balances.kvstore[txn.sender.token] += txn.amount
if txn.action == txn.ACTION_TRANSFER:
user_balances.kvstore[txn.sender.token] -= txn.amount
user_balances.kvstore[txn.recipient.token] += txn.amount
if txn.action == txn.ACTION_DESTROY:
user_balances.kvstore[txn.sender.token] -= txn.amount
def __tx_play_all(session):
## assumes lock is held
assert not user_balances.kvstore
user_balances.kvstore = {}
for tx in PayDbTransaction.all(session):
__tx_play(tx)
def __check_balances_inited(session):
## assumes lock is held
# check user_balances.kvstore has been initialized
if user_balances.kvstore is None:
logger.info('user_balances.kvstore not initialized, initializing now..')
__tx_play_all(session)
def user_balance_from_user(session, user):
with user_balances.lock:
__check_balances_inited(session)
return __balance(user)
def user_balance(session, api_key):
if not api_key.has_permission(Permission.PERMISSION_BALANCE):
return -1
return user_balance_from_user(session, api_key.user)
def balance_total(session):
with user_balances.lock:
__check_balances_inited(session)
return __balance_total()
def tx_play_all(session):
with user_balances.lock:
__tx_play_all(session)
def tx_transfer_authorized(session, sender_email, recipient_email, amount, attachment):
logger.info('%s: %s: %s, %s', sender_email, recipient_email, amount, attachment)
with user_balances.lock:
__check_balances_inited(session)
error = ''
sender = User.from_email(session, sender_email)
recipient = User.from_email(session, recipient_email)
if not sender:
error = 'ACTION_TRANSFER: sender ({}) is not valid'.format(sender_email)
elif not recipient:
error = 'ACTION_TRANSFER: recipient ({}) is not valid'.format(recipient_email)
if error:
logger.error(error)
return None, error
sender_balance = __balance(sender)
if sender_balance < amount:
error = 'ACTION_TRANSFER: user balance ({}) is too low'.format(sender_balance)
logger.error(error)
return None, error
tx = PayDbTransaction(PayDbTransaction.ACTION_TRANSFER, sender, recipient, amount, attachment)
__tx_play(tx)
session.add(tx)
session.commit()
return tx, ''
def tx_issue_authorized(session, sender_email, amount, attachment):
logger.info('%s: %s, %s', sender_email, amount, attachment)
with user_balances.lock:
__check_balances_inited(session)
error = ''
sender = User.from_email(session, sender_email)
if not sender:
error = 'ACTION_ISSUE: sender ({}) is not valid'.format(sender_email)
if error:
logger.error(error)
return None, error
tx = PayDbTransaction(PayDbTransaction.ACTION_ISSUE, sender, sender, amount, attachment)
__tx_play(tx)
session.add(tx)
session.commit()
return tx, ''
def tx_create_and_play(session, api_key, action, recipient_email, amount, attachment):
logger.info('%s (%s): %s: %s, %s, %s', api_key.token, api_key.user.email, action, recipient_email, amount, attachment)
with user_balances.lock:
__check_balances_inited(session)
error = ''
user = api_key.user
if not user.is_active:
error = '{}: {} is not active'.format(action, user.email)
elif amount <= 0:
error = '{}: amount ({}) is less then or equal to zero'.format(action, amount)
if error:
logger.error(error)
return None, error
recipient = User.from_email(session, recipient_email)
if action == PayDbTransaction.ACTION_ISSUE:
if not api_key.has_permission(Permission.PERMISSION_ISSUE):
error = 'ACTION_ISSUE: {} is not authorized'.format(api_key.token)
elif not user.has_role(Role.ROLE_ADMIN):
error = 'ACTION_ISSUE: {} is not authorized'.format(user.email)
elif not recipient == user:
error = 'ACTION_ISSUE: recipient should be {}'.format(user.email)
if action == PayDbTransaction.ACTION_TRANSFER:
user_bal = __balance(user)
if not api_key.has_permission(Permission.PERMISSION_TRANSFER):
error = 'ACTION_TRANSFER: {} is not authorized'.format(api_key.token)
elif not recipient:
error = 'ACTION_TRANSFER: recipient ({}) is not valid'.format(recipient_email)
elif user_bal < amount:
error = 'ACTION_TRANSFER: user balance ({}) is too low'.format(user_bal)
if action == PayDbTransaction.ACTION_DESTROY:
user_bal = __balance(user)
if not api_key.has_permission(Permission.PERMISSION_TRANSFER):
error = 'ACTION_TRANSFER: {} is not authorized'.format(api_key.token)
elif not recipient == user:
error = 'ACTION_ISSUE: recipient should be {}'.format(user.email)
elif user_bal < amount:
error = 'ACTION_DESTROY: user balance ({}) is too low'.format(user_bal)
if error:
logger.error(error)
return None, error
tx = PayDbTransaction(action, user, recipient, amount, attachment)
__tx_play(tx)
session.add(tx)
session.commit()
return tx, ''