""" Export service - business logic for data export and formatting operations. """ import json from typing import List, Dict, Any, Optional from datetime import datetime from gitea.models import Issue from .issue_service import IssueService class ExportService: """Service for export and data formatting operations.""" def __init__(self): self.issue_service = IssueService() def get_issues_data(self, state: str = "all", sort_by: str = "number", filter_state: Optional[str] = None, filter_priority: Optional[str] = None, include_state: bool = False) -> List[Dict[str, Any]]: """Get structured issue data for export. Args: state: Issue state filter (all, open, closed) sort_by: Sort field (number, title, priority, state, created, updated) filter_state: Additional state filter (open, closed) filter_priority: Priority filter (low, medium, high, critical, none) include_state: Whether to include detailed state information Returns: List of issue data dictionaries """ issues = self.issue_service.list_issues(state) # Convert to structured data issue_data = [] for issue in issues: # Get priority and state from labels priority = issue.priority or "none" status = issue.status or "none" issue_info = { 'number': issue.number, 'title': issue.title.replace('\t', ' ').replace('\n', ' '), # Clean for TSV 'priority': priority, 'state': issue.state, # open/closed from basic data 'status': status, # detailed status from labels 'created': issue.created_at.strftime('%Y-%m-%d'), 'updated': issue.updated_at.strftime('%Y-%m-%d') } issue_data.append(issue_info) # Apply filters if filter_state: if filter_state == "open": issue_data = [i for i in issue_data if i['state'] == 'open'] elif filter_state == "closed": issue_data = [i for i in issue_data if i['state'] == 'closed'] if filter_priority: issue_data = [i for i in issue_data if i['priority'] == filter_priority] # Sort issues sort_key_map = { 'number': lambda x: x['number'], 'title': lambda x: x['title'].lower(), 'priority': lambda x: {'critical': 4, 'high': 3, 'medium': 2, 'low': 1, 'none': 0}[x['priority']], 'state': lambda x: x['state'], 'created': lambda x: x['created'], 'updated': lambda x: x['updated'] } if sort_by in sort_key_map: issue_data.sort(key=sort_key_map[sort_by], reverse=(sort_by in ['number', 'priority', 'created', 'updated'])) return issue_data def format_issues_tsv(self, issue_data: List[Dict[str, Any]], include_state: bool = False) -> str: """Format issues as TSV.""" lines = [] for issue in issue_data: if include_state: lines.append(f'{issue["number"]}\t{issue["title"]}\t{issue["priority"]}\t{issue["state"]}\t{issue["created"]}\t{issue["updated"]}') else: lines.append(f'{issue["number"]}\t{issue["title"]}\t{issue["priority"]}\t{issue["created"]}\t{issue["updated"]}') return '\n'.join(lines) def format_issues_csv(self, issue_data: List[Dict[str, Any]], include_state: bool = False) -> str: """Format issues as CSV.""" lines = [] # Header if include_state: lines.append("number,title,priority,state,created,updated") for issue in issue_data: title = issue['title'].replace('"', '""') # Escape quotes lines.append(f'{issue["number"]},"{title}",{issue["priority"]},{issue["state"]},{issue["created"]},{issue["updated"]}') else: lines.append("number,title,priority,created,updated") for issue in issue_data: title = issue['title'].replace('"', '""') lines.append(f'{issue["number"]},"{title}",{issue["priority"]},{issue["created"]},{issue["updated"]}') return '\n'.join(lines) def format_issues_json(self, issue_data: List[Dict[str, Any]]) -> str: """Format issues as JSON.""" return json.dumps(issue_data, indent=2) def format_issues_fields(self, issue_data: List[Dict[str, Any]], include_state: bool = False) -> str: """Format issues as space-separated fields for awk processing.""" lines = [] # Header if include_state: lines.append("NUMBER TITLE PRIORITY STATE CREATED UPDATED") for issue in issue_data: title = issue['title'].replace(' ', '_') lines.append(f'{issue["number"]} {title} {issue["priority"]} {issue["state"]} {issue["created"]} {issue["updated"]}') else: lines.append("NUMBER TITLE PRIORITY CREATED UPDATED") for issue in issue_data: title = issue['title'].replace(' ', '_') lines.append(f'{issue["number"]} {title} {issue["priority"]} {issue["created"]} {issue["updated"]}') return '\n'.join(lines) def export_issues(self, format_type: str = "tsv", **kwargs) -> str: """Export issues in specified format. Args: format_type: Output format (tsv, csv, json, fields) **kwargs: Export parameters (sort_by, filter_state, etc.) Returns: Formatted string output """ issue_data = self.get_issues_data(**kwargs) if format_type == "json": return self.format_issues_json(issue_data) elif format_type == "csv": return self.format_issues_csv(issue_data, kwargs.get('include_state', False)) elif format_type == "fields": return self.format_issues_fields(issue_data, kwargs.get('include_state', False)) else: # Default TSV return self.format_issues_tsv(issue_data, kwargs.get('include_state', False))