Skip to content
Snippets Groups Projects
Commit d9640ae2 authored by prechelt's avatar prechelt
Browse files

mycampusscript.py: semi-complete function upload_attachment()

parent 53325e94
No related branches found
No related tags found
No related merge requests found
import collections.abc import collections.abc
import datetime as dt import datetime as dt
import mimetypes
import os.path
import random import random
import re import re
import sys import sys
import typing as tg import typing as tg
import urllib.parse
import bs4 import bs4
import yaml import yaml
...@@ -129,7 +132,8 @@ def main(scriptname: str, cmdname: str, configfile: str): ...@@ -129,7 +132,8 @@ def main(scriptname: str, cmdname: str, configfile: str):
dynamic=get_gradebook_categories) dynamic=get_gradebook_categories)
send_grades_to_gradebook_category: int = find_value_or_help(config, 'send_grades_to_gradebook_category') send_grades_to_gradebook_category: int = find_value_or_help(config, 'send_grades_to_gradebook_category')
released_grade_notification_email: bool = find_value_or_help(config, 'released_grade_notification_email') released_grade_notification_email: bool = find_value_or_help(config, 'released_grade_notification_email')
upload_attachments(config, attachments) for attachment in attachments:
upload_attachment(config, attachment)
def find_value_or_help(config: StrAnyDict, key: str, dynamic: ReplacementsFunc = None) -> tg.Any: def find_value_or_help(config: StrAnyDict, key: str, dynamic: ReplacementsFunc = None) -> tg.Any:
...@@ -235,7 +239,7 @@ def obtain_tokens(config: StrAnyDict): ...@@ -235,7 +239,7 @@ def obtain_tokens(config: StrAnyDict):
config[RBCS_TOKEN_CONFIGENTRY_NAME] = rbcstoken_input_elem['value'] config[RBCS_TOKEN_CONFIGENTRY_NAME] = rbcstoken_input_elem['value']
def upload_attachments(config: StrAnyDict, attachments: list[str]): def upload_attachment(config: StrAnyDict, filepath: str):
""" """
Make POST request with multipart/formdata body, many headers, and the following format of URL: Make POST request with multipart/formdata body, many headers, and the following format of URL:
POST /portal/site/<site-id>/tool/1f8f054a-4e58-4965-8d32-141b236e0023/sakai.filepicker.helper?special=upload&sakai_csrf_token=<hexstring>&sakai_action=doAttachupload POST /portal/site/<site-id>/tool/1f8f054a-4e58-4965-8d32-141b236e0023/sakai.filepicker.helper?special=upload&sakai_csrf_token=<hexstring>&sakai_action=doAttachupload
...@@ -249,7 +253,39 @@ def upload_attachments(config: StrAnyDict, attachments: list[str]): ...@@ -249,7 +253,39 @@ def upload_attachments(config: StrAnyDict, attachments: list[str]):
# See "POST Multiple Multipart-Encoded Files" in https://requests.readthedocs.io/en/latest/user/advanced/ # See "POST Multiple Multipart-Encoded Files" in https://requests.readthedocs.io/en/latest/user/advanced/
# We have so far failed to obtain the HTML of the form to be posted, which we need to find the # We have so far failed to obtain the HTML of the form to be posted, which we need to find the
# name of the attachment file form element. # name of the attachment file form element.
# in c:/temp/a.json:
# Request 164 ist der POST-Request, den wir analog nachbilden müssen.
# Das JSON ist dafür unpraktisch, weil der ganze multipart-Rumpf nur als Text dasteht.
# In der Word-Datei findet sich die aufgeschlüsselte Form, die der Browser dafür anzeigt.
# Erzeugung eines solchen Requests, siehe https://stackoverflow.com/a/12385661
filename = os.path.basename(filepath)
content_type, encoding = mimetypes.guess_type(filename)
multipart_body = dict(
source='0',
collectionId=f'/group/{site_id(config["site_url"])}',
sakai_action='',
navRoot='',
criteria='title',
rt_action='',
selectedItemId='',
upload=(filename, slurp(filepath), content_type),
url='',
sakai_csrf_token=config[CSRF_TOKEN_CONFIGENTRY_NAME]
)
multipart_body['from'] = 'list' # separate because 'from' is a keyword
requests.post(...)
def site_id(site_url: str) -> str:
"""From e.g. https://qmycampus.imp.fu-berlin.de/portal/site/724a527a-db9d, retrieve 724a527a-db9d"""
path = urllib.parse.urlparse(site_url).path
the_id = os.path.basename(path)
return the_id
def slurp(filename: str) -> bytes:
with open(filename, 'rb') as f:
return f.read()
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) != 2+1 or sys.argv[1] != 'create_multigroup_assgmt': if len(sys.argv) != 2+1 or sys.argv[1] != 'create_multigroup_assgmt':
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment