Completed
Push — master ( 47a02e...98f9f2 )
by
unknown
39:53
created

chezbetty.terminal_item_id()   A

Complexity

Conditions 3

Size

Total Lines 15

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 3
dl 0
loc 15
rs 9.4285
1
from pyramid.events import subscriber
2
from pyramid.events import BeforeRender
3
from pyramid.httpexceptions import HTTPFound
4
from pyramid.renderers import render
5
from pyramid.renderers import render_to_response
6
from pyramid.response import Response
7
from pyramid.view import view_config, forbidden_view_config
8
9
from pyramid.i18n import TranslationStringFactory
10
_ = TranslationStringFactory('betty')
11
12
from sqlalchemy.sql import func
13
from sqlalchemy.exc import DBAPIError
14
from sqlalchemy.orm.exc import NoResultFound
15
16
from .models import *
17
from .models.model import *
18
from .models import user as __user
19
from .models.user import User
20
from .models.item import Item
21
from .models.box import Box
22
from .models.transaction import Transaction, BTCDeposit, PurchaseLineItem
23
from .models.account import Account, VirtualAccount, CashAccount
24
from .models.event import Event
25
from .models.announcement import Announcement
26
from .models.btcdeposit import BtcPendingDeposit
27
from .models.pool import Pool
28
from .models.tag import Tag
29
30
from .utility import user_password_reset
31
from .utility import send_email
32
33
from pyramid.security import Allow, Everyone, remember, forget
34
35
import chezbetty.datalayer as datalayer
36
import transaction
37
38
import math
39
40
# Custom exception
41
class DepositException(Exception):
42
    pass
43
44
45
# Check for a valid user by UMID.
46
#
47
# Input: form encoded umid=11223344
48
#
49
# Note: will not create new user if this user does not exist.
50
@view_config(route_name='terminal_umid_check',
51
             request_method='POST',
52
             renderer='json',
53
             permission='service')
54
def terminal_umid_check(request):
55
    try:
56
        User.from_umid(request.POST['umid'])
57
        return {}
58
    except:
59
        return {'error': _('mcard-keypad-error', default='First time using Betty? You need to swipe your M-Card the first time you log in.')}
60
61
62
## Main terminal page with purchase/cash deposit.
63
@view_config(route_name='terminal',
64
             renderer='templates/terminal/terminal.jinja2',
65
             permission='service')
66
def terminal(request):
67
    try:
68
        if len(request.matchdict['umid']) != 8:
69
            raise __user.InvalidUserException()
70
71
        with transaction.manager:
72
            user = User.from_umid(request.matchdict['umid'], create_if_never_seen=True)
73
        user = DBSession.merge(user)
74
        if not user.enabled:
75
            request.session.flash(_(
76
                'user-not-enabled',
77
                default='User is not enabled. Please contact ${email}.',
78
                mapping={'email':request.registry.settings['chezbetty.email']},
79
                ), 'error')
80
            return HTTPFound(location=request.route_url('index'))
81
82
        # For Demo mode:
83
        items = DBSession.query(Item)\
84
                         .filter(Item.enabled == True)\
85
                         .order_by(Item.name)\
86
                         .limit(6).all()
87
88
        # Determine initial wall-of-shame fee (if applicable)
89
        purchase_fee_percent = 0.0
90
        if float(user.balance) <= -5.0:
91
            purchase_fee_percent = 5.0 + math.floor((float(user.balance)+5.0) / -5.0)
92
93
        # Figure out if any pools can be used to pay for this purchase
94
        purchase_pools = []
95
        deposit_pools = []
96
        for pool in Pool.all_by_owner(user, True):
97
            deposit_pools.append(pool)
98
            if pool.balance > (pool.credit_limit * -1):
99
                purchase_pools.append(pool)
100
101
        for pu in user.pools:
102
            deposit_pools.append(pu.pool)
103
            if pu.pool.enabled and pu.pool.balance > (pu.pool.credit_limit * -1):
104
                purchase_pools.append(pu.pool)
105
106
        # Get the list of tags that have items without barcodes in them
107
        tags_with_nobarcode_items = Tag.get_tags_with_nobarcode_items();
