Search code examples
google-apps-scriptgoogle-sheetsgoogle-drive-apigoogle-classroom

How do I attach file to Google Classroom 'materials' assignment using Apps Script?


Using apps script in Google Sheet I can create a new assignment or 'materials' for students in a Google Classroom, passing the information programmatically from Google Sheet.

One of the fields in the Google Sheet - responses from a Google Form - is a link to a file uploaded as evidence. I want to attach that linked file to the 'materials' assignment in Google Classroom.

I have a function that passes all the other information to Google Classroom and I'm sure the file itself is being found and passed to Google Drive but my code is not attaching the file to the 'Materials' assignment. The problem seems to be here -

      Classroom.Courses.CourseWorkMaterials.create({
        assigneeMode: "INDIVIDUAL_STUDENTS",
        individualStudentsOptions: { studentIds: [studentId] },
        title: pupil + " - " + curriculumArea,
        description: materials.description, 
        materials: materials.materials 
      }, courseId);

The error message is

Error   
GoogleJsonResponseException: API call to classroom.courses.courseWorkMaterials.create failed with error: Invalid JSON payload received. Unknown name "id" at 'course_work_material.materials[0].drive_file': Cannot find field.
Invalid JSON payload received. Unknown name "title" at 'course_work_material.materials[0].drive_file': Cannot find field.
Invalid JSON payload received. Unknown name "driveFileId" at 'course_work_material.materials[1].drive_file': Cannot find field.
Invalid JSON payload received. Unknown name "title" at 'course_work_material.materials[1].drive_file': Cannot find field.
createMaterialsFromGoogleSheet  

Which I think refers to

    // Define the materials array
    var materials = {
      title: pupil + " - " + curriculumArea,
      description: "Learning intentions: " + learningIntentions + "\n\nSuccess criteria: " + successCriteria + "\n\nAssessment comments: " + assessmentComments + "\n\nNext steps: " + nextSteps,
      materials: [
      {
        driveFile: {
          id: evidenceId,
          title: fileName
        }
      }
    ]
    };

and

      // Add the evidence file to the materials
materials.materials.push({
  driveFile: {
    id: evidenceId,
    title: fileName
  }
});

This is how these snippets fit into the function

 // Loop through each row of data and create a new material for each student
  for (var i = 1; i < data.length; i++) {
    var pupil = data[i][1];
    var curriculumArea = data[i][2];
    var learningIntentions = data[i][3];
    var successCriteria = data[i][5];
    var assessmentComments = data[i][6];
    var nextSteps = data[i][7];
    var evidenceLink = data[i][8];

    // Define the materials array
    var materials = {
      title: pupil + " - " + curriculumArea,
      description: "Learning intentions: " + learningIntentions + "\n\nSuccess criteria: " + successCriteria + "\n\nAssessment comments: " + assessmentComments + "\n\nNext steps: " + nextSteps,
      materials: [
      {
        driveFile: {
          id: evidenceId,
          title: fileName
        }
      }
    ]
    };

    var evidenceId = "";
    var fileName = "";
    if (evidenceLink) {
      evidenceId = uploadFileToDrive(evidenceLink);
      if (!evidenceId) {
        Logger.log("Could not upload file: " + evidenceLink);
        continue;
      }
      
      // Get the file name from the evidenceLink
      var fileName = evidenceLink.split("/").pop();
      
      // Add the evidence file to the materials
materials.materials.push({
  driveFile: {
    id: evidenceId,
    title: fileName
  }
});
    
      // Add the evidence link to the description
      assessmentComments += "\n\nEvidence: " + evidenceLink;
    }


    if (pupil) {
      var studentId = getStudentId(pupil, courseId);
      if (!studentId) {
        Logger.log("Could not find student with name '" + pupil + "' in course. Skipping row.");
        continue;
      }
      
      Classroom.Courses.CourseWorkMaterials.create({
        assigneeMode: "INDIVIDUAL_STUDENTS",
        individualStudentsOptions: { studentIds: [studentId] },
        title: pupil + " - " + curriculumArea,
        description: materials.description, 
        materials: materials.materials 
      }, courseId);
    }
  }
} 

Looks like the error is to do with the drive file. In the google sheet it looks like this - https://drive.google.com/open?id=18xxMxkYp5W5x3NbbMAqVnJOx6pwlxxxx

The code that is called by evidenceId = uploadFileToDrive(evidenceLink); is

function uploadFileToDrive(url) {
  var response = UrlFetchApp.fetch(url, {
    headers: {
      Authorization: 'Bearer ' + ScriptApp.getOAuthToken()
    }
  });
  var file = Drive.Files.insert({
    title: "evidence",
    mimeType: response.getHeaders()['Content-Type']
  }, response.getBlob());
  return file.id;
}

Solution

  • Modification points:

    • In your script, in the following part, evidenceId and fileName are not declared. I think that this is the reason for 1st Unknown name "title" at .

        var materials = {
          title: pupil + " - " + curriculumArea,
          description: "Learning intentions: " + learningIntentions + "\n\nSuccess criteria: " + successCriteria + "\n\nAssessment comments: " + assessmentComments + "\n\nNext steps: " + nextSteps,
          materials: [
          {
            driveFile: {
              id: evidenceId,
              title: fileName
            }
          }
        ]
        }
      
    • It seems that {driveFile: {id: evidenceId, title: fileName}} should be {driveFile: {driveFile: {id: evidenceId, title: fileName}}}. I think that this is the reason for the 2nd Unknown name "title" at .

    When these points are reflected in your script, it becomes as follows.

    Modified script:

      for (var i = 1; i < data.length; i++) {
        var pupil = data[i][1];
        var curriculumArea = data[i][2];
        var learningIntentions = data[i][3];
        var successCriteria = data[i][5];
        var assessmentComments = data[i][6];
        var nextSteps = data[i][7];
        var evidenceLink = data[i][8];
    
        // Define the materials array
        var materials = {
          title: pupil + " - " + curriculumArea,
          description: "Learning intentions: " + learningIntentions + "\n\nSuccess criteria: " + successCriteria + "\n\nAssessment comments: " + assessmentComments + "\n\nNext steps: " + nextSteps,
          materials: []
        };
    
        var evidenceId = "";
        var fileName = "";
        if (evidenceLink) {
          evidenceId = uploadFileToDrive(evidenceLink);
          if (!evidenceId) {
            Logger.log("Could not upload file: " + evidenceLink);
            continue;
          }
    
          // Get the file name from the evidenceLink
          var fileName = evidenceLink.split("/").pop();
    
          // Add the evidence file to the materials
          materials.materials.push({
            driveFile: {
              driveFile: {
                id: evidenceId,
                title: fileName
              }
            }
          });
    
          // Add the evidence link to the description
          assessmentComments += "\n\nEvidence: " + evidenceLink;
        }
    
        if (pupil) {
          var studentId = = getStudentId(pupil, courseId);
          if (!studentId) {
            Logger.log("Could not find student with name '" + pupil + "' in course. Skipping row.");
            continue;
          }
    
          Classroom.Courses.CourseWorkMaterials.create({
            assigneeMode: "INDIVIDUAL_STUDENTS",
            individualStudentsOptions: { studentIds: [studentId] },
            title: pupil + " - " + curriculumArea,
            description: materials.description,
            materials: materials.materials
          }, courseId);
        }
      }
    

    Note:

    • In this modification, it supposes that your all values for using the request body are valid values. If the invalid values are included, I'm worried that another error occurs. Please be careful about this.