Completed
Push — master ( bce3b1...2804a0 )
by Pat
01:30
created

item_request_new()   B

Complexity

Conditions 4

Size

Total Lines 26

Duplication

Lines 11
Ratio 42.31 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
c 1
b 0
f 0
dl 11
loc 26
rs 8.5806
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.response import FileResponse
8
from pyramid.view import view_config, forbidden_view_config
9
10
from sqlalchemy.sql import func
11
from sqlalchemy.exc import DBAPIError, IntegrityError
12
from sqlalchemy.orm.exc import NoResultFound
13
14
from . import views_data
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.box_item import BoxItem
23
from .models.transaction import Transaction, Deposit, CashDeposit, CCDeposit, BTCDeposit, Purchase
24
from .models.transaction import Inventory, InventoryLineItem
25
from .models.transaction import PurchaseLineItem, SubTransaction, SubSubTransaction
26
from .models.account import Account, VirtualAccount, CashAccount
27
from .models.event import Event
28
from .models import event as __event
29
from .models.vendor import Vendor
30
from .models.item_vendor import ItemVendor
31
from .models.box_vendor import BoxVendor
32
from .models.request import Request
33
from .models.request_post import RequestPost
34
from .models.announcement import Announcement
35
from .models.btcdeposit import BtcPendingDeposit
36
from .models.receipt import Receipt
37
from .models.pool import Pool
38
from .models.pool_user import PoolUser
39
40
from .utility import post_stripe_payment
41
42
from pyramid.security import Allow, Everyone, remember, forget
43
44
import chezbetty.datalayer as datalayer
45
from .btc import Bitcoin, BTCException
46
47
import uuid
48
import math
49
import pytz
50
import traceback
51
import arrow
52
53
###
54
### User Admin
55
###
56
57
58
### Common helper code
59
60
def transaction_history_queries(request, user_or_pool):
61
    # Web library native date format: 2015/06/19 19:00
62
    # DO NOT CHANGE: The datetimepicker has a bug and tries to parse the
63
    #                prepopulated value before reading the format string,
64
    #                which means you have to use its native format string
65
    TS_FORMAT = 'YYYY/MM/DD HH:mm'
66
    if 'history-end' not in request.GET:
67
        request.GET['history-end'] =\
68
                arrow.now()\
69
                .replace(hours=+1)\
70
                .floor('hour')\
71
                .format(TS_FORMAT)
72
    if 'history-start' not in request.GET:
73
        request.GET['history-start'] =\
74
                arrow.get(request.GET['history-end'], TS_FORMAT)\
75
                .replace(months=-1)\
76
                .format(TS_FORMAT)
77
78
    start = arrow.get(request.GET['history-start'], TS_FORMAT)
79
    end   = arrow.get(request.GET['history-end'],   TS_FORMAT)
80
    start = start.replace(tzinfo='US/Eastern')
81
    end   = end  .replace(tzinfo='US/Eastern')
82
    start = start.to('utc')
83
    end   = end  .to('utc')
84
85
    query = user_or_pool.get_transactions_query()
86
    query = query\
87
            .filter(event.Event.timestamp > start.datetime)\
88
            .filter(event.Event.timestamp < end.datetime)
89
90
    for t in ('purchase', 'adjustment'):
91
        if 'history-filter-'+t in request.GET:
92
            query = query.filter(event.Event.type!=t)
93
    for t in ('cashdeposit', 'ccdeposit', 'btcdeposit'):
94
        if 'history-filter-'+t in request.GET:
95
            query = query.filter(Transaction.type!=t)
96
    transactions = query.all()
97
98
    withdrawls  = query.filter(event.Event.type=='purchase').all()
99
    deposits    = query.filter(event.Event.type=='deposit').all()
100
    adjustments = query.filter(event.Event.type=='adjustment').all()
101
102
    withdrawls  = sum(w.amount for w in withdrawls)
103
    deposits    = sum(d.amount for d in deposits)
104
    adjustments = sum(a.amount for a in adjustments) if len(adjustments) else None
