Aug 19 - Update New Inspection Schedule page layout
This commit is contained in:
@@ -530,6 +530,31 @@ def index():
|
||||
completed_count=completed_count)
|
||||
|
||||
|
||||
def _active_contracts():
|
||||
"""Contracts offered in the UI-only contract selector on the form.
|
||||
|
||||
Narrowed to a Customer Director's own contracts so the selector cannot even
|
||||
name another customer's contract. The selector is not submitted — the
|
||||
facility is what the route validates (rule 61) — so this is presentation,
|
||||
with _scope_errors() doing the enforcing.
|
||||
"""
|
||||
q = Project.query.filter_by(active=True)
|
||||
if _is_customer_director(current_user):
|
||||
pids = _customer_project_ids()
|
||||
q = q.filter(Project.id.in_(pids)) if pids else q.filter(False)
|
||||
return q.order_by(Project.name).all()
|
||||
|
||||
|
||||
def _project_for_facility(facility_id):
|
||||
"""The contract a facility belongs to — seeds the contract selector so an
|
||||
edit, or a re-render after a validation error, comes back with both
|
||||
dropdowns as the user left them."""
|
||||
if not facility_id:
|
||||
return None
|
||||
fac = db.session.get(Facility, facility_id)
|
||||
return fac.project_id if fac else None
|
||||
|
||||
|
||||
def _form_choices():
|
||||
"""Lists offered on the schedule form, narrowed to the actor's scope.
|
||||
|
||||
@@ -569,6 +594,8 @@ def _form_choices():
|
||||
@schedule_manager_required
|
||||
def create():
|
||||
templates, facilities, inspectors = _form_choices()
|
||||
projects = _active_contracts()
|
||||
selected_project_id = None
|
||||
|
||||
if request.method == 'POST':
|
||||
name = request.form.get('name', '').strip()
|
||||
@@ -576,6 +603,8 @@ def create():
|
||||
facility_id = request.form.get('facility_id', type=int)
|
||||
area_id = request.form.get('area_id', type=int) or None
|
||||
inspector_id = request.form.get('inspector_id', type=int)
|
||||
# Re-seeds the contract selector when this POST comes back invalid.
|
||||
selected_project_id = _project_for_facility(facility_id)
|
||||
frequency = request.form.get('frequency', 'weekly')
|
||||
mode = request.form.get('mode', 'auto')
|
||||
notes = request.form.get('notes', '').strip() or None
|
||||
@@ -600,6 +629,8 @@ def create():
|
||||
for e in errors:
|
||||
flash(e, 'warning')
|
||||
return render_template('inspection_schedules/form.html',
|
||||
projects=projects,
|
||||
selected_project_id=selected_project_id,
|
||||
templates=templates, facilities=facilities,
|
||||
inspectors=inspectors, frequencies=_FREQUENCIES,
|
||||
frequency_labels=InspectionSchedule.FREQUENCY_LABELS,
|
||||
@@ -633,6 +664,8 @@ def create():
|
||||
for e in end_errors:
|
||||
flash(e, 'warning')
|
||||
return render_template('inspection_schedules/form.html',
|
||||
projects=projects,
|
||||
selected_project_id=selected_project_id,
|
||||
templates=templates, facilities=facilities,
|
||||
inspectors=inspectors, frequencies=_FREQUENCIES,
|
||||
frequency_labels=InspectionSchedule.FREQUENCY_LABELS,
|
||||
@@ -652,6 +685,8 @@ def create():
|
||||
return redirect(url_for('inspection_schedules.index'))
|
||||
|
||||
return render_template('inspection_schedules/form.html',
|
||||
projects=projects,
|
||||
selected_project_id=selected_project_id,
|
||||
templates=templates, facilities=facilities,
|
||||
inspectors=inspectors, frequencies=_FREQUENCIES,
|
||||
frequency_labels=InspectionSchedule.FREQUENCY_LABELS,
|
||||
@@ -668,6 +703,8 @@ def edit(schedule_id):
|
||||
if not _schedule_in_scope(schedule):
|
||||
abort(403)
|
||||
templates, facilities, inspectors = _form_choices()
|
||||
projects = _active_contracts()
|
||||
selected_project_id = _project_for_facility(schedule.facility_id)
|
||||
|
||||
if request.method == 'POST':
|
||||
old_inspector_id = schedule.inspector_id
|
||||
@@ -675,6 +712,8 @@ def edit(schedule_id):
|
||||
template_id = request.form.get('template_id', type=int)
|
||||
facility_id = request.form.get('facility_id', type=int)
|
||||
inspector_id = request.form.get('inspector_id', type=int)
|
||||
selected_project_id = (_project_for_facility(facility_id)
|
||||
or selected_project_id)
|
||||
frequency = request.form.get('frequency', schedule.frequency)
|
||||
|
||||
if frequency not in _FREQUENCIES:
|
||||
@@ -688,6 +727,8 @@ def edit(schedule_id):
|
||||
for e in errors:
|
||||
flash(e, 'warning')
|
||||
return render_template('inspection_schedules/form.html',
|
||||
projects=projects,
|
||||
selected_project_id=selected_project_id,
|
||||
schedule=schedule, templates=templates,
|
||||
facilities=facilities, inspectors=inspectors,
|
||||
frequencies=_FREQUENCIES,
|
||||
@@ -736,6 +777,8 @@ def edit(schedule_id):
|
||||
for e in end_errors:
|
||||
flash(e, 'warning')
|
||||
return render_template('inspection_schedules/form.html',
|
||||
projects=projects,
|
||||
selected_project_id=selected_project_id,
|
||||
schedule=schedule, templates=templates,
|
||||
facilities=facilities, inspectors=inspectors,
|
||||
frequencies=_FREQUENCIES,
|
||||
@@ -763,7 +806,9 @@ def edit(schedule_id):
|
||||
flash(f'Inspection schedule "{schedule.name}" updated.', 'success')
|
||||
return redirect(url_for('inspection_schedules.index'))
|
||||
|
||||
return render_template('inspection_schedules/form.html', schedule=schedule,
|
||||
return render_template('inspection_schedules/form.html',
|
||||
projects=projects,
|
||||
selected_project_id=selected_project_id, schedule=schedule,
|
||||
templates=templates, facilities=facilities,
|
||||
inspectors=inspectors, frequencies=_FREQUENCIES,
|
||||
frequency_labels=InspectionSchedule.FREQUENCY_LABELS,
|
||||
|
||||
@@ -476,10 +476,23 @@ def areas_for_facility(facility_id):
|
||||
@bp.route('/facilities_for_project/<int:project_id>')
|
||||
@login_required
|
||||
def facilities_for_project(project_id):
|
||||
facilities = (Facility.query
|
||||
.filter_by(active=True, project_id=project_id)
|
||||
.order_by(Facility.name)
|
||||
.all())
|
||||
"""Active facilities on one contract, for the Contract -> Facility cascade.
|
||||
|
||||
**Scoped to the caller.** Every page that renders a facility dropdown
|
||||
already limits it to what the viewer may see; this endpoint refills that
|
||||
same dropdown, so without the same scope it would happily list another
|
||||
customer's building names to anyone who guessed a contract id — the leak
|
||||
rule 96 describes on the mobile API. Empty list rather than 403, so it does
|
||||
not confirm whether the contract exists either.
|
||||
"""
|
||||
q = Facility.query.filter_by(active=True, project_id=project_id)
|
||||
if current_user.is_inspector:
|
||||
fids = get_inspector_scope(current_user) or []
|
||||
q = q.filter(Facility.id.in_(fids)) if fids else q.filter(False)
|
||||
elif current_user.role == 'customer':
|
||||
fids = get_customer_scope(current_user) or []
|
||||
q = q.filter(Facility.id.in_(fids)) if fids else q.filter(False)
|
||||
facilities = q.order_by(Facility.name).all()
|
||||
return jsonify([{'id': f.id, 'name': f.name} for f in facilities])
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user