Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions backend/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ class Issue(Base):
longitude = Column(Float, nullable=True, index=True)
location = Column(String, nullable=True)
action_plan = Column(JSONEncodedDict, nullable=True)
Emergency-and-High-Severity-#290
severity = Column(Enum(SeverityLevel), default=SeverityLevel.MEDIUM, index=True)
integrity_hash = Column(String, nullable=True) # Blockchain integrity seal
main
Comment on lines +147 to +150
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unresolved git merge conflict markers — this file will not parse.

Lines 147 and 150 are leftover branch-name markers from an unresolved merge/rebase (Emergency-and-High-Severity-#290 and main). Python will raise a SyntaxError on import, preventing the entire backend from starting.

Remove the conflict markers and keep only the intended code.

🐛 Proposed fix
     action_plan = Column(JSONEncodedDict, nullable=True)
-    Emergency-and-High-Severity-#290
     severity = Column(Enum(SeverityLevel), default=SeverityLevel.MEDIUM, index=True)
     integrity_hash = Column(String, nullable=True)  # Blockchain integrity seal
-    main
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Emergency-and-High-Severity-#290
severity = Column(Enum(SeverityLevel), default=SeverityLevel.MEDIUM, index=True)
integrity_hash = Column(String, nullable=True) # Blockchain integrity seal
main
action_plan = Column(JSONEncodedDict, nullable=True)
severity = Column(Enum(SeverityLevel), default=SeverityLevel.MEDIUM, index=True)
integrity_hash = Column(String, nullable=True) # Blockchain integrity seal
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 147-147: Expected an identifier, but found a keyword and that cannot be used here

(invalid-syntax)


[warning] 147-148: Expected an expression

(invalid-syntax)

🤖 Prompt for AI Agents
In `@backend/models.py` around lines 147 - 150, There are leftover merge markers
"Emergency-and-High-Severity-#290" and "main" breaking parsing; open the section
around the Column definitions for severity and integrity_hash and remove the
stray branch-name tokens so only the intended declarations remain (e.g., keep
severity = Column(Enum(SeverityLevel), default=SeverityLevel.MEDIUM, index=True)
and integrity_hash = Column(String, nullable=True) and delete the merge artifact
strings); ensure no other conflict markers remain in models.py and run a quick
import to verify syntax.


class PushSubscription(Base):
__tablename__ = "push_subscriptions"
Expand Down
15 changes: 14 additions & 1 deletion backend/routers/grievances.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from fastapi import APIRouter, Depends, HTTPException, Query, Request
from sqlalchemy.orm import Session, joinedload
from sqlalchemy import func
from sqlalchemy import func, case
from typing import List, Optional
import os
import json
import logging
from datetime import datetime, timezone

from backend.database import get_db
Emergency-and-High-Severity-#290
from backend.models import Grievance, EscalationAudit, SeverityLevel
from backend.models import Grievance, EscalationAudit, GrievanceFollower, ClosureConfirmation
main
Comment on lines +11 to +14
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unresolved merge conflict markers and duplicate imports — SyntaxError at startup.

Lines 11 and 14 are conflict remnants. Lines 12 and 13 are two separate imports from backend.models that should be merged into one after resolving the conflict.

🐛 Proposed fix
-  Emergency-and-High-Severity-#290
- from backend.models import Grievance, EscalationAudit, SeverityLevel
- from backend.models import Grievance, EscalationAudit, GrievanceFollower, ClosureConfirmation
-  main
+ from backend.models import Grievance, EscalationAudit, SeverityLevel, GrievanceFollower, ClosureConfirmation
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Emergency-and-High-Severity-#290
from backend.models import Grievance, EscalationAudit, SeverityLevel
from backend.models import Grievance, EscalationAudit, GrievanceFollower, ClosureConfirmation
main
from backend.models import Grievance, EscalationAudit, SeverityLevel, GrievanceFollower, ClosureConfirmation
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 11-11: Unexpected indentation

(invalid-syntax)


[warning] 11-11: Expected an identifier, but found a keyword and that cannot be used here

(invalid-syntax)


[warning] 11-12: Expected an expression

(invalid-syntax)


[warning] 12-12: Expected a statement

(invalid-syntax)


[warning] 14-14: Unexpected indentation

(invalid-syntax)

🤖 Prompt for AI Agents
In `@backend/routers/grievances.py` around lines 11 - 14, Remove the unresolved
merge conflict markers and duplicate import lines; replace the two separate
imports and the conflict text with a single cleaned import from backend.models
that includes Grievance, EscalationAudit, GrievanceFollower,
ClosureConfirmation, and SeverityLevel so there are no duplicate imports or
leftover conflict strings in the module (look for the existing import
occurrences referencing Grievance, EscalationAudit, SeverityLevel,
GrievanceFollower, ClosureConfirmation and the conflict markers like
"Emergency-and-High-Severity-#290" / "main" and remove them).

from backend.schemas import (
GrievanceSummaryResponse, EscalationAuditResponse, EscalationStatsResponse,
ResponsibilityMapResponse,
Expand Down Expand Up @@ -44,6 +47,16 @@ def get_grievances(
if category:
query = query.filter(Grievance.category == category)

# Priority Queue Logic: Sort by Severity (Critical > High > Medium > Low) then by Date (Oldest first for resolution)
severity_order = case(
(Grievance.severity == SeverityLevel.CRITICAL, 1),
(Grievance.severity == SeverityLevel.HIGH, 2),
(Grievance.severity == SeverityLevel.MEDIUM, 3),
(Grievance.severity == SeverityLevel.LOW, 4),
else_=5
)
query = query.order_by(severity_order.asc(), Grievance.created_at.asc())

grievances = query.offset(offset).limit(limit).all()

# Convert to response format
Expand Down
21 changes: 21 additions & 0 deletions backend/routers/issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ async def create_issue(
background_tasks: BackgroundTasks,
description: str = Form(..., min_length=10, max_length=1000),
category: str = Form(..., pattern=f"^({'|'.join([cat.value for cat in IssueCategory])})$"),
severity: str = Form('medium', pattern="^(low|medium|high|critical)$"),
language: str = Form('en'),
user_email: str = Form(None),
latitude: float = Form(None, ge=-90, le=90),
Expand Down Expand Up @@ -187,7 +188,10 @@ async def create_issue(
longitude=longitude,
location=location,
action_plan=None,
Emergency-and-High-Severity-#290
severity=severity
integrity_hash=integrity_hash
main
Comment on lines +191 to +194
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unresolved merge conflict markers in Issue constructor — SyntaxError.

Lines 191 and 194 are conflict remnants. Additionally, line 192 (severity=severity) is missing a trailing comma before integrity_hash=integrity_hash on line 193.

🐛 Proposed fix
             action_plan=None,
-        Emergency-and-High-Severity-#290
-                severity=severity
-                integrity_hash=integrity_hash
-         main
+                severity=severity,
+                integrity_hash=integrity_hash,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Emergency-and-High-Severity-#290
severity=severity
integrity_hash=integrity_hash
main
action_plan=None,
severity=severity,
integrity_hash=integrity_hash,
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 191-192: Expected a parameter name

(invalid-syntax)


[warning] 191-191: Expected an identifier, but found a keyword and that cannot be used here

(invalid-syntax)


[warning] 193-193: Expected ,, found name

(invalid-syntax)


[warning] 194-194: Expected ,, found name

(invalid-syntax)

🤖 Prompt for AI Agents
In `@backend/routers/issues.py` around lines 191 - 194, The Issue constructor call
contains leftover merge conflict markers and a missing comma causing a
SyntaxError: remove the conflict marker lines
("Emergency-and-High-Severity-#290" and "main") so the call is clean, and add
the missing comma after the severity=severity argument so the arguments read
..., severity=severity, integrity_hash=integrity_hash ...; update the code where
the Issue is constructed to ensure only valid keyword arguments remain and the
commas separate them correctly.

)

# Offload blocking DB operations to threadpool
Expand Down Expand Up @@ -592,6 +596,22 @@ def get_recent_issues(

# Convert to Pydantic models for validation and serialization
data = []
Emergency-and-High-Severity-#290
for i in issues:
data.append(IssueSummaryResponse(
id=i.id,
category=i.category,
description=i.description[:100] + "..." if len(i.description) > 100 else i.description,
created_at=i.created_at,
image_path=i.image_path,
status=i.status,
upvotes=i.upvotes if i.upvotes is not None else 0,
location=i.location,
latitude=i.latitude,
longitude=i.longitude,
severity=i.severity.value if hasattr(i.severity, 'value') else i.severity
# action_plan is deferred and excluded
).model_dump(mode='json'))
for row in results:
# Manually construct dict from named tuple row to avoid full object overhead
desc = row.description or ""
Expand All @@ -609,6 +629,7 @@ def get_recent_issues(
"latitude": row.latitude,
"longitude": row.longitude
})
main

# Thread-safe cache update
recent_issues_cache.set(data, cache_key)
Expand Down
8 changes: 8 additions & 0 deletions backend/schemas.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,17 @@ class IssueSummaryResponse(BaseModel):
location: Optional[str] = None
latitude: Optional[float] = None
longitude: Optional[float] = None
Emergency-and-High-Severity-#290
severity: Optional[str] = "medium"
action_plan: Optional[Any] = None

model_config = ConfigDict(from_attributes=True)

model_config = ConfigDict(from_attributes=True)

class IssueResponse(IssueSummaryResponse):
action_plan: Optional[Union[Dict[str, Any], Any]] = Field(None, description="Generated action plan")
main
Comment on lines +47 to +57
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Unresolved merge conflict markers and duplicate model_config — will cause SyntaxError.

Lines 47 and 57 are leftover branch markers. Additionally, after removing them, model_config would be declared twice (lines 51 and 53). Keep only one.

🐛 Proposed fix
     latitude: Optional[float] = None
     longitude: Optional[float] = None
-      Emergency-and-High-Severity-#290
     severity: Optional[str] = "medium"
     action_plan: Optional[Any] = None
 
     model_config = ConfigDict(from_attributes=True)
 
-    model_config = ConfigDict(from_attributes=True)
-
 class IssueResponse(IssueSummaryResponse):
     action_plan: Optional[Union[Dict[str, Any], Any]] = Field(None, description="Generated action plan")
-     main
🧰 Tools
🪛 Ruff (0.14.14)

[warning] 47-47: Unexpected indentation

(invalid-syntax)


[warning] 47-47: Expected an identifier, but found a keyword and that cannot be used here

(invalid-syntax)


[warning] 47-48: Expected an expression

(invalid-syntax)


[warning] 55-55: Expected a statement

(invalid-syntax)


[warning] 57-57: Unexpected indentation

(invalid-syntax)

🤖 Prompt for AI Agents
In `@backend/schemas.py` around lines 47 - 57, Remove the leftover merge markers
("Emergency-and-High-Severity-#290" and "main") and the stray token so the file
parses; then eliminate the duplicate model_config declaration leaving a single
model_config = ConfigDict(from_attributes=True) in the class (or module) scope,
and ensure IssueResponse (which subclasses IssueSummaryResponse) has only the
intended field declarations (action_plan) with correct indentation and no
extraneous tokens.


class IssueCreateRequest(BaseModel):
description: str = Field(..., min_length=10, max_length=1000, description="Issue description")
Expand All @@ -57,6 +63,7 @@ class IssueCreateRequest(BaseModel):
latitude: Optional[float] = Field(None, ge=-90, le=90, description="Latitude coordinate")
longitude: Optional[float] = Field(None, ge=-180, le=180, description="Longitude coordinate")
location: Optional[str] = Field(None, max_length=200, description="Location description")
severity: Optional[str] = Field("medium", pattern="^(low|medium|high|critical)$", description="Severity level")

@field_validator('description')
@classmethod
Expand Down Expand Up @@ -156,6 +163,7 @@ class NearbyIssueResponse(BaseModel):
upvotes: int = Field(..., description="Number of upvotes")
created_at: datetime = Field(..., description="Issue creation timestamp")
status: str = Field(..., description="Issue status")
severity: str = Field(default="medium", description="Issue severity")


class DeduplicationCheckResponse(BaseModel):
Expand Down
11 changes: 11 additions & 0 deletions backend/sla_config_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ def get_sla_hours(self, severity: SeverityLevel, jurisdiction_level: Jurisdictio
return sla_config.sla_hours

# Return default
# Return default based on severity if available
severity_defaults = {
SeverityLevel.CRITICAL: 6,
SeverityLevel.HIGH: 24,
SeverityLevel.MEDIUM: 48,
SeverityLevel.LOW: 72
}

if severity in severity_defaults:
return severity_defaults[severity]

return self.default_sla_hours

finally:
Expand Down
15 changes: 14 additions & 1 deletion backend/tasks.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import logging
import json
import os
import hashlib
from pywebpush import webpush, WebPushException
from backend.database import SessionLocal
from backend.models import Issue, PushSubscription
Expand Down Expand Up @@ -59,7 +60,19 @@ async def create_grievance_from_issue_background(issue_id: int):
'vandalism': 'medium'
}

severity = severity_mapping.get(issue.category.lower(), 'medium')
# Prefer issue's own severity if set, otherwise fallback to mapping
if hasattr(issue, 'severity') and issue.severity:
severity = issue.severity.value if hasattr(issue.severity, 'value') else issue.severity
else:
severity = severity_mapping.get(issue.category.lower(), 'medium')

# Check for immediate escalation triggers (e.g. Critical severity)
if severity == 'critical':
# Log critical issue with safe identifiers only (no PII)
description_text = issue.description or ""
desc_hash = hashlib.sha256(description_text.encode('utf-8')).hexdigest()[:12]
logger.warning(f"CRITICAL ISSUE REPORTED: ID={issue.id} [Hash={desc_hash}]")
# Here we could trigger immediate SMS/Call alerts or specialized notifications

# Create grievance data
grievance_data = {
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@
"civicServices": "Civic Services",
"management": "Management"
},
"urgent": "URGENT",
"issues": {
"noise": "Noise",
"crowd": "Crowd",
"waterLeak": "Water Leak",
"wasteSorter": "Waste Sorter",
"civicEye": "Civic Eye",
"pothole": "Pothole",
"blockedRoad": "Blocked Road",
"illegalParking": "Illegal Parking",
Expand Down
Loading