这是 Google 课堂插件演练系列中的第七个演练。
在此演练中,您将为 Web 应用添加行为,以从 Google 课堂外部创建附件。使用此行为可让用户通过现有产品或网站创建插件附件。对于 CourseWork 集成,这也是一个很好的补充,因为您可以将现有流量引导至插件提供的改进版用户体验,而无需更改用户流程。如需了解建议的流程,请参阅我们的在 Google 课堂之外创建附件指南页面。
您还可以向插件添加行为,以通过编程方式修改包含插件附件的作业。您可以修改附加了插件附件的任何作业,无论该作业是谁创建的。这对于学生在完成活动后提交作业非常有用,可以向教师表明学生已完成布置的任务,并且其作业已准备好接受检查。
您扩展支持内容类型或activity 类型附件的插件的最终版本。本指南中使用了 content-type 附件。
添加作业管理 OAuth 范围
确保您的应用请求以下范围:
- https://www.googleapis.com/auth/classroom.addons.teacher
- https://www.googleapis.com/auth/classroom.addons.student
- https://www.googleapis.com/auth/classroom.coursework.students
之前不需要 classroom.coursework.students 范围,该范围用于创建或修改 CourseWork 分配。将此范围添加到 Cloud 项目的  Google Workspace Marketplace SDK、OAuth 同意屏幕和服务器代码中的范围列表。
Python
  SCOPES = [
    "https://www.googleapis.com/auth/classroom.addons.teacher",
    "https://www.googleapis.com/auth/classroom.addons.student",
    "https://www.googleapis.com/auth/classroom.coursework.students",
  ]
在 Google 课堂中创建作业
向非 iframe 网页添加按钮
本演示中描述的流程允许用户从非 Google 产品创建 Google 课堂作业和附件。在实践中,这很可能是您现有的网站或应用。在此示例中,您需要创建一个模拟网页作为外部网站。您需要一个按钮或链接,点击该按钮或链接后,系统会打开一个新路线,该路线会执行建议的 CourseWork 流程来创建新作业。
如果您还没有按钮或链接,还需要添加一个按钮或链接,以便用户登录。您需要用户凭据才能发出后续 API 请求,因此用户必须完成 OAuth 2.0 握手。如需具体指导,请参阅登录演练。
Python
提供的 Python 示例修改了第一个演练步骤中介绍的 /index 路由。
<!-- /webapp/templates/index.html -->
<a href="clear-credentials.html">Logout</a>
<a href="start-auth-flow.html">Login</a>
<br>
<a href="create-coursework-assignment.html">Create a CourseWork Assignment</a>
添加一个 HTML 模板来表示您网站中的目的地。此页面将显示将附加到 CourseWork 作业的内容。
<!-- /webapp/templates/example-coursework-assignment.html -->
<h1>CourseWork assignment loaded!</h1>
<p>You've loaded a CourseWork assignment! It was created from an external web page.</p>
创建一个新的 Python 模块文件来处理与 CourseWork 相关的路由。
在提供的示例中,此值为 coursework_routes.py。添加以下三条路线;请注意,您稍后会填写部分内容。
# /webapp/coursework_routes.py
@app.route("/create-coursework-assignment")
def create_coursework_assignment():
  """
  Completes the assignment creation flow.
  """
  # Check that the user is signed in. If not, perform the OAuth 2.0
  # authorization flow.
  credentials = get_credentials()
  if not credentials:
    return start_auth_flow("coursework_assignment_callback")
  # Construct the Google Classroom service.
  classroom_service = get_classroom_service()
  pass  # To be completed later.
@app.route("/example-coursework-assignment/<assignment_type>")
def example_coursework_assignment(assignment_type):
  """
  Renders the "example-coursework-assignment.html" template.
  """
  return flask.render_template(
      "example-coursework-assignment.html", assignment_type=assignment_type
  )