105
106
    return {'transactions': transactions,
107
            'withdrawls': withdrawls,
108
            'deposits': deposits,
109
            'adjustments': adjustments,
110
            }
111
112
113
114
@view_config(route_name='user_ajax_bool',
115
             permission='user')
116
def user_ajax_bool(request):
117
    obj_str = request.matchdict['object']
118
    obj_id  = int(request.matchdict['id'])
119
    obj_field = request.matchdict['field']
120
    obj_state = request.matchdict['state'].lower() == 'true'
121
122
    if obj_str == 'pool':
123
        obj = Pool.from_id(obj_id)
124
        obj_owner_id = obj.owner
125
    elif obj_str == 'pool_user':
126
        obj = PoolUser.from_id(obj_id)
127
        obj_owner_id = obj.pool.owner
128
    elif obj_str == 'request_post':
129
        obj = RequestPost.from_id(obj_id)
130
        obj_owner_id = obj.user_id
131
    else:
132
        # Return an error, object type not recognized
133
        request.response.status = 502
134
        return request.response
135
136
    if obj_owner_id != request.user.id:
137
        request.response.status = 502
138
        return request.response
139
140
    setattr(obj, obj_field, obj_state)
141
    DBSession.flush()
142
143
    return request.response
144
145
@view_config(route_name='user_index',
146
             renderer='templates/user/index.jinja2',
147
             permission='user')
148
def user_index(request):
149
    r = transaction_history_queries(request, request.user)
150
    r['user'] = request.user
151
    r['my_pools'] = Pool.all_by_owner(request.user)
152
153
    return r
154
155
@view_config(route_name='user_index_slash',
156
             renderer='templates/user/index.jinja2',
157
             permission='user')
158
def user_index_slash(request):
159
    return HTTPFound(location=request.route_url('user_index'))
160
161
@view_config(route_name='user_deposit_cc',
162
             renderer='templates/user/deposit_cc.jinja2',
163
             permission='user')
164
def user_deposit_cc(request):
165
    pools = Pool.all_accessable(request.user, True)
166
    pool = None
167
    if 'acct' in request.GET:
168
        account = request.GET['acct']
169
        if account != 'user':
170
            pool = Pool.from_id(account.split('-')[1])
171
    else:
172
        account = 'user'
173
    return {'user': request.user,
174
            'account': account,
175
            'pool': pool,
176
            'pools': pools,
177
            'stripe_pk': request.registry.settings['stripe.publishable_key'],
178
            }
179
180
@view_config(route_name='user_deposit_cc_custom',
181
             renderer='templates/user/deposit_cc_custom.jinja2',
182
             permission='user')
183
def user_deposit_cc_custom(request):
184
    account = request.GET['betty_to_account']
185
    if account != 'user':
186
        pool = Pool.from_id(account.split('-')[1])
187
    else:
188
        pool = None
189
    return {'user': request.user,
190
            'stripe_pk': request.registry.settings['stripe.publishable_key'],
191
            'amount': round(Decimal(request.GET['deposit-amount']), 2),
192
            'account': account,
193
            'pool': pool,
194
            }
195
196
@view_config(route_name='user_deposit_cc_submit',
197
             request_method='POST',
198
             permission='user')
199
def user_deposit_cc_submit(request):
200
    token = request.POST['stripeToken']
201
    amount = Decimal(request.POST['betty_amount'])
202
    total_cents = int(request.POST['betty_total_cents'])
203
    to_account = request.POST['betty_to_account']
204
205
    try:
206
        if to_account != 'user':
207
            pool = Pool.from_id(to_account.split('-')[1])
208
            if pool.enabled == False:
209
                print("to_account:", to_account)
210
                raise NotImplementedError
211
            if pool.owner != request.user.id:
212
                if pool not in map(lambda pu: getattr(pu, 'pool'), request.user.pools):
213
                    print("to_account:", to_account)
214
                    raise NotImplementedError
215
    except Exception as e:
216
        traceback.print_exc()
217
        request.session.flash('Unexpected error processing transaction. Card NOT charged.', 'error')
218
        return HTTPFound(location=request.route_url('user_index'))
