05/25 Improvement 2
This commit is contained in:
@@ -666,7 +666,7 @@ timeout = 30
|
||||
| 31 | **Do not sync an issue when its parent `LocalInspection.syncStatus == "failed"`** | Submitting without `inspection_id` creates orphaned server records |
|
||||
| 32 | **f-string fallback strings must use double-quotes inside single-quoted f-strings** | Python 3.11 raises `SyntaxError` on nested same-delimiter quotes |
|
||||
| 33–38 | *(field ID casting, photo sentinel, notify event_type, follow-up, OperationalError)* | See prior rule entries |
|
||||
| 39 | **Issue API scope: inspectors see assigned OR reported issues** | `GET /issues`, `GET /issues/<id>`, `PATCH /issues/<id>/status`, `PATCH /issues/<id>/photos` all enforce `assigned_to == user.id OR reported_by == user.id` for the inspector role |
|
||||
| 39 | **Inspector issue scope: assigned OR reported — web and API must match** | `issues.index()`, `issues.view()`, and all API issue endpoints (`GET /issues`, `GET /issues/<id>`, `PATCH /issues/<id>/status`, `PATCH /issues/<id>/photos`) enforce `assigned_to == user.id OR reported_by == user.id` for the inspector role |
|
||||
| 40 | **`_issue_payload()` must return `photo_path`, `mobile_photo_paths`, and `result_photos`** | iPad reads `photo_path` + `mobile_photo_paths` into `photoServerPaths`; omitting `mobile_photo_paths` means extra evidence photos are invisible on the iPad after sync |
|
||||
| 41 | **`log_action()` commits internally — always call after `db.session.commit()`** | audit.py calls `db.session.commit()` to write the AuditLog row |
|
||||
| 42 | **`~Inspection.follow_ups.any()` not `== None` for dynamic relationships** | `follow_ups` is `lazy='dynamic'`; use `~.any()` which emits `NOT EXISTS` |
|
||||
|
||||
@@ -80,7 +80,8 @@ def index():
|
||||
)
|
||||
|
||||
if current_user.role == 'inspector':
|
||||
q = q.filter(Issue.assigned_to == current_user.id)
|
||||
q = q.filter(db.or_(Issue.assigned_to == current_user.id,
|
||||
Issue.reported_by == current_user.id))
|
||||
elif current_user.role == 'customer':
|
||||
customer_facility_ids = get_customer_scope(current_user)
|
||||
if not customer_facility_ids:
|
||||
@@ -171,8 +172,10 @@ def view(issue_id):
|
||||
if issue is None:
|
||||
abort(404)
|
||||
|
||||
if current_user.role == 'inspector' and issue.assigned_to != current_user.id:
|
||||
flash('Access denied. You can only view issues assigned to you.', 'danger')
|
||||
if current_user.role == 'inspector' and \
|
||||
issue.assigned_to != current_user.id and \
|
||||
issue.reported_by != current_user.id:
|
||||
flash('Access denied.', 'danger')
|
||||
return redirect(url_for('issues.index'))
|
||||
if current_user.role == 'customer':
|
||||
cids = get_customer_scope(current_user) or []
|
||||
|
||||
@@ -175,7 +175,7 @@
|
||||
{% if p %}
|
||||
<li class="page-item {{ 'active' if p == issues.page }}">
|
||||
<a class="page-link"
|
||||
href="{{ url_for('issues.index', page=p, severity=severity_filter, status=status_filter, facility_id=facility_filter) }}">{{ p }}</a>
|
||||
href="{{ url_for('issues.index', page=p, severity=severity_filter, status=status_filter, sla=sla_filter, facility_id=facility_filter) }}">{{ p }}</a>
|
||||
</li>
|
||||
{% else %}<li class="page-item disabled"><span class="page-link">…</span></li>{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
Reference in New Issue
Block a user