@app.route("/coursework-assignment-callback")
def coursework_assignment_callback():
  """
  Completes the OAuth 2.0 handshake and stores credentials in the session.
  This is identical to the callback introduced in the sign-in walkthrough,
  but redirects the user to the index page instead of the attachment
  discovery page.
  """
  flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
      CLIENT_SECRETS_FILE,
      scopes=SCOPES,
      state=flask.session["state"],
      redirect_uri=flask.url_for("coursework_assignment_callback", _external=True),
  )
  flow.fetch_token(authorization_response=flask.request.url)
  credentials = flow.credentials
  flask.session["credentials"] = session_credentials_to_dict(
      credentials
  )
  # Close the current window and redirect the user to the index page.
  return flask.render_template("close-me.html", redirect_destination="index")
检查用户是否符合创建附件的条件
用户必须满足多项前提条件,您才能代表他们创建附件。为方便起见,Google 提供了 userProfiles.checkUserCapability 方法来确定用户是否满足这些前提条件。满足前提条件的用户称为符合条件的用户。
将资格条件检查添加到 CourseWork 创建路线实现中。
然后,测试响应中的 allowed 字段。对于符合条件的用户,请按照逻辑创建附加了加购项的布置。否则,请创建 LinkMaterial。您需要知道用户想要在哪个课程中创建作业。通常,您会提示用户指定要使用的课程。为简单起见,我们在本示例中使用硬编码的值。
Python
# /webapp/coursework_routes.py
@app.route("/create-coursework-assignment")
def create_coursework_assignment():
  """
  Completes the assignment creation flow.
  """
  # ... Check that the user is signed in and get the Classroom service ...
  # Check whether the user can create add-on attachments.
  eligibility_response = (
      classroom_service.userProfiles()
      .checkUserCapability(
        userId="me",
        capability="CREATE_ADD_ON_ATTACHMENT",
        # The previewVersion is necessary while the method is available in the
        # Workspace Developer Preview Program.
        previewVersion="V1_20240930_PREVIEW",
      ).execute()
  )
  is_create_attachment_eligible = eligibility_response.get("allowed")
  if is_create_attachment_eligible:
    # See the "Create an assignment with add-on attachment for eligible users" section for implementation.
  if not is_create_attachment_eligible:
    # See the "Create a Link Material" section for implementation.
为符合条件的用户创建包含插件附件的作业
如果用户有资格创建附件,请执行以下操作:
- 发送 API 请求,以在 Google 课堂中创建不含附件的 courseWork作业。
- 提取新创建的布置的 id。
- 构造新的 CourseWork AddOnAttachment。
- 发送请求,以在 Google 课堂中新创建的作业上创建插件附件。
Python
# The ID of the course to which the assignment will be added.
course_id = 1234567890  # TODO(developer) Replace with an actual course ID.
# /webapp/coursework_routes.py
if is_create_attachment_eligible:
  # Create an assignment.
  coursework = {
      "title": "My CourseWork Assignment with Add-on Attachment",
      "description": "Created using the Classroom CourseWork API.",
      "workType": "ASSIGNMENT",
      "state": "DRAFT",  # Set to 'PUBLISHED' to assign to students.
  }
  # Issue a request to create the assignment.
  create_assignment_response = (
      classroom_service.courses()
      .courseWork()
      .create(courseId=course_id, body=coursework)
      .execute()
  )
  # Create an add-on attachment that links to the selected content and
  # associate it with the new assignment.
  content_url = flask.url_for(
      "example_coursework_assignment",
      assignment_type="add-on-attachment",
      _scheme="https",
      _external=True,
  )
  # Construct an AddOnAttachment instance.
  attachment = {
      "teacherViewUri": {"uri": content_url},
      "studentViewUri": {"uri": content_url},
      "title": f'Test Attachment for Assignment {create_assignment_response.get("id")}',
  }
  # Issue a request to create the attachment.
  add_on_attachment_response = (
      classroom_service.courses()
      .courseWork()
      .addOnAttachments()
      .create(
          courseId=course_id,
          itemId=create_assignment_response.get("id"),  # ID of the new assignment.
          body=attachment,
      )
      .execute()
  )
