Finish Canvas Submission Comment

RobbieWatling
Community Novice
1
1227

Hi all,

I would like to attach a zip file to all of my students submissions. I have been able to upload the file via the Cavnas API. However, I cannot seem to get the file to attach a student's submission. Acccording to https://canvas.instructure.com/doc/api/submission_comments.html I need to "PUT" the file id to the submission API. Can someone who knows rest API better assist me? The main issue is not really understanding how to use the "parameters" for a submission comment here https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.update 

 

I've attached a portion of my script below, but a linux command would be sufficient too.

 

REQUIREMENTS = """
certifi==2018.11.29
chardet==3.0.4
idna==2.8
python-magic==0.4.15
requests==2.21.0
urllib3==1.24.1
"""

# https://stackoverflow.com/a/44873382
def sha256sum(filename):
    h = hashlib.sha256()
    b = bytearray(128 * 1024)
    mv = memoryview(b)
    with open(filename, "rb", buffering=0) as f:
        for n in iter(lambda: f.readinto(mv), 0):
            h.update(mv[:n])
    return h.hexdigest()


# https://stackoverflow.com/a/16696317 with tweaks
def download_file(url, f):
    # NOTE the stream=True parameter below
    with requests.get(url, stream=True) as r:
        r.raise_for_status()
        for chunk in r.iter_content(chunk_size=8192):
            if chunk:  # filter out keep-alive new chunks
                f.write(chunk)
    # possibly unneeded.
    f.flush()


def add_custom_site_packages_directory(raise_if_failure=True):
    digest = hashlib.sha256(REQUIREMENTS.encode("utf8")).hexdigest()
    dep_root = os.path.join(gettempdir(), "pyallinone_{}".format(digest))
    os.makedirs(dep_root, exist_ok=True)

    for dirpath, dirnames, filenames in os.walk(dep_root):
        if dirpath.endswith(os.path.sep + "site-packages"):
            # that's our dir!
            sys.path.insert(0, os.path.abspath(dirpath))
            return dep_root

    if raise_if_failure:
        raise ValueError("could not find our site-packages dir")

    return dep_root


dep_root = add_custom_site_packages_directory(False)

deps_installed = False

while True:
    try:
        import requests
        import magic

        break
    except ImportError:
        if deps_installed:
            raise ValueError("Something was broken, could not install dependencies")
        try:
            from pip import main as pipmain
        except ImportError:
            from pip._internal import main as pipmain

        with NamedTemporaryFile() as req:
            req.write(REQUIREMENTS.encode("utf-8"))
            req.flush()
            pipmain(
                [
                    "install",
                    "--prefix",
                    dep_root,
                    "--upgrade",
                    "--no-cache-dir",
                    "--no-deps",
                    "-r",
                    req.name,
                ]
            )

        add_custom_site_packages_directory()
        deps_installed = True

print("Step 1...")
hashes = {}
file_ids = []
file_sizes = []
for fn in FILENAMES:
    print(
        "uploading {fn} for assignment {ASSIGNMENT_ID}".format(
            fn=fn, ASSIGNMENT_ID=ASSIGNMENT_ID
        )
    )
    with requests.post(
        CANVAS_API_BASE
        + "courses/{COURSE_ID}/assignments/{ASSIGNMENT_ID}/submissions/{SUBMISSION_ID}/comments/files".format(
            COURSE_ID=COURSE_ID, ASSIGNMENT_ID=ASSIGNMENT_ID, SUBMISSION_ID=SUBMISSION_ID
        ),
        json={
            "access_token": CANVAS_KEY,
            "name": fn,
            "size": os.stat(fn).st_size,
            "content_type": magic.from_file(fn, mime=True),
        },
    ) as r:
        r.raise_for_status()
        response = r.json()
    upload_url = response["upload_url"]
    upload_params = response["upload_params"]

    hashes[fn] = sha256sum(fn)
    with requests.post(
        upload_url, data=upload_params, files={"file": (fn, open(fn, "rb"))}
    ) as r2:
        r2.raise_for_status()
        upload_response = r2.json()

    file_ids.append(upload_response["id"])
    location = upload_response["location"]

print(file_ids)

 

1 Comment
maguire
Community Champion

See the program insert_grades_and_comments.py

you just insert an entry for comment[file_ids][] with a list of the file IDs into the payload - see the function function assign_grade_for_assignment -- it shows how to submit text comments, but shows the variety of types of comments you can add as parameters.

The program is available at https://github.com/gqmaguirejr/Canvas-tools