108
109
        return {'user': user,
110
                'items': items,
111
                'purchase_pools': purchase_pools,
112
                'deposit_pools': deposit_pools,
113
                'purchase_fee_percent': purchase_fee_percent,
114
                'tags_with_nobarcode_items': tags_with_nobarcode_items}
115
116
    except __user.InvalidUserException as e:
117
        request.session.flash(_(
118
            'mcard-error',
119
            default='Failed to read M-Card. Please try swiping again.',
120
            ), 'error')
121
        return HTTPFound(location=request.route_url('index'))
122
123
124
## Get all items without barcodes in a tag
125
@view_config(route_name='terminal_purchase_tag',
126
             renderer='json',
127
             permission='service')
128
def terminal_purchase_tag(request):
129
    try:
130
        tag_id = int(request.matchdict['tag_id'])
131
        tag = Tag.from_id(tag_id)
132
    except:
133
        if request.matchdict['tag_id'] == 'other':
134
            tag = {'name': 'other',
135
                   'nobarcode_items': Item.get_nobarcode_notag_items()}
136
        else:
137
            return {'error': 'Unable to parse TAG ID'}
138
139
    item_array = render('templates/terminal/purchase_nobarcode_items.jinja2',
140
                        {'tag': tag})
141
142
    return {'items_html': item_array}
143
144
145
## Add a cash deposit.
146
@view_config(route_name='terminal_deposit',
147
             request_method='POST',
148
             renderer='json',
149
             permission='service')
150
def terminal_deposit(request):
151
    try:
152
        user = User.from_umid(request.POST['umid'])
153
        amount = Decimal(request.POST['amount'])
154
        account = request.POST['account']
155
156
        # Check if the deposit amount is too great.
157
        # This if block could be tighter, but this is easier to understand
158
        if amount > 100.0:
159
            # Anything above 100 is blocked
160
            raise DepositException('Deposit amount of ${:,.2f} exceeds the limit'.format(amount))
161
162
        if amount < 100.0 and amount > 20.0 and (user.total_deposits < 10.0 or user.total_purchases < 10.0):
163
            # If the deposit is between 20 and 100 and the user hasn't done much
164
            # with betty. Block the deposit. We do allow deposits up to 100 for
165
            # customers that have shown they know how to scan/purchase and
166
            # deposit
167
            raise DepositException('Deposit amount of ${:,.2f} exceeds the limit'.format(amount))
168
169
        if amount <= 0.0:
170
            raise DepositException('Deposit amount must be greater than $0.00')
171
172
        # At this point the deposit can go through
173
        ret = {}
174
175
        if account == 'user':
176
            deposit = datalayer.deposit(user, user, amount)
177
        elif account == 'pool':
178
            pool = Pool.from_id(request.POST['pool_id'])
179
            deposit = datalayer.deposit(user, pool, amount)
180
            ret['pool_name'] = pool.name
181
            ret['pool_balance'] = float(pool.balance)
182
            ret['pool_id'] = pool.id
183
184
        # Return a JSON blob of the transaction ID so the client can redirect to
185
        # the deposit success page
186
        ret['amount'] = float(deposit['amount'])
187
        ret['event_id'] = deposit['event'].id
188
        ret['user_balance'] = float(user.balance)
189
        return ret
190
191
    except __user.InvalidUserException as e:
192
        request.session.flash('Invalid user error. Please try again.', 'error')
193
        return {'error': 'Error finding user.'}
194
195
    except ValueError as e:
196
        return {'error': 'Error understanding deposit amount.'}
197
198
    except DepositException as e:
199
        return {'error': str(e)}
200
201
    except Exception as e:
202
        return {'error': str(e)}
203
204
205
## Delete a just completed transaction.
206
@view_config(route_name='terminal_deposit_delete',
207
             request_method='POST',
208
             renderer='json',
209
             permission='service')
210
def terminal_deposit_delete(request):
211
    try:
212
        user = User.from_umid(request.POST['umid'])
213
        old_event = Event.from_id(request.POST['old_event_id'])
214
215
        if old_event.type != 'deposit' or \
216
           old_event.transactions[0].type != 'cashdeposit' or \
217
           (old_event.transactions[0].to_account_virt_id != user.id and \
218
            old_event.user_id != user.id):
219
           # Something went wrong, can't undo this deposit
220
           raise DepositException('Cannot undo that deposit')
