Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Position Description Interface #335

Open
wants to merge 59 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
a4629f0
modifying the lsf model
mupotsal Jan 29, 2021
3c7c3b5
modified models
mupotsal Jan 29, 2021
bc6791b
updated positionDescription model and added it to the migration file
bryantal Feb 2, 2021
ff76a71
UI build for position description
Feb 17, 2021
a01960b
added all the selectpickers and all working
Feb 18, 2021
553e40e
Added in CKeditor, need to fix the toolbar
GuillermoCruz32 Feb 22, 2021
a17ec69
Merge branch 'development' of https://bitbucket.org/laborstudents/lsf…
Feb 22, 2021
fd3a767
working on the ckeditor
Feb 23, 2021
8aaa175
fixed the ckeditor issue
Feb 23, 2021
146fd3c
fixed the backend so that pos desc can start being populated
GuillermoCruz32 Feb 23, 2021
fd30925
Merge branch 'positionDescription' of https://bitbucket.org/laborstud…
GuillermoCruz32 Feb 23, 2021
844e338
merging changes from development
Feb 24, 2021
bfca598
Merge branch 'positionDescription' of https://bitbucket.org/laborstud…
Feb 24, 2021
6d08857
Pushing to show Scott an error
Feb 24, 2021
4c6d52a
Found an issue in the model, fixed and now need to test
Feb 25, 2021
315c9ca
Fixed the .get() issue with the new model
GuillermoCruz32 Feb 25, 2021
53b62fa
Fixed the query issue
GuillermoCruz32 Feb 25, 2021
fe95315
Still need to fix the textarea
GuillermoCruz32 Mar 1, 2021
43abed5
Commiting last changes before overhual
GuillermoCruz32 Mar 26, 2021
f7d001e
Fixed all of the files naming, fixed the model based on feedback from…
GuillermoCruz32 Apr 1, 2021
1c3d15a
Fixed the position description textarea getting populated with header…
GuillermoCruz32 Apr 6, 2021
f794b4b
Going to stop using data tables, and instead try to use accordions to…
GuillermoCruz32 Apr 8, 2021
4563f91
Merge branch 'development' of https://bitbucket.org/laborstudents/lsf…
Apr 8, 2021
b8e552c
Merge branch 'positionDescription' of https://bitbucket.org/laborstud…
Apr 8, 2021
f6fbf5a
started on adding collapsibles
Apr 8, 2021
0a66910
Cannot open my accordian
GuillermoCruz32 Apr 12, 2021
f9139e9
trying js for accordion, opening finally
Apr 13, 2021
5092813
cannot make the accordions work
GuillermoCruz32 Apr 13, 2021
01fc783
the first card in accordion opens now, id problem
Apr 13, 2021
00e4899
tables are added and they are editable, data is added as well
Apr 14, 2021
8a47206
Fixed the buttons and spacing
GuillermoCruz32 Apr 15, 2021
067abcc
implemented the sorting functionality
Apr 15, 2021
9cc4e4c
Finishing up controller for user
GuillermoCruz32 Apr 19, 2021
3269636
working on adding the changes to the db
Apr 19, 2021
aa98a1a
Fixed the submission for users, now need to fix the approval and deni…
GuillermoCruz32 Apr 20, 2021
cd66297
Almost finished with admin approve
GuillermoCruz32 Apr 22, 2021
7b29e5b
Finished the controller, now need to fix the WLS button
GuillermoCruz32 Apr 26, 2021
77a0317
Fixing the controller to add enddates
GuillermoCruz32 Apr 26, 2021
414e4ec
last big changes for the page
Apr 26, 2021
3b3e734
Fixed the WLS modal, small css work needs to be done and then we can …
GuillermoCruz32 Apr 27, 2021
08d5cf7
added the modal and improved some looks:
Apr 27, 2021
8aa4c14
Fixed the authorization, now need to fix the front end
GuillermoCruz32 Apr 28, 2021
f008ef0
changed the layout of the first UI
Apr 28, 2021
c2ba56b
fixed the layout based on the feedback:
Apr 29, 2021
2aa6591
the script to convert doc to txt
May 4, 2021
0bbfbec
Added in the position scraper code, now we need to write the script t…
GuillermoCruz32 May 6, 2021
e92610b
Scraper is ready, need to bacth convert files now
GuillermoCruz32 May 10, 2021
773f4ac
added more scripts
May 10, 2021
a488c02
scripts to rename convert and add to database
May 10, 2021
0a01f5c
Pushing new scraper for review
GuillermoCruz32 May 11, 2021
7fb9bda
Testing more files
GuillermoCruz32 May 11, 2021
582482b
Scraper needs more testing
GuillermoCruz32 May 11, 2021
85c86ec
some problems with scraping fixed
May 11, 2021
0db6879
Fixed the scraper and fixed all the folders, everything is put in cor…
GuillermoCruz32 May 17, 2021
34daa6c
Merge branch 'development' of https://bitbucket.org/laborstudents/lsf…
May 17, 2021
bf3270b
Merge branch 'positionDescription' of https://bitbucket.org/laborstud…
May 17, 2021
a62f78b
cleaning up the files
May 17, 2021
7136a68
adding some requirments
May 17, 2021
3cb245f
removed the file path that needs to be added later
May 17, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/controllers/admin_routes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ def injectGlobalData():
from app.controllers.admin_routes import financialAidOverload
from app.controllers.admin_routes import emailTemplateController
from app.controllers.admin_routes import search
from app.controllers.admin_routes import viewPositionDescriptions
31 changes: 31 additions & 0 deletions app/controllers/admin_routes/viewPositionDescriptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from app.controllers.admin_routes import *
from app.models.user import User
from app.controllers.admin_routes import admin
from app.login_manager import require_login
from app.models.term import Term
from app.models.positionDescription import *
from app.models.positionDescriptionItem import *
from app.models.position import *
from datetime import datetime
from flask import json, jsonify
from flask import request, redirect
from peewee import IntegrityError

