Passed
Pull Request — master (#16)
by William
01:31
created

app.main.get_effective_user_id()   A

Complexity

Conditions 2

Size

Total Lines 12
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nop 0
dl 0
loc 12
rs 10
c 0
b 0
f 0
1
from flask import request, redirect, url_for, send_from_directory, flash, send_file, Response
2
from flask_login import login_required, current_user
3
from flask import Blueprint, render_template
4
from .models import Schedule, Balance, User, Settings, Email, Hold, Skip
5
from app import db
6
from datetime import datetime
7
import os
8
from sqlalchemy import desc, extract, asc
9
from werkzeug.security import generate_password_hash, check_password_hash
10
from .cashflow import update_cash, plot_cash
11
from .auth import admin_required, global_admin_required, account_owner_required
12
from .files import export, upload, version
13
14
15
main = Blueprint('main', __name__)
16
17
18
def get_effective_user_id():
19
    """
20
    Get the effective user ID for data filtering.
21
    For guest users, returns their account owner's ID.
22
    For account owners, returns their own ID.
23
    """
24
    if current_user.account_owner_id:
25
        # Guest user - return account owner's ID
26
        return current_user.account_owner_id
27
    else:
28
        # Account owner or standalone user - return their own ID
29
        return current_user.id
30
31
32
@main.route('/', methods=('GET', 'POST'))
33
@login_required
34
def index():
35
    # Get effective user ID (account owner for guests, self for owners)
36
    user_id = get_effective_user_id()
37
38
    # get today's date
39
    todaydate = datetime.today().strftime('%A, %B %d, %Y')
40
41
    # query the latest balance information for this user
42
    balance = Balance.query.filter_by(user_id=user_id).order_by(desc(Balance.date), desc(Balance.id)).first()
43
44
    try:
45
        float(balance.amount)
46
        db.session.query(Balance).filter_by(user_id=user_id).delete()
47
        balance = Balance(amount=balance.amount, date=datetime.today(), user_id=user_id)
48
        db.session.add(balance)
49
        db.session.commit()
50
    except:
51
        balance = Balance(amount='0', date=datetime.today(), user_id=user_id)
52
        db.session.add(balance)
53
        db.session.commit()
54
55
    # Pre-filter data by user before passing to cashflow
56
    schedules = Schedule.query.filter_by(user_id=user_id).all()
57
    holds = Hold.query.filter_by(user_id=user_id).all()
58
    skips = Skip.query.filter_by(user_id=user_id).all()
59
60
    trans, run = update_cash(float(balance.amount), schedules, holds, skips)
61
62
    # plot cash flow results
63
    minbalance, graphJSON = plot_cash(run)
64
65
    if current_user.admin:
66
        return render_template('index.html', title='Index', todaydate=todaydate, balance=balance.amount,
67
                           minbalance=minbalance, graphJSON=graphJSON)
68
    else:
69
        return render_template('index_guest.html', title='Index', todaydate=todaydate, balance=balance.amount,
70
                           minbalance=minbalance, graphJSON=graphJSON)
71
72
73
@main.route('/refresh')
74
@login_required
75
def refresh():
76
77
    return redirect(url_for('main.index'))
78
79
80
@main.route('/settings')
81
@login_required
82
def settings():
83
    # get about info - available to all users
84
    about = version()
85
86
    return render_template('settings.html', about=about)
87
88
89
@main.route('/schedule')
90
@login_required
91
@admin_required
92
def schedule():
93
    user_id = get_effective_user_id()
94
    schedule = Schedule.query.filter_by(user_id=user_id).order_by(asc(extract('day', Schedule.startdate)))
95
96
    return render_template('schedule_table.html', title='Schedule Table', schedule=schedule)
97
98
99
@main.route('/holds')
100
@login_required
101
@admin_required
102
def holds():
103
    user_id = get_effective_user_id()
104
    hold = Hold.query.filter_by(user_id=user_id)
105
    skip = Skip.query.filter_by(user_id=user_id)
106
107
    return render_template('holds_table.html', title='Holds Table', hold=hold, skip=skip)
108
109
110
@main.route('/create', methods=('GET', 'POST'))
111
@login_required
112
@admin_required
113
def create():
114
    # create a new schedule item
115
    user_id = get_effective_user_id()
116
    format = '%Y-%m-%d'
117
    if request.method == 'POST':
118
        name = request.form['name']
119
        amount = request.form['amount']
120
        frequency = request.form['frequency']
121
        startdate = request.form['startdate']
122
        type = request.form['type']
123
        schedule = Schedule(name=name,
124
                            type=type,
125
                            amount=amount,
126
                            frequency=frequency,
127
                            startdate=datetime.strptime(startdate, format).date(),
128
                            firstdate=datetime.strptime(startdate, format).date(),
129
                            user_id=user_id)
130
        existing = Schedule.query.filter_by(name=name, user_id=user_id).first()
131
        if existing:
132
            flash("Schedule already exists")
133
            return redirect(url_for('main.schedule'))
134
        db.session.add(schedule)
135
        db.session.commit()
136
        flash("Added Successfully")
137
138
        return redirect(url_for('main.schedule'))
139
140
    return redirect(url_for('main.schedule'))
141
142
143
@main.route('/update', methods=['GET', 'POST'])
144
@login_required
145
@admin_required
146
def update():
147
    # update an existing schedule item
148
    user_id = get_effective_user_id()
149
    format = '%Y-%m-%d'
150
151
    if request.method == 'POST':
152
        current = Schedule.query.filter_by(id=int(request.form['id']), user_id=user_id).first()
153
        existing = Schedule.query.filter_by(name=request.form['name'], user_id=user_id).first()
154
        if existing:
155
            if current.name != request.form['name']:
156
                flash("Schedule name already exists")
157
                return redirect(url_for('main.schedule'))
158
        my_data = Schedule.query.filter_by(id=int(request.form.get('id')), user_id=user_id).first()
159
        my_data.name = request.form['name']
160
        my_data.amount = request.form['amount']
161
        my_data.type = request.form['type']
162
        my_data.frequency = request.form['frequency']
163
        startdate = request.form['startdate']
164
        if (datetime.strptime(startdate, format).date() != my_data.startdate and my_data.startdate.day !=
165
                datetime.strptime(startdate, format).day):
166
            my_data.firstdate = datetime.strptime(startdate, format).date()
167
        my_data.startdate = datetime.strptime(startdate, format).date()
168
        db.session.commit()
169
        flash("Updated Successfully")
170
171
        return redirect(url_for('main.schedule'))
172
173
    return redirect(url_for('main.schedule'))
174
175
176
@main.route('/addhold/<id>')
177
@login_required
178
@admin_required
179
def addhold(id):
180
    # add a hold item from the schedule
181
    user_id = get_effective_user_id()
182
    schedule = Schedule.query.filter_by(id=int(id), user_id=user_id).first()
183
    hold = Hold(name=schedule.name, type=schedule.type, amount=schedule.amount, user_id=user_id)
184
    db.session.add(hold)
185
    db.session.commit()
186
    flash("Added Hold")
187
188
    return redirect(url_for('main.schedule'))
189
190
191
@main.route('/addskip/<id>')
192
@login_required
193
@admin_required
194
def addskip(id):
195
    # add a skip item from the schedule
196
    user_id = get_effective_user_id()
197
    balance = Balance.query.filter_by(user_id=user_id).order_by(desc(Balance.date), desc(Balance.id)).first()
198
199
    # Pre-filter data by user
200
    schedules = Schedule.query.filter_by(user_id=user_id).all()
201
    holds = Hold.query.filter_by(user_id=user_id).all()
202
    skips = Skip.query.filter_by(user_id=user_id).all()
203
204
    trans, run = update_cash(float(balance.amount), schedules, holds, skips)
205
    transaction = trans.loc[int(id)]
206
    trans_type = ""
207
    if transaction[1] == "Expense":
208
        trans_type = "Income"
209
    elif transaction[1] == "Income":
210
        trans_type = "Expense"
211
    skip = Skip(name=transaction[0] + " (SKIP)", type=trans_type, amount=transaction[2], date=transaction[3], user_id=user_id)
212
    db.session.add(skip)
213
    db.session.commit()
214
    flash("Added Skip")
215
216
    return redirect(url_for('main.transactions'))
217
218
219
@main.route('/deletehold/<id>')
220
@login_required
221
@admin_required
222
def holds_delete(id):
223
    # delete a hold item
224
    user_id = get_effective_user_id()
225
    hold = Hold.query.filter_by(id=int(id), user_id=user_id).first()
226
227
    if hold:
228
        db.session.delete(hold)
229
        db.session.commit()
230
        flash("Deleted Successfully")
231
232
    return redirect(url_for('main.holds'))
233
234
235
@main.route('/deleteskip/<id>')
236
@login_required
237
@admin_required
238
def skips_delete(id):
239
    # delete a skip item
240
    user_id = get_effective_user_id()
241
    skip = Skip.query.filter_by(id=int(id), user_id=user_id).first()
242
243
    if skip:
244
        db.session.delete(skip)
245
        db.session.commit()
246
        flash("Deleted Successfully")
247
248
    return redirect(url_for('main.holds'))
249
250
251
@main.route('/clearholds')
252
@login_required
253
@admin_required
254
def clear_holds():
255
    # clear holds
256
    user_id = get_effective_user_id()
257
    db.session.query(Hold).filter_by(user_id=user_id).delete()
258
    db.session.commit()
259
260
    return redirect(url_for('main.holds'))
261
262
263
@main.route('/clearskips')
264
@login_required
265
@admin_required
266
def clear_skips():
267
    # clear skips
268
    user_id = get_effective_user_id()
269
    db.session.query(Skip).filter_by(user_id=user_id).delete()
270
    db.session.commit()
271
272
    return redirect(url_for('main.holds'))
273
274
275
@main.route('/delete/<id>')
276
@login_required
277
@admin_required
278
def schedule_delete(id):
279
    # delete a schedule item
280
    user_id = get_effective_user_id()
281
    schedule = Schedule.query.filter_by(id=int(id), user_id=user_id).first()
282
283
    if schedule:
284
        db.session.delete(schedule)
285
        db.session.commit()
286
        flash("Deleted Successfully")
287
288
    return redirect(url_for('main.schedule'))
289
290
291
@main.route('/favicon')
292
def favicon():
293
    return send_from_directory(os.path.join(main.root_path, 'static'),
294
                               'favicon.ico', mimetype='image/vnd.microsoft.icon')
295
296
297
@main.route('/appleicon')
298
def appleicon():
299
    return send_from_directory(os.path.join(main.root_path, 'static'),
300
                               'apple-touch-icon.png', mimetype='image/png')
301
302
303
@main.route('/balance', methods=('GET', 'POST'))
304
@login_required
305
@admin_required
306
def balance():
307
    # manually update the balance from the balance button
308
    user_id = get_effective_user_id()
309
    format = '%Y-%m-%d'
310
    if request.method == 'POST':
311
        amount = request.form['amount']
312
        dateentry = request.form['date']
313
        balance = Balance(amount=amount,
314
                          date=datetime.strptime(dateentry, format).date(),
315
                          user_id=user_id)
316
        db.session.add(balance)
317
        db.session.commit()
318
319
        return redirect(url_for('main.index'))
320
321
322
@main.route('/changepw', methods=('GET', 'POST'))
323
@login_required
324
def changepw():
325
    # change the users password from the settings page
326
    if request.method == 'POST':
327
        curr_user = current_user.id
328
        my_user = User.query.filter_by(id=curr_user).first()
329
        current = request.form['current']
330
        password = request.form['password']
331
        password2 = request.form['password2']
332
        if password == password2 and check_password_hash(my_user.password, current):
333
            my_user.password = generate_password_hash(password, method='scrypt')
334
            db.session.commit()
335
            flash('Password change successful')
336
        elif password != password2:
337
            flash('Passwords do not match')
338
        elif not check_password_hash(my_user.password, current):
339
            flash('Incorrect password')
340
341
        return redirect(url_for('main.settings'))
342
343
    return redirect(url_for('main.settings'))
344
345
346
@main.route('/signups', methods=('GET', 'POST'))
347
@login_required
348
@global_admin_required
349
def signups():
350
    # set the settings options, in this case disable signups, from the profile page
351
    if request.method == 'POST':
352
        signupsettingname = Settings.query.filter_by(name='signup').first()
353
354
        if signupsettingname:
355
            if request.form['signupvalue'] == "True":
356
                signupvalue = True
357
            else:
358
                signupvalue = False
359
            signupsettingname.value = signupvalue
360
            db.session.commit()
361
362
            return redirect(url_for('main.settings'))
363
364
        # store the signup option value in the database to check when the user clicks signup
365
        if request.form['signupvalue'] == "True":
366
            signupvalue = True
367
        else:
368
            signupvalue = False
369
        settings = Settings(name="signup", value=signupvalue)
370
        db.session.add(settings)
371
        db.session.commit()
372
373
        return redirect(url_for('main.settings'))
374
375
    return redirect(url_for('main.settings'))
376
377
378
@main.route('/transactions')
379
@login_required
380
@admin_required
381
def transactions():
382
    user_id = get_effective_user_id()
383
    balance = Balance.query.filter_by(user_id=user_id).order_by(desc(Balance.date), desc(Balance.id)).first()
384
385
    # Pre-filter data by user
386
    schedules = Schedule.query.filter_by(user_id=user_id).all()
387
    holds = Hold.query.filter_by(user_id=user_id).all()
388
    skips = Skip.query.filter_by(user_id=user_id).all()
389
390
    trans, run = update_cash(float(balance.amount), schedules, holds, skips)
391
392
    return render_template('transactions_table.html', total=trans.to_dict(orient='records'))
393
394
395
@main.route('/email', methods=('GET', 'POST'))
396
@login_required
397
@admin_required
398
def email():
399
    # set the users email address, password, and server for the auto email balance update
400
    user_id = get_effective_user_id()
401
402
    if request.method == 'POST':
403
        emailsettings = Email.query.filter_by(user_id=user_id).first()
404
405
        if emailsettings:
406
            email = request.form['email']
407
            password = request.form['password']
408
            server = request.form['server']
409
            subjectstr = request.form['subject_str']
410
            startstr = request.form['start_str']
411
            endstr = request.form['end_str']
412
            emailsettings.email = email
413
            emailsettings.password = password
414
            emailsettings.server = server
415
            emailsettings.subjectstr = subjectstr
416
            emailsettings.startstr = startstr
417
            emailsettings.endstr = endstr
418
            db.session.commit()
419
420
            return redirect(url_for('main.settings'))
421
422
        email = request.form['email']
423
        password = request.form['password']
424
        server = request.form['server']
425
        subjectstr = request.form['subject_str']
426
        startstr = request.form['start_str']
427
        endstr = request.form['end_str']
428
        emailentry = Email(email=email, password=password, server=server, subjectstr=subjectstr, startstr=startstr,
429
                           endstr=endstr, user_id=user_id)
430
        db.session.add(emailentry)
431
        db.session.commit()
432
433
        return redirect(url_for('main.settings'))
434
435
    return redirect(url_for('main.settings'))
436
437
438
@main.route('/update_user', methods=['GET', 'POST'])
439
@login_required
440
@admin_required
441
def update_user():
442
    # update an existing user
443
    if request.method == 'POST':
444
        current = User.query.filter_by(id=int(request.form['id'])).first()
445
446
        # Check if the current user has permission to update this user
447
        if not current_user.is_global_admin and current.account_owner_id != current_user.id:
448
            flash("You don't have permission to update this user")
449
            if current_user.is_global_admin:
450
                return redirect(url_for('main.global_admin_panel'))
451
            else:
452
                return redirect(url_for('main.manage_guests'))
453
454
        existing = User.query.filter_by(email=request.form['email']).first()
455
        if existing:
456
            if current.email != request.form['email']:
457
                flash("Email already exists")
458
                if current_user.is_global_admin:
459
                    return redirect(url_for('main.global_admin_panel'))
460
                else:
461
                    return redirect(url_for('main.manage_guests'))
462
        my_data = User.query.get(request.form.get('id'))
463
        my_data.name = request.form['name']
464
        my_data.email = request.form['email']
465
466
        # Global admins can change roles, regular admins cannot
467
        if current_user.is_global_admin:
468
            # Handle role assignment
469
            role = request.form.get('role', 'user')
470
            if role == 'global_admin':
471
                my_data.admin = True
472
                my_data.is_global_admin = True
473
                # IMPORTANT: Global admins must always be active
474
                my_data.is_active = True
475
            elif role == 'admin':
476
                my_data.admin = True
477
                my_data.is_global_admin = False
478
            else:  # user
479
                my_data.admin = False
480
                my_data.is_global_admin = False
481
482
        db.session.commit()
483
        flash("Updated Successfully")
484
485
        # Redirect based on user role
486
        if current_user.is_global_admin:
487
            return redirect(url_for('main.global_admin_panel'))
488
        else:
489
            return redirect(url_for('main.manage_guests'))
490
491
    # Redirect based on user role
492
    if current_user.is_global_admin:
493
        return redirect(url_for('main.global_admin_panel'))
494
    else:
495
        return redirect(url_for('main.manage_guests'))
496
497
498 View Code Duplication
@main.route('/delete_user/<id>')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
499
@login_required
500
@admin_required
501
def delete_user(id):
502
    # delete a user
503
    user = User.query.filter_by(id=int(id)).first()
504
505
    if user:
506
        # Global admins can delete any user (except themselves), regular admins can only delete their guests
507
        if current_user.is_global_admin or user.account_owner_id == current_user.id:
508
            # Prevent deleting yourself
509
            if user.id == current_user.id:
510
                flash("You cannot delete your own account")
511
                if current_user.is_global_admin:
512
                    return redirect(url_for('main.global_admin_panel'))
513
                else:
514
                    return redirect(url_for('main.manage_guests'))
515
516
            db.session.delete(user)
517
            db.session.commit()
518
            flash("Deleted Successfully")
519
        else:
520
            flash("You don't have permission to delete this user")
521
522
    # Redirect based on user role
523
    if current_user.is_global_admin:
524
        return redirect(url_for('main.global_admin_panel'))
525
    else:
526
        return redirect(url_for('main.manage_guests'))
527
528
529
@main.route('/activate_user/<id>')
530
@login_required
531
@admin_required
532
def activate_user(id):
533
    # activate a user account
534
    user = User.query.filter_by(id=int(id)).first()
535
536
    if user:
537
        # Global admins can activate any user, regular admins can only activate their guests
538
        if current_user.is_global_admin or user.account_owner_id == current_user.id:
539
            user.is_active = True
540
            db.session.commit()
541
            flash(f"User {user.name} has been activated successfully")
542
        else:
543
            flash("You don't have permission to activate this user")
544
545
    # Redirect based on user role
546
    if current_user.is_global_admin:
547
        return redirect(url_for('main.global_admin_panel'))
548
    else:
549
        return redirect(url_for('main.manage_guests'))
550
551
552 View Code Duplication
@main.route('/deactivate_user/<id>')
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
553
@login_required
554
@admin_required
555
def deactivate_user(id):
556
    # deactivate a user account
557
    user = User.query.filter_by(id=int(id)).first()
558
559
    if user:
560
        # IMPORTANT: Global admins are always active and cannot be deactivated
561
        if user.is_global_admin:
562
            flash("Cannot deactivate a global admin. Global admins must always remain active.")
563
            if current_user.is_global_admin:
564
                return redirect(url_for('main.global_admin_panel'))
565
            else:
566
                return redirect(url_for('main.manage_guests'))
567
568
        # Global admins can deactivate any user, regular admins can only deactivate their guests
569
        if current_user.is_global_admin or user.account_owner_id == current_user.id:
570
            user.is_active = False
571
            db.session.commit()
572
            flash(f"User {user.name} has been deactivated successfully")
573
        else:
574
            flash("You don't have permission to deactivate this user")
575
576
    # Redirect based on user role
577
    if current_user.is_global_admin:
578
        return redirect(url_for('main.global_admin_panel'))
579
    else:
580
        return redirect(url_for('main.manage_guests'))
581
582
583
@main.route('/create_user', methods=('GET', 'POST'))
584
@login_required
585
@admin_required
586
def create_user():
587
    # create a new user
588
    if request.method == 'POST':
589
        name = request.form['name']
590
        email = request.form['email']
591
        password = generate_password_hash(request.form['password'], method='scrypt')
592
593
        # Handle role assignment
594
        role = request.form.get('role', 'user')
595
596
        # Global admins can create any type of user
597
        if current_user.is_global_admin:
598
            if role == 'global_admin':
599
                admin = True
600
                is_global_admin = True
601
            elif role == 'admin':
602
                admin = True
603
                is_global_admin = False
604
            else:  # user
605
                admin = False
606
                is_global_admin = False
607
            account_owner_id = None
608
            # Users created by global admin are active by default
609
            is_active = True
610
        else:
611
            # Regular admins can only create guest users (non-admin users)
612
            admin = False
613
            is_global_admin = False
614
            account_owner_id = current_user.id
615
            # Guests created by regular admins are active by default
616
            is_active = True
617
618
        user = User(name=name, email=email, admin=admin, is_global_admin=is_global_admin,
619
                    is_active=is_active, password=password, account_owner_id=account_owner_id)
620
        existing = User.query.filter_by(email=email).first()
621
        if existing:
622
            flash("User already exists")
623
            if current_user.is_global_admin:
624
                return redirect(url_for('main.global_admin_panel'))
625
            else:
626
                return redirect(url_for('main.manage_guests'))
627
        db.session.add(user)
628
        db.session.commit()
629
        flash("Added Successfully")
630
631
        # Redirect based on user role
632
        if current_user.is_global_admin:
633
            return redirect(url_for('main.global_admin_panel'))
634
        else:
635
            return redirect(url_for('main.manage_guests'))
636
637
    # Redirect based on user role
638
    if current_user.is_global_admin:
639
        return redirect(url_for('main.global_admin_panel'))
640
    else:
641
        return redirect(url_for('main.manage_guests'))
642
643
644
@main.route('/export', methods=('GET', 'POST'))
645
@login_required
646
@admin_required
647
def export_csv():
648
    user_id = get_effective_user_id()
649
650
    csv_data = export(user_id)
651
652
    # Create a direct download response with the CSV data and appropriate headers
653
    response = Response(csv_data, content_type="text/csv")
654
    response.headers["Content-Disposition"] = "attachment; filename=schedule_export.csv"
655
656
    return response
657
658
659
@main.route('/import', methods=('GET', 'POST'))
660
@login_required
661
@admin_required
662
def import_csv():
663
    if request.method == 'POST':
664
        user_id = get_effective_user_id()
665
        csv_file = request.files.get('file')
666
667
        upload(csv_file, user_id)
668
669
        flash("Import Successful")
670
671
    return redirect(url_for('main.schedule'))
672
673
674
@main.route('/manage_guests')
675
@login_required
676
@account_owner_required
677
def manage_guests():
678
    """Account owners can manage their guest users"""
679
    guests = User.query.filter_by(account_owner_id=current_user.id).all()
680
    return render_template('manage_guests.html', guests=guests)
681
682
683
@main.route('/add_guest', methods=['POST'])
684
@login_required
685
@account_owner_required
686
def add_guest():
687
    """Create a guest user linked to current account owner"""
688
    email = request.form.get('email')
689
    name = request.form.get('name')
690
691
    # Check if user already exists
692
    existing_user = User.query.filter_by(email=email).first()
693
    if existing_user:
694
        flash('A user with this email already exists')
695
        return redirect(url_for('main.manage_guests'))
696
697
    # Generate a random password for guest (they can change it later)
698
    import secrets
699
    temp_password = secrets.token_urlsafe(16)
700
701
    new_guest = User(
702
        email=email,
703
        name=name,
704
        password=generate_password_hash(temp_password, method='scrypt'),
705
        admin=False,  # Guests are not admins
706
        is_global_admin=False,
707
        account_owner_id=current_user.id
708
    )
709
    db.session.add(new_guest)
710
    db.session.commit()
711
712
    flash(f'Guest user {name} added successfully. Temporary password: {temp_password}')
713
    return redirect(url_for('main.manage_guests'))
714
715
716
@main.route('/remove_guest/<int:guest_id>', methods=['POST'])
717
@login_required
718
@account_owner_required
719
def remove_guest(guest_id):
720
    """Remove a guest user (account owner only)"""
721
    guest = User.query.filter_by(id=int(guest_id), account_owner_id=current_user.id).first()
722
723
    if guest:
724
        db.session.delete(guest)
725
        db.session.commit()
726
        flash('Guest user removed successfully')
727
    else:
728
        flash('Guest user not found or you do not have permission to remove them')
729
730
    return redirect(url_for('main.manage_guests'))
731
732
733
@main.route('/global_admin')
734
@login_required
735
@global_admin_required
736
def global_admin_panel():
737
    """Global admin can see all users and accounts"""
738
    all_users = User.query.all()
739
740
    # Organize users by account owners
741
    account_owners = [u for u in all_users if u.account_owner_id is None and not u.is_global_admin]
742
    global_admins = [u for u in all_users if u.is_global_admin]
743
    standalone_users = [u for u in all_users if u.account_owner_id is None and not u.admin]
744
745
    return render_template('global_admin.html',
746
                         all_users=all_users,
747
                         account_owners=account_owners,
748
                         global_admins=global_admins,
749
                         standalone_users=standalone_users)
750
751
752
@main.route('/manifest.json')
753
def serve_manifest():
754
    return send_file('manifest.json', mimetype='application/manifest+json')
755
756
757
@main.route('/sw.js')
758
def serve_sw():
759
    return send_file('sw.js', mimetype='application/javascript')
760