Passed
Push — master ( cda9c3...cb1fed )
by William
01:25
created

app.main.changepw()   B

Complexity

Conditions 6

Size

Total Lines 22
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 19
nop 0
dl 0
loc 22
rs 8.5166
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, Transactions, Email, Hold, Skip
5
from app import db
6
from datetime import datetime
7
import os
8
from sqlalchemy import desc, extract, asc, select
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
12
from .files import export, upload, version
13
14
15
main = Blueprint('main', __name__)
16
17
18
@main.route('/', methods=('GET', 'POST'))
19
@login_required
20
def index():
21
    # get today's date
22
    todaydate = datetime.today().strftime('%A, %B %d, %Y')
23
24
    # query the latest balance information
25
    balance = Balance.query.order_by(desc(Balance.date), desc(Balance.id)).first()
26
27
    refresh=0
28
29
    update_cash(balance, refresh)
30
31
    # plot cash flow results
32
    minbalance, graphJSON = plot_cash()
33
34
    if current_user.admin:
35
        return render_template('index.html', title='Index', todaydate=todaydate, balance=balance.amount,
36
                           minbalance=minbalance, graphJSON=graphJSON)
37
    else:
38
        return render_template('index_guest.html', title='Index', todaydate=todaydate, balance=balance.amount,
39
                           minbalance=minbalance, graphJSON=graphJSON)
40
41
42
@main.route('/refresh')
43
@login_required
44
def refresh():
45
    balance = Balance.query.order_by(desc(Balance.date), desc(Balance.id)).first()
46
    refresh=1
47
48
    update_cash(balance, refresh)
49
50
    return redirect(url_for('main.index'))
51
52
53
@main.route('/profile')
54
@login_required
55
def profile():
56
57
    if current_user.admin:
58
        return render_template('profile.html')
59
    else:
60
        return render_template('profile_guest.html')
61
62
63
@main.route('/settings')
64
@login_required
65
@admin_required
66
def settings():
67
    # get about info
68
    about = version()
69
70
    return render_template('settings.html', about=about)
71
72
73
@main.route('/schedule')
74
@login_required
75
@admin_required
76
def schedule():
77
    schedule = Schedule.query.order_by(asc(extract('day', Schedule.startdate)))
78
79
    return render_template('schedule_table.html', title='Schedule Table', schedule=schedule)
80
81
82
@main.route('/holds')
83
@login_required
84
@admin_required
85
def holds():
86
    hold = Hold.query
87
    skip = Skip.query
88
89
    return render_template('holds_table.html', title='Holds Table', hold=hold, skip=skip)
90
91
92
@main.route('/create', methods=('GET', 'POST'))
93
@login_required
94
@admin_required
95
def create():
96
    # create a new schedule item
97
    format = '%Y-%m-%d'
98
    if request.method == 'POST':
99
        name = request.form['name']
100
        amount = request.form['amount']
101
        frequency = request.form['frequency']
102
        startdate = request.form['startdate']
103
        type = request.form['type']
104
        schedule = Schedule(name=name,
105
                          type=type,
106
                          amount=amount,
107
                          frequency=frequency,
108
                          startdate=datetime.strptime(startdate, format).date())
109
        existing = Schedule.query.filter_by(name=name).first()
110
        if existing:
111
            flash("Schedule already exists")
112
            return redirect(url_for('main.schedule'))
113
        db.session.add(schedule)
114
        db.session.commit()
115
        flash("Added Successfully")
116
117
        return redirect(url_for('main.schedule'))
118
119
    return redirect(url_for('main.schedule'))
120
121
122
@main.route('/update', methods=['GET', 'POST'])
123
@login_required
124
@admin_required
125
def update():
126
    # update an existing schedule item
127
    format = '%Y-%m-%d'
128
129
    if request.method == 'POST':
130
        current = Schedule.query.filter_by(id=request.form['id']).first()
131
        existing = Schedule.query.filter_by(name=request.form['name']).first()
132
        if existing:
133
            if current.name != request.form['name']:
134
                flash("Schedule name already exists")
135
                return redirect(url_for('main.schedule'))
136
        my_data = Schedule.query.get(request.form.get('id'))
137
        my_data.name = request.form['name']
138
        my_data.amount = request.form['amount']
139
        my_data.type = request.form['type']
140
        my_data.frequency = request.form['frequency']
141
        my_data.startdate = request.form['startdate']
142
        startdate = request.form['startdate']
143
        my_data.startdate = datetime.strptime(startdate, format).date()
144
        db.session.commit()
145
        flash("Updated Successfully")
146
147
        return redirect(url_for('main.schedule'))
148
149
    return redirect(url_for('main.schedule'))
150
151
152
@main.route('/addhold/<id>')
153
@login_required
154
@admin_required
155
def addhold(id):
156
    # add a hold item from the schedule
157
    schedule = Schedule.query.filter_by(id=id).first()
158
    hold = Hold(name=schedule.name, type=schedule.type, amount=schedule.amount)