@admin.route('/admin/viewPositionDescriptions', methods=['GET', 'POST'])
# @login_required

def viewPositionDescriptions():
currentUser = require_login()
if not currentUser: # Not logged in
return render_template('errors/403.html')
if not currentUser.isLaborAdmin: # Not an admin
if currentUser.student: # logged in as a student
return redirect('/laborHistory/' + currentUser.student.ID)
elif currentUser.supervisor:
return render_template('errors/403.html'), 403

pendingPositionDescriptions = PositionDescription.select().where(PositionDescription.status == "Pending")
return render_template( 'admin/viewPositionDescriptions.html',
title='Position Descriptions',
pendingPositionDescriptions = pendingPositionDescriptions
)
2 changes: 2 additions & 0 deletions app/controllers/main_routes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,5 @@ def injectGlobalData():
from app.controllers.main_routes import download
from app.controllers.main_routes import laborReleaseForm
from app.controllers.main_routes import contributors
from app.controllers.main_routes import positionDescription
from app.controllers.main_routes import positionDescriptionEdit
100 changes: 100 additions & 0 deletions app/controllers/main_routes/positionDescription.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from flask_login import login_required
from app.controllers.main_routes import *
from app.login_manager import require_login
from app.models.user import *
from app.models.formHistory import *
from app.models.positionDescription import *
from app.models.positionDescriptionItem import *
from app.models.position import *
from flask import json, jsonify
from flask import request
from datetime import datetime, date, timedelta
from flask import Flask, redirect, url_for, flash
from app import cfg
from app.logic.emailHandler import*
from app.logic.userInsertFunctions import*

@main_bp.route('/positionDescriptions', methods=['GET'])
def PositionDescriptionView():
""" Render Position Description Form"""
currentUser = require_login()
if not currentUser: # Not logged in
return render_template('errors/403.html'), 403
if not currentUser.isLaborAdmin:
if currentUser.student and not currentUser.supervisor:
return redirect('/laborHistory/' + currentUser.student.ID)
if not currentUser.student and currentUser.supervisor:
# Checks all the forms where the current user has been the creator or the supervisor, and grabs all the departments associated with those forms. Will only grab each department once.
departments = FormHistory.select(FormHistory.formID.department.DEPT_NAME, FormHistory.formID.department.ACCOUNT, FormHistory.formID.department.ORG) \
.join_from(FormHistory, LaborStatusForm) \
.join_from(LaborStatusForm, Department) \
.where((FormHistory.formID.supervisor == currentUser.supervisor.ID) | (FormHistory.createdBy == currentUser)) \
.order_by(FormHistory.formID.department.DEPT_NAME.asc()) \
.distinct()

