From 5d7403984d806f441da7f9385b16c6f4fc059bdc Mon Sep 17 00:00:00 2001 From: null Date: Wed, 20 May 2026 01:44:31 -0500 Subject: [PATCH] bug: (timestamp) git --- backend/app/api/forgejo_issues.py | 27 ++++++++++++++++++++-- backend/app/services/forgejo_client.py | 1 - backend/app/services/forgejo_issue_sync.py | 16 ++++++------- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/backend/app/api/forgejo_issues.py b/backend/app/api/forgejo_issues.py index eeb95c0..cce7d5b 100644 --- a/backend/app/api/forgejo_issues.py +++ b/backend/app/api/forgejo_issues.py @@ -6,6 +6,7 @@ from typing import TYPE_CHECKING from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query, status +from sqlalchemy import cast, String from sqlmodel import select, func from app.api.deps import get_board_for_user_write, require_org_member @@ -54,10 +55,23 @@ async def list_issues( if state: statement = statement.where(ForgejoIssue.state == state) + if label: + # Filter by label name — search within the JSON labels array cast to text + statement = statement.where( + cast(ForgejoIssue.labels, String).ilike(f"%{label}%") + ) + + if assignee: + # Filter by assignee login — search within the JSON assignees array cast to text + statement = statement.where( + cast(ForgejoIssue.assignees, String).ilike(f"%{assignee}%") + ) + if search: statement = statement.where( (ForgejoIssue.title.ilike(f"%{search}%")) | - (ForgejoIssue.body_preview.ilike(f"%{search}%")) + (ForgejoIssue.body_preview.ilike(f"%{search}%")) | + (ForgejoIssue.body.ilike(f"%{search}%")) ) # Count total @@ -70,10 +84,19 @@ async def list_issues( pass if state: total_statement = total_statement.where(ForgejoIssue.state == state) + if label: + total_statement = total_statement.where( + cast(ForgejoIssue.labels, String).ilike(f"%{label}%") + ) + if assignee: + total_statement = total_statement.where( + cast(ForgejoIssue.assignees, String).ilike(f"%{assignee}%") + ) if search: total_statement = total_statement.where( (ForgejoIssue.title.ilike(f"%{search}%")) | - (ForgejoIssue.body_preview.ilike(f"%{search}%")) + (ForgejoIssue.body_preview.ilike(f"%{search}%")) | + (ForgejoIssue.body.ilike(f"%{search}%")) ) total_result = await session.exec(total_statement) total = total_result.one() diff --git a/backend/app/services/forgejo_client.py b/backend/app/services/forgejo_client.py index b383522..88d56d3 100644 --- a/backend/app/services/forgejo_client.py +++ b/backend/app/services/forgejo_client.py @@ -198,7 +198,6 @@ class ForgejoAPIClient: List of repository dicts with name, full_name, owner, default_branch, etc. """ client = await self._get_client() - params = {"limit": limit, "page": page, "token": ""} response = await client.get("/api/v1/repos/search", params={"limit": limit, "page": page}) response.raise_for_status() data = response.json() diff --git a/backend/app/services/forgejo_issue_sync.py b/backend/app/services/forgejo_issue_sync.py index 77d3311..b23ecc3 100644 --- a/backend/app/services/forgejo_issue_sync.py +++ b/backend/app/services/forgejo_issue_sync.py @@ -112,9 +112,9 @@ class IssueSyncService: body_full = raw_body if raw_body else None body_preview = raw_body[:1000] if raw_body else None - # Parse dates - created_at = self._parse_iso_date(issue_data.get("created_at")) - updated_at = self._parse_iso_date(issue_data.get("updated_at")) + # Parse dates — required fields fall back to utcnow(), optional closed_at stays None + created_at = self._parse_iso_date(issue_data.get("created_at")) or utcnow() + updated_at = self._parse_iso_date(issue_data.get("updated_at")) or utcnow() closed_at = self._parse_iso_date(issue_data.get("closed_at")) # Check if issue exists @@ -234,15 +234,13 @@ class IssueSyncService: results = await self.session.exec(statement) return results.first() - def _parse_iso_date(self, date_str: str | None) -> datetime: - """Parse ISO format date string to datetime.""" + def _parse_iso_date(self, date_str: str | None) -> datetime | None: + """Parse ISO format date string to datetime. Returns None for absent/empty values.""" if not date_str: - return utcnow() + return None try: - # Handle Z suffix cleaned = date_str.replace("Z", "+00:00") parsed = datetime.fromisoformat(cleaned) - # Strip timezone info for naive UTC storage return parsed.replace(tzinfo=None) except (ValueError, AttributeError): - return utcnow() \ No newline at end of file + return None \ No newline at end of file