Aug 25 - Fixed inspection access denied by inspector
This commit is contained in:
@@ -772,7 +772,11 @@ def view(inspection_id):
|
||||
if inspection is None:
|
||||
abort(404)
|
||||
|
||||
if current_user.is_inspector and inspection.inspector_id != current_user.id:
|
||||
# Read access matches the LIST (rule 58) — an inspector may open anything
|
||||
# at their contracted facilities, not only what they performed. Editing
|
||||
# someone else's inspection is still refused (execute / save-draft /
|
||||
# upload-photo / flag-issue keep the authorship check).
|
||||
if current_user.is_inspector and not _inspector_may_read(inspection, current_user):
|
||||
flash('Access denied.', 'danger')
|
||||
return redirect(url_for('inspections.index'))
|
||||
if current_user.role == 'customer':
|
||||
@@ -970,8 +974,22 @@ def view(inspection_id):
|
||||
}
|
||||
|
||||
followup_assignees = _followup_assignees_for(inspection, current_user)
|
||||
# An inspector viewing SOMEBODY ELSE's inspection gets a read-only page.
|
||||
# Without this the buttons would all render and then fail on click — the
|
||||
# same list-says-yes / page-says-no mismatch this change removes.
|
||||
is_own_inspection = (not current_user.is_inspector
|
||||
or inspection.inspector_id == current_user.id)
|
||||
# Whoever is expected to carry out the follow-up (phase53) may start the
|
||||
# re-inspection even though the original inspection is not theirs.
|
||||
owns_follow_up = bool(
|
||||
inspection.follow_up_required
|
||||
and inspection.follow_up_owner
|
||||
and inspection.follow_up_owner.id == current_user.id
|
||||
)
|
||||
return render_template('inspections/view.html',
|
||||
followup_assignees=followup_assignees,
|
||||
is_own_inspection=is_own_inspection,
|
||||
owns_follow_up=owns_follow_up,
|
||||
inspection=inspection,
|
||||
form_fields=form_fields,
|
||||
form_data=form_data,
|
||||
@@ -1311,7 +1329,11 @@ def export_pdf(inspection_id):
|
||||
if inspection is None:
|
||||
abort(404)
|
||||
|
||||
if current_user.is_inspector and inspection.inspector_id != current_user.id:
|
||||
# Read access matches the LIST (rule 58) — an inspector may open anything
|
||||
# at their contracted facilities, not only what they performed. Editing
|
||||
# someone else's inspection is still refused (execute / save-draft /
|
||||
# upload-photo / flag-issue keep the authorship check).
|
||||
if current_user.is_inspector and not _inspector_may_read(inspection, current_user):
|
||||
flash('Access denied.', 'danger')
|
||||
return redirect(url_for('inspections.index'))
|
||||
if current_user.role == 'customer':
|
||||
@@ -1396,6 +1418,28 @@ def _view_url(inspection_id):
|
||||
return url_for('inspections.view', inspection_id=inspection_id)
|
||||
|
||||
|
||||
def _inspector_may_read(inspection, user):
|
||||
"""May this inspector OPEN someone else's inspection?
|
||||
|
||||
Yes, when it happened at a facility on one of their contracts — the same
|
||||
scope `index()` uses (rule 58: an inspector's scope covers all data in their
|
||||
contracted facilities, not just their own work).
|
||||
|
||||
This used to test authorship instead, and the two disagreed: the list
|
||||
showed every inspection at the inspector's facilities, then clicking one
|
||||
said "Access denied". It also blocked the phase53 follow-up assignee from
|
||||
opening the parent inspection they had just been asked to re-inspect —
|
||||
the button they needed was on a page they could not reach.
|
||||
|
||||
READ only. Editing someone else's inspection is still refused: execute,
|
||||
save-draft, upload-photo and flag-issue all keep the authorship check.
|
||||
"""
|
||||
fids = get_inspector_scope(user)
|
||||
if fids is None: # not an inspector — no scoping applies here
|
||||
return True
|
||||
return bool(fids) and inspection.facility_id in fids
|
||||
|
||||
|
||||
def _followup_assignees_for(inspection, actor):
|
||||
"""Inspectors who may be handed this inspection's follow-up.
|
||||
|
||||
@@ -1826,6 +1870,26 @@ def reinspect(inspection_id):
|
||||
flash('Access denied.', 'danger')
|
||||
return redirect(url_for('inspections.index'))
|
||||
|
||||
# An inspector may re-inspect their OWN work, or work they have been
|
||||
# handed the follow-up for (phase53). Anything else at a contracted
|
||||
# facility is readable but not theirs to redo — starting a re-inspection
|
||||
# of a colleague's inspection uninvited only creates confusion about who
|
||||
# is doing it.
|
||||
if current_user.is_inspector:
|
||||
if parent.follow_up_required and parent.follow_up_owner:
|
||||
# A live follow-up has exactly ONE owner (phase53). Even the
|
||||
# original inspector does not start it once it has been handed to
|
||||
# someone else — that is the whole point of assigning it, and two
|
||||
# people turning up is the failure being designed out.
|
||||
may = parent.follow_up_owner.id == current_user.id
|
||||
else:
|
||||
# No follow-up outstanding: re-inspecting your own work is fine,
|
||||
# someone else's is not yours to redo uninvited.
|
||||
may = parent.inspector_id == current_user.id
|
||||
if not may:
|
||||
flash('That re-inspection has been assigned to someone else.', 'warning')
|
||||
return redirect(_view_url(inspection_id))
|
||||
|
||||
session['reinspect_parent_id'] = parent.id
|
||||
session['reinspect_template_id'] = parent.template_id
|
||||
session['reinspect_facility_id'] = parent.facility_id
|
||||
|
||||
Reference in New Issue
Block a user