I have a Django project that will insert a comment with image to basecamp 3. So after I got a key token (Authorization using Oauth 2) I need to insert a comment with image to basecamp todos. The image is from URL contained in JSON that user input. The JSON is look like this:
{
"uuid":"763eadb9-7c6b-4383-9013-34859e0ab062",
"event":"capture.new",
"id":"1",
"url":{
"id":"2",
"url":"https://pagescreen.io",
"http_code":"200",
"title":"Pagescreen (test)",
"description":""
},
"permalink":"https://i.pagescreen.io/i/123.png",
"generated":"1",
"status":"1",
"requested_on":"2022-12-14T07:05:10+00:00",
"last_updated":"2022-12-14T07:05:38+00:00",
"options":{
"delay":"0",
"format":"png",
"fullpage":"1",
"viewport":{
"width":"1440",
"height":"960"
}
},
"automation_id":"1",
"file":{
"width":"1440",
"height":"11216",
"size":"639570"
},
"colors":{
"rgb(109, 118, 139)":304,
"rgb(255, 255, 255)":169,
"rgb(51, 51, 51)":4,
"rgba(0, 0, 0, 0)":523,
"rgb(0, 0, 0)":82,
"rgb(239, 239, 239)":5,
"rgb(33, 68, 146)":27,
"rgb(0, 131, 221)":37,
"rgb(120, 129, 149)":27,
"rgba(255, 255, 255, 0.063)":2,
"rgba(255, 255, 255, 0.314)":2,
"rgba(255, 255, 255, 0.5)":2,
"rgb(255, 194, 10)":5,
"rgb(0, 26, 62)":42,
"rgb(70, 188, 102)":11,
"rgb(238, 82, 83)":5,
"rgb(255, 165, 0)":6,
"rgb(61, 129, 214)":22,
"rgb(0, 122, 255)":4,
"rgb(30, 144, 255)":8,
"rgb(248, 248, 248)":6,
"rgb(240, 240, 240)":7,
"rgb(80, 102, 144)":15,
"rgba(0, 0, 0, 0.1)":1,
"rgb(0, 201, 183)":4
},
"navigation":{
"previous":{
"id":"1"
},
"next":null
}
}
So from that JSON I saved the image from permalink (“permalink”:”https://i.pagescreen.io/i/123.png”) to my local storage project.
Then after saved the image, I upload/attach it to basecamp API (Attach endpoint) like in this documentation https://github.com/basecamp/bc3-api/blob/master/sections/attachments.md. So my code look like this:
def upload_attachment_to_basecamp(access_token, account_id, file_path, file_name):
basecamp_url = f'https://3.basecampapi.com/{account_id}/attachments.json?name={file_name}'
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'image/png',
}
with open(file_path, 'rb') as file:
files = {'file': (file_name, file)}
response = requests.post(basecamp_url, headers=headers, files=files)
if response.status_code == 201:
attachable_sgid = response.json().get('attachable_sgid')
return {'status': 'success', 'attachable_sgid': attachable_sgid}
else:
return {'status': 'error', 'message': f'Failed to upload attachment to Basecamp. Status Code: {response.status_code}'}
So after that I get the attachable_sgid, then I use this sgid for attaching my image to basecamp comment. This is a documentation https://github.com/basecamp/bc3-api/blob/master/sections/rich_text.md#inserting-an-image-or-file-attachment. And my code to post a comment is look like this:
@csrf_exempt
@require_POST
def post_image_to_basecamp(request):
ACCESS_TOKEN = 'BAhbB0kixxx'
ACCOUNT_ID = '361xxx'
IMAGE_NAME = 'image.png'
# Get the image from permalink
data = json.loads(request.body.decode('utf-8'))
image_url = data.get('image_url')
print(image_url)
if image_url:
# Get the image from permalink
image_response = requests.get(image_url)
if image_response.status_code == 200:
image_content = image_response.content
image_path = os.path.join(settings.MEDIA_ROOT, 'images', IMAGE_NAME)
with open(image_path, 'wb') as image_file:
image_file.write(image_content)
# Save and upload image
upload_result = upload_attachment_to_basecamp(ACCESS_TOKEN, ACCOUNT_ID, image_path, IMAGE_NAME)
if upload_result['status'] == 'success':
attachable_sgid = upload_result['attachable_sgid']
# Tag <bc-attachment>
attachment_tag = f'<bc-attachment sgid="{attachable_sgid}"></bc-attachment>'
# URL API Basecamp for posting a comment
api_url = f'https://3.basecampapi.com/{ACCOUNT_ID}/buckets/14151271/recordings/6935867532/comments.json'
headers_comment = {
'Authorization': f'Bearer {ACCESS_TOKEN}',
'Content-Type': 'image/png'
}
# Data caption, image, any
data = {
'content': f'<div>My image <br> {attachment_tag}</div>',
}
response = requests.post(api_url, json=data, headers=headers_comment)
if response.status_code == 201:
result = response.json()
return JsonResponse({'status': 'success', 'attachable_sgid': attachable_sgid, 'result': result})
else:
return JsonResponse({'status': 'error', 'message': f'Failed to post comment. Status Code: {response.status_code}'})
else:
return JsonResponse({'status': 'error', 'message': f'Failed to upload image to Basecamp. {upload_result["message"]}'})
else:
return JsonResponse({'status': 'error', 'message': f'Failed to fetch image from URL. Status Code: {image_response.status_code}'})
else:
return JsonResponse({'status': 'error', 'message': 'Image URL is required'})
(xxx = I censored)
After that I got a error 422 which is a unprocessable entity/content, but if I change the header ‘Content-type’ from image to ‘application/json’ the image its uploaded but its blank.
I need to post a comment with an image in basecamp from my local project, the result I’m expecting is the image is showing with preview.
This is the result if i using content-type : application/json header when post a comment with image pasteboard.co/peG6oZK2ZkMb.png
So i need to post a comment with image like this, with image preview in basecamp pasteboard.co/vZzFR4gHGNKp.png
This is the image from permalink url JSON, the image already saved in my local project storage pasteboard.co/Nw71H1waeLmY.png