221
222
        # Now undo old deposit
223
        datalayer.undo_event(old_event, user)
224
225
        purchase_pools = []
226
        for pool in Pool.all_by_owner(user, True):
227
            if pool.balance > (pool.credit_limit * -1):
228
                purchase_pools.append({'id': pool.id, 'balance': float(pool.balance)})
229
230
        for pu in user.pools:
231
            if pu.pool.enabled and pu.pool.balance > (pu.pool.credit_limit * -1):
232
                purchase_pools.append({'id': pu.pool.id, 'balance': float(pu.pool.balance)})
233
234
        return {'user_balance': float(user.balance),
235
                'pools': purchase_pools}
236
237
    except __user.InvalidUserException as e:
238
        return {'error': 'Invalid user error. Please try again.'}
239
240
    except DepositException as e:
241
        return {'error': str(e)}
242
243
    except Exception as e:
244
        if request.debug: raise(e)
245
        return {'error': 'Error.'}
246
247
248
## Add an item to a shopping cart.
249
@view_config(route_name='terminal_item_barcode',
250
             renderer='json',
251
             permission='service')
252
def terminal_item_barcode(request):
253
    try:
254
        item = Item.from_barcode(request.matchdict['barcode'])
255
    except:
256
        # Could not find the item. Check to see if the user scanned a box
257
        # instead. This could lead to two cases: a) the box only has 1 item in it
258
        # in which case we just add that item to the cart. This likely occurred
259
        # because the individual items do not have barcodes so we just use
260
        # the box. b) The box has multiple items in it in which case we throw
261
        # an error for now.
262
        try:
263
            box = Box.from_barcode(request.matchdict['barcode'])
264
            if box.subitem_number == 1:
265
                item = box.items[0].item
266
            else:
267
                return {'error': 'Cannot add that entire box to your order. Please scan an individual item.'}
268
        except:
269
            return {'error': 'Could not find that item.'}
270
271
    if not item.enabled:
272
        return {'error': 'That product is not currently for sale.'}
273
274
    item_html = render('templates/terminal/purchase_item_row.jinja2', {'item': item})
275
    return {'id':item.id,
276
            'item_row_html': item_html}
277
278
279
## Add an item to a shopping cart.
280
@view_config(route_name='terminal_item_id',
281
             renderer='json',
282
             permission='service')
283
def terminal_item_id(request):
284
    try:
285
        item = Item.from_id(request.matchdict['item_id'])
286
    except:
287
        return {'error': 'Could not find that item.'}
288
289
    if not item.enabled:
290
        return {'error': 'That product is not currently for sale.'}
291
292
    item_html = render('templates/terminal/purchase_item_row.jinja2', {'item': item})
293
    return {'id': item.id,
294
            'item_row_html': item_html}
295
296
297
## Make a purchase from the terminal.
298
@view_config(route_name='terminal_purchase',
299
             request_method='POST',
300
             renderer='json',
301
             permission='service')
302
def terminal_purchase(request):
303
    try:
304
        user = User.from_umid(request.POST['umid'])
305
306
        ignored_keys = ['umid', 'pool_id']
307
308
        # Bundle all purchase items
309
        items = {}
310
        for item_id,quantity in request.POST.items():
311
            if item_id in ignored_keys:
312
                continue
313
            item = Item.from_id(int(item_id))
314
            items[item] = int(quantity)
315
316
        # What should pay for this?
317
        # Note: should do a bunch of checking to make sure all of this
318
        # is kosher. But given our locked down single terminal, we're just
319
        # going to skip all of that.
320
        if 'pool_id' in request.POST:
321
            pool = Pool.from_id(int(request.POST['pool_id']))
322
            purchase = datalayer.purchase(user, pool, items)
323
        else:
324
            purchase = datalayer.purchase(user, user, items)
325
326
        # Create a order complete view
327
        order = {'total': purchase.amount,
328
                 'discount': purchase.discount,
329
                 'items': []}
330
        for subtrans in purchase.subtransactions:
331
            item = {}
332
            item['name'] = subtrans.item.name
333
            item['quantity'] = subtrans.quantity
334
            item['price'] = subtrans.item.price
335
            item['total_price'] = subtrans.amount
336
            order['items'].append(item)
337
338
        if purchase.fr_account_virt_id == user.id:
