Google Classroom, Google Sheets, Google Apps Script: Classroom API, SpreadsheetApp, map, forEach
At the date of writing this the world is in the midst of a worldwide pandemic – the Corona Virus.
For educators and their Igors administrators like me, it has been an incredibly busy couple of months.
Many of us have quickly sort to use online resources and tools to keep in contact with our students and take a crash course into the world of online teaching.
Google Classroom has become one of the darlings of the teaching world that has come out of this crisis. Its shallow learning curve and attractive UI made it an obvious choice for most educators. Oh, and I am sure the fact that it is free helped too.
For all of Google Classroom’s ease of use, I still feel the application is in its fledgling stages and does have a few limitations that, I’m sure, Google is constantly working on and improving.
One of the limitations is that you cannot simply upload grades from, say Google Sheets or another assessment tool. Well…not directly in the Google Classroom platform, yet.
However, you can still upload grades from an external source using Google Apps Script. You could use GAS to upload a whole courses grades from a Google Sheet. You could even use GAS to upload grades on a trigger from another assessment’s API into your Google Classroom.
In this tutorial, I am going to run you through the basics of uploading grades into Google Classroom using Google Apps Script with the Classroom API.
NOTE! This tutorial is for a wide audience. Feel free to read the post all the way through, or take what you need and get cracking!
Table of Contents
The Example: Dyson Sphere Construction 101
The best way to explain how to upload grades into Course Work in Google Classroom is with an example.
Behold! My example Google Classroom: Dyson Sphere Construction 101:
If you click on the Classwork tab you will see that we have separated our classwork into 3 units.
The units are created by selecting the Create button and selecting, Topic.
Imagine that we have used an external assessment tool that we have then downloaded the results from and put into a spreadsheet:
Fortunately for us, the downloaded grades use our student’s emails. We can use these as a reference ID to the students in our Google Classroom.
The Setup
In Google Classroom, all the courses, students, teachers, coursework etc all use unique numerical reference numbers to locate this information. This means before we can run our upload, we need to find all these IDs.
Creating a new Google Apps Script Project
Navigate to your Google Apps Script main page and create a new project.
Give your project a title. Then rename the Code.gs file to “Setup”.
Next, go to File > New > Script file and create a new *.gs file called, “Test”.
Set up the Classroom API
Google Classroom API is an advanced API. This means that you will need to add it to your project before it will run.
To do this, go to your GAS console and navigate to Services.
You may get a warning to accept the Cloud Console Terms of Service. If so, click the link.
Another browser tab will open in the Cloud Console. Accept the terms of service and click AGREE AND CONTINUE:
Go back to your GAS console and try again (Services)
Navigate to Google Classroom API and select it. Then hit, Add.
Noice! You are ready to start coding.
Find the Course and Owner
First, we need to find the ID of the course we want to add our grades into.
In your Setup.gs file type in the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
/******************************************************* * Logs the Courses in your accounts domain and the owners. * * If you have the admin privelages in GSuite Domain, you will * see all users who have classes in your domain. * * returns : Array containing, course name, id, and owner. */ function findCourseAndOwner() { const courseList = Classroom.Courses.list().courses; const courseData = courseList.map(course => { let ownerName = Classroom .Courses .Teachers .get(course.id, course.ownerId) .profile .name .fullName return `${course.name} : ${course.id} : ${ownerName}`; }); return courseData; }; |
In your Test.gs file, add the following run code:
1 2 3 |
function runGetCoursesID() { console.log(findCourseAndOwner()); }; |
This code will return a list of courses with the following details:
- The course name.
- The course id.
- The owner of the course.
From this information, we should be able to easily find the course we want to add our grades into.
Go to the Test.gs file and run the runGetCoursesID()
function.
You will need to accept a bunch of permissions to run this code.
Once complete, the code will have logged all the courses that you have created*. Next, head over to the Stackdriver log to view the logged results (View > Stackdriver Logging). This will open a separate tab.
*If you are on your own GSuite domain (e.g. www.yagisanatode.com) and you have full administration privileges, then you may be able to see all the courses that all the users in your domain created.
You should end up with something like this:
1 2 3 4 |
[ 'Kardashev scale basics : 83743632554 : Yagisan Atode', 'Dyson Sphere Construction 101 : 83743632546 : Yagisan Atode' ] |
You can now see that our Dyson Sphere course has an id of: “83743632546”.
Your ID will, of course, be different.
Save the ID for your course. You will use this later.
Code Breakdown
runGetCoursesID()
The runGetCoursesID()
function simply logs the results of the findCourseAndOwner()
function.
findCourseAndOwner()
First, we want to get a list of all the courses. We do this with the Google Classroom API’s Courses reference.
If we use the list method we can then get a detailed object list of each course with a heap of details (Line 11). Part of this object will contain the course ID and its title.
1 |
const courseList = Classroom.Courses.list().courses; |
Don’t forget to add the courses
bit at the end to get to the array of courses.
Next, we will use Javascript’s map to iterate through each course and return only the course (Line 13):
- ID
- Title
- Owner of the course
1 |
const courseData = courseList.map(course => { |
To find the owner of the course we need to dig into the Courses Teachers resource(Line 14).
1 2 3 4 5 6 7 |
let ownerName = Classroom .Courses .Teachers .get(course.id, course.ownerId) .profile .name .fullName |
We use the get method here. The Courses.Teachers.get method takes two arguments:
- The course ID
- The teacher ID
We draw our course ID from our list of courses as our map iterates through each course. We want the name of the owner who will be one of the teachers on the course. In our get method, we reference the currently iterated course ID and the ID of the owner. This will give us a detailed set of key-value pairs about the teacher. We then select the profile key, its child, name, and that child key fullName. The name of this teacher will be the owner of the course.
Finally, we return a string containing our owner name, the course id and the course name.
1 |
return `${course.name} : ${course.id} : ${ownerName}`; |
The ownerName
array of mapped items is then returned once the findCourseAndOwner()
function is run.
Getting a list of students in your Google Classroom Course
While not a directly essential part of uploading grades to Google Classroom. You may need to use your list of student emails, and ids for your course to compare against the grades you are going to upload from your Google Sheet or via some other resource.
This code will provide you with a list of the student’s:
- ID
- Full name
To upload grades you will need to reference either the student’s ID or email address. The Full name is used as a visual reference so you know what students you are looking at.
In your Test.gs file paste the following code:
1 2 3 4 5 |
function getStudents(){ const courseID = "83743632546";// << Update this console.log(getStudentDetails(courseID)); }; |
You will need to add your selected course ID you discovered from running the runGetCoursesID()
function previously.
In your Setup.gs file add this code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/******************************************************* * Gets a list of alls students in a course. * * param {string} : course ID taken from findCourseAndOwner() * * returns : an array of students full name, id and email address. */ function getStudentDetails(COURSE_ID){ const students = Classroom.Courses.Students.list(COURSE_ID).students return students.map(student => { return `${student.profile.name.fullName}`+ `: ${student.profile.id} `+ `: ${student.profile.emailAddress}` }); }; |
Running the getStudents()
function from the Test.gs file will result in a list of student details like this:
1 2 3 4 |
[ 'Yagisan Atode: 106843438463340235096 : yagi@gmail.com', 'Kidd O'Goat: 104130479130520260624 : kid@gmail.com' ] |
Code Breakdown
getStudents()
In the Test.gs file getStudents()
first requires the course ID we found earlier with findCourseAndOwner()
(Line 2).
Then we run the getStudentDetails(courseID)
from the Setup.gs file to return our student list of results. For us, we just logged the results (Line 4). However, you might want to directly input the student list into a Google Sheet or something.
getStudentDetails(COURSE_ID)
This function takes the course id parameter and returns a list of students from that course.
Our first step is to get our list of students using the Classroom API’s Course.Students.List method. This method takes one parameter, the courses ID. This will return a comprehensive list of details for each student on the course.
1 |
const students = Classroom.Courses.Students.list(COURSE_ID).students |
Next, we simply map through each of the students grabbing their ID, full names and emails:
1 2 3 4 5 |
return students.map(student => { return `${student.profile.name.fullName}`+ `: ${student.profile.id} `+ `: ${student.profile.emailAddress}` }); |
Getting the Classroom Topic Items
We want to put our course assignment and the grades into a specific Topic, Unit 2, in the Classwork tab of the Google Classroom dashboard. To do this we will need to find the topic’s ID.
To get a list of topics and their corresponding IDs, add the following code to your Test.gs script.
1 2 3 4 5 |
function getTopicList(){ const courseID = "83743632546"; // << Update this console.log(getTopics(courseID)); }; |
Then, add this function to your Setup.gs file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
/******************************************************* *Returns a list of Topics by name and id * * param {string} : course ID taken from findCourseAndOwner() * * returns : an array of students full name, id and email address. */ function getTopics(COURSE_ID){ const topics = Classroom.Courses.Topics.list(COURSE_ID).topic; const topicItems = topics.map(item => `${item.name} : ${item.topicId}`); return topicItems; }; |
When you run getTopicList()
from the Test.gs file, it should log the following results:
1 2 3 4 5 |
[ 'Unit 1 : 83743632578', 'Unit 2 : 83743632579', 'Unit 3 : 83743632580' ] |
Now we know that our Unit 2 has the ID, 83743632579.
Note: I think, by now you probably have figured out what the Test functions do, so I will skip them in the code breakdown from now on.
code Breakdown
getTopics(COURSE_ID)
The getTopics(COURSE_ID)
function takes the course ID and returns an array of all the topics along with their assigned unique IDs.
To get a list of all the Topics and their details we use the – yep…you guessed it – the Courses.Topics.List method.
1 |
const topics = Classroom.Courses.Topics.list(COURSE_ID).topic; |
We then use JS map to iterate through each topic and store the ID and name of the topic.
1 |
const topicItems = topics.map(item => `${item.name} : ${item.topicId}`); |
Uploading the grades
Once we have run our setup we should have 3 important IDs:
- Course ID
- Topic ID
- Emails and ID for students (we will use the emails here to put on our Google Sheet)
One of the challenges of uploading grades to Google Classroom is that we can’t create an assignment in the Classroom dashboard and then upload grades directly to that assignment. Instead, we need to create the assignment programmatically. For us, we will do this in Google Apps Script.
More on this in a minute.
The Code:
In your Google Apps Script editor, create a new file and call it CourseGrades.gs. Paste in the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
/******************************************************* * CREATE A COURESE WORK ITEM AND ADD GRADES */ /******************************************************* *Simultaneously create a coursework item and add grades to it. * * In this example, I have put all the global data we gained from our * tests in the first 3 global variables. * * You will need to update the Course infor where it says <<< UPDATE THIS */ function assignGradesToNewCourseWork(){ //****GLOBALS***** //Update the relevant items hwere. const COURSE_ID = "83743632546";// <<< UPDATE THIS const TOPIC_ID = "83743632579";// <<< UPDATE THIS const COURSE_INFO = { "assigneeMode": "ALL_STUDENTS", "associatedWithDeveloper": true, "description": "describe what your assignment is about here.",// <<< UPDATE THIS "maxPoints": 40, // <<< UPDATE THIS "state": "PUBLISHED", "submissionModificationMode": "SUBMISSION_MODIFICATION_MODE_UNSPECIFIED", "title": "Unit 2 - External Grade import", // <<< UPDATE THIS "workType": "ASSIGNMENT", "topicId":TOPIC_ID } const COURSEWORK_ID = createCourseWork_(COURSE_ID,COURSE_INFO); //A 2d array of grades = [[email@email.com,20],[email1@email.com, 18],[ ...etc]]; const GRADES = importGrades_() //You can import from any sourse. For this, I am just importing from Google Sheets. GRADES.forEach(student => setGrade_(COURSE_ID,COURSEWORK_ID,student[0],student[1])) }; //###################################################### /******************************************************* * Create a Coursework Item * * You can only upload grades for coursework items that have been created * in your GAS project. */ //###################################################### /******************************************************* * Helper functions */ /******************************************************* * Import Grades from a Google Sheet * * In this example, I have used a Google Sheet to import grades, * however, if you have access to an API from which your grades are * derrived, then you might like to use that instead. * * You will need to update the variables where it says <<< UPDATE THIS * * returns : a 2d array of email and grade values. */ function importGrades_(){ const ss = SpreadsheetApp.openById("1Ddv_Fv_f6pwbyPxDbJnkOcF2OSfNNjgv3K259G5WV8");// <<< UPDATE THIS const sheet = ss.getSheetByName("Sheet1");// <<< UPDATE THIS const range = sheet.getRange(2,1,sheet.getLastRow()-1,2); // <<< UPDATE THIS const values = range.getValues(); return values; }; /******************************************************* * Adds the grade for each available student. * * param {string} : COURSE_ID - ID of course. * param {string} : COURSEWORK_ID - ID of coursework item. * param {string} : USER_ID - ID of user. * param {string} : GRADE - users grade. */ function setGrade_(COURSE_ID, COURSEWORK_ID, USER_ID, GRADE){ try{ var grades = { 'assignedGrade': GRADE, 'draftGrade': GRADE } const studentSub = Classroom.Courses.CourseWork.StudentSubmissions let submissionID = studentSub.list( COURSE_ID, COURSEWORK_ID, {"userId":USER_ID} ).studentSubmissions[0].id studentSub.patch( grades, COURSE_ID, COURSEWORK_ID, submissionID, { "updateMask":"assignedGrade,draftGrade" } ); }catch(e){ console.error(e); console.log(`${USER_ID} could not be found and was not uploaded.`); } }; /******************************************************* * Creates a coruse work item that can be used for grade uploads. * * param {string} : COURSE_ID - ID of course. * param {object} : COURSE_INFO - Object array of data to be entered to created the coursework. * * return : the id for the course. Can be logged or used directly. */ function createCourseWork_(COURSE_ID,COURSE_INFO){ const newCourseAssignment = Classroom.Courses.CourseWork.create(COURSE_INFO,COURSE_ID); const courseAssId = newCourseAssignment.id; //Store the newly created ID of the coursework item. console.log(courseAssId); return courseAssId; }; |
Quick Use Guide
assignGradesToNewCourseWork()
is your main run function to upload your grades into Google Classroom.
You will notice at the start of the function that there are 3 global variables:
- COURSE_ID
- TOPIC_ID
- COURSE_INFO
For the COURSE_ID
and the TOPIC_ID
, you will need to update the IDs based on the results of running the functions in the setup.
COURSE_INFO
The COURSE_INFO
variable is an object containing all the information you will need to create a new coursework assignment. Essentially, anywhere where you see a // <<< UPDATE THIS
, you will need to modify for your project.
Let’s take a look at what is in this object:
"assigneeMode": "ALL_STUDENTS"
– Keep this. This will assign the assignment to all students in your course."associatedWithDeveloper": true
– Keep this. This is a must-have item that tells your classroom that this assignment was built programmatically and can, then be updated programmatically."description": ""
– Update this. You will need to put your description of the assignment here. You can also leave it blank."maxPoints": 40
– Update this. Assign the maximum points for this assessment."state": "PUBLISHED"
– Keep this. You will probably want to publish this assignment right away for your students."submissionModificationMode": "SUBMISSION_MODIFICATION_MODE_UNSPECIFIED"
– Keep this. This sets the assignment so that the assignment is never returned. Basically, student are not going to submit anything – they are just going to see their grades."title": ""
– Update this. This is the title for your assignment."workType": "ASSIGNMENT"
– You can make this an assignment or COURSE_WORK_TYPE_UNSPECIFIED the grades will be retained the same way."topicId":TOPIC_ID
– This is the id of the topic we want to add our assignment to.
GRADES
On line 34, we collect the grades to be uploaded into your Google Classroom coursework. The file should return a 2d array containing either a student ID or their email and a grade.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[ ["student@gmail.com",13], ["student1@gmail.com",20], ["student2@gmail.com",15], ["student3@gmail.com",10], ] // OR [ ["11265894894",13], ["12549987795",20], ["10255498777",15], ["11878878912",10], ] |
For our example, we are calling a Google sheet with a list of grades. I’d imagine that this would be a fairly common use case unless you are directly connecting to an assessment API.
The GRADES
variable runs our importGrades_()
function that grabs our grades.
const GRADES = importGrades_()
If you are also importing grades from a Google Sheet, you can navigate to line 56.
1 2 3 4 5 6 7 |
function importGrades_(){ const ss = SpreadsheetApp.openById("1Ddv_Fvw_f6pwbyPxDbJnkOcF2OSfNNjgv3K259G5WV8");// <<< UPDATE THIS const sheet = ss.getSheetByName("Sheet1");// <<< UPDATE THIS const range = sheet.getRange(2,1,sheet.getLastRow()-1,2); // <<< UPDATE THIS const values = range.getValues(); return values; }; |
Here is what you will have to update:
- ss – Change the ID to your own sheet id. You can find this in your browser when you are in your Google Sheet.
- sheet – select the sheet tab name that your data is on.
- range – This is currently set for a sheet containing two columns with a header starting in row 1.
If you want to find out more about working in sheets, you can check this post out:
Run The Code
After setting up your global variables in the assignGradesToNewCourseWork()
function and preparing your function to grab your grades for import. You can run the assignGradesToNewCourseWork()
function.
Once the code is has completed its run, you can return to your Classroom Coursework page and see that the new coursework item had been created and the grades have been added.
For our example, it will look like this.
You can see that our new Assignment has been created with our title and description. We can also see that the marks have been assigned.
Click on View assignment to see the grading.
Here you can see the Max points of 40 at the top under the title. And the two marked grades for our students.
Creating Just the Coursework Assignment
Perhaps you want to simply create the coursework for your Google Classroom so that you can show your students what is coming but upload the course results later.
To do this you can add this function to your project:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
//###################################################### /******************************************************* * Create a Coursework Item * * You can only upload grades for coursework items that have been created * in your GAS project. */ function createCourseWorkItem(){ //****GLOBALS***** //Update the relevant items hwere. const COURSE_ID = "83743632546";// <<< UPDATE THIS const TOPIC_ID = "83743632579";// <<< UPDATE THIS const COURSE_INFO = { "assigneeMode": "ALL_STUDENTS", "associatedWithDeveloper": true, "description": "describe what your assignment is about here.",// <<< UPDATE THIS "maxPoints": 40, // <<< UPDATE THIS "state": "PUBLISHED", "submissionModificationMode": "SUBMISSION_MODIFICATION_MODE_UNSPECIFIED", "title": "Unit 2 - External Grade import", // <<< UPDATE THIS "workType": "ASSIGNMENT", "topicId":TOPIC_ID } const COURSEWORK_ID = createCourseWork_(COURSE_ID,COURSE_INFO); console.log(COURSEWORK_ID) //Check the log and copy and paste in to assignGradesToCourseWork() - COURSEWORK_ID }; |
This will also log the coursework ID once the course is created so that you can keep a record of it to use it later when you want to upload the grades.
Check out the Quick Use Guide in the Uploading the grades section for details on how to make changes for your own project.
Uploading the Grades Only
If you already have the coursework built, you may only need to upload the grades. To do this, use the code below.
Just keep in mind that you must create the coursework in your Google Apps Script console instead of your Google Classroom dashboard.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
/******************************************************* * Add grades to a Coursework Item that was generated previously in this project. * * In this example, I have put all the global data we gained from our * tests in the first 3 global variables. * * You will need to update the Course infor where it says <<< UPDATE THIS */ function assignGradesToCourseWork(){ //****GLOBALS***** //Update the relevant items hwere. const COURSE_ID = "83743632546";// <<< UPDATE THIS const TOPIC_ID = "83743632579";// <<< UPDATE THIS const COURSEWORK_ID = "84502364647";// <<< UPDATE THIS //A 2d array of grades = [[email@email.com,20],[email1@email.com, 18],[ ...etc]]; const GRADES = importGrades_() //You can import from any sourse. For this, I am just importing from Google Sheets. GRADES.forEach(student => setGrade_(COURSE_ID,COURSEWORK_ID,student[0],student[1])) }; |
Here you can see that we have copied our coursework ID we logged in our createCourseWorkItem()
from the previous section and added it to our COURSEWORK_ID
variable.
If you want to learn about how the code works, read on…
Looking to learn more about Google Apps Scripts in a more structured format? Udemy has some great courses that can get you from the basics to a real Google Apps Script pro!
Got a more specific problem you need help with, but don’t have the time to develop the skills? Fiverr’s your best bet to find a skilled Google Apps Script professional to solve your problem quickly and cheaply. *
*The above affiliate links have been carefully researched to get you to what you specifically need. If you decide to click on one of these links it will cost you just the same as going to the site. If you decide to sign up, I just get a little pocket money to help pay for the costs of running this website.
Code Breakdown Of Upload Process
In this code breakdown, we will go over the working parts of the assignGradesToNewCourseWork()
function and its helper functions we haven’t yet covered.
You can pop out the code and follow along or just review the code snippets during the walkthrough.
assignGradesToNewCourseWork()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/******************************************************* *Simultaneously create a coursework item and add grades to it. * * In this example, I have put all the global data we gained from our * tests in the first 3 global variables. * * You will need to update the Course infor where it says <<< UPDATE THIS */ function assignGradesToNewCourseWork(){ //****GLOBALS***** //Update the relevant items hwere. const COURSE_ID = "83743632546";// <<< UPDATE THIS const TOPIC_ID = "83743632579";// <<< UPDATE THIS const COURSE_INFO = { "assigneeMode": "ALL_STUDENTS", "associatedWithDeveloper": true, "description": "describe what your assignment is about here.",// <<< UPDATE THIS "maxPoints": 40, // <<< UPDATE THIS "state": "PUBLISHED", "submissionModificationMode": "SUBMISSION_MODIFICATION_MODE_UNSPECIFIED", "title": "Unit 2 - External Grade import", // <<< UPDATE THIS "workType": "ASSIGNMENT", "topicId":TOPIC_ID } const COURSEWORK_ID = createCourseWork_(COURSE_ID,COURSE_INFO); //A 2d array of grades = [[email@email.com,20],[email1@email.com, 18],[ ...etc]]; const GRADES = importGrades_() //You can import from any sourse. For this, I am just importing from Google Sheets. GRADES.forEach(student => setGrade_(COURSE_ID,COURSEWORK_ID,student[0],student[1])) }; |
We have already covered our main variables in our quick guide. Let’s move down to line 27.
The COURSEWORK_ID
variable deploys the createCourseWork_()
function. This function takes two arguments:
- The course ID
- The course Info
This function creates a new course based on all the information you added to the COURSE_INFO
object inside your selected course and returns the ID of the newly created course.
Next, on line 30, we collect the grades from the importGrades_()
function. The grades are returned as a 2d array of ID values (either student id or their email) and their corresponding grade.
Our importGrades_()
function simply grabs the grades from a Google Sheet, however, you could import grades directly from an assessment API so that the entire process is automated.
Lastly, we loop through our GRADES
array using the forEach method calling the setGrade_()
function to upload the grades to our newly created coursework assignment. The setGrade_()
function takes 4 arguments:
COURSE_ID
– the id of the course.COURSEWORK_ID
– this was created when we ran ourcreateCourseWork_()
function.student[0]
– this is the first item in the GRADES row that has the ID for the student.student[1]
– this is the second item in the GRADES row which is the grade for the student.
That’s all there is to the assignGradesToNewCourseWork()
run function.
createCourseWork_()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/******************************************************* * Creates a coruse work item that can be used for grade uploads. * * param {string} : COURSE_ID - ID of course. * param {object} : COURSE_INFO - Object array of data to be entered to created the coursework. * * return : the id for the course. Can be logged or used directly. */ function createCourseWork_(COURSE_ID,COURSE_INFO){ const newCourseAssignment = Classroom.Courses.CourseWork.create(COURSE_INFO,COURSE_ID); const courseAssId = newCourseAssignment.id; //Store the newly created ID of the coursework item. console.log(courseAssId); return courseAssId; }; |
As the name suggests, the createCourseWork_()
function builds a new coursework assignment for your selected Google Classroom course. This function takes two parameters:
- COURSE_ID – The id of the course you want to add your coursework item to.
- COURSE_INFO – The object containing all the information you need like the name of the course, description, max grade, etc.
The function then returns the new coursework assignment ID so it can be referenced later when uploading grades.
Our primary task occurs on line 11.
Here we use the Google Classroom API Courses.Coursework
resource and select the create
method. This method takes our COURSE_INFO and COURSE_ID data as arguments.
1 |
const newCourseAssignment = Classroom.Courses.CourseWork.create(COURSE_INFO,COURSE_ID); |
This will build our new coursework assignment. newCourseAssigmnet
then becomes an object of the new coursework with all the assigned information to it. However, all we need from the newCourseAssigmnet
course assignment is the id object which we call on line 13.
1 |
const courseAssId = newCourseAssignment.id; |
It’s probably a good idea for us to log the ID of the newly created course somewhere so that we can keep a record of it. We do this on line 15 before returning the ID so it can be used in our main run function.
1 2 |
console.log(courseAssId); return courseAssId; |
setGrade_()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
/******************************************************* * Adds the grade for each available student. * * param {string} : COURSE_ID - ID of course. * param {string} : COURSEWORK_ID - ID of coursework item. * param {string} : USER_ID - ID of user. * param {string} : GRADE - users grade. */ function setGrade_(COURSE_ID, COURSEWORK_ID, USER_ID, GRADE){ try{ var grades = { 'assignedGrade': GRADE, 'draftGrade': GRADE } const studentSub = Classroom.Courses.CourseWork.StudentSubmissions let submissionID = studentSub.list( COURSE_ID, COURSEWORK_ID, {"userId":USER_ID} ).studentSubmissions[0].id studentSub.patch( grades, COURSE_ID, COURSEWORK_ID, submissionID, { "updateMask":"assignedGrade,draftGrade" } ); }catch(e){ console.error(e); console.log(`${USER_ID} could not be found and was not uploaded.`); } }; |
Our setGrade_()
function uploads the grades to our coursework assignment. The function takes 4 parameters:
- COURSE_ID
- COURSEWORK_ID
- USER_ID
- GRADE
This function is called from the main assignGradesToNewCourseWork()
run function each time it iterates through the list of GRADES.
We kick off by setting up a try…catch statement. This will make an attempt to upload a grade, but if an issue exists in the upload (most likely with the wrong user ID credentials) it will ‘catch’ it and then it will record the error to the console and log the userID that could not be uploaded (Lines 34-37).
1 2 3 4 |
}catch(e){ console.error(e); console.log(`${USER_ID} could not be found and was not uploaded.`); } |
The e parameter logs the error information that we will display with our console.error. We then log the user ID with a template literal which allows us to put our user ID in line with our text.
Back up to the top on line 12, we assign our GRADE
to our grades
object which contains an assigned grade and a draft grade.
1 2 3 4 |
var grades = { 'assignedGrade': GRADE, 'draftGrade': GRADE } |
These two keys represent the grades before it is returned to the student in the Google Classroom console and the final grade. We may as well give the grade to both.
Next, we need to find all the student submissions, by calling the StudentSubmissions resource in the Google Classroom API.
1 |
const studentSub = Classroom.Courses.CourseWork.StudentSubmissions |
This resource contains a list of all the students in your course. Each item in the list is an object with key information containing things like the student’s ID, their grades (Both assigned and draft), whether they were late, etc.(Line 17)
With our resource in hand, we then need to find the submission ID for our currently selected user. We can use the Student Submissions list method to do this.
This method requires a course ID and coursework ID. We can also add an optional query parameter that will allow us to isolate a student by their email or google ID. From here we can then grab the id value for that user. This id is the specific coursework ID unique to that student.
1 2 3 4 5 |
let submissionID = studentSub.list( COURSE_ID, COURSEWORK_ID, {"userId":USER_ID} ).studentSubmissions[0].id |
Our final step is to add in the grade using the Student Submission resource again. We this time call the patch method.
The patch method can only be used on coursework that had been created by you programmatically. Luckily, we did this earlier.
1 2 3 4 5 6 7 8 9 |
studentSub.patch( grades, COURSE_ID, COURSEWORK_ID, submissionID, { "updateMask":"assignedGrade,draftGrade" } ); |
Our patch will take 4 arguments. First, we will add our grades object with the grades for our assigned and draft grades. Next, we add the course ID, coursework ID and the submission Id we just collected. Finally, we need to tell patch what we need to update with updateMask
.
Conclusion
Google Classroom API
I found traversing the Classroom API to be quite challenging, particularly when translating it into the context of Google Apps Script. While the docs do shed some light on the capabilities of the API, it doesn’t have many examples using programming languages so that you can get an idea of the format.
On the bright side, when you add the API to your Google Apps Script project, it is kind enough to help out with word completion. However, the problem mostly lies in how you must apply the arguments inside methods. In other Google APIs you usually apply an argument one branch at a time so for example instead of something like this:
1 2 3 4 5 |
Classroom.Courses.CourseWork.StudentSubmissions.List( course id, coursework ID, {"userId":USER_ID} ) |
…to me, it would seem more intuitive to have something like this:
1 2 3 4 5 6 7 |
Classroom .Courses(courseID) .CourseWork(courseworkID) .StudentSubmissions .List( {"userId":USER_ID} ) |
But that’s just me. There are really smart folks at Google making decisions for approaches I could not possibly comprehend, so I am cool.
I also liked the Try This sidebar that allows you to play with the API.
Uploading Grades To Google Classroom
The code I have written in this example is fairly stripped down so that the process is as clear as possible. In my production code, I have put a lot more checks for potential errors. Some things you might want to consider are:
- Greater than max grade check.
- Grade is a number or a string containing a number check.
- Connectivity check with Google classroom before running.
What other checks can you think of?
Anyway, I hope you found this tutorial useful. I really love hearing how these tutorials have been applied in other projects so please tell me about it in the comments below.
If you found this post useful, please consider subscribing (Top Right). I usually post twice a month and a bit more frequently in June and July.
Cheers,
Need help with Google Workspace development?
Go something to solve bigger than Chat GPT?
I can help you with all of your Google Workspace development needs, from custom app development to integrations and security. I have a proven track record of success in helping businesses of all sizes get the most out of Google Workspace.
Schedule a free consultation today to discuss your needs and get started or learn more about our services here.
Yagi
Full Code
Setup.gs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
/******************************************************** SETUP - FIND THE DATA YOU NEED TO UPLOAD GRADES */ /******************************************************* * Logs the Courses in your accounts domain and the owners. * * If you have the admin privelages in GSuite Domain, you will * see all users who have classes in your domain. * * returns : Array containing, course name, id, and owner. */ function findCourseAndOwner() { const courseList = Classroom.Courses.list().courses; const courseData = courseList.map(course => { let ownerName = Classroom .Courses .Teachers .get(course.id, course.ownerId) .profile .name .fullName return `${course.name} : ${course.id} : ${ownerName}`; }); return courseData; }; /******************************************************* * Logs the Coursework Items in a course. * * param {string} : course ID taken from findCourseAndOwner() * * returns : an array of couse work items with their IDs. */ function findCourseworkItems(COURSE_ID){ const courseWork = Classroom.Courses.CourseWork.list(COURSE_ID).courseWork return courseWork.map(item => `${item.title} : ${item.id}`); }; /******************************************************* * Gets a list of alls students in a course. * * param {string} : course ID taken from findCourseAndOwner() * * returns : an array of students full name, id and email address. */ function getStudentDetails(COURSE_ID){ const students = Classroom.Courses.Students.list(COURSE_ID).students return students.map(student => { return `${student.profile.name.fullName}`+ `: ${student.profile.id} `+ `: ${student.profile.emailAddress}` }); }; /******************************************************* *Returns a list of Topics by name and id * * param {string} : course ID taken from findCourseAndOwner() * * returns : an array of students full name, id and email address. */ function getTopics(COURSE_ID){ const topics = Classroom.Courses.Topics.list(COURSE_ID).topic; const topicItems = topics.map(item => `${item.name} : ${item.topicId}`); return topicItems; }; |
CourseGrades.gs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
/******************************************************* * CREATE A COURESE WORK ITEM AND ADD GRADES */ /******************************************************* *Simultaneously create a coursework item and add grades to it. * * In this example, I have put all the global data we gained from our * tests in the first 3 global variables. * * You will need to update the Course infor where it says <<< UPDATE THIS */ function assignGradesToNewCourseWork(){ //****GLOBALS***** //Update the relevant items hwere. const COURSE_ID = "83743632546";// <<< UPDATE THIS const TOPIC_ID = "83743632579";// <<< UPDATE THIS const COURSE_INFO = { "assigneeMode": "ALL_STUDENTS", "associatedWithDeveloper": true, "description": "describe what your assignment is about here.",// <<< UPDATE THIS "maxPoints": 40, // <<< UPDATE THIS "state": "PUBLISHED", "submissionModificationMode": "SUBMISSION_MODIFICATION_MODE_UNSPECIFIED", "title": "Unit 2 - External Grade import", // <<< UPDATE THIS "workType": "ASSIGNMENT", "topicId":TOPIC_ID } const COURSEWORK_ID = createCourseWork_(COURSE_ID,COURSE_INFO); //A 2d array of grades = [[email@email.com,20],[email1@email.com, 18],[ ...etc]]; const GRADES = importGrades_() //You can import from any sourse. For this, I am just importing from Google Sheets. GRADES.forEach(student => setGrade_(COURSE_ID,COURSEWORK_ID,student[0],student[1])) }; //###################################################### /******************************************************* * Create a Coursework Item * * You can only upload grades for coursework items that have been created * in your GAS project. */ function createCourseWorkItem(){ //****GLOBALS***** //Update the relevant items hwere. const COURSE_ID = "83743632546";// <<< UPDATE THIS const TOPIC_ID = "83743632579";// <<< UPDATE THIS const COURSE_INFO = { "assigneeMode": "ALL_STUDENTS", "associatedWithDeveloper": true, "description": "describe what your assignment is about here.",// <<< UPDATE THIS "maxPoints": 40, // <<< UPDATE THIS "state": "PUBLISHED", "submissionModificationMode": "SUBMISSION_MODIFICATION_MODE_UNSPECIFIED", "title": "Unit 2 - External Grade import", // <<< UPDATE THIS "workType": "ASSIGNMENT", "topicId":TOPIC_ID } const COURSEWORK_ID = createCourseWork_(COURSE_ID,COURSE_INFO); console.log(COURSEWORK_ID) //Check the log and copy and paste in to assignGradesToCourseWork() - COURSEWORK_ID }; /******************************************************* * Add grades to a Coursework Item that was generated previously in this project. * * In this example, I have put all the global data we gained from our * tests in the first 3 global variables. * * You will need to update the Course infor where it says <<< UPDATE THIS */ function assignGradesToCourseWork(){ //****GLOBALS***** //Update the relevant items hwere. const COURSE_ID = "83743632546";// <<< UPDATE THIS const TOPIC_ID = "83743632579";// <<< UPDATE THIS const COURSEWORK_ID = "84502364647";// <<< UPDATE THIS //A 2d array of grades = [[email@email.com,20],[email1@email.com, 18],[ ...etc]]; const GRADES = importGrades_() //You can import from any sourse. For this, I am just importing from Google Sheets. GRADES.forEach(student => setGrade_(COURSE_ID,COURSEWORK_ID,student[0],student[1])) }; //###################################################### /******************************************************* * Helper functions */ /******************************************************* * Import Grades from a Google Sheet * * In this example, I have used a Google Sheet to import grades, * however, if you have access to an API from which your grades are * derrived, then you might like to use that instead. * * You will need to update the variables where it says <<< UPDATE THIS * * returns : a 2d array of email and grade values. */ function importGrades_(){ const ss = SpreadsheetApp.openById("1Ddv_Fvw_f6pwbyPxDbJnkOcF2OSfNNjgv3K259G5WV8");// <<< UPDATE THIS const sheet = ss.getSheetByName("Sheet1");// <<< UPDATE THIS const range = sheet.getRange(2,1,sheet.getLastRow()-1,2); // <<< UPDATE THIS const values = range.getValues(); return values; }; /******************************************************* * Adds the grade for each available student. * * param {string} : COURSE_ID - ID of course. * param {string} : COURSEWORK_ID - ID of coursework item. * param {string} : USER_ID - ID of user. * param {string} : GRADE - users grade. */ function setGrade_(COURSE_ID, COURSEWORK_ID, USER_ID, GRADE){ try{ var grades = { 'assignedGrade': GRADE, 'draftGrade': GRADE } const studentSub = Classroom.Courses.CourseWork.StudentSubmissions let submissionID = studentSub.list( COURSE_ID, COURSEWORK_ID, {"userId":USER_ID} ).studentSubmissions[0].id studentSub.patch( grades, COURSE_ID, COURSEWORK_ID, submissionID, { "updateMask":"assignedGrade,draftGrade" } ); }catch(e){ console.error(e); console.log(`${USER_ID} could not be found and was not uploaded.`); } }; /******************************************************* * Creates a coruse work item that can be used for grade uploads. * * param {string} : COURSE_ID - ID of course. * param {object} : COURSE_INFO - Object array of data to be entered to created the coursework. * * return : the id for the course. Can be logged or used directly. */ function createCourseWork_(COURSE_ID,COURSE_INFO){ const newCourseAssignment = Classroom.Courses.CourseWork.create(COURSE_INFO,COURSE_ID); const courseAssId = newCourseAssignment.id; //Store the newly created ID of the coursework item. console.log(courseAssId); return courseAssId; }; |
Test.gs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
function runGetCoursesID() { console.log(findCourseAndOwner()); }; function getCourseWorkID(){ const courseID = "83743632546"; // << Update this console.log(findCourseworkItems(courseID)); }; function getStudents(){ const courseID = "83743632546"; // << Update this console.log(getStudentDetails(courseID)); }; function getTopicList(){ const courseID = "83743632546"; // << Update this console.log(getTopics(courseID)); }; function getUserOnCourse(){ const courseWorkId ="84466118790"; const courseID = "83743632546"; const userID = "lkmdonald@gmail.com"; const studentSub = Classroom.Courses.CourseWork.StudentSubmissions const submissionID = studentSub.list( courseID, courseWorkId, {"userId":userID} ).studentSubmissions[0].id console.log(submissionID) }; |
I’m looking forward to working on this project this summer! Thank you, Yagisan!
Fantastic! Love hear your results.
Great work sir!
Thank you for keeping these posts relevant to current requirements and needs.
You’re welcome. It was fun to build.
I looks marvelous, something I was looking for. Well done!
Thanks, Ricado. Glad you found it useful.
Hi Yagi and friends.
Question: How do I post an assignment with attachments where students receive a copy?
Problem: I can get the materials posted in all shareModes except “STUDENT_COPY”.
So I’m able to add materials: Example:
“materials” : [
,{“link” : {“url” : “https://developers.google.com/classroom/reference/rest/v1/courses.courseWork/patch”}}
,{“driveFile”: {“shareMode”: “STUDENT_COPY”,”driveFile”: {“id”: “1eSd_fmsZSCL1jGPAayhXpID-D1ZDSaR7W0dOhkF8xEA”}}}
// ,{“driveFile”: {“shareMode”: “STUDENT_COPY”,”driveFile”: {“id”: “1XG2upXRVG5yzhfs1OJgxiQU5tIfGrGupSRpir1_1eho”}}}
,{“youtubeVideo”: {“id” : “k_cj46u904s”}}
],
but, I can’t seem to get the assignment to post with a copy for each student.
I’ve attempted to create a student work folder, but with no success.
Ex: “assignment” : {“studentWorkFolder” : {“id” : “1_qddMkFNeZFMBTCyGOhizn6Lr7xRKEPj”}},
Reference: https://developers.google.com/classroom/reference/rest/v1/courses.courseWork/create
Any suggestions?
I hate replying to myself, but apparently there is a work around (not ideal), but it may work.
You can add the scheduledTime name and add a few minutes, as noted in this Stackoverflow: https://stackoverflow.com/questions/58707261/internal-error-when-publishing-coursework-with-student-copies-in-google-classroo
Time must be in UTC (Coordinated Universal Time) Zulu.
Ex:
“scheduledTime”: “2020-06-08T01:34:55Z”,
A question I’m noodling:
Say you want the document link for the assignment, so you can you use your nifty rubric grader, would you it make more sense to have a script that creates documents through an iteration function and post the link to the pre-designated folder in Classroom or create a map of the assignment drive URL after Google Classroom creates the document? 🤔
Yagi, is it possible to filter the map by URL?
I came up with the following code, but I cannot correctly filter the double array (if it is truly a double array) to pull only the array with the correct link:
function findCourseByUrl() {
const courseList = Classroom.Courses.list({“courseStates”:[“ACTIVE”]}).courses;
Logger.log(data);
};
I figured it out…
Some help from the following video: https://youtu.be/PT_TDhMhWsE
/////////////////
/////////////////
/* Filter by URL
/* 1st constant filters active courses when mapped
/* return setup to create multidimensional array
/* map is filtered looking for a specific URL link
/* should return only one course with name, id, owner, URL
*/
/////////////////
/////////////////
function findCourseByUrl() {
const courseList = Classroom.Courses.list({“courseStates”:[“ACTIVE”]}).courses;
let theCourse = courseData.filter(filterCourse); //this could be a return if called by function in Test.gs
Logger.log(theCourse); //remove if using a function with console.log in Test.gs
};
////////////////////////////////////////
How did you find the classroom’s courseWork_id, title_id and all, please help me
Hi Yagi & Community.
I hit a bit of a snag, and while this may beyond the scope of the post, I’m hoping you could help.
I’m attempting to pull student submissions from an assignment. I can retrieve the full assignments, but not the specific properties. Using the Classroom API, I can get the desired results, but not through GAS.
https://stackoverflow.com/questions/63191922/get-student-submissions-from-google-classroom
Hi Anthony,
I replicated your code using the Dyson dummmy course and was successful with getting the following results:
[ '{"driveFile":{"thumbnailUrl":"https://drive.google.com/thumbnail?id=1hyAWafMJl0FAQIv-nP27wlEKuoOQqV2e&sz=s200","title":"Stage one Dyson Sphere best practice.pdf","alternateLink":"https://drive.google.com/open?id=1hyAWafMJl0FAQIv-nP27wlEKuoOQqV2e","id":"1hyAWafMJl0FAQIv-nP27wlEKuoOQqV2e"}}' ]
Now there is a known issue where the Classroom API in GAS doesn’t provided all the appropriate scopes out of the box. This might be the issue you are facing, but I am not 100% sure. Anyway to solve this you can update your Google Classroom scopes by going to View >> Show manifest files, then click on appscript.json in the side bar. Paste in the oauths below:
"oauthScopes": [
"https://www.googleapis.com/auth/classroom.courses",
"https://www.googleapis.com/auth/classroom.coursework.me.readonly",
"https://www.googleapis.com/auth/classroom.profile.emails",
"https://www.googleapis.com/auth/classroom.profile.photos",
"https://www.googleapis.com/auth/classroom.rosters",
],
Sourabh Choraria got a good explanation here.
You also mentioned that specific types of attachments result in
undefined
. Which file types are causing the issues?If you can manage to get the file ID:
return submissions.map(submission => {
return submission.assignmentSubmission.attachments.map(attachments => {
return
${attachments.driveFile.id}
})
});
You could then use the DriveApp class to check for Mime types and other data:
function run(){
const attachIDs = getStudSubs();
const attachDetails = attachIDs[0].map(id => {
const file = DriveApp.getFileById(id);
console.log(file.getDownloadUrl())
return ({
date: file.getDateCreated(),
description: file.getDescription(),
downloadURL: file.getDownloadUrl(),
mimeType: file.getMimeType(),
owmer : file.getOwner(),
name: file.getName(),
})
});
console.log(attachDetails);
}
I’m not sure if that answered your question, but I hope it helps.
Cheers,
Yagi
Brilliant. This allows me to pull the specific object with the others being undefined. I can’t seem to drill into the object with the property accessor. I will attempt object destructuring. I’m a history teacher, so wish me luck! Thanks again Yagi.
If anyone ventures to point and wants to learn about destructuring, here’s a site:
https://dmitripavlutin.com/javascript-object-destructuring/#:~:text=The%20object%20destructuring%20is%20a,the%20property%20doesn't%20exist.
Yagi, you were a huge help!
I essentially flattened the array and removed undefined objects…and then mapped the result to get the desired fields.
Here is the code:
Great to hear, Anthony! Good work.
Here’s an Easter Egg for your readers:
https://docs.google.com/presentation/d/1rlUwDf0mXQC6HFEXRbUaO1H3X7G2a_CPX74zMPcMBYk/preview?slide=id.g96d87ac482_0_5
Hopefully fellow readers can use the web app.
Thanks Anthony,
This an outstanding project. I am sure some of the other readers will get a lot of value out of your hard work.
~Yagi
Hi, it is possible to import the grade from classroom to google sheets
Yes it is available in the API.
Could you tell me where to look? I don’t know about programming and I loved how you explained the code.
Kaijon,
If you are looking to only download the grades for an assignment, you can do this within Classroom, and it will be much easier for you.
In the assignment, click on the sprocket ⚙️ on the right hand side of the screen. Click, download grades as CSV. The file will download to your PC.
Open a blank Google Sheet. Click File -> import. In the modal window, select upload. Drag the recent CSV file to the upload modal. Hit okay. And now your grades are in a google sheet.
This may be a little faster for you than programming using the API.
Hi,
I know that option, but it does not update automatically, it is necessary to download each time changes are made.
I have a worksheet with form qualifications, they are automatically collected when you receive a response.
Thanks for your answer.
Your getTopics got GoogleJsonResponseException: API call to classroom.courses.topics.list failed with error: Request had insufficient authentication scopes.
at getTopics(getTopics:12:43)
at testGetTopics(getTopics:22:15) my manifest has even more than you suggested:
“oauthScopes”: [
“https://www.googleapis.com/auth/spreadsheets”,
“https://www.googleapis.com/auth/classroom.courses”,
“https://www.googleapis.com/auth/classroom.rosters”,
“https://www.googleapis.com/auth/classroom.profile.emails”,
“https://www.googleapis.com/auth/classroom.profile.photos”,
“https://www.googleapis.com/auth/classroom.coursework.me”,
“https://www.googleapis.com/auth/classroom.coursework.me.readonly”,
“https://www.googleapis.com/auth/classroom.coursework.students”,
“https://www.googleapis.com/auth/classroom.coursework.students.readonly”,
“https://www.googleapis.com/auth/classroom.announcements.readonly”],
No auth is mention on Topics documentation. https://developers.google.com/classroom/reference/rest/v1/courses.topics
any ideas. I am just a teacher.
Hi L. Klein,
This discussion with Anthony might help you.
https://yagisanatode.com/2020/05/13/google-apps-script-upload-grades-into-a-google-classroom-coursework-assignment/#comment-3639
I’m successfully running the script in these scopes at the moment:
See, edit, create, and permanently delete your Google Classroom classes https://www.googleapis.com/auth/classroom.courses
Manage your Google Classroom class rosters https://www.googleapis.com/auth/classroom.rosters
View the email addresses of people in your classes https://www.googleapis.com/auth/classroom.profile.emails
View the profile photos of people in your classes https://www.googleapis.com/auth/classroom.profile.photos
Manage course work and grades for students in the Google Classroom classes you teach and view the course work and grades for classes you administer https://www.googleapis.com/auth/classroom.coursework.students
See, edit, create, and delete your spreadsheets in Google Drive https://www.googleapis.com/auth/spreadsheets
View topics in Google Classroom https://www.googleapis.com/auth/classroom.topics.readonly
The scopes should appear automatically as you run and test your project. Thus no mention of them in the tutorial.
your scopes in your manifest seem good the only one that might be missing is the https://www.googleapis.com/auth/spreadsheets one.
Let me know how you go with this and if you are still facing problems, I will have a deeper dive.
cheers,
Yagi
I came back to this after a lot of other coding. All other classroom objects code you create or I created works except topics. I turned on advanced for spreadsheets (classroom was already on). I added all the auths I could find (even the totally unrelated ones). The help on stackover flow talks about credentials files and ‘pickles’. I cannot find anything containing the word credentilas on My Drive. Code is Google Apps Script so run from their editor on their servers. When I added the advanced spreadsheet I got to reauthorrized but still getting API call to classroom.courses.topics.list failed with error: Request had insufficient authentication scopes.
Hmm, that is a weird one. I think the credential files and ‘pickles’ refer to how the API is used externally with other programming language projects.
It’s been a while since I have worked in this API, but I do recall a problem with getting all of the scopes that I needed authenticating. I take it you complete this process in the Test.gs file to attempt to get the Topics. Getting the Classroom Topic Item
From memory, you needed to run a test script that simply runs the courses. If you want to share the script with the error you can send me a message on my contacts form and I can take a look when I get a chance.
For now, these are the scopes that I have for this project:
See, edit, create, and permanently delete your Google Classroom classes https://www.googleapis.com/auth/classroom.courses
Manage your Google Classroom class rosters https://www.googleapis.com/auth/classroom.rosters
View the email addresses of people in your classes https://www.googleapis.com/auth/classroom.profile.emails
View the profile photos of people in your classes https://www.googleapis.com/auth/classroom.profile.photos
Manage course work and grades for students in the Google Classroom classes you teach and view the course work and grades for classes you administer https://www.googleapis.com/auth/classroom.coursework.students
See, edit, create, and delete your spreadsheets in Google Drive https://www.googleapis.com/auth/spreadsheets
View topics in Google Classroom https://www.googleapis.com/auth/classroom.topics.readonly
~Yagi
There is an auth that is not documented!!!! developers.google.com/classroom/guides/auth as of today. courses.topics.get() requires ttps://www.googleapis.com/auth/classroom.topics.readonly. I don’t see that in your list. ref https://developers.google.com/classroom/reference/rest/v1/courses.topics/get – #MetaMan answered https://stackoverflow.com/questions/67246403/insufficient-authentication-scope-error-listing-google-classroom-topics
sorry to ask twice
Good find there. Glad you got a response.
Hi Yagi, I don’t have much experience coding, but I find your code a bit easy to understand and to follow. I wanted to ask you how you could import grades or whether the students have turned their work in from Classroom to a google sheets. Thanks a lot for having read this message.
Hi carlos,
I am glad you found the code relatively easy to read. I try hard to make my tutorials approachable from a variety of levels.
The tutorial as it is will import grades from a selected Google Sheet.
If you are importing grades from another LMS like Moodle, for example, you would need to access the Moodle API (And activate it). You can then call the API through Google App Script’s UrlFetch Service.
You could then set triggers to call the LMS API when you want to and update your Classroom assignment.
It’s a bit of a trial, but it can be done.
Apologies if I misunderstood your question.
~Yagi.
Hi did you ever come right with this?
I’m trying to do the same thing – get a live sheet with all the grades, or download them periodically to the same sheet with a script