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

chezbetty.index_terminal()   B

Complexity

Conditions 4

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 4
dl 0
loc 27
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.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
29
from .utility import user_password_reset
30
from .utility import send_email
31
from .utility import post_stripe_payment
32
33
from pyramid.security import Allow, Everyone, remember, forget
34
35
import chezbetty.datalayer as datalayer
36
from .btc import Bitcoin, BTCException
37
import binascii
38
import transaction
39
40
import traceback
41
42
###
43
### Catch-all error page
44
###
45
46
@view_config(route_name='exception_view', renderer='templates/public/exception.jinja2')
47
def exception_view(request):
48
    return {}
49
50
@view_config(context=Exception)
51
def exception_view_handler(context, request):
52
    print('-'*80)
53
    print('An unknown error occurred:')
54
    print('\t** Some potentially useful information:')
55
    try:
56
        print('\t** request {}'.format(request))
57
        print('\t** client_addr {}'.format(request.client_addr))
58
        print('\t** authenticated_userid {}'.format(request.authenticated_userid))
59
        print('\t** GET {}'.format(request.GET))
60
        print('\t** POST {}'.format(request.POST))
61
        print('\t** url {}'.format(request.url))
62
        print('\t** user_agent {}'.format(request.user_agent))
63
        print('\t** headers.environ {}'.format(request.headers.environ))
64
        print('\t** referer {}'.format(request.referer))
65
        print('\t** body {}'.format(request.body))
66
    except:
67
        pass
68
    traceback.print_exc()
69
    print('-'*80)
70
    return HTTPFound(location=request.route_url('exception_view'))
71
72
73
###
74
### HTML Pages
75
###
76
77
### No login needed
78
79
@view_config(route_name='lang')
80
def lang(request):
81
    code = request.matchdict['code']
82
    response = Response()
83
    response.set_cookie('_LOCALE_', value=code, max_age=15*60) # reset lang after 15min
84
85
    return HTTPFound(location='/', headers=response.headers)
86
87
88
from pyramid.view import view_config
89
90
# Use to select which homepage to show, the only-on-the-betty-terminal version
91
# or the publically accessible version.   
92
def IsTerminalPredicate(boolean):
93
    def is_terminal(context, request):
94
        return ((request.user != None) and (request.user.role == 'serviceaccount')) == boolean
95
    return is_terminal
96
97
98
99
# Terminal home page
100
@view_config(route_name='index',
101
             renderer='templates/terminal/index.jinja2',
102
             custom_predicates=(IsTerminalPredicate(True),))
103
def index_terminal(request):
104
    announcements = Announcement.all_enabled()
105
106
    try:
107
        top_debtors = DBSession.query(User)\
108
                         .filter(User.balance < -5)\
109
                         .order_by(User.balance)\
110
                         .limit(5).all()
111
    except NoResultFound:
112
        top_debtors = None
113
114
    # For the demo mode
115
    if 'demo' in request.cookies and request.cookies['demo'] == '1':
116
        admins = User.get_admins()
117
    else:
118
        admins = []
119
120
    shame_users = User.get_shame_users()
121
122
    return {'announcements': announcements,
123
            'admins': admins,
124
            'top_debtors': top_debtors,
125
            'owed_by_users': User.get_amount_owed(),
126
            'shame_users': shame_users}
127
128
129
# General internet homepage
130
@view_config(route_name='index',
131
             renderer='templates/public/index.jinja2',
132
             custom_predicates=(IsTerminalPredicate(False),))
133
def index(request):
134
135
    try:
136
        top_debtors = DBSession.query(User)\
137
                         .filter(User.balance < -5)\
138
                         .order_by(User.balance)\
139
                         .limit(5).all()
140
    except NoResultFound:
141
        top_debtors = None
142
143
    return {'top_debtors': top_debtors,
144
            'owed_by_users': User.get_amount_owed()}
145
146
# Login routes
147
@view_config(route_name='login',
148
             renderer='templates/public/login.jinja2')
149
@forbidden_view_config(renderer='templates/public/login.jinja2')
150
def login(request):
151
152
    return dict(
153
        login_message = '',
154
        url = '',
155
        came_from = request.params.get('came_from', request.url),
156
        login = '',
157
        password = ''
158
    )
159
160
161
@view_config(route_name='login_submit',
162
             renderer='templates/public/login.jinja2')
163
def login_submit(request):
164
    # Need to set this in case the password is wrong
165
    came_from = request.params.get('came_from', request.url)
166
167
    messages = []
168
169
    # See if this is a valid login attempt
170
    login    = request.params.get('login', '')
171
    password = request.params.get('password', '')
172
    user     = DBSession.query(User).filter(User.uniqname == login).first()
173
    if user and not user.enabled:
174
        messages.append('Login failed. User not allowed to login.')
175
    elif user and user.check_password(password):
176
        # Got a successful login. Now decide where to direct the user.
177
        headers = remember(request, login)
178
179
        if user.role == 'serviceaccount':
180
            # This is the service account for using the terminal.
181
            # Go back to the home page
182
            return HTTPFound(location=request.route_url('index'), headers=headers)
183
184
        else:
185
            # If we got a normal user, check if the login form had
186
            # a "came_from" input which tells us where to go back to.
187
            # Otherwise, default to '/user'.
188
            came_from = request.params.get('came_from', '')
189
190
            # Fetch some strings to compare against
191
            login_url     = request.resource_url(request.context, 'login')
192
            login_sub_url = request.resource_url(request.context, 'login', 'submit')
193
            reset_pw_url  = request.resource_url(request.context, 'login', 'reset_pw')
194
            user_url      = request.resource_url(request.context, 'user')
195
196
            # Make sure we don't send the user back to useless pages
197
            if came_from in ['', login_url, login_sub_url, reset_pw_url]:
198
                came_from = user_url
199
        
200
        return HTTPFound(location=came_from, headers=headers)
201
    else:
202
        messages.append('Login failed. Incorrect username or password.')
203
204
    return dict(
205
        login_message = messages,
206
        url           = request.application_url + '/login',
207
        came_from     = came_from,
208
        login         = login,
209
        password      = password
210
    )
211
212
213
@view_config(route_name='login_reset_pw',
214
             request_method='POST',
215
             renderer='templates/public/login.jinja2')
216
def login_reset_pw(request):
217
    login_url = request.resource_url(request.context, 'login')
218
    login_reset_url = request.resource_url(request.context, 'login_reset_pw')
219
    referrer = request.url
220
    if referrer == login_url or referrer == login_reset_url:
221
        referrer = '/' # never use the login form itself as came_from
222
    came_from = request.params.get('came_from', referrer)
223
224
    succ = '',
225
    err = '',
226
227
    # This will create a user automatically if they do not already exist
228
    try:
229
        with transaction.manager:
230
            user = User.from_umid(request.POST['umid'])
231
        user = DBSession.merge(user)
232
233
        if request.POST['uniqname'] != user.uniqname:
234
            raise __user.InvalidUserException()
235
    except:
236
        err = 'Bad uniqname or umid',
237
    else:
238
        user_password_reset(user)
239
        succ = ('Password set and emailed to {}@umich.edu.'.format(user.uniqname),)
240
241
    return dict(
242
        forgot_error = err,
243
        forgot_success = succ,
244
        url = request.application_url + '/login',
245
        came_from = came_from,
246
    )
247
248
249
@view_config(route_name='logout')
250
def logout(request):
251
    headers = forget(request)
252
    return HTTPFound(location = request.route_url('index'),
253
                     headers  = headers)
254
255