bug: (timestamp) git
This commit is contained in:
parent
ad5ca38a86
commit
5d7403984d
|
|
@ -6,6 +6,7 @@ from typing import TYPE_CHECKING
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||||
|
from sqlalchemy import cast, String
|
||||||
from sqlmodel import select, func
|
from sqlmodel import select, func
|
||||||
|
|
||||||
from app.api.deps import get_board_for_user_write, require_org_member
|
from app.api.deps import get_board_for_user_write, require_org_member
|
||||||
|
|
@ -54,10 +55,23 @@ async def list_issues(
|
||||||
if state:
|
if state:
|
||||||
statement = statement.where(ForgejoIssue.state == 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:
|
if search:
|
||||||
statement = statement.where(
|
statement = statement.where(
|
||||||
(ForgejoIssue.title.ilike(f"%{search}%")) |
|
(ForgejoIssue.title.ilike(f"%{search}%")) |
|
||||||
(ForgejoIssue.body_preview.ilike(f"%{search}%"))
|
(ForgejoIssue.body_preview.ilike(f"%{search}%")) |
|
||||||
|
(ForgejoIssue.body.ilike(f"%{search}%"))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Count total
|
# Count total
|
||||||
|
|
@ -70,10 +84,19 @@ async def list_issues(
|
||||||
pass
|
pass
|
||||||
if state:
|
if state:
|
||||||
total_statement = total_statement.where(ForgejoIssue.state == 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:
|
if search:
|
||||||
total_statement = total_statement.where(
|
total_statement = total_statement.where(
|
||||||
(ForgejoIssue.title.ilike(f"%{search}%")) |
|
(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_result = await session.exec(total_statement)
|
||||||
total = total_result.one()
|
total = total_result.one()
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,6 @@ class ForgejoAPIClient:
|
||||||
List of repository dicts with name, full_name, owner, default_branch, etc.
|
List of repository dicts with name, full_name, owner, default_branch, etc.
|
||||||
"""
|
"""
|
||||||
client = await self._get_client()
|
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 = await client.get("/api/v1/repos/search", params={"limit": limit, "page": page})
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
data = response.json()
|
data = response.json()
|
||||||
|
|
|
||||||
|
|
@ -112,9 +112,9 @@ class IssueSyncService:
|
||||||
body_full = raw_body if raw_body else None
|
body_full = raw_body if raw_body else None
|
||||||
body_preview = raw_body[:1000] if raw_body else None
|
body_preview = raw_body[:1000] if raw_body else None
|
||||||
|
|
||||||
# Parse dates
|
# Parse dates — required fields fall back to utcnow(), optional closed_at stays None
|
||||||
created_at = self._parse_iso_date(issue_data.get("created_at"))
|
created_at = self._parse_iso_date(issue_data.get("created_at")) or utcnow()
|
||||||
updated_at = self._parse_iso_date(issue_data.get("updated_at"))
|
updated_at = self._parse_iso_date(issue_data.get("updated_at")) or utcnow()
|
||||||
closed_at = self._parse_iso_date(issue_data.get("closed_at"))
|
closed_at = self._parse_iso_date(issue_data.get("closed_at"))
|
||||||
|
|
||||||
# Check if issue exists
|
# Check if issue exists
|
||||||
|
|
@ -234,15 +234,13 @@ class IssueSyncService:
|
||||||
results = await self.session.exec(statement)
|
results = await self.session.exec(statement)
|
||||||
return results.first()
|
return results.first()
|
||||||
|
|
||||||
def _parse_iso_date(self, date_str: str | None) -> datetime:
|
def _parse_iso_date(self, date_str: str | None) -> datetime | None:
|
||||||
"""Parse ISO format date string to datetime."""
|
"""Parse ISO format date string to datetime. Returns None for absent/empty values."""
|
||||||
if not date_str:
|
if not date_str:
|
||||||
return utcnow()
|
return None
|
||||||
try:
|
try:
|
||||||
# Handle Z suffix
|
|
||||||
cleaned = date_str.replace("Z", "+00:00")
|
cleaned = date_str.replace("Z", "+00:00")
|
||||||
parsed = datetime.fromisoformat(cleaned)
|
parsed = datetime.fromisoformat(cleaned)
|
||||||
# Strip timezone info for naive UTC storage
|
|
||||||
return parsed.replace(tzinfo=None)
|
return parsed.replace(tzinfo=None)
|
||||||
except (ValueError, AttributeError):
|
except (ValueError, AttributeError):
|
||||||
return utcnow()
|
return None
|
||||||
Loading…
Reference in New Issue