339
            account_type = 'user'
340
            pool = None
341
        else:
342
            account_type = 'pool'
343
            pool = Pool.from_id(purchase.fr_account_virt_id)
344
345
        summary = render('templates/terminal/purchase_complete.jinja2',
346
            {'user': user,
347
             'event': purchase.event,
348
             'order': order,
349
             'transaction': purchase,
350
             'account_type': account_type,
351
             'pool': pool})
352
353
        # Return the committed transaction ID
354
        return {'order_table': summary,
355
                'user_balance': float(user.balance)}
356
357
    except __user.InvalidUserException as e:
358
        return {'error': _('invalid-user-error',
359
                           default='Invalid user error. Please try again.')
360
               }
361
362
    except ValueError as e:
363
        return {'error': 'Unable to parse Item ID or quantity'}
364
365
    except NoResultFound as e:
366
        # Could not find an item
367
        return {'error': 'Unable to identify an item.'}
368
369
370
## Delete a just completed purchase.
371
@view_config(route_name='terminal_purchase_delete',
372
             request_method='POST',
373
             renderer='json',
374
             permission='service')
375
def terminal_purchase_delete(request):
376
    try:
377
        user = User.from_umid(request.POST['umid'])
378
        old_event = Event.from_id(request.POST['old_event_id'])
379
380
        if old_event.type != 'purchase' or \
381
           old_event.transactions[0].type != 'purchase' or \
382
           (old_event.transactions[0].fr_account_virt_id != user.id and \
383
            old_event.user_id != user.id):
384
           # Something went wrong, can't undo this purchase
385
           raise DepositException('Cannot undo that purchase')
386
387
        # Now undo old deposit
388
        datalayer.undo_event(old_event, user)
389
390
        return {'user_balance': float(user.balance)}
391
392
    except __user.InvalidUserException as e:
393
        return {'error': 'Invalid user error. Please try again.'}
394
395
    except DepositException as e:
396
        return {'error': str(e)}