159
    db.session.add(hold)
160
    db.session.commit()
161
    flash("Added Hold")
162
163
    return redirect(url_for('main.schedule'))
164
165
166
@main.route('/addskip/<id>')
167
@login_required
168
@admin_required
169
def addskip(id):
170
    # add a skip item from the schedule
171
    transaction = Transactions.query.filter_by(id=id).first()
172
    trans_type = ""
173
    if transaction.type == "Expense":
174
        trans_type = "Income"
175
    elif transaction.type == "Income":
176
        trans_type = "Expense"
177
    skip = Skip(name=transaction.name + " (SKIP)", type=trans_type, amount=transaction.amount, date=transaction.date)
178
    db.session.add(skip)
179
    db.session.commit()
180
    flash("Added Skip")
181
182
    return redirect(url_for('main.transactions'))
183
184
185
@main.route('/deletehold/<id>')
186
@login_required
187
@admin_required
188
def holds_delete(id):
189
    # delete a hold item
190
    hold = Hold.query.filter_by(id=id).first()
191
192
    if hold:
193
        db.session.delete(hold)
194
        db.session.commit()
195
        flash("Deleted Successfully")
196
197
    return redirect(url_for('main.holds'))
198
199
200
@main.route('/deleteskip/<id>')
201
@login_required
202
@admin_required
203
def skips_delete(id):
204
    # delete a skip item
205
    skip = Skip.query.filter_by(id=id).first()
206
207
    if skip:
208
        db.session.delete(skip)
209
        db.session.commit()
210
        flash("Deleted Successfully")
211
212
    return redirect(url_for('main.holds'))
213
214
215
@main.route('/clearholds')
216
@login_required
217
@admin_required
218
def clear_holds():
219
    # clear holds
220
    db.session.query(Hold).delete()
221
    db.session.commit()
222
223
    return redirect(url_for('main.holds'))
224
225
226
@main.route('/clearskips')
227
@login_required
228
@admin_required
229
def clear_skips():
230
    # clear skips
231
    db.session.query(Skip).delete()
232
    db.session.commit()
233
234
    return redirect(url_for('main.holds'))
235
236
237
@main.route('/delete/<id>')
238
@login_required
239
@admin_required
240
def schedule_delete(id):
241
    # delete a schedule item
242
    schedule = Schedule.query.filter_by(id=id).first()
243
244
    if schedule:
245
        db.session.delete(schedule)
246
        db.session.commit()
247
        flash("Deleted Successfully")
248
249
    return redirect(url_for('main.schedule'))
250
251
252
@main.route('/favicon')
253
def favicon():
254
    return send_from_directory(os.path.join(main.root_path, 'static'),
255
                               'favicon.ico', mimetype='image/vnd.microsoft.icon')
256
257
258
@main.route('/appleicon')
259
def appleicon():
260
    return send_from_directory(os.path.join(main.root_path, 'static'),
261
                               'apple-touch-icon.png', mimetype='image/png')
262
263
264
@main.route('/balance', methods=('GET', 'POST'))
265
@login_required
266
@admin_required
267
def balance():
268
    # manually update the balance from the balance button
269
    format = '%Y-%m-%d'
270
    if request.method == 'POST':
271
        amount = request.form['amount']
272
        dateentry = request.form['date']
273
        balance = Balance(amount=amount,
274
                          date=datetime.strptime(dateentry, format).date())
275
        db.session.add(balance)
276
        db.session.commit()
277
278
        return redirect(url_for('main.index'))
279
280
281
@main.route('/changepw', methods=('GET', 'POST'))
282
@login_required
283
def changepw():
284
    # change the users password from the profile page
285
    if request.method == 'POST':
286
        curr_user = current_user.id
287
        my_user = User.query.filter_by(id=curr_user).first()
288
        current = request.form['current']
289
        password = request.form['password']
290
        password2 = request.form['password2']
291
        if password == password2 and check_password_hash(my_user.password, current):
292
            my_user.password = generate_password_hash(password, method='scrypt')
293
            db.session.commit()
294
            flash('Password change successful')
295
        elif password != password2:
296
            flash('Passwords do not match')
297
        elif not check_password_hash(my_user.password, current):
298
            flash('Incorrect password')
299
300
        return redirect(url_for('main.profile'))
301
302
    return redirect(url_for('main.profile'))
303
304
305
@main.route('/signups', methods=('GET', 'POST'))
306
@login_required
307
@admin_required
308
def signups():
309
    # set the settings options, in this case disable signups, from the profile page
310
    if request.method == 'POST':
311
        signupsettingname = Settings.query.filter_by(name='signup').first()
312
313
        if signupsettingname:
314
            signupvalue = request.form['signupvalue']
315
            signupsettingname.value = eval(signupvalue)
316
            db.session.commit()
317
318
            return redirect(url_for('main.settings'))
319
320
        # store the signup option value in the database to check when the user clicks signup
321
        signupvalue = request.form['signupvalue']
322
        signupvalue = eval(signupvalue)
