stc

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

commit fa1a16b584a17e98e524123acb962b317b7c851e
parent 3d5aeaa83b9332a6435a7ef357b72ea21b2636d1
Author: Youth Employment Program Production <youthemployment22@gmail.com>
Date:   Fri, 24 May 2024 08:48:10 -0600

push for offline work

Diffstat:
MTODO.md | 4+++-
Mapp/forms.py | 2++
Aapp/meetings/templates/get_meeting_file.html | 18++++++++++++++++++
Mapp/routes.py | 130+++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mapp/static/css/main.css | 4++--
5 files changed, 95 insertions(+), 63 deletions(-)

diff --git a/TODO.md b/TODO.md @@ -42,7 +42,9 @@ ## OPTIONAL -- [ ] rework admin page flow to show agency for projects?... wanted to sort and display by agency, but is many to one relationship... +- [X] rework admin page flow to show agency for projects?... wanted to sort and display by agency, but is many to one relationship... +### Unclear on how to do the below, doesn't appear to be able to remove session from client or make invalid session... +### Will likely have to overload the @login_required fn to check for user is_active... will have to on route check for updates, not sure if user object is refreshing every page... likely just being set on login. - [ ] 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 diff --git a/app/forms.py b/app/forms.py @@ -131,6 +131,7 @@ class ConfirmRemove(FlaskForm): confirm = SubmitField('YES REMOVE') class NewProjectForm(BudgetForm): + fenumber = IntegerField('FE #', validators=[DataRequired()]) projectName = StringField('Project Name', validators=[DataRequired()]) agreement = SelectField('Part of Agreement', validators=[DataRequired()]) branch = SelectField('Organization Branch', validators=[DataRequired()]) @@ -141,6 +142,7 @@ class MoveProjectForm(FlaskForm): moveProject = SubmitField('Update Project') class RenameProjectForm(FlaskForm): + fenumber = IntegerField('FE #', validators=[DataRequired()]) newName = StringField('Project Name', validators=[DataRequired()]) renameProject = SubmitField('Update Project') diff --git a/app/meetings/templates/get_meeting_file.html b/app/meetings/templates/get_meeting_file.html @@ -0,0 +1,18 @@ +{% extends 'base.html' %} + +{% block title %}Get File{% endblock %} + +{% block content %} +{% with messages = get_flashed_messages() %} +{% if messages %} + {% for message in messages %} + <div id="messagebanner"><p>{{ message }}</p></div> + {% endfor %} +{% endif %} +{% endwith %} + <section class="hours-grid">{#class="meeting">#} + <ul>{% for file in files %} + <li><a href="{{ url_for('meetings.get_meeting_file', fid=file) }}">{{ file }}</a></li> + {% endfor %}</ul> + </section> +{% endblock %} diff --git a/app/routes.py b/app/routes.py @@ -10,6 +10,7 @@ from werkzeug.urls import url_parse from werkzeug.security import generate_password_hash, check_password_hash from flask_login import current_user, login_user, logout_user, login_required from app.branches.routes import get_available_branches +from app.equipment.equipment import get_available_equipment_type from app.models import User, Time, Fleet, Agreement, Projects from bson.objectid import ObjectId import bson.json_util as json_util @@ -43,12 +44,25 @@ def fetch_user_from_username(username): else: return user +# Add ability to get users by role type... case match statement inside if for default no arguments? +# TODO currently doesn't care about active state. FIX +def get_available_users(active=True,role=None,branch=None): + availableUsers = [("","Select User")] + for user in mongo.db.users_collection.find(): + if branch: + if 'branch' in user: + if user['branch'] == 'Global' or user['branch'] == branch: + availableUsers.append((user['_id'],user['username'])) + else: + availableUsers.append((user['_id'],user['username'])) + return availableUsers + def get_available_projects(branch=None): availableProjects = [("","Select Project")] for project in mongo.db.projects_collection.find(): if branch: if 'branch' in project: - if project['branch'] == 'Global' or project['branch'] == branch: + if project['branch'] == 'Global' or project['branch'] == ObjectId(branch): availableProjects.append((project['_id'],project['project_name'])) else: availableProjects.append((project['_id'],project['project_name'])) @@ -209,17 +223,11 @@ def chgpass_by_uid(uid): #### #### @app.route('/index') -#def hello(): -# return redirect(url_for('dashboard')) @app.route("/dashboard", methods=['GET', 'POST']) @login_required def dashboard(): currentdate = datetime.datetime.now() - #Banner, TODO create a MOTD framework, for admin messages - if currentdate.strftime('%Y-%m-%d') == current_user.birthday: - flash("Happy Birthday {}!".format(current_user.fname)) - ## END Banner dashperms=mongo.db.permissions_collection.find_one({'label': current_user.role},{'dashboard':1,'_id':0}) dashperms=dashperms['dashboard'] @@ -287,14 +295,14 @@ def dashboard(): flash('Unable to check out vehicle') return redirect(url_for('dashboard')) -# Temp values, change to db dependent values - #availableVehicles = ['Vehicle 1', 'Vehicle 2', 'Vehicle 3', 'Vehicle 4'] - availableVehicles = mongo.db.fleet_collection.find_one({'_id':'Fleet Pool'},{'available':1})['available'] - lastMileage = 103483 + #def newfleet_check_out(vehicle_id,start_milage,additional_notes=None,safety_checks=None) + #availableVehicles = mongo.db.fleet_collection.find_one({'_id':'Fleet Pool'},{'available':1})['available'] + availableVehicles = [("","Select Vehicle")] + for vehicle in get_available_equipment_type('vehicle',branch=current_user.branch): + availableVehicles.append((vehicle['_id'],"Vehicle {}".format(vehicle['vehicle_id']))) + #currently gets ALL projects TODO make filter by available agreements/projects - availableProjects = get_available_projects() - #for project in mongo.db.projects_collection.find(): - # availableProjects.append((project['_id'],project['project_name'])) + availableProjects = get_available_projects(current_user.branch) # GET_CLOCKED out users clocked_out_active_users=[] clocked_in_active_users=[] @@ -369,11 +377,11 @@ def dashboard(): @login_required def updateProjectTime(mod_username,timeid): timeid = ObjectId(timeid) - availableProjects = [] #change to get_available_projects() -> projects where user branch == project['branch'] + availableProjects = get_available_projects(current_user.branch)#[] #change to get_available_projects() -> projects where user branch == project['branch'] form = updateProject() - for project in mongo.db.projects_collection.find(): - availableProjects.append((project['_id'],project['project_name'])) +# for project in mongo.db.projects_collection.find(): +# availableProjects.append((project['_id'],project['project_name'])) form.projectSel.choices = availableProjects @@ -568,9 +576,10 @@ def toggle_per_diem(timeid): @login_required def clockin_new_user(): clocked_in_users = mongo.db.time_collection.find({'clock_out': {'$exists':False}}) - availableProjects = [] - for project in mongo.db.projects_collection.find(): - availableProjects.append((project['_id'],project['project_name'])) + availableProjects = get_available_projects(current_user.branch)#[] + #TODO Might be helpful to make available projects search for projects available to the selected user... +# for project in mongo.db.projects_collection.find(): +# availableProjects.append((project['_id'],project['project_name'])) # GET_CLOCKED out users clocked_out_active_users=[] clocked_in_active_users=[] @@ -604,9 +613,9 @@ def clockin_new_user(): @login_required def new_time(usernm): user = mongo.db.user_collection.find_one({"username": usernm}) - availableProjects = [] - for project in mongo.db.projects_collection.find(): - availableProjects.append((project['_id'],project['project_name'])) + availableProjects = get_available_projects(current_user.branch) #[] +# for project in mongo.db.projects_collection.find(): +# availableProjects.append((project['_id'],project['project_name'])) # availableProjects = [("","Select Project")] # for project in mongo.db.projects_collection.find(): # if 'branch' in project: @@ -647,9 +656,9 @@ def new_time(usernm): @login_required def new_user_time(): clocked_in_users = mongo.db.time_collection.find({'clock_out': {'$exists':False}}) - availableProjects = [] - for project in mongo.db.projects_collection.find(): - availableProjects.append((project['_id'],project['project_name'])) + availableProjects = get_available_projects(current_user.branch) +# for project in mongo.db.projects_collection.find(): +# availableProjects.append((project['_id'],project['project_name'])) # GET_CLOCKED out users clocked_out_active_users=[] clocked_in_active_users=[] @@ -674,26 +683,6 @@ def new_user_time(): dateentry = datetime.datetime.combine(form.dateSel.data,datetime.time()) starttime = datetime.datetime.combine(form.dateSel.data,form.startTime.data) endtime = datetime.datetime.combine(form.dateSel.data,form.endTime.data) -# if form.userSel.data is current_user.username: -# mongo.db.time_collection.insert_one({ -# 'modified_by' : [form.userSel.data], -# 'date' : dateentry, -# 'clock_in' : [starttime], -# 'clock_out' : [endtime], -# 'project' : ObjectId(form.projectSel.data), -# 'lunch': form.lunchSel.data, -# 'per_diem':form.perDiemSel.data}) -# else: -# mongo.db.time_collection.insert_one({ -# 'modified_by' : [form.userSel.data, current_user.username], -# 'date' : dateentry, -# 'clock_in' : [starttime], -# 'clock_out' : [endtime], -# 'project' : ObjectId(form.projectSel.data), -# 'lunch': form.lunchSel.data, -# 'per_diem':form.perDiemSel.data}) - - #New entryevent = { 'date' : dateentry, 'clock_in' : [starttime], @@ -708,9 +697,14 @@ def new_user_time(): entryevent['modified_by'] = [form.userSel.data,current_user.username] if form.note.data != '' and form.note.data != None: entryevent['note'] = form.note.data - mongo.db.time_collection.insert_one(entryevent) - - return redirect(url_for('new_user_time')) + try: + mongo.db.time_collection.insert_one(entryevent) + except: + flash("Unhandled error occured") + else: + flash("Created time entry for {}".format(userSel.data)) + finally: + return redirect(url_for('new_user_time')) return render_template('dashboard/punchclock/otheruser.html',form=form,ORGNAME=OrganizationName) @@ -881,8 +875,16 @@ def hoursd(username):#userid goes into call to db to get user[] -> then returns } ] )# Time Spent Per Project (filter entries by username, then group and sum hours by project) + #Banner, TODO create a MOTD framework, for admin messages + currentdate = datetime.datetime.now() + currentdate = currentdate.strftime('%Y-%m-%d') + currentdate = currentdate.split('-') + birthday = current_user.birthday.split("-") + if currentdate[1] == birthday[1] and currentdate[2] == birthday[2]: + flash("Happy Birthday {}!".format(current_user.fname)) + ## END Banner - return render_template ('dashboard/punchclock/index.dev.html',hours=dbhours,tspp=tspp,ORGNAME=OrganizationName) + return render_template ('dashboard/punchclock/index.dev.html',cd=currentdate, bd=birthday,hours=dbhours,tspp=tspp,ORGNAME=OrganizationName) @@ -905,9 +907,9 @@ def hours(username): #dashperms=dashperms['dashboard'] #total_hours=0 user = mongo.db.user_collection.find_one({"username": username}) - availableProjects = [] - for project in mongo.db.projects_collection.find(): #TODO TO RESOLVE BELOW ISSUE, JUST USE aggregator QUERY, WILL ALLOW SORTING AS WELL AS PROPER SUMMATION OF HOURS - availableProjects.append((project['_id'],project['project_name']))#TODO FIND OUT WHY THIS RETURNS THE OBJECTID VALUE .str THROWS AttributeError: 'ObjectId' object has no attribute 'str' + availableProjects = get_available_projects(current_user.branch) +# for project in mongo.db.projects_collection.find(): #TODO TO RESOLVE BELOW ISSUE, JUST USE aggregator QUERY, WILL ALLOW SORTING AS WELL AS PROPER SUMMATION OF HOURS +# availableProjects.append((project['_id'],project['project_name']))#TODO FIND OUT WHY THIS RETURNS THE OBJECTID VALUE .str THROWS AttributeError: 'ObjectId' object has no attribute 'str' #'completed':{'$exists':False} dbhours = mongo.db.time_collection.aggregate( [ { @@ -1094,8 +1096,14 @@ def activate_user(userid): @login_required def removetime(timeid): timeid = ObjectId(timeid) - mongo.db.time_collection.delete_one({'_id':timeid}) - return redirect(url_for('dashboard')) + try: + mongo.db.time_collection.delete_one({'_id':timeid}) + except: + flash("An unhandled error occured removing time") + else: + flash("Removed Time") + finally: + return redirect(url_for('dashboard')) #@app.route("/clockoutuser/<modusernm>/<timeid>", methods=['GET','POST']) #@login_required #def clockout_by_id(modusernm,timeid): @@ -1127,7 +1135,6 @@ def moduser(uid): dashperms=dashperms['dashboard'] for perm in dashperms: - #availableProjects.append((project['_id'],project['project_name'])) availableRoles.append((perm['_id'],perm['label'])) defaultBranch = 'Dillon' @@ -1311,8 +1318,10 @@ def newproject(): if form.otherBudget.data is None: form.otherBudget.data = 0.0 + pjname = "FE " + str(form.fenumber.data) + ": " + form.projectName.data + mongo.db.projects_collection.insert_one({ - 'project_name':form.projectName.data, + 'project_name':pjname, 'agreement':ObjectId(form.agreement.data), 'branch':form.branch.data, #'branch':ObjectId(form.branch.data), @@ -1339,7 +1348,7 @@ def newproject(): 'other':0 }] }) - pj_id = mongo.db.projects_collection.find_one({'project_name':form.projectName.data})['_id'] + pj_id = mongo.db.projects_collection.find_one({'project_name':pjname})['_id'] mongo.db.agreements_collection.update_one({ '_id':ObjectId(form.agreement.data) },{ '$push':{ 'projects':pj_id }}) flash("{} part of {} added".format(form.projectName.data, form.agreement.data )) #Will need to sendmail password to form.email.data later @@ -1377,15 +1386,16 @@ def project(project_id): def rename_project(project_id): form = RenameProjectForm() if form.validate_on_submit(): + pjname = "FE " + str(form.fenumber.data) + ": " + form.newName.data try: project = mongo.db.projects_collection.find_one({'_id':project_id}) except: flash("Issue finding Project with id {}".format(project_id)) else: try: - mongo.db.projects_collection.update_one({'_id':ObjectId(project_id)},{'$set':{'project_name':form.newName.data}}) + mongo.db.projects_collection.update_one({'_id':ObjectId(project_id)},{'$set':{'project_name':pjname}}) except: - flash("Issue setting {} as project name for {}".format(form.newName.data,project_id)) + flash("Issue setting {} as project name for {}".format(pjname,project_id)) finally: return redirect(url_for('project', project_id=project_id)) return render_template('admin/agreements/projects/update/rename.html',form=form,ORGNAME=OrganizationName) diff --git a/app/static/css/main.css b/app/static/css/main.css @@ -57,7 +57,7 @@ button, input[type="submit"], input[type="checkbox"] { /*margin-left: 25px;*/ box-shadow: 0 3px 6px 0 rgba(0,0,0,0.2); &:hover { - transform: translateY(-10px); + transform: translateY(-2px); box-shadow: 0 6px 6px 0 rgba(0,0,0,0.2); } } @@ -138,7 +138,7 @@ dl { color: white; margin-left: 25px; box-shadow: 0 3px 6px 0 rgba(0,0,0,0.2); -/* &:hover { transform: translateY(-10px); box-shadow: 0 6px 6px 0 rgba(0,0,0,0.2); };*/ +/* &:hover { transform: translateY(-5px); box-shadow: 0 6px 6px 0 rgba(0,0,0,0.2); };*/ } .action-button { border: none;