5 # This is where BookStack API details can be hard-coded if you prefer
6 # to write them in this script instead of using environment variables.
7 default_bookstack_options = {
14 # Gather the BookStack API options either from the hard-coded details above otherwise
15 # it defaults back to environment variables.
16 def gather_api_options() -> dict:
18 "url": default_bookstack_options["url"] or os.getenv("BS_URL"),
19 "token_id": default_bookstack_options["token_id"] or os.getenv("BS_TOKEN_ID"),
20 "token_secret": default_bookstack_options["token_secret"] or os.getenv("BS_TOKEN_SECRET"),
24 # Send a multipart post request to BookStack, at the given endpoint with the given data.
25 def bookstack_post_multipart(endpoint: str, data: dict) -> dict:
26 # Fetch the API-specific options
27 bs_api_opts = gather_api_options()
29 # Format the request URL and the authorization header, so we can access the API
30 request_url = bs_api_opts["url"].rstrip("/") + "/api/" + endpoint.lstrip("/")
32 "Authorization": "Token {}:{}".format(bs_api_opts["token_id"], bs_api_opts["token_secret"])
35 # Make the request to bookstack with the gathered details
36 response = requests.post(request_url, headers=request_headers, files=data)
38 # Throw an error if the request was not successful
39 response.raise_for_status()
41 # Return the response data decoded from it's JSON format
42 return response.json()
45 # Error out and exit the app
46 def error_out(message: str):
51 # Run this when called on command line
52 if __name__ == '__main__':
54 # Check arguments provided
56 error_out("Both <page_id> and <file_path> arguments need to be provided")
58 # Gather details from the command line arguments and create a file name
61 file_path = sys.argv[2]
62 file_name = os.path.basename(file_path)
64 # Ensure the file exists
65 if not os.path.isfile(file_path):
66 error_out("Could not find provided file: {}".format(file_path))
68 # Gather the data we'll be sending to BookStack.
69 # The format matches that what the "requests" library expects
70 # to be provided for its "files" parameter.
72 "file": open(file_path, "rb"),
73 "name": (None, file_name),
74 "uploaded_to": (None, page_id)
77 # Send the upload request and get back the attachment data
79 attachment = bookstack_post_multipart("/attachments", post_data)
80 except requests.HTTPError as e:
81 error_out("Upload failed with status {} and data: {}".format(e.response.status_code, e.response.text))
84 print("File successfully uploaded to page {}.".format(page_id))
85 print(" - Attachment ID: {}".format(attachment['id']))
86 print(" - Attachment Name: {}".format(attachment['name']))