Employee resolve diagnostic
This commit is contained in:
@@ -147,7 +147,13 @@ def resolve_employee_display_name(sso):
|
||||
if name:
|
||||
return name
|
||||
except Exception:
|
||||
pass
|
||||
# Logged, not swallowed. This is the branch that fails on a live
|
||||
# site - an unreachable HR host, a rotated credential, a renamed
|
||||
# column - and a bare pass made all of those look identical to
|
||||
# "no such employee": a lowercase SSO where a name should be, and
|
||||
# no photo, with nothing written down anywhere.
|
||||
current_app.logger.exception(
|
||||
'Employee directory lookup failed for SSO %s', sso)
|
||||
|
||||
# 2. Fallback: a shopdb login account for this SSO (e.g. a user from another
|
||||
# location not carried in the directory). Their name lives on the User
|
||||
@@ -160,7 +166,8 @@ def resolve_employee_display_name(sso):
|
||||
if name:
|
||||
return name
|
||||
except Exception:
|
||||
pass
|
||||
current_app.logger.exception(
|
||||
'User-account name fallback failed for SSO %s', sso)
|
||||
return None
|
||||
|
||||
|
||||
@@ -189,6 +196,83 @@ def _with_photo_url(employee):
|
||||
return employee
|
||||
|
||||
|
||||
@employees_bp.route('/resolve/<sso>', methods=['GET'])
|
||||
@jwt_required()
|
||||
def resolve_employee(sso):
|
||||
"""Resolve one SSO to a name and photo, and say HOW.
|
||||
|
||||
Built because the failure it diagnoses is invisible. The shopfloor board
|
||||
resolves names and photos through two functions that returned None on any
|
||||
problem, so an unreachable HR host, a rotated credential and a genuinely
|
||||
unknown SSO all produced the same thing: a lowercase SSO where a name
|
||||
should be, and no photo. Nothing distinguished them and nothing was logged.
|
||||
|
||||
This returns the same answer the board gets, plus which source produced it,
|
||||
which mode the directory is in, and the error when a source failed. It is
|
||||
the difference between "the board is broken" and "the HR host refused the
|
||||
connection at 09:12".
|
||||
"""
|
||||
result = {
|
||||
'sso': sso,
|
||||
'mode': 'selfhosted' if _selfhosted() else 'external',
|
||||
'name': None,
|
||||
'photourl': None,
|
||||
'source': None,
|
||||
'error': None,
|
||||
}
|
||||
|
||||
if sso is None or not str(sso).isdigit():
|
||||
result['error'] = 'SSO must be digits'
|
||||
return success_response(result)
|
||||
|
||||
if _selfhosted():
|
||||
employee = db.session.get(DirectoryEmployee, int(sso))
|
||||
if employee:
|
||||
name = '{} {}'.format(employee.firstname or '',
|
||||
employee.lastname or '').strip()
|
||||
if name:
|
||||
result['name'] = name
|
||||
result['source'] = 'directory'
|
||||
else:
|
||||
try:
|
||||
conn = employee_connection()
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
'SELECT First_Name, Last_Name FROM employees WHERE SSO = %s',
|
||||
(int(sso),))
|
||||
row = cur.fetchone()
|
||||
conn.close()
|
||||
if row:
|
||||
name = '{} {}'.format((row.get('First_Name') or '').strip(),
|
||||
(row.get('Last_Name') or '').strip()).strip()
|
||||
if name:
|
||||
result['name'] = name
|
||||
result['source'] = 'hrdirectory'
|
||||
else:
|
||||
result['error'] = 'No row in the HR directory for this SSO'
|
||||
except Exception as exception:
|
||||
# Reported, not hidden. This string is the whole point of the
|
||||
# endpoint.
|
||||
result['error'] = '{}: {}'.format(type(exception).__name__, exception)
|
||||
current_app.logger.exception(
|
||||
'Employee directory lookup failed for SSO %s', sso)
|
||||
|
||||
if not result['name']:
|
||||
from shopdb.api import User
|
||||
user = User.query.filter_by(username=str(sso)).first()
|
||||
if user:
|
||||
name = '{} {}'.format((user.firstname or '').strip(),
|
||||
(user.lastname or '').strip()).strip()
|
||||
if name:
|
||||
result['name'] = name
|
||||
result['source'] = 'useraccount'
|
||||
|
||||
result['photourl'] = resolve_employee_photo_url(sso)
|
||||
if result['name'] is None and result['error'] is None:
|
||||
result['error'] = 'No name found in the directory or in a user account'
|
||||
return success_response(result)
|
||||
|
||||
|
||||
@employees_bp.route('/search', methods=['GET'])
|
||||
def search_employees():
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user