snapshot of https://github.com/makeplane/plane.git @ d868349a55de79979eb8b98701bf1702c67ad634 (2026-09-15)
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled
This commit is contained in:
107
apps/api/plane/utils/porters/exporter.py
Normal file
107
apps/api/plane/utils/porters/exporter.py
Normal file
@@ -0,0 +1,107 @@
|
||||
# Copyright (c) 2023-present Plane Software, Inc. and contributors
|
||||
# SPDX-License-Identifier: AGPL-3.0-only
|
||||
# See the LICENSE file for details.
|
||||
|
||||
from typing import Dict, List, Union
|
||||
from .formatters import BaseFormatter, CSVFormatter, JSONFormatter, XLSXFormatter
|
||||
|
||||
|
||||
class DataExporter:
|
||||
"""
|
||||
Export data using DRF serializers with built-in format support.
|
||||
|
||||
Usage:
|
||||
# New simplified interface
|
||||
exporter = DataExporter(BookSerializer, format_type='csv')
|
||||
filename, content = exporter.export('books_export', queryset)
|
||||
|
||||
# Legacy interface (still supported)
|
||||
exporter = DataExporter(BookSerializer)
|
||||
csv_string = exporter.to_string(queryset, CSVFormatter())
|
||||
"""
|
||||
|
||||
# Available formatters
|
||||
FORMATTERS = {
|
||||
"csv": CSVFormatter,
|
||||
"json": JSONFormatter,
|
||||
"xlsx": XLSXFormatter,
|
||||
}
|
||||
|
||||
def __init__(self, serializer_class, format_type: str = None, **serializer_kwargs):
|
||||
"""
|
||||
Initialize exporter with serializer and optional format type.
|
||||
|
||||
Args:
|
||||
serializer_class: DRF serializer class to use for data serialization
|
||||
format_type: Optional format type (csv, json, xlsx). If provided, enables export() method.
|
||||
**serializer_kwargs: Additional kwargs to pass to serializer
|
||||
"""
|
||||
self.serializer_class = serializer_class
|
||||
self.serializer_kwargs = serializer_kwargs
|
||||
self.format_type = format_type
|
||||
self.formatter = None
|
||||
|
||||
if format_type:
|
||||
if format_type not in self.FORMATTERS:
|
||||
raise ValueError(f"Unsupported format: {format_type}. Available: {list(self.FORMATTERS.keys())}")
|
||||
# Create formatter with default options
|
||||
self.formatter = self._create_formatter(format_type)
|
||||
|
||||
def _create_formatter(self, format_type: str) -> BaseFormatter:
|
||||
"""Create formatter instance with appropriate options."""
|
||||
formatter_class = self.FORMATTERS[format_type]
|
||||
|
||||
# Apply format-specific options
|
||||
if format_type == "xlsx":
|
||||
return formatter_class(list_joiner=", ")
|
||||
else:
|
||||
return formatter_class()
|
||||
|
||||
def serialize(self, queryset) -> List[Dict]:
|
||||
"""QuerySet → list of dicts"""
|
||||
serializer = self.serializer_class(
|
||||
queryset,
|
||||
many=True,
|
||||
**self.serializer_kwargs
|
||||
)
|
||||
return serializer.data
|
||||
|
||||
def export(self, filename: str, queryset) -> tuple[str, Union[str, bytes]]:
|
||||
"""
|
||||
Export queryset to file with configured format.
|
||||
|
||||
Args:
|
||||
filename: Base filename (without extension)
|
||||
queryset: Django QuerySet to export
|
||||
|
||||
Returns:
|
||||
Tuple of (filename_with_extension, content)
|
||||
|
||||
Raises:
|
||||
ValueError: If format_type was not provided during initialization
|
||||
"""
|
||||
if not self.formatter:
|
||||
raise ValueError("format_type must be provided during initialization to use export() method")
|
||||
|
||||
data = self.serialize(queryset)
|
||||
content = self.formatter.encode(data)
|
||||
full_filename = f"{filename}.{self.formatter.extension}"
|
||||
|
||||
return full_filename, content
|
||||
|
||||
def to_string(self, queryset, formatter: BaseFormatter) -> Union[str, bytes]:
|
||||
"""Export to formatted string (legacy interface)"""
|
||||
data = self.serialize(queryset)
|
||||
return formatter.encode(data)
|
||||
|
||||
def to_file(self, queryset, filepath: str, formatter: BaseFormatter) -> str:
|
||||
"""Export to file (legacy interface)"""
|
||||
content = self.to_string(queryset, formatter)
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
return filepath
|
||||
|
||||
@classmethod
|
||||
def get_available_formats(cls) -> List[str]:
|
||||
"""Get list of available export formats."""
|
||||
return list(cls.FORMATTERS.keys())
|
||||
Reference in New Issue
Block a user