if currentUser.isLaborAdmin:
# Grabs every single department that currently has at least one labor status form in it
departments = FormHistory.select(FormHistory.formID.department.DEPT_NAME, FormHistory.formID.department.ACCOUNT, FormHistory.formID.department.ORG) \
.join_from(FormHistory, LaborStatusForm) \
.join_from(LaborStatusForm, Department) \
.order_by(FormHistory.formID.department.DEPT_NAME.asc()) \
.distinct()

# Logged in
todayDate = date.today()
openTerms = Term.select().where(Term.termEnd > todayDate)
closedTerms = Term.select().where(Term.termEnd < todayDate)

return render_template( 'main/positionDescription.html',
title=('Position Description'),
UserID = currentUser,
openTerms = openTerms,
closedTerms = closedTerms,
departments = departments)

@main_bp.route("/positionDescriptions/getPositions/<departmentOrg>/<departmentAcct>", methods=['GET'])
def getDepartmentPositions(departmentOrg, departmentAcct):
""" Get all of the positions that are in the selected department """
positions = Tracy().getPositionsFromDepartment(departmentOrg,departmentAcct)
positionDict = {}
for position in positions:
positionDict[position.POSN_CODE] = {"position": position.POSN_TITLE, "WLS":position.WLS, "positionCode":position.POSN_CODE}
return json.dumps(positionDict)

@main_bp.route("/positionDescriptions/getVersions", methods=['POST'])
def getVersions():
""" Get all of the positions that are in the selected department """
try:
rsp = eval(request.data.decode("utf-8"))
returnDict = {}
versions = PositionDescription.select().where(PositionDescription.POSN_CODE == rsp["POSN_CODE"])
for version in versions:
if not version.endDate:
returnDict[version.positionDescriptionID] = {"createdDate": version.createdDate.strftime('%m/%d/%y'), "endDate": "None", "status": version.status.statusName}
else:
returnDict[version.positionDescriptionID] = {"createdDate": version.createdDate.strftime('%m/%d/%y'), "endDate": version.endDate.strftime('%m/%d/%y'), "status": version.status.statusName}
return jsonify(returnDict)
except Exception as e:
print ("ERROR", e)

@main_bp.route("/positionDescriptions/getPositionDescription", methods=['POST'])
def getDescription():
""" Get all of the positions that are in the selected department """
try:
rsp = eval(request.data.decode("utf-8"))
returnList = []
positionDescriptionQualifications = PositionDescriptionItem.select().where((PositionDescriptionItem.itemType == "Qualification") & (PositionDescriptionItem.positionDescription == rsp["positionDescriptionID"]))
positionDescriptionLearningOBJ = PositionDescriptionItem.select().where((PositionDescriptionItem.positionDescription == rsp["positionDescriptionID"]) & (PositionDescriptionItem.itemType == "Learning Objective"))
positionDescriptionDuty = PositionDescriptionItem.select().where((PositionDescriptionItem.positionDescription == rsp["positionDescriptionID"]) & (PositionDescriptionItem.itemType == "Duty"))
returnList.append("<p><strong>Qualifications</strong></p>")
for item in positionDescriptionQualifications:
returnList.append("<p>" + item.itemDescription + "</p>")
returnList.append("<p><strong>Learning Objectives</strong></p>")
for item in positionDescriptionLearningOBJ:
returnList.append("<p>" + item.itemDescription + "</p>")
returnList.append("<p><strong>Duties</strong></p>")
for item in positionDescriptionDuty:
returnList.append("<p>" + item.itemDescription + "</p>")
return jsonify(returnList)
except Exception as e:
print ("ERROR", e)
152 changes: 152 additions & 0 deletions app/controllers/main_routes/positionDescriptionEdit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
from flask_login import login_required
from app.controllers.main_routes import *
from app.login_manager import require_login
from app.models.user import *
from app.models.formHistory import *
from app.models.position import *
from app.models.positionDescription import *
from app.models.positionDescriptionItem import *
from app.models.position import *
from flask import json, jsonify
from flask import request
from datetime import datetime, date, timedelta
from flask import Flask, redirect, url_for, flash
from app import cfg
from app.logic.emailHandler import*
from app.logic.userInsertFunctions import*

