GASでスプレッドシート上の生徒をGoogle Classroomのクラスに招待する

GoogleAppsScriptを用いてスプレッドシート上の名簿の生徒をGoogle Classroomのクラスに招待する方法を紹介します。

概要

今回は作成したクラスへの副担任・生徒の招待をGASを用いて自動化してみたいと思います。
Google Classroomの簡単な説明と、GASへのGoogle Classroom APIの導入方法については以前の記事をご参照ください。

実行するアカウントが対象のクラスの「担任」または「副担任」である前提で作成していきます。

下記の流れで紹介していきます。

  1. スプレッドシートの準備
  2. GASのコード作成
    (1) クラス一覧の取得
    (2) 対象クラスの取得
    (3) 副担任の招待
    (4) 生徒の招待

1. スプレッドシートの準備

今回は、「スプレッドシートに紐づいたGAS」を使用します。
GASの準備については以前の記事の「スプレッドシートに紐づいたGASの作成方法」の項目を参考にしてください。

まずはクラスに招待したい生徒等の名簿を作成します。
今回は副担任と生徒をそれぞれ招待したいので、役割の列を追加した名簿にします。

シート名はわかりやすく「名簿」とします。

2.GASのコード作成

早速GASコードの作成をしていきます。

前準備として、先ほどのスプレッドシートに紐づいたGASにGoogle Classroom APIを導入します。
GASへのGoogle Classroom APIの導入方法については以前の記事をご参照ください。

(1) クラス一覧の取得

クラス一覧の取得では、基本的に自分が参加しているクラス全てが対象になります。
つまり、自分が作成し担任となっているクラス・副担任として参加しているクラス・生徒として参加しているクラスが全て取得されます。
もちろん取得するクラスを絞り込む方法もありますので後述したいと思います。

公式のサンプルをベースに作成していきたいと思います。
内容を一部変更・修正し、各部に解説コメントを添えています。
複雑な部分などについては別途解説を後述しているので理解の参考にしてください。

このlistCourses()という関数では、返り値としてクラス一覧を返すようにします。

function listCourses() {
  // 取得したクラス一覧の格納用変数
  var courses = [];

  // 次ページの有無確認用変数
  var pageToken = null;

  // クラス一覧取得時のオプション(1ページに100件)
  var optionalArgs = {
    pageToken: pageToken,
    pageSize: 100
  };

  // while文 pageTokenが有効な値の間実行
  while (true) {
    // クラス一覧オブジェクト取得
    let response = Classroom.Courses.list(optionalArgs);

    // クラス一覧情報を変数に格納
    courses = courses.concat(response.courses);

    // 次ページの有無を変数に格納(次ページが無ければundefined)
    pageToken = response.nextPageToken;

    // while文続行判定 (次ページが無ければ終了、あればオプションの内容を更新し繰り返し)
    if (!pageToken) {
       break;
    }
    else {
      optionalArgs.pageToken = pageToken;
    }
  }

  // クラス一覧が0件の場合
  if (courses.length === 0) {
    Logger.log("No courses found.");
  } 
  // クラス一覧が1件以上の場合
  else {
    Logger.log("Courses:");
    // クラスの数だけ実行
    for (course in courses) {
      Logger.log('%s (%s)', courses[course].name, courses[course].id);
    }
  }
  // 返り値 クラス一覧
  return courses;
}

pageTokenとは:

取得したいページの目印のようなものです。
今回取得しているクラス一覧のデータは、場合によってはとても多くの件数になるため、ページ単位で区切って取得します。
クラス一覧取得時のオプションoptionalArgspageSizeで1ページの最大件数を指定し、pageTokenでどのページを取得するのかを指定しています。
このときpageTokennullであれば最初のページを取得します。

while文とは:

繰り返し処理のひとつで、GASではなくJavascriptに含まれる機能です。
Javascript以外にもC++やPython、PHPなど広く一般に用いられています。
今回のWhile文はbreakが実行されるまで繰り返すという形になっています。
つまり、if(!pageToken)trueになるまで(=pageTokenの値がnullundefinedになるまで)while文中の処理を繰り返します。

返り値とは:

返り値とは、関数を実行した場合に返ってくる値のことです。
今回の例で言うと、listCourses()という関数を実行するとcoursesに格納されているクラス一覧のデータが返ってきます。
下記のようにすればreturnTest()という関数内でlistCourses()を呼び出し、返り値を変数に格納して用いることができます。

function returnTest() {
  let list = listCourses();
}

function listCourses() {
  // ここでは内容省略
}

実行結果(クラス一覧)

実行結果として、GASの実行ログには取得したクラス一覧の「クラス名」と「クラスID」が表示されます。
(クラスIDは黒塗りしています)

他のオプション

クラス一覧取得時のオプションoptionalArgsでは上記の2つ以外にも条件を指定できます。
これを用いて取得するクラスをあらかじめ絞り込むことが可能です。

courseStates:クラスの状態を指定し、該当するクラスのデータのみを取得します。
例)courseStates: ['ACTIVE', 'ARCHIVED']:活動中またはアーカイブされたクラスのみを取得します。

teacherId:教師を指定し、その教師が担任または副担任のクラスのみを取得します。自分を指定すれば自分が担任または副担任のクラスのみを取得できます。
例)teacherId: 'me':自分が担任または副担任のクラスのみを取得します。
例)teacherId: 'test-teacher@example.com'test-teacher@example.comという教師が担任または副担任のクラスのみを取得します。

studentId:生徒を指定し、その生徒が参加しているクラスのみを取得します。自分を指定すれば自分が生徒として参加しているクラスのみを取得できます。
例)studentId: 'me':自分が生徒として参加しているクラスのみを取得します。
例)studentId: 'test-student@example.com':自分が参加しているクラスのうちtest-student@example.comという生徒が参加しているクラスのみを取得します。

(2) 対象クラスの取得

次に、取得したクラス一覧の中から副担任や生徒を招待したいクラスを選んで取得します。
今回は「招待サンプル用クラス」というクラスを取得したいと思います。

手元で再現する場合は取得するクラス名を任意のものに変えてみるか、事前に「招待サンプル用クラス」という名前のクラスを作成してお試しください。

まずはselectCourse(courses, targetCourseName)という関数を新しく作成します。
第一引数のcoursesは先ほど取得したクラス一覧です。
第二引数のtargetCourseNameは取得したいクラスの「クラス名」です。

この関数は引数を必要とするため、GASエディターの「実行」や「デバッグ」を使って単体で動かすとエラーが発生します。
動作確認をする際には後述の例のように、別の関数内で引数を与えて呼び出す必要があります。

また、この関数は返り値として取得したクラスを返します。

function selectCourse(courses, targetCourseName) {

  let targetCourse = courses.find(c => c.name == targetCourseName);

  Logger.log("Target course:");
  Logger.log('%s (%s)', targetCourse.name, targetCourse.id);

  return targetCourse;
}

findについて:

配列に対する検索処理のひとつで、GASではなくJavascriptに含まれる機能です。
配列.find((データ, 順番, 配列※)=>{ 処理 }) というような書き方をします。

配列:find処理を行う配列
データ:配列の中のデータ1つ1つを指します
順番:現在処理しているデータが配列の中で何番目に存在するデータかを指します。0番目~(省略可)
配列※:find処理を行っている対象の配列(省略可)

今回の例では順番、配列※は使用しないため省略しています。
処理はboolean(TRUE or FALSE)を返す形である必要があります。
今回の例では、coursesの中のデータ1つ1つに対して、nametargetCourseNameと一致するものかどうかを判定し、一致するものをtargetCourseに格納しています。
ちなみに、もしも該当するデータが複数あった場合は最初に該当したものが格納されます。

この関数を実行してみましょう。
先ほどのクラス一覧取得関数listCourses()で取得したデータを使い、createInvitation()という新しい関数内で引数を渡して呼び出します。

この時点では何にも使用していませんが、ここで得たtargetCourseが招待対象のクラスとなります。

function createInvitation() {

  // クラス一覧取得
  const courses = listCourses();
  // 取得したいクラス名を指定
  const targetCourseName = '招待サンプル用クラス';

  // クラス一覧から指定の名前のクラスを取得
  const targetCourse = selectCourse(courses, targetCourseName);
}

実行結果(対象クラス取得)

GASの実行ログに「招待サンプル用クラス」の「クラス名」と「クラスID」が表示されます。

(3) 副担任の招待