397
398
399
400
401
# @view_config(route_name='user', renderer='templates/terminal/user.jinja2', permission='service')
402
# def user(request):
403
#     try:
404
#         user = User.from_umid(request.matchdict['umid'])
405
#         if not user.enabled:
406
#             request.session.flash('User not permitted to purchase items.', 'error')
407
#             return HTTPFound(location=request.route_url('index'))
408
409
#         transactions,count = limitable_request(
410
#                 request, user.get_transactions, limit=20, count=True)
411
#         return {'user': user,
412
#                 'transactions': transactions,
413
#                 'transactions_count': count,
414
#                 }
415
416
#     except __user.InvalidUserException as e:
417
#         request.session.flash('Invalid User ID.', 'error')
418
#         return HTTPFound(location=request.route_url('index'))
419
420
421
# @view_config(route_name='deposit', renderer='templates/terminal/deposit.jinja2', permission='service')
422
# def deposit(request):
423
#     try:
424
#         user = User.from_umid(request.matchdict['umid'])
425
426
#         # Record the deposit limit so we can show the user
427
#         if user.total_deposits > 10.0 and user.total_purchases > 10.0:
428
#             user.deposit_limit = 100.0
429
#         else:
430
#             user.deposit_limit = 20.0
431
432
#         try:
433
#             auth_key = binascii.b2a_hex(open("/dev/urandom", "rb").read(32))[:-3].decode("ascii")
434
#             btc_addr = Bitcoin.get_new_address(user.umid, auth_key)
435
#             btc_html = render('templates/terminal/btc.jinja2', {'addr': btc_addr})
436
437
#             e = BtcPendingDeposit(user, auth_key, btc_addr)
438
#             DBSession.add(e)
439
#             DBSession.flush()
440
#         except BTCException as e:
441
#             print('BTC error: %s' % str(e))
442
#             btc_html = ""
443
444
#         # Get pools the user can deposit to
445
#         pools = Pool.all_accessable(user, True)
446
447
#         return {'user' : user,
448
#                 'btc'  : btc_html,
449
#                 'pools': pools}
450
451
#     except __user.InvalidUserException as e:
452
#         request.session.flash('Invalid User ID.', 'error')
453
#         return HTTPFound(location=request.route_url('index'))
454
455
456
# @view_config(route_name='deposit_edit',
457
#              renderer='templates/terminal/deposit_edit.jinja2',
458
#              permission='service')
459
# def deposit_edit(request):
460
#     try:
461
#         user = User.from_umid(request.matchdict['umid'])
462
#         event = Event.from_id(request.matchdict['event_id'])
463
464
#         if event.type != 'deposit' or event.transactions[0].type != 'cashdeposit':
465
#             request.session.flash('Can only edit a cash deposit.', 'error')
466
#             return HTTPFound(location=request.route_url('index'))
467
468
#         # Get pools the user can deposit to
469
#         pools = []
470
#         for pool in Pool.all_by_owner(user, True):
471
#             pools.append(pool)
472
473
#         for pu in user.pools:
474
#             if pu.pool.enabled:
475
#                 pools.append(pu.pool)
476
477
#         return {'user': user,
478
#                 'old_event': event,
479
#                 'old_deposit': event.transactions[0],
480
#                 'pools': pools}
481
482
#     except __user.InvalidUserException as e:
483
#         request.session.flash('Invalid User ID.', 'error')
484
#         return HTTPFound(location=request.route_url('index'))
485
486
#     except Exception as e:
487
#         if request.debug: raise(e)
488
#         request.session.flash('Error.', 'error')
489
#         return HTTPFound(location=request.route_url('index'))
490
491
492
493
# @view_config(route_name='event', permission='service')
494
# def event(request):
495
#     try:
496
#         event = Event.from_id(request.matchdict['event_id'])
497
#         transaction = event.transactions[0]
498
#         user = User.from_id(event.user_id)
499
500
#         # Choose which page to show based on the type of event
501
#         if event.type == 'deposit':
502
#             # View the deposit success page
503
#             prev_balance = user.balance - transaction.amount
504
505
#             if transaction.to_account_virt_id == user.id:
506
#                 account_type = 'user'
507
#                 pool = None
508
#             else:
509
#                 account_type = 'pool'
510
#                 pool = Pool.from_id(transaction.to_account_virt_id)
511
512
#             return render_to_response('templates/terminal/deposit_complete.jinja2',
513
#                 {'deposit': transaction,
514
#                  'user': user,
515
#                  'event': event,
516
#                  'prev_balance': prev_balance,
517
#                  'account_type': account_type,
518
#                  'pool': pool}, request)
519
520
#         elif event.type == 'purchase':
521
#             # View the purchase success page
522
#             order = {'total': transaction.amount,
523
#                      'discount': transaction.discount,
524
#                      'items': []}
525
#             for subtrans in transaction.subtransactions:
526
#                 item = {}
527
#                 item['name'] = subtrans.item.name
528
#                 item['quantity'] = subtrans.quantity
529
#                 item['price'] = subtrans.item.price
530
#                 item['total_price'] = subtrans.amount
531
#                 order['items'].append(item)
532
533
#             if transaction.fr_account_virt_id == user.id:
534
#                 account_type = 'user'
535
#                 pool = None
536
#             else:
537
#                 account_type = 'pool'
538
#                 pool = Pool.from_id(transaction.fr_account_virt_id)
539
540
#             request.session.flash('Success! The purchase was added successfully', 'success')
541
#             return render_to_response('templates/terminal/purchase_complete.jinja2',
542
#                 {'user': user,
543
#                  'event': event,
544
#                  'order': order,
545
#                  'transaction': transaction,
546
#                  'account_type': account_type,
547
#                  'pool': pool}, request)
548
549
#     except NoResultFound as e:
550
#         # TODO: add generic failure page
551
#         pass
552
#     except Exception as e:
553
#         if request.debug: raise(e)
554
#         return HTTPFound(location=request.route_url('index'))
555
556
557
# @view_config(route_name='event_undo', permission='service')
558
# def event_undo(request):
559
#     # Lookup the transaction that the user wants to undo
560
#     try:
561
#         event = Event.from_id(request.matchdict['event_id'])
562
#     except:
563
#         request.session.flash('Error: Could not find transaction to undo.', 'error')
564
#         return HTTPFound(location=request.route_url('index'))
565
566
#     for transaction in event.transactions:
567
568
#         # Make sure transaction is a deposit, the only one the user is allowed
569
#         # to undo
570
#         if transaction.type not in ('cashdeposit', 'purchase'):
571
#             request.session.flash('Error: Only deposits and purchases may be undone.', 'error')
572
#             return HTTPFound(location=request.route_url('index'))
573
574
#         # Make sure that the user who is requesting the deposit was the one who
575
#         # actually placed the deposit.
576
#         try:
577
#             user = User.from_id(event.user_id)
578
#         except:
579
#             request.session.flash('Error: Invalid user for transaction.', 'error')
580
#             return HTTPFound(location=request.route_url('index'))
581
582
#         if user.umid != request.matchdict['umid']:
583
#             request.session.flash('Error: Transaction does not belong to specified user', 'error')
584
#             return HTTPFound(location=request.route_url('user', umid=request.matchdict['umid']))
585
586
#     # If the checks pass, actually revert the transaction
587
#     try:
588
#         line_items = datalayer.undo_event(event, user)
589
#         if event.type == 'deposit':
590
#             request.session.flash('Deposit successfully undone.', 'success')
591
#         elif event.type == 'purchase':
592
#             request.session.flash('Purchase undone. Please edit it as needed.', 'success')
593
#     except:
594
#         request.session.flash('Error: Failed to undo transaction.', 'error')
595
#         return HTTPFound(location=request.route_url('purchase', umid=user.umid))
596
597
#     if event.type == 'deposit':
598
#         return HTTPFound(location=request.route_url('user', umid=user.umid))
599
#     elif event.type == 'purchase':
600
#         return HTTPFound(location=request.route_url('purchase', umid=user.umid, _query=line_items))
601
#     else:
602
#         assert(False and "Should not be able to get here?")
603
604
605
# ###
606
# ### JSON Requests
607
# ###
608
609
# @view_config(route_name='purchase_item_row', renderer='json', permission='service')
610
# def item(request):
611
#     try:
612
#         item = Item.from_barcode(request.matchdict['barcode'])
613
#     except:
614
#         # Could not find the item. Check to see if the user scanned a box
615
#         # instead. This could lead to two cases: a) the box only has 1 item in it
616
#         # in which case we just add that item to the cart. This likely occurred
617
#         # because the individual items do not have barcodes so we just use
618
#         # the box. b) The box has multiple items in it in which case we throw
619
#         # an error for now.
620
#         try:
621
#             box = Box.from_barcode(request.matchdict['barcode'])
622
#             if box.subitem_number == 1:
623
#                 item = box.items[0].item
624
#             else:
625
#                 return {'status': 'scanned_box_with_multiple_items'}
626
#         except:
627
#             return {'status': 'unknown_barcode'}
628
#     if item.enabled:
629
#         status = 'success'
630
#     else:
631
#         status = 'disabled'
632
#     item_html = render('templates/terminal/purchase_item_row.jinja2', {'item': item})
633
#     return {'status': status, 'id':item.id, 'item_row_html' : item_html}
634
635
# ###
636
# ### POST Handlers
637
# ###
638
639
# @view_config(route_name='item_request_new', request_method='POST')
640
# def item_request_new(request):
641
#     try:
642
#         request_text = request.POST['request']
643
#         if len(request_text) < 5:
644
#             raise ValueError()
645
646
#         datalayer.new_request(None, request.POST['request'])
647
648
#         request.session.flash('Request added successfully', 'success')
649
#         return HTTPFound(location=request.route_url('index'))
650
651
#     except ValueError:
652
#         request.session.flash('If you are making a request, it should probably contain some characters.', 'error')
653
#         return HTTPFound(location=request.route_url('item_request'))
654
655
#     except:
656
#         request.session.flash('Error adding request.', 'error')
657
#         return HTTPFound(location=request.route_url('index'))
658
659
660
661
# # Handle the POST from coinbase saying Chez Betty got a btc deposit.
662
# # Store the bitcoin record in the DB
663
# @view_config(route_name='btc_deposit', request_method='POST', renderer='json')
664
# def btc_deposit(request):
665
666
#     user = User.from_umid(request.matchdict['umid'])
667
#     auth_key = request.matchdict['auth_key']
668
669
#     addr       = request.json_body['address']
670
#     amount_btc = request.json_body['amount']
671
#     txid       = request.json_body['transaction']['id']
672
#     created_at = request.json_body['transaction']['created_at']
673
#     txhash     = request.json_body['transaction']['hash']
674
675
#     try:
676
#         pending = BtcPendingDeposit.from_auth_key(auth_key)
677
#     except NoResultFound as e:
678
#         print("No result for auth_key %s" % auth_key)
679
#         return {}
680
681
682
#     if (pending.user_id != user.id or pending.address != addr):
683
#         print("Mismatch of BtcPendingDeposit userid or address: (%d/%d), (%s/%s)" % (pending.user_id, user.id, pending.address, addr))
684
#         return {}
685
686
#     #try:
687
#     usd_per_btc = Bitcoin.get_spot_price()
688
#     #except BTCException as e:
689
#     #    # unknown exchange rate?
690
#     #    print('Could not get exchange rate for addr %s txhash %s; failing...' % (addr, txhash))
691
#     #    return {}
692
693
#     amount_usd = Decimal(amount_btc) * usd_per_btc
694
695
#     # round down to nearest cent
696
#     amount_usd = Decimal(int(amount_usd*100))/Decimal(100)
697
698
#     ret = "addr: %s, amount: %s, txid: %s, created_at: %s, txhash: %s, exchange = $%s/BTC"\
699
#            % (addr, amount_btc, txid, created_at, txhash, usd_per_btc)
700
#     datalayer.bitcoin_deposit(user, amount_usd, txhash, addr, amount_btc)
701
#     DBSession.delete(pending)
702
#     print(ret)
703
704
#     return {}
705
706
707
# @view_config(route_name='btc_check', request_method='GET', renderer='json')
708
# def btc_check(request):
709
#     try:
710
#         deposit = BTCDeposit.from_address(request.matchdict['addr'])
711
#         return {"event_id": deposit.event.id}
712
#     except:
713
#         return {}
714
715
716
# @view_config(route_name='deposit_emailinfo',
717
#              renderer='json',
718
#              permission='service')
719
# def deposit_emailinfo(request):
720
#     try:
721
#         user = User.from_id(int(request.matchdict['user_id']))
722
#         if not user.has_password:
723
#             return deposit_password_create(request)
724
#         send_email(TO=user.uniqname+'@umich.edu',
725
#                    SUBJECT='Chez Betty Credit Card Instructions',
726
#                    body=render('templates/terminal/email_userinfo.jinja2', {'user': user}))
727
#         return {'status': 'success',
728
#                 'msg': 'Instructions emailed to {}@umich.edu.'.format(user.uniqname)}
729
#     except NoResultFound:
730
#         return {'status': 'error',
731
#                 'msg': 'Could not find user.'}
732
#     except Exception as e:
733
#         if request.debug: raise(e)
734
#         return {'status': 'error',
735
#                 'msg': 'Error.'}
736
737
738
# @view_config(route_name='deposit_password_create',
739
#              renderer='json',
740
#              permission='service')
741
# def deposit_password_create(request):
742
#     try:
743
#         user = User.from_id(int(request.matchdict['user_id']))
744
#         if user.has_password:
745
#             return {'status': 'error',
746
#                     'msg': 'Error: User already has password.'}
747
#         user_password_reset(user)
748
#         return {'status': 'success',
749
#                 'msg': 'Password set and emailed to {}@umich.edu.'.format(user.uniqname)}
750
#     except NoResultFound:
751
#         return {'status': 'error',
752
#                 'msg': 'Could not find user.'}
753
#     except Exception as e:
754
#         if request.debug: raise(e)
755
#         return {'status': 'error',
756
#                 'msg': 'Error.'}
757
758
# @view_config(route_name='deposit_password_reset',
759
#         renderer='json',
760
#         permission='service')
761
# def deposit_password_reset(request):
762
#     try:
763
#         user = User.from_id(int(request.matchdict['user_id']))
764
#         user_password_reset(user)
765
#         return {'status': 'success',
766
#                 'msg': 'Password set and emailed to {}@umich.edu.'.format(user.uniqname)}
767
#     except NoResultFound:
768
#         return {'status': 'error',
769
#                 'msg': 'Could not find user.'}
770
#     except Exception as e:
771
#         if request.debug: raise(e)
772
#         return {'status': 'error',
773
#                 'msg': 'Error.'}
774
775
776
777
778
779
780