JIRA Python add_attachment() 405 Method Not Allowed - python

I am trying to upload a file to JIRA via its REST API using the python lib found here: jira python documentation
It seems pretty straight forward I wrote a method that allows me to pass an issue and then it attaches a filename. and one that lets me retrieve an issue from JIRA.
from jira.client import JIRA
class JIRAReport (object):
def attach(self,issue):
print 'Attaching... '
attachment = self.jira.add_attachment(issue, attachment=self.reportpath, filename='Report.xlsx')
print 'Success!'
def getissue(self):
if not self.issue == None:
return self.jira.issue(self.issue)
return None
then in my main script I am getting the issue and attaching the file to an issue I retrieved from JIRA
report = JiraReport()
report.issue = 'ProjectKey-1'
report.reportpath = '../report_upload/tmp/' + filename
issue = report.getissue()
if not issue == None:
report.attach(issue)
else:
print "No Issue with Key Found"
I am able to get the issue/create issues if needed but when using the self.jira.add_attachment() method I am getting 405 Method Not Allowed.
The file exists and is able to be opened.
Here is the add_attachment() method from the source code:
def add_attachment(self, issue, attachment, filename=None):
"""
Attach an attachment to an issue and returns a Resource for it.
The client will *not* attempt to open or validate the attachment; it expects a file-like object to be ready
for its use. The user is still responsible for tidying up (e.g., closing the file, killing the socket, etc.)
:param issue: the issue to attach the attachment to
:param attachment: file-like object to attach to the issue, also works if it is a string with the filename.
:param filename: optional name for the attached file. If omitted, the file object's ``name`` attribute
is used. If you aquired the file-like object by any other method than ``open()``, make sure
that a name is specified in one way or the other.
:rtype: an Attachment Resource
"""
if isinstance(attachment, string_types):
attachment = open(attachment, "rb")
# TODO: Support attaching multiple files at once?
url = self._get_url('issue/' + str(issue) + '/attachments')
fname = filename
if not fname:
fname = os.path.basename(attachment.name)
content_type = mimetypes.guess_type(fname)[0]
if not content_type:
content_type = 'application/octet-stream'
files = {
'file': (fname, attachment, content_type)
}
r = self._session.post(url, files=files, headers=self._options['headers'])
raise_on_error(r)
attachment = Attachment(self._options, self._session, json.loads(r.text)[0])
return attachment

It is mentioned in documentation that as a argument they expect file-like object.
Try to do something like :
file_obj = open('test.txt','rb')
jira.add_attachment(issue,file_obj,'test.txt')
file_obj.close()

Check that the URL that you are specifying for JIRA (if using the on-demand service) is https://instance.atlassian.net.
I just hit this as well, and it sends a POST request to http://instance.atlassian.net and gets redirected to https://instance.atlassian.net, but the client sends a GET request to the redirected address (see: https://softwareengineering.stackexchange.com/questions/99894/why-doesnt-http-have-post-redirect for more information)

Related

Sending message with attachment in email BytesIO doesn't work - No errors shown - Python/Smtp/Email

I am trying to add attachment to the object created below and stored as email. It's all done within a class and this is how the class is initialised:
class <name>:
def __init__(self, **kwargs):
self.msg = kwargs.get("msg", MIMEMultipart())
self.subject = kwargs.get("subject", None)
self.body = kwargs.get("body", None)
self.attachment = kwargs.get("attachment", None)
Attachment is not being sent
The attachments works fine as long as the attachment is of the type str. Add other functionalities of adding body, subject, etc. works fine.
When I pass a BytesIO() type object, the mail gets sent without any errors or warnings, but the attachment is not being sent.
for i ,attachment in enumerate(self.attachment,start=1):
p = MIMEBase('application', 'octet-stream')
if isinstance(attachment, str):
p.set_payload(open(attachment,"rb").read())
else:
p.set_payload((attachment).read())
encoders.encode_base64(p)
p.add_header('Content-Disposition', "attachment", filename= f'attachment{i}.jpg')
self.msg.attach(p)
Why am I using BytesIO() in the first place?
Well, I am trying to send a QR Image, which is saved using
qr_img.save(BytesIO(),format="png")
I am trying to send the image generated from qrcode module without saving it locally.
Message is sent like this:
self.server.send_message(msg)
Where self.server is the smtplib.SMTP_SSL() object.
Any help is appreciated, thanks!
The issue was that the buffer values were not read using .read() method. Using the .getvalue() method instead worked for me.
Note: No errors are thrown when using .read().

Robot Framework: send binary data in POST request body with