323
        settings = Settings(name="signup",
324
                          value=signupvalue)
325
        db.session.add(settings)
326
        db.session.commit()
327
328
        return redirect(url_for('main.settings'))
329
330
    return redirect(url_for('main.settings'))
331
332
333
@main.route('/transactions')
334
@login_required
335
@admin_required
336
def transactions():
337
    total = Transactions.query
338
339
    return render_template('transactions_table.html', total=total)
340
341
342
@main.route('/email', methods=('GET', 'POST'))
343
@login_required
344
@admin_required
345
def email():
346
    # set the users email address, password, and server for the auto email balance update
347
    if request.method == 'POST':
348
        emailsettings = Email.query.filter_by(id=1).first()
349
350
        if emailsettings:
351
            email = request.form['email']
352
            password = request.form['password']
353
            server = request.form['server']
354
            subjectstr = request.form['subject_str']
355
            startstr = request.form['start_str']
356
            endstr = request.form['end_str']
357
            emailsettings.email = email
358
            emailsettings.password = password
359
            emailsettings.server = server
360
            emailsettings.subjectstr = subjectstr
361
            emailsettings.startstr = startstr
362
            emailsettings.endstr = endstr
363
            db.session.commit()
364
365
            return redirect(url_for('main.settings'))
366
367
        email = request.form['email']
368
        password = request.form['password']
369
        server = request.form['server']
370
        subjectstr = request.form['subject_str']
371
        startstr = request.form['start_str']
372
        endstr = request.form['end_str']
373
        emailentry = Email(email=email, password=password, server=server, subjectstr=subjectstr, startstr=startstr,
374
                           endstr=endstr)
375
        db.session.add(emailentry)
376
        db.session.commit()
377
378
        return redirect(url_for('main.settings'))
379
380
    return redirect(url_for('main.settings'))
381
382
383
@main.route('/users_table')
384
@login_required
385
@admin_required
386
def users():
387
    users = User.query
388
389
    return render_template('users_table.html', title='Users Table', users=users)
390
391
392
@main.route('/update_user', methods=['GET', 'POST'])
393
@login_required
394
@admin_required
395
def update_user():
396
    # update an existing user
397
    if request.method == 'POST':
398
        current = User.query.filter_by(id=request.form['id']).first()
399
        existing = User.query.filter_by(email=request.form['email']).first()
400
        if existing:
401
            if current.email != request.form['email']:
402
                flash("Email already exists")
403
                return redirect(url_for('main.users'))
404
        my_data = User.query.get(request.form.get('id'))
405
        my_data.name = request.form['name']
406
        my_data.email = request.form['email']
407
        my_data.admin = eval(request.form['admin'])
408
        db.session.commit()
409
        flash("Updated Successfully")
410
411
        return redirect(url_for('main.users'))
412
413
    return redirect(url_for('main.users'))
414
415
416
@main.route('/delete_user/<id>')
417
@login_required
418
@admin_required
419
def delete_user(id):
420
    # delete a user
421
    user = User.query.filter_by(id=id).first()
422
423
    if user:
424
        db.session.delete(user)
425
        db.session.commit()
426
        flash("Deleted Successfully")
427
428
    return redirect(url_for('main.users'))
429
430
431
@main.route('/create_user', methods=('GET', 'POST'))
432
@login_required
433
@admin_required
434
def create_user():
435
    # create a new user
436
    if request.method == 'POST':
437
        name = request.form['name']
438
        email = request.form['email']
439
        admin = eval(request.form['admin'])
440
        password = generate_password_hash(request.form['password'], method='scrypt')
441
        user = User(name=name, email=email, admin=admin, password=password)
442
        existing = User.query.filter_by(email=email).first()
443
        if existing:
444
            flash("User already exists")
445
            return redirect(url_for('main.users'))
446
        db.session.add(user)
447
        db.session.commit()
448
        flash("Added Successfully")
449
450
        return redirect(url_for('main.users'))
451
452
    return redirect(url_for('main.users'))
453
454
455
@main.route('/export', methods=('GET', 'POST'))
456
@login_required
457
@admin_required
458
def export_csv():
459
460
    csv_data = export()
461
462
    # Create a direct download response with the CSV data and appropriate headers
463
    response = Response(csv_data, content_type="text/csv")
464
    response.headers["Content-Disposition"] = "attachment; filename=schedule_export.csv"
465
466
    return response
467
468
469
@main.route('/import', methods=('GET', 'POST'))
470
@login_required
471
@admin_required
472
def import_csv():
473
    if request.method == 'POST':
474
        csv_file = request.files.get('file')
475
476
        upload(csv_file)
477
478
        flash("Import Successful")
479
480
    return redirect(url_for('main.schedule'))
481
482
483
@main.route('/manifest.json')
484
def serve_manifest():
485
    return send_file('manifest.json', mimetype='application/manifest+json')
486
487
488
@main.route('/sw.js')
489
def serve_sw():
490
    return send_file('sw.js', mimetype='application/javascript')
491