It is not a complete solution but here is some code that shows you how to use the Canvas API to download discussion posts (including photos and links to videos) as a local HTML page
# ConcatenateDiscussions.py
#
# This code is not a complete solution. Rather it is a proof of concept that you can download discussion posts as an HMTL file.
# It takes the Canvas ID number of single student and downloads all the discussion posts of that student, embedding the images and the videos as iFrames.
# You can modify this code as you like.
# For me the difficult part was getting the contents of the discussion posts, including images and videos, as there is no direct API for that.
# I will put in a loop to iterate through all the students in my course, providing a portfolio of the year's achievement for each student.
# You could put it some code so that it only downloads answers from one assignment.
# YOu could get the code to put the hmtl in Canvas and send a Canvas message with the link to each student.
# https://community.canvaslms.com/t5/Developers-Group/Canvas-APIs-Getting-started-the-practical-ins-an...
# Coding assisted by AI: perplexity.ai
import csv
from canvasapi import Canvas
import html
import re
API_URL = "https://canvas.education.tas.gov.au/"
API_KEY = "NotMyRealAPIKey"
def clean_html_content(raw_html):
# Unescape HTML entities
unescaped = html.unescape(raw_html)
# Remove unnecessary whitespace
cleaned = ' '.join(unescaped.split())
# Function to clean up iframe tags
def clean_iframe(match):
iframe = match.group(0)
# Remove any inline styles
iframe = re.sub(r'style="[^"]*"', '', iframe)
# Add our own styling
iframe = iframe.replace('<iframe', '<iframe style="width: 400px; height: 225px; display: inline-block; margin: 5px;"')
return iframe
# Clean up iframe tags
cleaned = re.sub(r'<iframe[^>]*>.*?</iframe>', clean_iframe, cleaned, flags=re.DOTALL)
return cleaned
#Put in your API key (from settings on your Canvas user page)
canvas = Canvas(API_URL, API_KEY)
#Put in the real course number, taken from the URL of your course
course = canvas.get_course(999999)
print(course.name)
# Get all assignments for the course
assignments = course.get_assignments()
# Filter assignments to include only discussion posts
discussion_assignments = [
assignment for assignment in assignments
if 'discussion_topic' in assignment.submission_types
]
# Put in the real student ID number to test
student_id = 999999
# Get the student object to access their name
student = course.get_user(student_id)
file_name = f"{student.name.replace(' ', '')}.html"
# Add this CSS to your HTML head section:
css_styles = """
<style>
.video-placeholder {
width: 400px;
height: 225px;
background-color: #f0f0f0;
display: inline-block;
margin: 5px;
text-align: center;
line-height: 225px;
color: #666;
}
</style>
"""
# Include the CSS in your HTML content
html_content = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Discussion Posts for {student.name}</title>
<style>
body {{ font-family: Arial, sans-serif; line-height: 1.6; padding: 20px; }}
h1 {{ color: #333; }}
h2 {{ color: #666; }}
.post {{ margin-bottom: 20px; border-bottom: 1px solid #ccc; padding-bottom: 10px; }}
.post-info {{ font-style: italic; color: #888; }}
.post-content {{ margin-top: 10px; }}
</style>
{css_styles}
</head>
<body>
<h1>Discussion Posts for {student.name}</h1>
</body>
</html>
"""
# Get student's submissions for discussion assignments
for assignment in discussion_assignments:
html_content += f"<h2>Assignment: {assignment.name}</h2>"
# Get the discussion topic
if hasattr(assignment, 'discussion_topic'):
topic_id = assignment.discussion_topic['id']
discussion_topic = course.get_discussion_topic(topic_id)
# Get all top-level entries for this discussion topic
entries = discussion_topic.get_topic_entries()
for entry in entries:
if entry.user_id == student_id:
cleaned_message = clean_html_content(entry.message)
html_content += f"""
<div class="post">
<p class="post-info">Author: {entry.user['display_name']}</p>
<p class="post-info">Created at: {entry.created_at}</p>
<div class="post-content">{cleaned_message}</div>
</div>
"""
html_content += """
</body>
</html>
"""
# Save the HTML content to a file
with open(file_name, 'w', encoding='utf-8') as f:
f.write(html_content)
print(f"HTML file '{file_name}' has been created with the student's discussion posts.")