@main_bp.route('/positionDescriptionEdit/<positionDescriptionID>', methods=['GET'])
@main_bp.route('/positionDescriptionEdit/newVersion/<positionCode>', methods=['GET'])
def PositionDescriptionEdit(positionDescriptionID = None, positionCode = None):
""" Render Position Description Form"""
currentUser = require_login()
if not currentUser: # Not logged in
return render_template('errors/403.html'), 403
if not currentUser.isLaborAdmin:
if currentUser.student and not currentUser.supervisor:
return redirect('/laborHistory/' + currentUser.student.ID)

if positionDescriptionID:
positionDescriptionItems = PositionDescriptionItem.select().where(PositionDescriptionItem.positionDescription == positionDescriptionID)
positionDescriptionRecord = PositionDescription.select().where(PositionDescription.positionDescriptionID == positionDescriptionID).get()
positionRecord = Position.select().where(Position.POSN_CODE == positionDescriptionRecord.POSN_CODE.POSN_CODE).get()
elif positionCode:
positionDescriptionItems = None
positionDescriptionRecord = None
positionRecord = Position.select().where(Position.POSN_CODE == positionCode).get()

pendingPositionDescription = PositionDescription.select().where(PositionDescription.POSN_CODE == positionRecord.POSN_CODE)

if not currentUser.isLaborAdmin:
# Checks all the forms where the current user has been the creator or the supervisor, and grabs all the departments associated with those forms. Will only grab each department once.
if pendingPositionDescription:
for record in pendingPositionDescription:
if record.status.statusName == "Pending":
return render_template('errors/403.html'), 403

authorizedUser = False
departments = FormHistory.select(FormHistory.formID.department.DEPT_NAME, FormHistory.formID.department.ACCOUNT, FormHistory.formID.department.ORG) \
.join_from(FormHistory, LaborStatusForm) \
.join_from(LaborStatusForm, Department) \
.where((FormHistory.formID.supervisor == currentUser.supervisor.ID) | (FormHistory.createdBy == currentUser)) \
.order_by(FormHistory.formID.department.DEPT_NAME.asc()) \
.distinct()
for department in departments:
if department.formID.department.DEPT_NAME == positionRecord.DEPT_NAME:
authorizedUser = True
break
if not authorizedUser:
return render_template('errors/403.html'), 403

itemTypes = ['Learning Objective', 'Qualification', 'Duty']

return render_template( 'main/positionDescriptionEdit.html',
showModal=True,
title=('Position Description'),
UserID = currentUser,
positionDescriptionItems = positionDescriptionItems,
itemTypes = itemTypes,
positionDescriptionRecord = positionDescriptionRecord,
positionRecord = positionRecord)

@main_bp.route("/positionDescriptionEdit/submitRevisions", methods=['POST'])
def submitRevisions():
""" Get all of the positions that are in the selected department """
try:
currentUser = require_login()
rsp = eval(request.data.decode("utf-8"))
position = Position.select().where(Position.POSN_CODE == rsp["positionCode"]).get()
positionDescription = PositionDescription.create( createdBy = currentUser,
status = "Pending",
POSN_CODE = rsp["positionCode"],
createdDate = date.today()
)
for duty in rsp["duties"]:
PositionDescriptionItem.create( positionDescription = positionDescription ,
itemDescription = duty,
itemType = "Duty"
)
for qualification in rsp["qualifications"]:
PositionDescriptionItem.create( positionDescription = positionDescription ,
itemDescription = qualification,
itemType = "Qualification"
)
for learningObjective in rsp["learningObjectives"]:
PositionDescriptionItem.create( positionDescription = positionDescription ,
itemDescription = learningObjective,
itemType = "Learning Objective"
)
message = "Your position description revision for {0} ({1}) - {2} has been submited.".format(position.POSN_TITLE, position.WLS, position.POSN_CODE)
flash(message, "success")
return jsonify({"Success":True})
except Exception as e:
print ("ERROR", e)
return jsonify({"Success": False})

