外部附件和上交

这是 Classroom 插件演练系列中的第七篇 演练。

在本演练中,您将为 Web 应用添加行为,以便在 Google 课堂外部创建插件附件 。借助此行为,您的用户可以从现有产品或网站创建插件附件。这对于 CourseWork 集成来说也是一个不错的补充,因为您可以将现有流量引导至插件提供的改进版用户体验,而无需更改其流程。如需了解建议的流程,请参阅我们的在课堂外部创建附件指南页面。

您还可以为插件添加行为,以便以编程方式修改带有插件附件的作业 。您可以修改任何带有插件附件的作业,无论作业是谁创建的。这对于在学生完成活动后上交作业尤其有用,可以向教师表明学生已完成分配的任务,并且学生的作品已准备好接受审核。

您将扩展支持内容类型活动类型附件的插件的最终版本。本指南中使用的是内容类型附件。

添加作业管理 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 SDKOAuth 权限请求页面和您的 服务器代码。

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",
  ]

在课堂中创建作业

向非 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 字段。对于符合条件的用户,请按照 逻辑创建带有插件 附件的作业。否则,请创建链接 资料。您需要知道用户要在哪个课程中创建作业的 ID。通常,您会提示用户指定要使用的课程。为简单起见,我们在本示例中使用硬编码的值。

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.

为符合条件的用户创建带有插件附件的作业

如果用户符合创建插件附件的条件,请执行以下操作:

  1. 发送 API 请求,以便在 Google 课堂中创建没有附件的 courseWork 作业
  2. 提取新创建的作业的 id
  3. 构建新的 CourseWork AddOnAttachment
  4. 发送请求,以便在 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 课堂信息流项,无论信息流项是谁创建的。信息流项可以是任何 AnnouncementCourseWork 作业或 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()
)

测试插件

为简单起见,提供的示例使用硬编码的课程和作业标识符。您可以使用教师凭据向 getlist 方法发出请求来获取这些标识符,这些方法属于 coursescourseWork 资源。创建 courseWork 作业时,这些标识符也会在响应中返回。

运行服务器,然后前往索引页,并以没有 Google Workspace 教育版教与学升级版或 Plus 版许可的教师用户身份登录 。您可以切换 用户的许可状态从您的测试域的 管理控制台。点击创建 CourseWork 作业 按钮,然后打开 Google 课堂界面,并验证是否已创建带有 链接资料附件的作业。附件应显示链接网页的标题和网址。

测试插件附件创建

返回到索引页,并以拥有 Google Workspace 教育版教与学升级版或 Plus 版许可的教师用户身份登录 。点击创建 CourseWork 作业 按钮,然后打开 Google 课堂界面,并验证是否已创建带有插件附件的作业。附件应显示插件应用的名称以及您在代码中指定的标题。

测试作业修改

返回到索引页,并确保您以拥有教与学升级版或 Plus 版许可的教师用户身份登录。点击修改 CourseWork 作业 按钮,然后返回到 Google 课堂界面,并验证作业标题是否已更改。

恭喜!您已完成本系列演练。