创建链接资料
如果用户不符合创建附加链接的条件,请改为创建链接素材资源,具体操作如下:
Python
# The ID of the course to which the assignment will be added.
course_id = 1234567890  # TODO(developer) Replace with an actual course ID.
if not is_create_attachment_eligible:
    coursework = {
        "title": "My CourseWork Assignment with Link Material",
        "description": "Created using the Classroom CourseWork API.",
        "workType": "ASSIGNMENT",
        "state": "DRAFT",  # Set to 'PUBLISHED' to assign to students.
        # Specify the URL for your content as a Link Material.
        "materials": [
            {
                "link": {
                    "url": flask.url_for(
                        "example_coursework_assignment",
                        assignment_type="link-material",
                        _scheme="https",
                        _external=True,
                    )
                }
            }
        ],
    }
    # Issue a request to create the assignment.
    assignment_response = (
        classroom_service.courses()
        .courseWork()
        .create(courseId=course_id, body=coursework)
        .execute()
    )
修改已创建的作业
您可以访问、修改、提交、回收或退回任何包含至少一个插件附件的 Google 课堂动态项目,无论该动态项目是谁创建的。信息流项可以是任何 Announcement、CourseWork 作业或 CourseWorkMaterial。
为了演示这一点,您将添加一个用于修改指定流项的路由。使用此方法可验证您是否可以访问和修改通过 API 和教师通过 Google 课堂界面创建的动态项目。
向您在本演练中首次修改的网页再添加一个链接或按钮。它应该会打开一个新路由来修改 CourseWork 分配。
Python
提供的 Python 示例会修改本演练前面部分修改的 /index 路由。
<!-- /webapp/templates/index.html -->
<a href="modify-coursework-assignment.html">Create a CourseWork Assignment</a>
创建新路由以处理与 CourseWork 相关的路由。在提供的示例中,此文件为 coursework_routes.py 文件。
# Check that the user is signed in.
credentials = get_credentials()
if not credentials:
  return start_auth_flow("coursework_assignment_callback")
# Get the Google Classroom service.
classroom_service = get_classroom_service()
# The ID of the course to which the assignment will be added.
# Ordinarily, you'll prompt the user to specify which course to use. For
# simplicity, we use a hard-coded value in this example.
course_id = 1234567890  # TODO(developer) Replace with an actual course ID.
assignment_id = 1234567890  # TODO(developer) Replace with an actual assignment ID.
# Retrieve details about the CourseWork assignment.
get_coursework_response = (
    classroom_service.courses()
    .courseWork()
    .get(courseId=course_id, id=assignment_id)
    .execute()
)
# Alter the current title.
assignment_title = f"{get_coursework_response.get('title')} (Modified by API request)"
# Issue a request to modify the assignment.
modify_coursework_response = (
    classroom_service.courses()
    .courseWork()
    .patch(
        courseId=course_id,
        id=assignment_id,
        updateMask="title",
        body={"title": assignment_title},
    )
    .execute()
)
测试插件
为简单起见,提供的示例使用硬编码的课程和作业标识符。您可以通过以下方式获取这些标识符:使用教师凭据向 courses 和 courseWork 资源的 get 和 list 方法发出请求。创建 courseWork 作业时,它们也会在响应中返回。
测试链接素材资源创建
运行服务器,然后前往您的首页,并以没有 Google Workspace 教育版教与学升级版或 Plus 版许可的教师用户身份登录。您可以在测试网域的管理控制台中切换用户的许可状态。点击创建 CourseWork 作业按钮,然后打开 Google 课堂界面,验证是否已创建附加了“链接材料”的作业。附件应显示所链接网页的标题和网址。
测试插件附件创建
返回到索引页,然后以教师用户身份登录(拥有 Google Workspace 教育版教与学或 Plus 许可)。点击创建课程作业按钮,然后打开 Google 课堂界面,验证是否已创建附加了插件的作业。附件应显示您的插件应用的名称以及代码中指定的标题。
测试作业修改
返回到索引页,确保您以拥有教与学升级版或 Plus 版许可的教师用户身份登录。点击 Modify a CourseWork Assignment 按钮,然后返回 Google 课堂界面,验证作业标题是否已更改。
恭喜!您已完成本演练系列。