Skip to content

Commit

Permalink
Add attachments (#12)
Browse files Browse the repository at this point in the history
Closes #10

Added all attachment methods
  • Loading branch information
Olegt0rr authored Aug 25, 2023
2 parents 93caf7c + 8bbcb6e commit 2712813
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 4 deletions.
52 changes: 52 additions & 0 deletions examples/attachments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import asyncio
from pathlib import Path

from yatracker import YaTracker

# CAUTION! Don't store credentials in your code!
ORG_ID = ...
TOKEN = ...
FILE_PATH = ...
FILE_NAME = ...


async def main() -> None:
"""Run basic example.
This way you may create, get and edit an issue.
"""
# define tracker (once)
tracker = YaTracker(ORG_ID, TOKEN)

# upload temp file
with Path.open(FILE_PATH, "rb") as file:
attachment = await tracker.upload_temp_file(file, FILE_NAME)

# create an issue with attachment
issue = await tracker.create_issue(
summary="New Issue",
queue="KEY",
attachment_ids=[attachment.id],
)

# attach another one... or the same! :)
with Path.open(FILE_PATH, "rb") as file:
await tracker.attach_file(
issue_id=issue.id,
file=file,
filename=FILE_NAME,
)

# list attachments
attachments = await tracker.get_attachments(issue.id)

# and delete them all
for att in attachments:
await tracker.delete_attachment(issue.id, att.id)

# don't forget to close tracker on app shutdown (once)
await tracker.close()


if __name__ == "__main__":
asyncio.run(main())
2 changes: 2 additions & 0 deletions yatracker/tracker/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from .base import BaseTracker
from .categories import (
Attachments,
Comments,
Issues,
Priorities,
Expand All @@ -16,6 +17,7 @@ class YaTracker(
Issues,
Comments,
Priorities,
Attachments,
BaseTracker,
):
"""Represents Yandex Tracker API client.
Expand Down
2 changes: 2 additions & 0 deletions yatracker/tracker/categories/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from .attached_files import Attachments
from .comments import Comments
from .issues import Issues
from .priorities import Priorities

__all__ = [
"Attachments",
"Comments",
"Issues",
"Priorities",
Expand Down
112 changes: 112 additions & 0 deletions yatracker/tracker/categories/attached_files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
from __future__ import annotations

from typing import BinaryIO

from aiohttp import FormData

from yatracker.tracker.base import BaseTracker
from yatracker.types import Attachment


class Attachments(BaseTracker):
async def get_attachments(self, issue_id: str) -> list[Attachment]:
"""Get a list of files attached to an issue.
Source:
https://cloud.yandex.com/en/docs/tracker/concepts/issues/get-attachments-list
"""
data = await self._client.request(
method="GET",
uri=f"/issues/{issue_id}/attachments",
)
decoder = self._get_decoder(list[Attachment])
return decoder.decode(data)

async def download_attachment(
self,
issue_id: str,
attachment_id: str | int,
filename: str,
) -> bytes:
"""Download file attached to an issue.
Source:
https://cloud.yandex.com/en/docs/tracker/concepts/issues/get-attachment
"""
return await self._client.request(
method="GET",
uri=f"/issues/{issue_id}/attachments/{attachment_id}/{filename}",
)

async def download_thumbnail(
self,
issue_id: str,
attachment_id: str | int,
) -> bytes:
"""Get thumbnails of image files attached to issues.
Source:
https://cloud.yandex.com/en/docs/tracker/concepts/issues/get-attachment-preview
"""
return await self._client.request(
method="GET",
uri=f"/issues/{issue_id}/thumbnails/{attachment_id}",
)

async def attach_file(
self,
issue_id: str,
file: BinaryIO,
filename: str | None = None,
) -> Attachment:
"""Attach a file to an issue.
Source:
https://cloud.yandex.com/en/docs/tracker/concepts/issues/post-attachment
"""
form = FormData()
form.add_field("file_data", file)
data = await self._client.request(
method="POST",
uri=f"/issues/{issue_id}/attachments",
params={"filename": filename} if filename else None,
form=form,
)
decoder = self._get_decoder(Attachment)
return decoder.decode(data)

async def upload_temp_file(
self,
file: BinaryIO,
filename: str | None = None,
) -> Attachment:
"""Upload temporary file.
Use this request to upload a file to Tracker first, and then
attach it when creating an issue or adding a comment.
Source:
https://cloud.yandex.com/en/docs/tracker/concepts/issues/temp-attachment
"""
form = FormData()
form.add_field("file_data", file)
data = await self._client.request(
method="POST",
uri="/attachments/",
params={"filename": filename} if filename else None,
form=form,
)
decoder = self._get_decoder(Attachment)
return decoder.decode(data)

async def delete_attachment(self, issue_id: str, attachment_id: str | int) -> bool:
"""Delete attached file.
Source:
https://cloud.yandex.com/en/docs/tracker/concepts/issues/delete-attachment
"""
await self._client.request(
method="DELETE",
uri=f"/issues/{issue_id}/attachments/{attachment_id}/",
)
return True
1 change: 1 addition & 0 deletions yatracker/tracker/categories/issues.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ async def create_issue(
priority: int | str | Priority | None = None,
followers: list[str] | None = None,
unique: str | None = None,
attachment_ids: list[str] | None = None,
**kwargs,
) -> FullIssue:
"""Create an issue."""
Expand Down
12 changes: 8 additions & 4 deletions yatracker/tracker/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,17 @@ async def request(
uri: str,
params: dict[str, Any] | None = None,
payload: dict[str, Any] | None = None,
form: FormData | None = None,
**kwargs,
) -> bytes:
"""Make request."""
bytes_payload = BytesPayload(
value=self._encoder.encode(payload),
content_type="application/json",
)
if form:
bytes_payload = form
else:
bytes_payload = BytesPayload(
value=self._encoder.encode(payload),
content_type="application/json",
)

# to support full links (e.g. Transition)
if not uri.startswith("http"):
Expand Down
2 changes: 2 additions & 0 deletions yatracker/types/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
__all__ = [
"Attachment",
"Comment",
"FullIssue",
"Issue",
Expand All @@ -12,6 +13,7 @@
"User",
]

from .attachment import Attachment
from .comment import Comment
from .full_issue import FullIssue
from .issue import Issue
Expand Down
28 changes: 28 additions & 0 deletions yatracker/types/attachment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from __future__ import annotations

__all__ = ["Attachment"]

from .base import Base, field
from .user import User


class Attachment(Base, kw_only=True, frozen=True):
"""Represents attachment object."""

url: str = field(name="self")
id: str
name: str
content: str
thumbnail: str | None = None
created_by: User
created_at: str
mimetype: str
size: int
metadata: Metadata | None = None
comment_id: str | None = None


class Metadata(Base, kw_only=True, frozen=True):
"""Represents attachment metadata."""

size: str | None = None

0 comments on commit 2712813

Please sign in to comment.