I have a problem with getting my test running using Robot Framework and robotframework-requests. I need to send a POST request and a binary data in the body. I looked at this question already, but it's not really answered. Here's how my test case looks like:
Upload ${filename} file
Create Session mysession http://${ADDRESS}
${data} = Get Binary File ${filename}
&{headers} = Create Dictionary Content-Type=application/octet-stream Accept=application/octet-stream
${resp} = Post Request mysession ${CGIPath} data=${data} headers=&{headers}
[Return] ${resp.status_code} ${resp.text}
The problem is that my binary data is about 250MB. When the data is read with Get Binary File I see that memory consumption goes up to 2.x GB. A few seconds later when the Post Request is triggered my test is killed by OOM. I already looked at files parameter, but it seems it uses multipart encoding upload, which is not what I need.
My other thought was about passing open file handler directly to underlying requests library, but I guess that would require robotframework-request modification. Another idea is to fall back to curl for this test only.
Am I missing something in my test? What is the better way to address this?
I proceeded with the idea of robotframework-request modification and added this method
def post_request_binary(
self,
alias,
uri,
path=None,
params=None,
headers=None,
allow_redirects=None,
timeout=None):
session = self._cache.switch(alias)
redir = True if allow_redirects is None else allow_redirects
self._capture_output()
method_name = "post"
method = getattr(session, method_name)
with open(path, 'rb') as f:
resp = method(self._get_url(session, uri),
data=f,
params=self._utf8_urlencode(params),
headers=headers,
allow_redirects=allow_redirects,
timeout=self._get_timeout(timeout),
cookies=self.cookies,
verify=self.verify)
self._print_debug()
# Store the last session object
session.last_resp = resp
self.builtin.log(method_name + ' response: ' + resp.text, 'DEBUG')
return resp
I guess I can improve it a bit and create a pull request.

Upload multiple files using simple-salesforce python

I started learning SalesForce and developing apps using django.
I need assistance with uploading a file to salesforce, For that I read simple-salesforce and this that help to upload file using rest and SOAP api.
My question is how do I upload one or more files using simple-salesforce?
Here is the code block I use for uploading files.
def load_attachments(sf, new_attachments):
'''
Method to attach the Template from the Parent Case to each of the children.
#param: new_attachments the dictionary of child cases to the file name of the template
'''
url = "https://" + sf.get_forced_url() + ".my.salesforce.com/services/data/v29.0/sobjects/Attachment/"
bearer = "Bearer " + sf.get_session_id()
header = {'Content-Type': 'application/json', 'Authorization': bearer}
for each in new_attachments:
body = ""
long_name = str(new_attachments[each]).split(sep="\\")
short_name = long_name[len(long_name) - 1]
with open(new_attachments[each], "rb") as upload:
body = base64.b64encode(upload.read())
data = json.dumps({
'ParentId': each,
'Name': short_name,
'body': body
})
response = requests.post(url, headers=header, data=data)
print(response.text)
Basically, to send the file, you need to use the requests module and submit the file via a post transaction. The post transaction requires the URL to which the request is sent, the header information, and the data.
Here, sf is the instance of returned by the simple-salesforce initialization. Since my instance uses custom domains, I had to create my own function in simple-salesforce to handle that; I call it get_forced_url(). Note: The URL is may be different for you depending on which version you are using [the v29.0 portion may change].
Then I set up my bearer and header.
The next thing is a loop that submits a new attachment for each attachment in a map from Parent ID to the File I wish to upload. This is important to note, attachments must have a Parent Object so you need to know the ParentId. For each attachment, I blank out the body, create a long and short name for the attachment. Then the important part. On attachments, the actual data of the file is stored as a base-64 binary array. So the file must be opened as binary, hence the "rb" and then encoded to base-64.
Once the file has been parsed to base-64 binary, I build my json string where ParentId is the object ID of the parent object, the Name is the short name, and the body is the base-64 encoded string of data.
Then the file is submitted to the URL with the headers and data. Then I print the response so I could watch it happening.
To upload files, you only need simple-salesforce
Complete example, including creating Account, Contact and Case. Then attaching the file to Case.
#Create Account, Contact and Case
AccountID = sf.Account.create({'Name':'Test12','Phone':'987654321'})["id"]
ContactID = sf.Contact.create({'LastName':'Smith2','Email':'example3#example.com'})["id"]
CaseID = sf.Case.create({'AccountId':AccountID,'ContactId':ContactID,'Description':'Test4321','Subject':'Test4321'})
#Convert image to Base64
import json, base64
with open('test1.png', mode='rb') as file:
img = file.read()
image = base64.encodebytes(img).decode('utf-8')
#The simple example
sf.Attachment.create({'ParentId': CaseID["id"],'Name':'TestFile1','body': image,'ContentType':'image/png'})
And how to change the 'one-file' example to multiple files
sf.bulk.Attachment.insert([
{'ParentId': CaseID["id"],'Name':'TestFile2','body': image,'ContentType':'image/png'},
{'ParentId': CaseID["id"],'Name':'TestFile3','body': image,'ContentType':'image/png'},
{'ParentId': CaseID["id"],'Name':'TestFile4','body': image,'ContentType':'image/png'},
{'ParentId': CaseID["id"],'Name':'TestFile5','body': image,'ContentType':'image/png'},
{'ParentId': CaseID["id"],'Name':'TestFile6','body': image,'ContentType':'image/png'},
{'ParentId': CaseID["id"],'Name':'TestFile7','body': image,'ContentType':'image/png'},
{'ParentId': CaseID["id"],'Name':'TestFile8','body': image,'ContentType':'image/png'},
{'ParentId': CaseID["id"],'Name':'TestFile9','body': image,'ContentType':'image/png'}],batch_size=1000,use_serial=True)
(you know how to fix the rest)

