stc

a simple time card webapp
git clone _git@git.brennen.work:stc.git
Log | Files | Refs | README

commit d946e91c1a818946d024d8e0dfee21e7bd7590a1
parent f37ec5bf5dec8be69178c924e5dde5c936392dae
Author: Youth Employment Program Production <youthemployment22@gmail.com>
Date:   Fri,  3 May 2024 11:47:41 -0600

bugfix: disallow inactive users from signing in. Add user password reset for admin/users/active route

Diffstat:
MTODO.md | 2+-
Mapp/routes.py | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mapp/templates/admin/users/active.html | 1+
3 files changed, 73 insertions(+), 22 deletions(-)

diff --git a/TODO.md b/TODO.md @@ -43,7 +43,7 @@ ## OPTIONAL - [ ] rework admin page flow to show agency for projects?... wanted to sort and display by agency, but is many to one relationship... - +- [ ] When users are set to inactive or active (probably just inactive) should remove all current/existing sessions #TODO TODAY!!! - [X] Change username to firstname lastname for today - [X] change all match from feb 1 to today for nolan to tnc management diff --git a/app/routes.py b/app/routes.py @@ -26,6 +26,23 @@ mongo = PyMongo(app) login_manager = LoginManager(app) login_manager.login_view = 'login' +class UserNotFoundError(Exception): + pass + +def fetch_user(user_id): + user = mongo.db.user_collection.find_one({"_id":ObjectId(user_id)}) + if user == None: + raise UserNotFoundError(f"User id {user_id} returned none") + else: + return user + +def fetch_user_from_username(username): + user = mongo.db.user_collection.find_one({"username":username}) + if user == None: + raise UserNotFoundError(f"User name {username} returned none") + else: + return user + def get_available_projects(branch=None): availableProjects = [("","Select Project")] for project in mongo.db.projects_collection.find(): @@ -125,19 +142,24 @@ def login(): form = LoginForm() if form.validate_on_submit(): # check form value for identity in db, if found AND form password matches stored hash, create User object - u = mongo.db.user_collection.find_one({"username": form.username.data}) - if u and User.check_password(u, form.password.data): - user_obj = User(fname=u['fname'],mname=u['mname'],lname=u['lname'],email=u['email'],branch=u['branch'],address=u['address'],birthday=u['birthday'],role=u['role'],phonenumber=u['phonenumber']) - #login with new user object - login_user(user_obj) - # check next redirect to stop cross-site-redirects, another example here : http://flask.pocoo.org/snippets/62/ - next = request.args.get('next') - if not next or url_parse(next).netloc != '': - next = url_for('dashboard') - return redirect(next) - else: + try: + u = fetch_user_from_username(form.username.data) + except: flash("Invalid username or password") return redirect(url_for('login')) + else: + if u['is_active'] and User.check_password(u, form.password.data): + user_obj = User(fname=u['fname'],mname=u['mname'],lname=u['lname'],email=u['email'],branch=u['branch'],address=u['address'],birthday=u['birthday'],role=u['role'],phonenumber=u['phonenumber']) + #login with new user object + login_user(user_obj) + # check next redirect to stop cross-site-redirects, another example here : http://flask.pocoo.org/snippets/62/ + next = request.args.get('next') + if not next or url_parse(next).netloc != '': + next = url_for('dashboard') + return redirect(next) + else: + flash("Invalid username or password") + return redirect(url_for('login')) return render_template('login.html',form=form,ORGNAME = OrganizationName) #### #### @@ -164,6 +186,24 @@ def chgpass(): return redirect(url_for('dashboard')) return render_template('admin/users/newpass.html',form=form,ORGNAME=OrganizationName) + + +@app.route('/newpass/<uid>',methods=['GET','POST']) +@login_required +def chgpass_by_uid(uid): + try: + user = fetch_user(uid) + except: + return "User not Found" + else: + form = ChangePasswordForm() + if form.validate_on_submit(): + mongo.db.user_collection.update_one({'username':user['username']},{'$set':{'password_hash':generate_password_hash(form.newpass.data)}}) + flash("Changed password for {} to {}".format(user['username'],form.newpass.data)) #Will need to sendmail password to form.email.data later + + return redirect(url_for('dashboard')) + + return render_template('admin/users/newpass.html',form=form,ORGNAME=OrganizationName) #### #### ####### Dashboard Route ####### #### #### @@ -186,7 +226,7 @@ def dashboard(): clocked_in_users = mongo.db.time_collection.find({'clock_out': {'$exists':False}}) def clock_user_out(time_id,notes='',lunch=False,perdiem=False): - if notes != '': + if notes != '' and notes != None: if mongo.db.time_collection.find({'_id': time_id}, {'clock_out':{'$exists':False}}): if lunch==True and perdiem==True: mongo.db.time_collection.update_one({'_id':time_id},{'$set':{'clock_out':[datetime.datetime.now()],'note':notes,'lunch':True,'per_diem':True}}) @@ -473,15 +513,25 @@ def updateNote(mod_username,timeid): except: flash("Issue finding/assigning time_id: {}".format(timeid)) else: - newNoted = form.note.data - try: - mongo.db.time_collection.update_one({'_id':timeid},{'$set':{'note':newNoted},'$push':{'modified_by':mod_username}}) - except: - flash("{}: Unable to set note to {}".format(mod_username,newNoted)) + if form.note.data != None and form.note.data != '': + newNoted = form.note.data + try: + mongo.db.time_collection.update_one({'_id':timeid},{'$set':{'note':newNoted},'$push':{'modified_by':mod_username}}) + except: + flash("{}: Unable to set note to {}".format(mod_username,newNoted)) + else: + flash('Updated note') + finally: + return redirect(url_for('dashboard'))#TODO RETURN LAST PAGE HERE! else: - flash('Updated note') - finally: - return redirect(url_for('dashboard'))#TODO RETURN LAST PAGE HERE! + try: + mongo.db.time_collection.update_one({'_id':timeid},{'$unset':{"note":""},'$push':{'modified_by':mod_username}}) + except: + flash("Unable to remove note") + else: + flash('Removed note') + finally: + return redirect(url_for('dashboard')) return render_template('dashboard/punchclock/update/note.html',form=form, ORGNAME=OrganizationName) @@ -656,7 +706,7 @@ def new_user_time(): entryevent['modified_by'] = [form.userSel.data] else: entryevent['modified_by'] = [form.userSel.data,current_user.username] - if form.note.data != '': + if form.note.data != '' and form.note.data != None: entryevent['note'] = form.note.data mongo.db.time_collection.insert_one(entryevent) diff --git a/app/templates/admin/users/active.html b/app/templates/admin/users/active.html @@ -8,6 +8,7 @@ <div class="usercard"> <h3>{{ user.fname }} {{ user.mname }} {{ user.lname }}</h3> <table> + <button><a href="{{ url_for('chgpass_by_uid',uid=user._id) }}">Reset Password</a></button> <tr><td>Username</td><td>{{ user.username }}</td></tr> <tr><td>Birthday</td><td>{{ user.birthday }}</td></tr> <tr><td>Role</td><td>{{ user.role }}</td></tr>