@@ -255,14 +255,68 @@ def get_attachment(self, attachment_id: T_id) -> T_resp_json:
255255 url = f"{ base_url } /{ attachment_id } "
256256 return self .get (url )
257257
258- def download_issue_attachments (self , issue : T_id , path : Optional [str ] = None ) -> Optional [str ]:
258+ def download_issue_attachments (
259+ self ,
260+ issue : str ,
261+ path : Optional [str ] = None ,
262+ overwrite : bool = False ,
263+ stream : bool = False ,
264+ block_size : Optional [int ] = 16384 ,
265+ timeout : Optional [int ] = None ,
266+ ) -> Optional [str ]:
259267 """
260268 Downloads all attachments from a Jira issue.
261269 :param issue: The issue-key of the Jira issue
262270 :param path: Path to directory where attachments will be saved. If None, current working directory will be used.
271+ :param overwrite: If True, always download and create new zip file.
272+ If False (default), download will be skipped when zip file already exists in path.
273+ :param stream: If True, request stream mode will be used to download and write files.
274+ If False (default), whole attachment content will be downloaded into memory first, then will be written to disk afterwards.
275+ :param block_size: Block size of each stream content chunks. This option is only applicable when stream=True is set.
276+ Default size of 16 KiB is used to balance speed and memory usage.
277+ Smaller value will decrease memory usage, but may also decrease download speed if too small.
278+ :param timeout: Request timeout parameter in seconds. None (default) will never cause timeout.
263279 :return: A message indicating the result of the download operation.
264280 """
265- return self .download_attachments_from_issue (issue = issue , path = path , cloud = self .cloud )
281+ try :
282+ if path is None :
283+ path = os .getcwd ()
284+ issue_id = self .issue (issue , fields = "id" )["id" ]
285+ attachment_name = f"{ issue_id } _attachments.zip"
286+ file_path = os .path .join (path , attachment_name )
287+ if not overwrite and os .path .isfile (file_path ):
288+ return "File already exists"
289+
290+ if self .cloud :
291+ url = self .url + f"/secure/issueAttachments/{ issue_id } .zip"
292+ else :
293+ url = self .url + f"/secure/attachmentzip/{ issue_id } .zip"
294+ response = self ._session .get (url , stream = stream , timeout = timeout )
295+ response .raise_for_status ()
296+
297+ # if Jira issue doesn't have any attachments _session.get
298+ # request response will return 22 bytes of PKzip format
299+ file_size = int (response .headers .get ("Content-Length" , 0 ))
300+ if file_size == 22 :
301+ return "No attachments found on the Jira issue"
302+
303+ with open (file_path , "wb" ) as file :
304+ if not stream :
305+ file .write (response .content )
306+ else :
307+ for data in response .iter_content (block_size ):
308+ file .write (data )
309+
310+ return "Attachments downloaded successfully"
311+
312+ except FileNotFoundError :
313+ raise FileNotFoundError ("Verify if directory path is correct and/or if directory exists" )
314+ except PermissionError :
315+ raise PermissionError (
316+ "Directory found, but there is a problem with saving file to this directory. Check directory permissions"
317+ )
318+ except Exception as e :
319+ raise e
266320
267321 @deprecated (version = "3.41.20" , reason = "Use download_issue_attachments instead" )
268322 def download_attachments_from_issue (
0 commit comments