Unable to upload file to Google cloud storage using python - get a 404 error

I am trying a upload a file to Google Cloud Storage via a python script but keep getting a 404 error! I am sure I am not trying to reference a non-available resource. My code snippet is:
uploadFile = open("testUploadFile.txt", "r")
httpObj = httplib.HTTPSConnection("googleapis.com", timeout = 10)
httpObj.request("PUT", requestString, uploadFile, headerString)
uploadResponse = httpObj.getresponse()
print "Request string is:" + requestString
print "Return status:" + str(uploadResponse.status)
print "Reason:" + str(uploadResponse.reason)
Where
requestString = /upload/storage/v1beta2/b/bucket_id_12345678/o?uploadType=resumable&name=1%2FtestUploadFile.txt%7Calm_1391258335&upload_id=AbCd-1234
headerString = {'Content-Length': '47', 'Content-Type': 'text/plain'}
Any idea where I'm going wrong?
If you're doing a resumable upload, you'll need to start with a POST as described here: https://developers.google.com/storage/docs/json_api/v1/how-tos/upload#resumable
However, for a 47-byte object, you can use a simple upload, which will be much ... simpler. Instructions are here:
https://developers.google.com/storage/docs/json_api/v1/how-tos/upload#simple
It should be easy enough for you to replace the appropriate lines in your code with:
httpObj.request("POST", requestString, uploadFile, headerString)
requestString = /upload/storage/v1beta2/b/bucket_id_12345678/o?uploadType=media&name=1%2FtestUploadFile.txt%7Calm_1391258335
As an aside, in your code, headerString is actually a dict, not a string.

How do I return the Instagram Realtime subscription challenge?

I'm trying to subscribe to a tag. It appears that the callback URL is being called correctly with a hub.challenge and hub.mode, and I figured out how to access the challenge using self.request.get('hub.challenge'). I thought I was just supposed to echo the challenge, but that doesn't appear to work since I receive the following errors in the GAE logs:
InstagramAPIError: (400) APISubscriptionError-Challenge verification failed. Sent "647bf6dbed31465093ee970577ce1b72", received "
647bf6dbed31465093ee970577ce1b72
".
Here is the full handler:
class InstagramHandler(BaseHandler):
def get(self):
def process_tag_update(update):
update = update
mode = self.request.get('hub.mode')
challenge = self.request.get('hub.challenge')
verify_token = self.request.get('hub.verify_token')
if challenge:
template_values = {'challenge':challenge}
path = os.path.join(os.path.dirname(__file__), '../templates/instagram.html')
html = template.render(path, template_values)
self.response.out.write(html)
else:
reactor = subscriptions.SubscriptionsReactor()
reactor.register_callback(subscriptions.SubscriptionType.TAG, process_tag_update)
x_hub_signature = self.request.headers.get('X-Hub-Signature')
raw_response = self.request.data
try:
reactor.process('INSTAGRAM_SECRET', raw_response, x_hub_signature)
except subscriptions.SubscriptionVerifyError:
logging.error('Instagram signature mismatch')
So returning it as a string worked. I should have payed closer attention to the error message, but it took a helpful person on the Python IRC to point out the extra line breaks in the message. Once I put the template files on one line, it seemed to work. I can now confirm that my app is authorized via Instagram's list subscription URL.

Categories

Resources