それでは取得したクラスへ副担任の教師を招待してみましょう。

まずはスプレッドシートの「名簿」シートから招待したい教師のメールアドレスリストを取得します。
関数の返り値を、取得した教師一覧にしておきます。
各部に解説コメントを添えています。

function getTeachers() {
  // スプレッドシートとシートを取得
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('名簿');

  // データの開始行(2行目)
  const firstRow = 2;
  // メールアドレスの列(B列=2番目)
  const mailCol = 2;
  // 役割の列(C列=3番目)
  const roleCol = 3;
  
  // データ数(行数)
  var rowLength = sheet.getLastRow() - (firstRow - 1);
  // 教師一覧
  var teachers = [];

  // 行数分繰り返し処理
  for(let i = 0; i < rowLength; i++) {
    // 役割を取得
    let role = sheet.getRange(firstRow + i, roleCol).getValue();

    // 役割が副担任の場合
    if(role == '副担任'){
    // メールアドレスを取得
    let mail = sheet.getRange(firstRow + i, mailCol).getValue();
    // 教師一覧に追加
    teachers.push(mail);
    }
  }

  // 返り値 教師一覧
  return teachers;
}

次に、取得した教師一覧を使って招待を作成します。
内容は(2)で作ったcreateInvitation()に追記していきたいと思います。

招待の作成にはClassroom.Invitations.create(invitation)というメソッドを用います。
引数のinvitationというオブジェクトでは下記の3つの情報が必要になります。
userId:招待する相手のIDまたはメールアドレスです。
courseId:招待したいクラスのIDです。
role:招待する相手が何の役割になるかの指定です。

今回は副担任を招待するのでroleTEACHERになります。

function createInvitation() {

  // クラス一覧取得
  const courses = listCourses();
  // 取得したいクラス名を指定
  const targetCourseName = '招待サンプル用クラス';
  
  // クラス一覧から指定の名前のクラスを取得
  const targetCourse = selectCourse(courses, targetCourseName);

  // スプレッドシートから教師一覧を取得
  const teachers = getTeachers();

  // 教師一覧のデータ1つ1つに処理を実行
  teachers.forEach(teacher => {

    // 招待データ作成
    let invitationData = {
    'userId': teacher,
    'courseId': targetCourse.id,
    'role': 'TEACHER'
    };
  
    // 招待作成
    Classroom.Invitations.create(invitationData);
  });

}

実行結果(副担任の招待)

招待を作成すると対象のアカウントへ通知されます。
これはGmailへ実際に届いた招待メールです。

(4) 生徒の招待

同様にしてクラスへ生徒を招待してみましょう。

まずはスプレッドシートの「名簿」シートから招待したい生徒のメールアドレスリストを取得します。
関数の返り値を、取得した生徒一覧にしておきます。
各部に解説コメントを添えています。

function getStudents() {
  // スプレッドシートとシートを取得
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('名簿');

  // データの開始行(2行目)
  const firstRow = 2;
  // メールアドレスの列(B列=2番目)
  const mailCol = 2;
  // 役割の列(C列=3番目)
  const roleCol = 3;
  
  // データ数(行数)
  var rowLength = sheet.getLastRow() - (firstRow - 1);
  // 生徒一覧
  var students = [];

  // 行数分繰り返し処理
  for(let i = 0; i < rowLength; i++) {
    // 役割を取得
    let role = sheet.getRange(firstRow + i, roleCol).getValue();

    // 役割が生徒の場合
    if(role == '生徒'){
    // メールアドレスを取得
    let mail = sheet.getRange(firstRow + i, mailCol).getValue();
    // 生徒一覧に追加
    students.push(mail);
    }
  }

  // 返り値 生徒一覧
  return students;
}

また同様に、取得した生徒一覧を使って招待を作成します。
内容は(3)のcreateInvitation()に追記していきたいと思います。

今回は生徒を招待するのでroleSTUDENTになります。