219
220
    post_stripe_payment(
221
            datalayer,
222
            request,
223
            token,
224
            amount,
225
            total_cents,
226
            request.user,
227
            request.user if to_account == 'user' else pool,
228
            )
229
230
    return HTTPFound(location=request.route_url('user_index'))
231
232
233
234
@view_config(route_name='user_item_request',
235
             renderer='templates/user/item_request.jinja2',
236
             permission='user')
237
def item_request(request):
238
    requests = Request.all()
239
    vendors = Vendor.all()
240
    return {
241
            'requests': requests,
242
            'vendors': vendors,
243
           }
244
245
246
@view_config(route_name='user_item_request_new',
247
             request_method='POST',
248
             permission='user')
249
def item_request_new(request):
250
    try:
251
        request_text = request.POST['request']
252
        vendor_id = request.POST['vendor']
253
        vendor = Vendor.from_id(vendor_id)
254
        vendor_url = request.POST['vendor-url']
255
        if len(request_text) < 5:
256
            raise ValueError()
257
258
        print(vendor)
259
        print(vendor_url)
260
        datalayer.new_request(request.user, request_text, vendor, vendor_url)
261 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
262
        request.session.flash('Request added successfully', 'success')
263
        return HTTPFound(location=request.route_url('user_item_request'))
264
265
    except ValueError:
266
        request.session.flash('Please include a detailed description of the item.', 'error')
267
        return HTTPFound(location=request.route_url('user_item_request'))
268
269
    except:
270
        request.session.flash('Error adding request.', 'error')
271
        return HTTPFound(location=request.route_url('user_item_request'))
272
273
274
@view_config(route_name='user_item_request_post_new',
275
             request_method='POST',
276
             permission='user')
277
def item_request_post_new(request):
278
    try:
279
        item_request = Request.from_id(request.matchdict['id'])
280
        post_text = request.POST['post']
281
        if post_text.strip() == '':
282
            request.session.flash('Empty comment not saved.', 'error')
283
            return HTTPFound(location=request.route_url('user_item_request'))
284
        post = RequestPost(item_request, request.user, post_text)
285
        DBSession.add(post)
286
        DBSession.flush()
287
    except Exception as e:
288
        if request.debug:
289
            raise(e)
290
        request.session.flash('Error posting comment.', 'error')
291
    return HTTPFound(location=request.route_url('user_item_request'))
292
293
294
295
296
@view_config(route_name='user_pools',
297
             renderer='templates/user/pools.jinja2',
298
             permission='user')
299
def user_pools(request):
300
    return {'user': request.user,
301
            'my_pools': Pool.all_by_owner(request.user)}
302
303
304
@view_config(route_name='user_pools_new_submit',
305
             request_method='POST',
306
             permission='user')
307
def user_pools_new_submit(request):
308
    try:
309
        pool_name = request.POST['pool-name'].strip()
310
        if len(pool_name) > 255:
311
            pool_name = pool_name[0:255]
312
        if len(pool_name) < 5:
313
            request.session.flash('Pool names must be at least 5 letters long', 'error')
314
            return HTTPFound(location=request.route_url('user_pools'))
315
316
        pool = Pool(request.user, pool_name)
317
        DBSession.add(pool)
318
        DBSession.flush()
319
320
        request.session.flash('Pool created.', 'succcess')
321
        return HTTPFound(location=request.route_url('user_pool', pool_id=pool.id))
322
323
    except Exception as e:
324
        if request.debug: raise(e)
325
        request.session.flash('Error creating pool.', 'error')
326
        return HTTPFound(location=request.route_url('user_pools'))
327
328
329
@view_config(route_name='user_pool',
330
             renderer='templates/user/pool.jinja2',
331
             permission='user')
332
def user_pool(request):
333
    try:
334
        pool = Pool.from_id(request.matchdict['pool_id'])
335
        if pool.owner != request.user.id:
336
            request.session.flash('You do not have permission to view that pool.', 'error')
337
            return HTTPFound(location=request.route_url('user_pools'))
338
339
        r = transaction_history_queries(request, pool)
340
        r['user'] = request.user