@main_bp.route("/positionDescriptionEdit/adminUpdate", methods=['POST'])
def adminUpdate():
""" Get all of the positions that are in the selected department """
try:
currentUser = require_login()
rsp = eval(request.data.decode("utf-8"))
position = PositionDescription.select().where(PositionDescription.positionDescriptionID == rsp["recordID"]).get()
if rsp["adminChoice"] == "Deny":
position.status = "Denied"
position.save()
message = "The position description revision for {0} ({1}) - {2} has been denied.".format(position.POSN_CODE.POSN_TITLE, position.POSN_CODE.WLS, position.POSN_CODE.POSN_CODE)
messageType = "danger"
elif rsp["adminChoice"] == "Approve":
descriptionItems = PositionDescriptionItem.select().where(PositionDescriptionItem.positionDescription == position.positionDescriptionID)
try:
lastPositionDescription = PositionDescription.select().where((PositionDescription.POSN_CODE == position.POSN_CODE) & (PositionDescription.status == "Approved")).order_by(PositionDescription.createdDate.desc())[0]
except:
lastPositionDescription = None
if lastPositionDescription:
lastPositionDescription.endDate = date.today()
lastPositionDescription.save()
position.status = "Approved"
position.save()
for item in descriptionItems:
item.delete_instance()
for duty in rsp["duties"]:
PositionDescriptionItem.create( positionDescription = position.positionDescriptionID,
itemDescription = duty,
itemType = "Duty"
)
for qualification in rsp["qualifications"]:
PositionDescriptionItem.create( positionDescription = position.positionDescriptionID,
itemDescription = qualification,
itemType = "Qualification"
)
for learningObjective in rsp["learningObjectives"]:
PositionDescriptionItem.create( positionDescription = position.positionDescriptionID,
itemDescription = learningObjective,
itemType = "Learning Objective"
)
message = "The position description revision for {0} ({1}) - {2} has been approved.".format(position.POSN_CODE.POSN_TITLE, position.POSN_CODE.WLS, position.POSN_CODE.POSN_CODE)
messageType = "success"
flash(message, messageType)
return jsonify({"Success":True})
except Exception as e:
print ("ERROR On Admin Position Description Update:", e)
return jsonify({"Success": False})
5 changes: 3 additions & 2 deletions app/models/laborStatusForm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from app.models.user import User
from app.models.department import Department
from app.models.supervisor import Supervisor
from app.models.positionDescription import PositionDescription


# All caps fields are pulled from TRACY
Expand All @@ -14,17 +15,17 @@ class LaborStatusForm (baseModel):
studentSupervisee = ForeignKeyField(Student, on_delete="cascade") # foreign key to student
supervisor = ForeignKeyField(Supervisor, on_delete="cascade") # foreign key to supervisor
department = ForeignKeyField(Department, on_delete="cascade") # Foreign key to department
PositionDescription = ForeignKeyField(PositionDescription, null=True, on_delete="cascade")
jobType = CharField() # Primary or secondary
WLS = CharField()
POSN_TITLE = CharField() # eg. student programmer, customer engagement specialist, receptionist, teaching assistant
POSN_CODE = CharField()
positionDescription = CharField(null=True)
contractHours = IntegerField(null=True) # total hours for break terms
weeklyHours = IntegerField(null=True) # weekly hours 10,12,15...
startDate = DateField(null=True) # in case they start different than term start date
endDate = DateField(null=True)
supervisorNotes = TextField(null=True)
laborDepartmentNotes = TextField(null=True)


def __str__(self):
return str(self.__dict__)
13 changes: 13 additions & 0 deletions app/models/position.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from app.models import *

class Position (baseModel):

POSN_CODE = CharField(primary_key=True)
POSN_TITLE = CharField()
WLS = CharField()
ORG = CharField()
ACCOUNT = CharField()
DEPT_NAME = CharField()

def __str__(self):
return str(self.__dict__)
15 changes: 15 additions & 0 deletions app/models/positionDescription.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from app.models import *
from app.models.user import User
from app.models.status import Status
from app.models.position import Position

class PositionDescription (baseModel):
positionDescriptionID = PrimaryKeyField()
createdBy = ForeignKeyField(User, on_delete="cascade")
status = ForeignKeyField(Status)
POSN_CODE = ForeignKeyField(Position)
createdDate = DateField()
endDate = DateField(null=True)

def __str__(self):
return str(self.__dict__)
11 changes: 11 additions & 0 deletions app/models/positionDescriptionItem.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from app.models import *
from app.models.positionDescription import PositionDescription

class PositionDescriptionItem (baseModel):
positionDescriptionItemID = PrimaryKeyField()
positionDescription = ForeignKeyField(PositionDescription, on_delete="cascade")
itemDescription = CharField(max_length=10000)
itemType = CharField()

def __str__(self):
return str(self.__dict__)
Loading