function createInvitation() {

  // クラス一覧取得
  const courses = listCourses();
  // 取得したいクラス名を指定
  const targetCourseName = '招待サンプル用クラス';
  
  // クラス一覧から指定の名前のクラスを取得
  const targetCourse = selectCourse(courses, targetCourseName);

  // スプレッドシートから教師一覧を取得
  const teachers = getTeachers();

  // スプレッドシートから生徒一覧を取得
  const students = getStudents();

  // 教師一覧のデータ1つ1つに処理を実行
  teachers.forEach(teacher => {

    // 招待データ作成
    let invitationData = {
    'userId': teacher,
    'courseId': targetCourse.id,
    'role': 'TEACHER'
    };
  
    // 招待作成
    Classroom.Invitations.create(invitationData);
  });

  // 生徒一覧のデータ1つ1つに処理を実行
  students.forEach(student => {

    // 招待データ作成
    let invitationData = {
    'userId': student,
    'courseId': targetCourse.id,
    'role': 'STUDENT'
    };
  
    // 招待作成
    Classroom.Invitations.create(invitationData);
  });
}

コードの整理

ここまでのコードでも動作は問題ありません。
しかし、このコードでは同じような内容の反復が多くかっこ悪いので整理してみたいと思います。

まずはgetTeachers()getStudents()を合わせて1つの関数にしてみます。
前半は同じで、後半の役割で判定していた部分を除いてオブジェクト形式で配列に追加するようにしました。

function getMembers() {
  // スプレッドシートとシートを取得
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName('名簿');

  // データの開始行(2行目)
  const firstRow = 2;
  // メールアドレスの列(B列=2番目)
  const mailCol = 2;
  // 役割の列(C列=3番目)
  const roleCol = 3;
  
  // データ数(行数)
  var rowLength = sheet.getLastRow() - (firstRow - 1);
  // 名簿データ
  var members = [];

  // 行数分繰り返し処理
  for(let i = 0; i < rowLength; i++) {
    // メールアドレスと役割を取得
    let mail = sheet.getRange(firstRow + i, mailCol).getValue();
    let role = sheet.getRange(firstRow + i, roleCol).getValue();

    // 1人分のデータをオブジェクトとして作成
    let memberData = {
      mail: mail,
      role: role
    }
    // 名簿データに1人分のデータを追加
    members.push(memberData);
  }

  // 返り値 名簿データ
  return members;
}

そしてcreateInvitation()を上記に合わせていきます。
名簿データはmailroleの項目を持つオブジェクトなので、それを利用してそれぞれのroleを指定してあげます。

function createInvitation() {

  // クラス一覧取得
  const courses = listCourses();
  // 取得したいクラス名を指定
  const targetCourseName = '招待サンプル用クラス';
  
  // クラス一覧から指定の名前のクラスを取得
  const targetCourse = selectCourse(courses, targetCourseName);

  // スプレッドシートから名簿データを取得
  const members = getMembers();

  // 名簿データ1つ1つに処理を実行
  members.forEach(member => {

    // データのroleが副担任か生徒の場合、それぞれのroleを指定
    if(member.role == '副担任'){
      var role = 'TEACHER';
    }
    else if(member.role == '生徒') {
      var role = 'STUDENT';
    }
    // 副担任でも生徒でもない場合は以降の処理をスキップ
    else{
      return;
    }

    // 招待データ作成
    let invitationData = {
    'userId': member.mail,
    'courseId': targetCourse.id,
    'role': role
    };
  
    // 招待作成
    Classroom.Invitations.create(invitationData);
  });
}

まとめ

今回はGoogle Classroom APIを使ったクラスへの生徒や副担任の招待を行うGASをご紹介しました。
とはいえ、このままだと実行する度に同じメンバーに招待を作ろうとしてしまったり、GASを編集しないと他のクラスへの招待が作れなかったりと実用面では不便なところがたくさんあります。
次回はこのGASを応用・改良して、スプレッドシートベースの実用的なGASにしてみたいと思います。

Google Cloudの導入は当社にご相談ください

ITディストリビューターであるTD SYNNEXはGoogle Cloud™ Partner Award を受賞するなど、長年にわたりGoogle™のグローバル認定ディストリビューターとして、総合的な Googleソリューションを提供しています。お客様にとって最適なソリューションの提案や導入、活用をサポートします。

製品・サービスについてのお問合せ

情報収集中の方へ

導入事例やソリューションをまとめた資料をご提供しております。

資料ダウンロード
導入をご検討中の方へ

折り返し詳細のご案内を差し上げます。お問い合わせお待ちしております。

お問い合わせ