"""Attachment operations for JIRA."""
import logging
from typing import Any, Dict, List
from jira.exceptions import JIRAError
from mcp_jira.client import JiraClient
logger = logging.getLogger(__name__)
class AttachmentOperations:
"""Handles JIRA attachment operations."""
def __init__(self, client: JiraClient):
"""Initialize attachment operations.
Args:
client: JiraClient instance
"""
self.client = client
def add_attachment(
self,
issue_key: str,
attachment: str,
filename: str = None,
) -> Dict[str, Any]:
"""Add an attachment to an issue.
Args:
issue_key: Issue key
attachment: File path or file-like object
filename: Optional filename (used if attachment is file-like object)
Returns:
Dictionary with attachment information
Raises:
JIRAError: If attachment upload fails
"""
try:
jira = self.client.jira
logger.info(f"Adding attachment to issue {issue_key}")
result = jira.add_attachment(
issue=issue_key,
attachment=attachment,
filename=filename,
)
# Result is a list of attachments
if isinstance(result, list) and result:
att = result[0]
return {
"id": att.id,
"filename": att.filename,
"size": att.size,
"mime_type": att.mimeType if hasattr(att, "mimeType") else None,
"created": att.created if hasattr(att, "created") else None,
"author": att.author.displayName if hasattr(att, "author") else None,
}
return {"uploaded": True, "issue_key": issue_key}
except JIRAError as e:
logger.error(f"Failed to add attachment to {issue_key}: {e}")
raise
def get_attachments(
self,
issue_key: str,
) -> List[Dict[str, Any]]:
"""Get all attachments for an issue.
Args:
issue_key: Issue key
Returns:
List of attachments
Raises:
JIRAError: If retrieval fails
"""
try:
jira = self.client.jira
logger.info(f"Getting attachments for issue {issue_key}")
issue = jira.issue(issue_key)
attachments = issue.fields.attachment
return [
{
"id": att.id,
"filename": att.filename,
"size": att.size,
"mime_type": att.mimeType if hasattr(att, "mimeType") else None,
"created": att.created if hasattr(att, "created") else None,
"author": att.author.displayName if hasattr(att, "author") else None,
"content_url": att.content if hasattr(att, "content") else None,
}
for att in attachments
]
except JIRAError as e:
logger.error(f"Failed to get attachments for {issue_key}: {e}")
raise
def delete_attachment(
self,
attachment_id: str,
) -> Dict[str, Any]:
"""Delete an attachment.
Args:
attachment_id: Attachment ID
Returns:
Dictionary with deletion result
Raises:
JIRAError: If deletion fails
"""
try:
jira = self.client.jira
logger.info(f"Deleting attachment {attachment_id}")
# Use the internal API to delete attachment
jira._session.delete(
f"{jira._options['server']}/rest/api/latest/attachment/{attachment_id}"
)
return {
"id": attachment_id,
"deleted": True,
}
except JIRAError as e:
logger.error(f"Failed to delete attachment {attachment_id}: {e}")
raise