Completed
Push — master ( d337ae...93075a )
by Pat
57s
created

chezbetty.index_terminal()   A

Complexity

Conditions 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 5
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
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
def _index_terminal(request):
100
    announcements = Announcement.all_enabled()
101
102
    try:
103
        top_debtors = DBSession.query(User)\
104
                         .filter(User.balance < -5)\
105
                         .order_by(User.balance)\
106
                         .limit(5).all()
107
    except NoResultFound:
108
        top_debtors = None
109
110
    # For the demo mode
111
    if 'demo' in request.cookies and request.cookies['demo'] == '1':
112
        admins = User.get_admins()
113
    else:
114
        admins = []
115
116
    shame_users = User.get_shame_users()
117
118
    return {'announcements': announcements,
119
            'admins': admins,
120
            'top_debtors': top_debtors,
121
            'owed_by_users': User.get_amount_owed(),
122
            'shame_users': shame_users}
123
124
125
# Terminal home page
126
@view_config(route_name='index',
127
             renderer='templates/terminal/index.jinja2',
128
             custom_predicates=(IsTerminalPredicate(True),))
129
def index_terminal(request):
130
    return _index_terminal(request)
131
132
133
# Convenience route for checking in on things
134
@view_config(route_name='terminal_force_index',
135
             renderer='templates/terminal/index.jinja2')
136
def terminal_force_index(request):
137
    return _index_terminal(request)
138
139
140
# General internet homepage
141
@view_config(route_name='index',
142
             renderer='templates/public/index.jinja2',
143
             custom_predicates=(IsTerminalPredicate(False),))
144
def index(request):
145
146
    try:
147
        top_debtors = DBSession.query(User)\
148
                         .filter(User.balance < -5)\
149
                         .order_by(User.balance)\
150
                         .limit(5).all()
151
    except NoResultFound:
152
        top_debtors = None
153
154
    return {'top_debtors': top_debtors,
155
            'owed_by_users': User.get_amount_owed()}
156
157
# Login routes
158
@view_config(route_name='login',
159
             renderer='templates/public/login.jinja2')
160
@forbidden_view_config(renderer='templates/public/login.jinja2')
161
def login(request):
162
163
    return dict(
164
        login_message = '',
165
        url = '',
166
        came_from = request.params.get('came_from', request.url),
167
        login = '',
168
        password = ''
169
    )
170
171
172
@view_config(route_name='login_submit',
173
             renderer='templates/public/login.jinja2')
174
def login_submit(request):
175
    # Need to set this in case the password is wrong
176
    came_from = request.params.get('came_from', request.url)
177
178
    messages = []
179
180
    # See if this is a valid login attempt
181
    login    = request.params.get('login', '')
182
    password = request.params.get('password', '')
183
    user     = DBSession.query(User).filter(User.uniqname == login).first()
184
    if user and not user.enabled:
185
        messages.append('Login failed. User not allowed to login.')
186
    elif user and user.check_password(password):
187
        # Got a successful login. Now decide where to direct the user.
188
        headers = remember(request, login)
189
190
        if user.role == 'serviceaccount':
191
            # This is the service account for using the terminal.
192
            # Go back to the home page
193
            return HTTPFound(location=request.route_url('index'), headers=headers)
194
195
        else:
196
            # If we got a normal user, check if the login form had
197
            # a "came_from" input which tells us where to go back to.
198
            # Otherwise, default to '/user'.
199
            came_from = request.params.get('came_from', '')
200
201
            # Fetch some strings to compare against
202
            login_url     = request.resource_url(request.context, 'login')
203
            login_sub_url = request.resource_url(request.context, 'login', 'submit')
204
            reset_pw_url  = request.resource_url(request.context, 'login', 'reset_pw')
205
            user_url      = request.resource_url(request.context, 'user')
206
207
            # Make sure we don't send the user back to useless pages
208
            if came_from in ['', login_url, login_sub_url, reset_pw_url]:
209
                came_from = user_url
210
        
211
        return HTTPFound(location=came_from, headers=headers)
212
    else:
213
        messages.append('Login failed. Incorrect username or password.')
214
215
    return dict(
216
        login_message = messages,
217
        url           = request.application_url + '/login',
218
        came_from     = came_from,
219
        login         = login,
220
        password      = password
221
    )
222
223
224
@view_config(route_name='login_reset_pw',
225
             request_method='POST',
226
             renderer='templates/public/login.jinja2')
227
def login_reset_pw(request):
228
    login_url = request.resource_url(request.context, 'login')
229
    login_reset_url = request.resource_url(request.context, 'login_reset_pw')
230
    referrer = request.url
231
    if referrer == login_url or referrer == login_reset_url:
232
        referrer = '/' # never use the login form itself as came_from
233
    came_from = request.params.get('came_from', referrer)
234
235
    succ = '',
236
    err = '',
237
238
    # This will create a user automatically if they do not already exist
239
    try:
240
        with transaction.manager:
241
            user = User.from_umid(request.POST['umid'])
242
        user = DBSession.merge(user)
243
244
        if request.POST['uniqname'] != user.uniqname:
245
            raise __user.InvalidUserException()
246
    except:
247
        err = 'Bad uniqname or umid',
248
    else:
249
        user_password_reset(user)
250
        succ = ('Password set and emailed to {}@umich.edu.'.format(user.uniqname),)
251
252
    return dict(
253
        forgot_error = err,
254
        forgot_success = succ,
255
        url = request.application_url + '/login',
256
        came_from = came_from,
257
    )
258
259
260
@view_config(route_name='logout')
261
def logout(request):
262
    headers = forget(request)
263
    return HTTPFound(location = request.route_url('index'),
264
                     headers  = headers)
265
266