นี่เป็นบทแนะนำที่ 4 ในชุดบทแนะนำส่วนเสริมของ Classroom
ในบทแนะนำนี้ คุณโต้ตอบกับ Google Classroom API เพื่อสร้างไฟล์แนบ คุณระบุเส้นทางให้ผู้ใช้ดูเนื้อหาไฟล์แนบ โดยมุมมองจะแตกต่างกันไปตามบทบาทของผู้ใช้ในชั้นเรียน คำแนะนำแบบทีละขั้นตอนนี้จะอธิบายเกี่ยวกับไฟล์แนบประเภทเนื้อหา ซึ่งไม่จําเป็นต้องให้นักเรียนส่ง
ในระหว่างการแนะนำนี้ คุณจะทำสิ่งต่อไปนี้
- เรียกข้อมูลและใช้พารามิเตอร์การค้นหาของส่วนเสริมต่อไปนี้
addOnToken
: โทเค็นการให้สิทธิ์ที่ส่งไปยังมุมมองการค้นพบไฟล์แนบitemId
: ตัวระบุที่ไม่ซ้ำกันสำหรับงาน CourseWorkMaterial หรือประกาศที่รับไฟล์แนบของส่วนเสริมitemType
: "courseWork", "courseWorkMaterials" หรือ "announcement"courseId
: ตัวระบุที่ไม่ซ้ำกันสำหรับหลักสูตร Google Classroom ที่กำลังสร้างงานattachmentId
: ตัวระบุที่ไม่ซ้ำกันซึ่ง Google Classroom กําหนดให้กับไฟล์แนบของส่วนเสริมหลังจากสร้าง
- ใช้พื้นที่เก็บข้อมูลถาวรสำหรับไฟล์แนบประเภทเนื้อหา
- ระบุเส้นทางเพื่อสร้างไฟล์แนบและแสดง iframe ของมุมมองครูและมุมมองนักเรียน
- ส่งคำขอต่อไปนี้ไปยัง API ของส่วนเสริม Google Classroom
- สร้างไฟล์แนบใหม่
- รับบริบทของส่วนเสริม ซึ่งจะระบุว่าผู้ใช้ที่เข้าสู่ระบบเป็นนักเรียนหรือครู
เมื่อดำเนินการเสร็จแล้ว คุณสามารถสร้างไฟล์แนบประเภทเนื้อหาในงานผ่าน UI ของ Google Classroom เมื่อเข้าสู่ระบบในฐานะครู ครูและนักเรียนในชั้นเรียนจะดูเนื้อหาดังกล่าวได้ด้วย
เปิดใช้ Classroom API
เรียกใช้ Classroom API โดยเริ่มจากขั้นตอนนี้ คุณต้องเปิดใช้ API สำหรับโปรเจ็กต์ Google Cloud ก่อนจึงจะเรียก API ได้ ไปที่รายการไลบรารีของ Google Classroom API แล้วเลือกเปิดใช้
จัดการพารามิเตอร์การค้นหาของมุมมองการค้นพบไฟล์แนบ
ดังที่ได้กล่าวไว้ก่อนหน้านี้ Google Classroom จะส่งพารามิเตอร์การค้นหาเมื่อโหลดมุมมองการค้นพบไฟล์แนบใน iframe
courseId
: รหัสของหลักสูตรปัจจุบันใน ClassroomitemId
: ตัวระบุที่ไม่ซ้ำกันสำหรับงาน CourseWorkMaterial หรือประกาศที่รับไฟล์แนบของส่วนเสริมitemType
: "courseWork", "courseWorkMaterials" หรือ "announcement"addOnToken
: โทเค็นที่ใช้เพื่อให้สิทธิ์การดำเนินการบางอย่างของส่วนเสริม Classroomlogin_hint
: รหัส Google ของผู้ใช้ปัจจุบัน
คำแนะนำแบบทีละขั้นตอนนี้เกี่ยวข้องกับ courseId
, itemId
, itemType
และ addOnToken
เก็บและส่งค่าเหล่านี้เมื่อเรียกใช้ Classroom API
เช่นเดียวกับในขั้นตอนแนะนำก่อนหน้านี้ ให้จัดเก็บค่าพารามิเตอร์การค้นหาที่ส่งในเซสชันของเรา เราจำเป็นต้องดำเนินการดังกล่าวเมื่อเปิดมุมมองการค้นพบไฟล์แนบเป็นครั้งแรก เนื่องจากนี่เป็นโอกาสเดียวที่ Classroom จะส่งพารามิเตอร์การค้นหาเหล่านี้ได้
Python
ไปที่ไฟล์เซิร์ฟเวอร์ Flask ที่ให้เส้นทางสำหรับมุมมองการค้นพบไฟล์แนบ (attachment-discovery-routes.py
หากคุณทำตามตัวอย่างที่ระบุไว้) ที่ด้านบนของเส้นทางหน้า Landing Page ของส่วนเสริม (/classroom-addon
ในตัวอย่างที่เราให้ไว้) ให้ดึงข้อมูลและจัดเก็บพารามิเตอร์การค้นหา courseId
, itemId
, itemType
และ addOnToken
# Retrieve the itemId, courseId, and addOnToken query parameters.
if flask.request.args.get("itemId"):
flask.session["itemId"] = flask.request.args.get("itemId")
if flask.request.args.get("itemType"):
flask.session["itemType"] = flask.request.args.get("itemType")
if flask.request.args.get("courseId"):
flask.session["courseId"] = flask.request.args.get("courseId")
if flask.request.args.get("addOnToken"):
flask.session["addOnToken"] = flask.request.args.get("addOnToken")
เขียนค่าเหล่านี้ลงในเซสชันเฉพาะในกรณีที่มีเท่านั้น ระบบจะไม่ส่งค่าเหล่านี้อีกครั้งหากผู้ใช้กลับมาที่มุมมองการค้นพบไฟล์แนบในภายหลังโดยไม่ปิด iframe
เพิ่มพื้นที่เก็บข้อมูลถาวรสำหรับไฟล์แนบประเภทเนื้อหา
คุณต้องมีบันทึกในเครื่องของไฟล์แนบที่สร้างไว้ ซึ่งจะช่วยให้คุณค้นหาเนื้อหาที่ครูเลือกโดยใช้ตัวระบุที่ Classroom มีให้
ตั้งค่าสคีมาฐานข้อมูลสําหรับ Attachment
ตัวอย่างที่เราให้ไว้แสดงไฟล์แนบที่มีรูปภาพและคําบรรยาย Attachment
มีแอตทริบิวต์ต่อไปนี้
attachment_id
: ตัวระบุที่ไม่ซ้ำกันสำหรับไฟล์แนบ กำหนดโดย Classroom และแสดงในการตอบกลับเมื่อสร้างไฟล์แนบimage_filename
: ชื่อไฟล์ในเครื่องของรูปภาพที่จะแสดงimage_caption
: คำบรรยายที่จะแสดงพร้อมกับรูปภาพ
Python
ขยายการใช้งาน SQLite และ flask_sqlalchemy
จากขั้นตอนก่อนหน้า
ไปที่ไฟล์ที่คุณได้กำหนดตารางผู้ใช้ (models.py
หากคุณทำตามตัวอย่างที่เราให้ไว้) เพิ่มข้อมูลต่อไปนี้ที่ด้านล่างของไฟล์ใต้คลาส User
class Attachment(db.Model):
# The attachmentId is the unique identifier for the attachment.
attachment_id = db.Column(db.String(120), primary_key=True)
# The image filename to store.
image_filename = db.Column(db.String(120))
# The image caption to store.
image_caption = db.Column(db.String(120))
นําเข้าคลาสไฟล์แนบใหม่ไปยังไฟล์เซิร์ฟเวอร์ด้วยเส้นทางการจัดการไฟล์แนบ
ตั้งค่าเส้นทางใหม่
เริ่มขั้นตอนแนะนำนี้ด้วยการตั้งค่าหน้าใหม่ในแอปพลิเคชัน ซึ่งช่วยให้ผู้ใช้สร้างและดูเนื้อหาผ่านส่วนเสริมของเราได้
เพิ่มเส้นทางการสร้างไฟล์แนบ
คุณต้องมีหน้าเว็บเพื่อให้ครูเลือกเนื้อหาและส่งคำขอสร้างไฟล์แนบ ใช้เส้นทาง /attachment-options
เพื่อแสดงตัวเลือกเนื้อหาให้ครูเลือก คุณต้องมีเทมเพลตสําหรับหน้าการเลือกเนื้อหาและหน้ายืนยันการสร้างด้วย ตัวอย่างที่เราให้ไว้มีเทมเพลตสำหรับสิ่งเหล่านี้ และยังแสดงคำขอและการตอบกลับจาก Classroom API ได้ด้วย
โปรดทราบว่าคุณอาจแก้ไขหน้า Landing Page ของมุมมองการค้นพบไฟล์แนบที่มีอยู่เพื่อแสดงตัวเลือกเนื้อหาแทนการสร้างหน้า/attachment-options
ใหม่ก็ได้ เราขอแนะนําให้สร้างหน้าใหม่เพื่อวัตถุประสงค์ของการฝึกนี้เพื่อให้คุณคงลักษณะการทํางานของ SSO ที่ติดตั้งใช้งานในขั้นตอนที่ 2 ของบทแนะนํา เช่น การเพิกถอนสิทธิ์ของแอป ซึ่งจะเป็นประโยชน์เมื่อคุณสร้างและทดสอบส่วนเสริม
ครูสามารถเลือกจากชุดรูปภาพที่มีคำบรรยายเล็กๆ น้อยๆ ในตัวอย่างที่เราให้ไว้ เราได้จัดเตรียมรูปภาพสถานที่สำคัญอันโด่งดัง 4 รูปซึ่งมีคำบรรยายที่มาจากชื่อไฟล์
Python
ในตัวอย่างที่เราให้ไว้ ข้อมูลนี้อยู่ในไฟล์ webapp/attachment_routes.py
@app.route("/attachment-options", methods=["GET", "POST"])
def attachment_options():
"""
Render the attachment options page from the "attachment-options.html"
template.
This page displays a grid of images that the user can select using
checkboxes.
"""
# A list of the filenames in the static/images directory.
image_filenames = os.listdir(os.path.join(app.static_folder, "images"))
# The image_list_form_builder method creates a form that displays a grid
# of images, checkboxes, and captions with a Submit button. All images
# passed in image_filenames will be shown, and the captions will be the
# title-cased filenames.
# The form must be built dynamically due to limitations in WTForms. The
# image_list_form_builder method therefore also returns a list of
# attribute names in the form, which will be used by the HTML template
# to properly render the form.
form, var_names = image_list_form_builder(image_filenames)
# If the form was submitted, validate the input and create the attachments.
if form.validate_on_submit():
# Build a dictionary that maps image filenames to captions.
# There will be one dictionary entry per selected item in the form.
filename_caption_pairs = construct_filename_caption_dictionary_list(
form)
# Check that the user selected at least one image, then proceed to
# make requests to the Classroom API.
if len(filename_caption_pairs) > 0:
return create_attachments(filename_caption_pairs)
else:
return flask.render_template(
"create-attachment.html",
message="You didn't select any images.",
form=form,
var_names=var_names)
return flask.render_template(
"attachment-options.html",
message=("You've reached the attachment options page. "
"Select one or more images and click 'Create Attachment'."),
form=form,
var_names=var_names,
)
ซึ่งจะสร้างหน้า "สร้างไฟล์แนบ" ที่มีลักษณะดังต่อไปนี้
ครูสามารถเลือกรูปภาพได้หลายรูป สร้างไฟล์แนบ 1 รายการสำหรับรูปภาพแต่ละรูปที่ครูเลือกในวิธีการ create_attachments
ส่งคำขอสร้างไฟล์แนบ
เมื่อทราบแล้วว่าครูต้องการแนบเนื้อหาใด ให้ส่งคำขอไปยัง Classroom API เพื่อสร้างไฟล์แนบในงาน จัดเก็บรายละเอียดไฟล์แนบในฐานข้อมูลหลังจากได้รับการตอบกลับจาก Classroom API
เริ่มต้นด้วยการสร้างอินสแตนซ์ของบริการ Classroom โดยทำดังนี้
Python
ในตัวอย่างที่เราให้ไว้ ข้อมูลนี้อยู่ในไฟล์ webapp/attachment_routes.py
def create_attachments(filename_caption_pairs):
"""
Create attachments and show an acknowledgement page.
Args:
filename_caption_pairs: A dictionary that maps image filenames to
captions.
"""
# Get the Google Classroom service.
classroom_service = googleapiclient.discovery.build(
serviceName="classroom",
version="v1",
credentials=credentials)
ส่งคำขอ CREATE
ไปยังปลายทาง courses.courseWork.addOnAttachments
สำหรับรูปภาพแต่ละรูปที่ครูเลือก ให้สร้างAddOnAttachment
ออบเจ็กต์ก่อน โดยทำดังนี้
Python
ในตัวอย่างที่เราให้ไว้ การดำเนินการนี้เป็นการดำเนินการต่อจากcreate_attachments
method
# Create a new attachment for each image that was selected.
attachment_count = 0
for key, value in filename_caption_pairs.items():
attachment_count += 1
# Create a dictionary with values for the AddOnAttachment object fields.
attachment = {
# Specifies the route for a teacher user.
"teacherViewUri": {
"uri":
flask.url_for(
"load_content_attachment", _scheme='https', _external=True),
},
# Specifies the route for a student user.
"studentViewUri": {
"uri":
flask.url_for(
"load_content_attachment", _scheme='https', _external=True)
},
# The title of the attachment.
"title": f"Attachment {attachment_count}",
}
ต้องระบุฟิลด์ teacherViewUri
, studentViewUri
และ title
อย่างน้อย 1 ช่องสําหรับไฟล์แนบแต่ละรายการ teacherViewUri
และ studentViewUri
แสดง URL ที่โหลดเมื่อผู้ใช้ประเภทนั้นๆ เปิดไฟล์แนบ
ส่งออบเจ็กต์ AddOnAttachment
ในเนื้อหาของคำขอไปยังปลายทาง addOnAttachments
ที่เหมาะสม ระบุตัวระบุ courseId
, itemId
, itemType
และ addOnToken
กับคำขอแต่ละรายการ
Python
ในตัวอย่างที่เราให้ไว้ การดำเนินการนี้เป็นการดำเนินการต่อจากcreate_attachments
method
# Use the itemType to determine which stream item type the teacher created
match flask.session["itemType"]:
case "announcements":
parent = classroom_service.courses().announcements()
case "courseWorkMaterials":
parent = classroom_service.courses().courseWorkMaterials()
case _:
parent = classroom_service.courses().courseWork()
# Issue a request to create the attachment.
resp = parent.addOnAttachments().create(
courseId=flask.session["courseId"],
itemId=flask.session["itemId"],
addOnToken=flask.session["addOnToken"],
body=attachment).execute()
สร้างรายการสำหรับไฟล์แนบนี้ในฐานข้อมูลในเครื่องเพื่อให้คุณโหลดเนื้อหาที่ถูกต้องได้ในภายหลัง Classroom จะแสดงผลค่า id
ที่ไม่ซ้ำกันในการตอบกลับคำขอสร้าง ดังนั้นให้ใช้ค่านี้เป็นคีย์หลักในฐานข้อมูลของเรา โปรดทราบว่า Classroom จะส่งattachmentId
พารามิเตอร์การค้นหาเมื่อเปิดมุมมองของครูและนักเรียน
Python
ในตัวอย่างที่เราให้ไว้ การดำเนินการนี้ต่อจากcreate_attachments
method
# Store the value by id.
new_attachment = Attachment(
# The new attachment's unique ID, returned in the CREATE response.
attachment_id=resp.get("id"),
image_filename=key,
image_caption=value)
db.session.add(new_attachment)
db.session.commit()
พิจารณานำผู้ใช้ไปยังหน้ายืนยัน ณ จุดนี้เพื่อแจ้งให้ผู้ใช้ทราบว่าสร้างไฟล์แนบเรียบร้อยแล้ว
อนุญาตให้แนบไฟล์จากส่วนเสริม
ตอนนี้เป็นโอกาสที่ดีในการเพิ่มที่อยู่ที่เหมาะสมลงในช่องคำนำหน้า URI ของไฟล์แนบที่อนุญาตในหน้าการกำหนดค่าแอปของ SDK ของ Google Workspace Marketplace ส่วนเสริมสามารถสร้างไฟล์แนบจากคำนำหน้า URI รายการใดรายการหนึ่งที่อยู่ในหน้านี้ได้เท่านั้น ซึ่งเป็นมาตรการรักษาความปลอดภัยที่ช่วยลดโอกาสที่จะถูกโจมตีจาก "คนกลาง"
วิธีที่ง่ายที่สุดคือระบุโดเมนระดับบนสุดในช่องนี้ เช่น https://example.com
https://localhost:<your port number>/
จะทำงานได้หากคุณใช้เครื่องคอมพิวเตอร์เป็นเว็บเซิร์ฟเวอร์
เพิ่มเส้นทางสำหรับมุมมองของครูและนักเรียน
มี iframe 4 รายการที่อาจโหลดส่วนเสริมของ Google Classroom จนถึงตอนนี้คุณได้สร้างเฉพาะเส้นทางที่แสดง iframe ของมุมมองการค้นพบไฟล์แนบเท่านั้น จากนั้นให้เพิ่มเส้นทางเพื่อแสดง iframe ของมุมมองครูและนักเรียนด้วย
ต้องใช้ iframe มุมมองของครูเพื่อแสดงตัวอย่างประสบการณ์การใช้งานของนักเรียน แต่คุณอาจใส่ข้อมูลเพิ่มเติมหรือฟีเจอร์การแก้ไขก็ได้
มุมมองนักเรียนคือหน้าเว็บที่แสดงต่อนักเรียนแต่ละคนเมื่อเปิดไฟล์แนบของส่วนเสริม
เพื่อสร้างแบบฝึกหัดนี้ ให้สร้าง/load-content-attachment
เส้นทางเดียวที่แสดงทั้งมุมมองของครูและนักเรียน ใช้เมธอดของ Classroom API เพื่อระบุว่าผู้ใช้เป็นครูหรือนักเรียนเมื่อหน้าเว็บโหลด
Python
ในตัวอย่างที่เราให้ไว้ ข้อมูลนี้อยู่ในไฟล์ webapp/attachment_routes.py
@app.route("/load-content-attachment")
def load_content_attachment():
"""
Load the attachment for the user's role."""
# Since this is a landing page for the Teacher and Student View iframes, we
# need to preserve the incoming query parameters.
if flask.request.args.get("itemId"):
flask.session["itemId"] = flask.request.args.get("itemId")
if flask.request.args.get("itemType"):
flask.session["itemType"] = flask.request.args.get("itemType")
if flask.request.args.get("courseId"):
flask.session["courseId"] = flask.request.args.get("courseId")
if flask.request.args.get("attachmentId"):
flask.session["attachmentId"] = flask.request.args.get("attachmentId")
โปรดทราบว่าคุณควรตรวจสอบสิทธิ์ผู้ใช้ด้วยในขั้นตอนนี้ นอกจากนี้ คุณควรจัดการพารามิเตอร์การค้นหา login_hint
ที่นี่ และกำหนดเส้นทางให้ผู้ใช้ไปยังขั้นตอนการให้สิทธิ์หากจำเป็น ดูข้อมูลเพิ่มเติมเกี่ยวกับขั้นตอนนี้ได้ที่รายละเอียดคำแนะนำในการเข้าสู่ระบบที่กล่าวถึงในบทแนะนำก่อนหน้านี้
จากนั้นส่งคำขอไปยังปลายทาง getAddOnContext
ที่ตรงกับประเภทรายการ
Python
ในตัวอย่างที่ระบุไว้ การดำเนินการนี้เป็นการดำเนินการต่อจากเมธอด load_content_attachment
# Create an instance of the Classroom service.
classroom_service = googleapiclient.discovery.build(
serviceName="classroom"
version="v1",
credentials=credentials)
# Use the itemType to determine which stream item type the teacher created
match flask.session["itemType"]:
case "announcements":
parent = classroom_service.courses().announcements()
case "courseWorkMaterials":
parent = classroom_service.courses().courseWorkMaterials()
case _:
parent = classroom_service.courses().courseWork()
addon_context_response = parent.getAddOnContext(
courseId=flask.session["courseId"],
itemId=flask.session["itemId"]).execute()
เมธอดนี้จะแสดงข้อมูลเกี่ยวกับบทบาทของผู้ใช้ปัจจุบันในชั้นเรียน
เปลี่ยนมุมมองที่แสดงต่อผู้ใช้โดยขึ้นอยู่กับบทบาทของผู้ใช้ ระบบจะป้อนข้อมูลในช่อง studentContext
หรือ teacherContext
เพียงช่องเดียวในออบเจ็กต์การตอบกลับ ตรวจสอบข้อมูลเหล่านี้เพื่อพิจารณาวิธีกล่าวถึงผู้ใช้
ไม่ว่าในกรณีใดก็ตาม ให้ใช้ค่าพารามิเตอร์การค้นหา attachmentId
เพื่อดูว่าควรดึงข้อมูลไฟล์แนบใดจากฐานข้อมูลของเรา ระบบจะระบุพารามิเตอร์การค้นหานี้เมื่อเปิด URI ของมุมมองครูหรือนักเรียน
Python
ในตัวอย่างที่ระบุไว้ การดำเนินการนี้เป็นการดำเนินการต่อจากเมธอด load_content_attachment
# Determine which view we are in by testing the returned context type.
user_context = "student" if addon_context_response.get(
"studentContext") else "teacher"
# Look up the attachment in the database.
attachment = Attachment.query.get(flask.session["attachmentId"])
# Set the text for the next page depending on the user's role.
message_str = f"I see that you're a {user_context}! "
message_str += (
f"I've loaded the attachment with ID {attachment.attachment_id}. "
if user_context == "teacher" else
"Please enjoy this image of a famous landmark!")
# Show the content with the customized message text.
return flask.render_template(
"show-content-attachment.html",
message=message_str,
image_filename=attachment.image_filename,
image_caption=attachment.image_caption,
responses=response_strings)
ทดสอบส่วนเสริม
ทําตามขั้นตอนต่อไปนี้เพื่อทดสอบการสร้างไฟล์แนบ
- ลงชื่อเข้าใช้ [Google Classroom] ในฐานะผู้ใช้ทดสอบครู
- ไปที่แท็บงานของชั้นเรียน แล้วสร้างงานใหม่
- คลิกปุ่มส่วนเสริมใต้พื้นที่ข้อความ แล้วเลือกส่วนเสริม iframe จะเปิดขึ้นและส่วนเสริมจะโหลด URI การตั้งค่าไฟล์แนบที่คุณระบุไว้ในหน้าการกำหนดค่าแอปของ SDK ของ Google Workspace Marketplace
- เลือกเนื้อหาที่จะแนบไปกับงาน
- ปิด iframe หลังจากขั้นตอนการสร้างไฟล์แนบเสร็จสมบูรณ์
คุณควรเห็นการ์ดไฟล์แนบปรากฏใน UI การสร้างงานใน Google Classroom คลิกการ์ดเพื่อเปิด iframe ของมุมมองสำหรับครู และตรวจสอบว่าไฟล์แนบที่ถูกต้องปรากฏขึ้น คลิกปุ่มมอบหมาย
ทำตามขั้นตอนต่อไปนี้เพื่อทดสอบประสบการณ์การใช้งานของนักเรียน
- จากนั้นลงชื่อเข้าใช้ Classroom ในฐานะผู้ใช้ทดสอบที่เป็นนักเรียนในชั้นเรียนเดียวกับผู้ใช้ทดสอบที่เป็นครู
- ค้นหางานทดสอบในแท็บงานของชั้นเรียน
- ขยายงานแล้วคลิกการ์ดไฟล์แนบเพื่อเปิดเฟรมในแท็บ "มุมมองนักเรียน"
ยืนยันว่าไฟล์แนบที่ถูกต้องปรากฏขึ้นสำหรับนักเรียน
ยินดีด้วย คุณพร้อมที่จะไปยังขั้นตอนถัดไป ซึ่งก็คือการสร้างไฟล์แนบประเภทกิจกรรม