341
        r['pool'] = pool
342
343
        return r
344
    except Exception as e:
345
        if request.debug: raise(e)
346
        request.session.flash('Could not load pool.', 'error')
347
        return HTTPFound(location=request.route_url('user_pools'))
348
349
350
@view_config(route_name='user_pool_addmember_submit',
351
             request_method='POST',
352
             permission='user')
353
def user_pool_addmember_submit(request):
354
    try:
355
        pool = Pool.from_id(request.POST['pool-id'])
356
        if pool.owner != request.user.id:
357 View Code Duplication
            request.session.flash('You do not have permission to view that pool.', 'error')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
358
            return HTTPFound(location=request.route_url('user_pools'))
359
360
        # Look up the user that is being added to the pool
361
        user = User.from_uniqname(request.POST['uniqname'].strip(), True)
362
        if user == None:
363
            request.session.flash('Could not find that user.', 'error')
364
            return HTTPFound(location=request.route_url('user_pool', pool_id=pool.id))
365
366
        # Can't add yourself
367
        if user.id == pool.owner:
368
            request.session.flash('You cannot add yourself to a pool. By owning the pool you are automatically a part of it.', 'error')
369
            return HTTPFound(location=request.route_url('user_pool', pool_id=pool.id))
370
371
        # Make sure the user isn't already in the pool
372
        for u in pool.users:
373
            if u.user_id == user.id:
374
                request.session.flash('User is already in pool.', 'error')
375
                return HTTPFound(location=request.route_url('user_pool', pool_id=pool.id))
376
377
        # Add the user to the pool
378
        pooluser = PoolUser(pool, user)
379
        DBSession.add(pooluser)
380
        DBSession.flush()
381
382
        request.session.flash('{} added to the pool.'.format(user.name), 'succcess')
383
        return HTTPFound(location=request.route_url('user_pool', pool_id=pool.id))
384
385
    except Exception as e:
386
        if request.debug: raise(e)
387
        request.session.flash('Error adding user to pool.', 'error')
388
        return HTTPFound(location=request.route_url('user_pools'))
389
390
391
@view_config(route_name='user_pool_changename_submit',
392
             request_method='POST',
393
             permission='user')
394
def user_pool_changename_submit(request):
395
    try:
396
        pool = Pool.from_id(request.POST['pool-id'])
397
        if pool.owner != request.user.id:
398
            request.session.flash('You do not have permission to view that pool.', 'error')
399
            return HTTPFound(location=request.route_url('user_pools'))
400
401
        pool_name = request.POST['newname'].strip()
402
        if len(pool_name) > 255:
403
            pool_name = pool_name[0:255]
404
        if len(pool_name) < 5:
405
            request.session.flash('Pool names must be at least 5 letters long', 'error')
406
            return HTTPFound(location=request.route_url('user_pool', pool_id=int(pool.id)))
407
408
        pool.name = pool_name
409
410
        request.session.flash('Pool created.', 'succcess')
411
        return HTTPFound(location=request.route_url('user_pool', pool_id=pool.id))
412
    except Exception as e:
413
        if request.debug: raise(e)
414
        request.session.flash('Error changing pool name.', 'error')
415
        return HTTPFound(location=request.route_url('user_pools'))
416
417
418
@view_config(route_name='user_password_edit',
419
             renderer='templates/user/password_edit.jinja2',
420
             permission='user')
421
def user_password_edit(request):
422
    return {}
423
424
425
@view_config(route_name='user_password_edit_submit',
426
             request_method='POST',
427
             permission='user')
428
def user_password_edit_submit(request):
429
    pwd0 = request.POST['edit-password-0']
430
    pwd1 = request.POST['edit-password-1']
431
    if pwd0 != pwd1:
432
        request.session.flash('Error: Passwords do not match', 'error')
433
        return HTTPFound(location=request.route_url('user_password_edit'))
434
    request.user.password = pwd0
435
    request.session.flash('Password changed successfully.', 'success')
436
    return HTTPFound(location=request.route_url('user_index'))
437
    # check that changing password for actually logged in user
438
439
440