05/21 Fix issue with multiple photos 2
This commit is contained in:
+34
-37
@@ -58,10 +58,12 @@ def _issue_payload(issue):
|
||||
'reported_at': issue.reported_at.isoformat() if issue.reported_at else None,
|
||||
'resolved_at': issue.resolved_at.isoformat() if issue.resolved_at else None,
|
||||
'mobile_local_id': issue.mobile_local_id,
|
||||
# photo_path is the primary issue photo; result_photos are resolution photos.
|
||||
# Both are relative paths from the server static root.
|
||||
'photo_path': issue.photo_path or None,
|
||||
'result_photos': issue.result_photos or [],
|
||||
# photo_path: primary evidence photo (first iPad photo).
|
||||
# mobile_photo_paths: extra evidence photos from iPad (shown under Photo Evidence).
|
||||
# result_photos: resolution photos added via the web update form.
|
||||
'photo_path': issue.photo_path or None,
|
||||
'mobile_photo_paths': issue.mobile_photo_paths or [],
|
||||
'result_photos': issue.result_photos or [],
|
||||
}
|
||||
|
||||
|
||||
@@ -204,26 +206,24 @@ def create_issue():
|
||||
inspection = None
|
||||
|
||||
# ── Create ────────────────────────────────────────────────────────────
|
||||
# result_photos may be supplied by the mobile app as a list of paths that
|
||||
# were already uploaded via /api/v1/photos/upload (one call per photo).
|
||||
# Validate that it is a list of non-empty strings; silently drop bad entries.
|
||||
raw_result_photos = data.get('result_photos')
|
||||
if isinstance(raw_result_photos, list):
|
||||
result_photos = [p for p in raw_result_photos if isinstance(p, str) and p.strip()]
|
||||
else:
|
||||
result_photos = []
|
||||
# result_photos in the POST body = extra evidence photos from the iPad.
|
||||
# Store in mobile_photo_paths (not result_photos) so they appear under
|
||||
# "Photo Evidence" on the web, not "Resolution Details".
|
||||
raw_mobile = data.get('result_photos')
|
||||
mobile_photo_paths = [p for p in raw_mobile if isinstance(p, str) and p.strip()] \
|
||||
if isinstance(raw_mobile, list) else []
|
||||
|
||||
issue = Issue(
|
||||
inspection_id = inspection_id,
|
||||
facility_id = facility_id,
|
||||
severity = severity,
|
||||
description = description,
|
||||
photo_path = data.get('photo_path') or None,
|
||||
result_photos = result_photos or None,
|
||||
status = 'open',
|
||||
reported_at = now_eastern(),
|
||||
reported_by = user.id,
|
||||
mobile_local_id = mobile_local_id,
|
||||
inspection_id = inspection_id,
|
||||
facility_id = facility_id,
|
||||
severity = severity,
|
||||
description = description,
|
||||
photo_path = data.get('photo_path') or None,
|
||||
mobile_photo_paths = mobile_photo_paths or None,
|
||||
status = 'open',
|
||||
reported_at = now_eastern(),
|
||||
reported_by = user.id,
|
||||
mobile_local_id = mobile_local_id,
|
||||
)
|
||||
db.session.add(issue)
|
||||
db.session.flush() # get issue.id
|
||||
@@ -352,17 +352,16 @@ def update_issue_status(issue_id):
|
||||
@jwt_required
|
||||
def update_issue_photos(issue_id):
|
||||
"""
|
||||
Attach additional photos to an existing issue created from the mobile app.
|
||||
Attach additional evidence photos to an issue created from the mobile app.
|
||||
|
||||
Called by the iOS app immediately after create_issue when the inspector
|
||||
attached more than one photo. The photos are already uploaded to the server
|
||||
via /api/v1/photos/upload; this endpoint stores their paths in result_photos.
|
||||
Called by the iOS app after create_issue when the inspector attached more
|
||||
than one photo. Photos are already uploaded via /api/v1/photos/upload.
|
||||
Stored in mobile_photo_paths so they display under "Photo Evidence" on the
|
||||
web, not "Resolution Details".
|
||||
|
||||
Request JSON
|
||||
------------
|
||||
{
|
||||
"result_photos": ["uploads/issue_photos/a.jpg", "uploads/issue_photos/b.jpg"]
|
||||
}
|
||||
{ "result_photos": ["uploads/issue_photos/a.jpg", "uploads/issue_photos/b.jpg"] }
|
||||
|
||||
Response 200
|
||||
------------
|
||||
@@ -376,12 +375,11 @@ def update_issue_photos(issue_id):
|
||||
if issue is None:
|
||||
return api_error('Issue not found', 404)
|
||||
|
||||
# Inspectors may only update issues they reported or are assigned to
|
||||
if user.role == 'inspector' and issue.assigned_to != user.id and issue.reported_by != user.id:
|
||||
return api_error('Access denied', 403)
|
||||
|
||||
data = request.get_json(silent=True) or {}
|
||||
raw = data.get('result_photos')
|
||||
raw = data.get('result_photos')
|
||||
|
||||
if not isinstance(raw, list):
|
||||
return api_error('result_photos must be a list of path strings', 400)
|
||||
@@ -390,19 +388,18 @@ def update_issue_photos(issue_id):
|
||||
if not new_photos:
|
||||
return api_error('result_photos must contain at least one valid path', 400)
|
||||
|
||||
# Merge with any existing result_photos rather than overwriting,
|
||||
# so multiple PATCH calls (e.g. retry) are idempotent.
|
||||
existing = issue.result_photos or []
|
||||
# Merge idempotently with any existing mobile_photo_paths
|
||||
existing = issue.mobile_photo_paths or []
|
||||
merged = existing + [p for p in new_photos if p not in existing]
|
||||
issue.result_photos = merged
|
||||
issue.mobile_photo_paths = merged
|
||||
|
||||
db.session.commit()
|
||||
|
||||
log_action(ACTION_UPDATE, 'Issue', issue.id,
|
||||
f'result_photos updated (+{len(new_photos)} photos)',
|
||||
f'mobile_photo_paths updated (+{len(new_photos)} photos)',
|
||||
f'source=mobile; updated_by={user.username}')
|
||||
|
||||
logger.info('API ISSUES | photos_updated | issue_id=%d | added=%d | user=%s',
|
||||
issue.id, len(new_photos), user.username)
|
||||
|
||||
return api_ok({'issue_id': issue.id, 'result_photos_count': len(merged)})
|
||||
return api_ok({'issue_id': issue.id, 'result_photos_count': len(merged)})
|
||||
|
||||
Reference in New Issue
Block a user