How to delete CourseWork (Assignments) by title in Google Classroom - google-apps-script

I have several courses that all have the same set of topics with coursework (Assignments) that have the same title in each of those topics. I am trying to delete those assignments from just a few of the topics in each course using Apps Script. I expected to be able to use Classroom.Courses.CourseWork.delete(), but, so far, my code does nothing. No error - just no change in the Assignments. I think my permissions and such are in order, because these are assignments that I created with this same account/permissions.
My issue might be that I am not able to get the coursework ids from the name of the assignment. I'm not sure how to do that, but I think it could be missing from my code.
Here's what I tried:
function deleteAssignments() {
var courseIds = ['100000000000','100000000001','100000000002'];
var topicNames = ['topic3','topic2','topic1'];
for (var i = 0; i < courseIds.length; i++) {
var topics = Classroom.Courses.Topics.list(courseIds[i]).topic;
var topicObj = topics.reduce((o, e) => Object.assign(o, {[e.name]: e.topicId}), {});
for (var j = 0; j < topicNames.length; j++) {
var topicId = topicObj[topicNames[j]];
var exec = Classroom.Courses.CourseWork.delete({
title: "Example Assignment",
topicId: topicId,
workType: "ASSIGNMENT",
}, courseIds[i]);
}
}
}
I checked the Google Classroom courses.courseWork docs, but I think I don't understand well enough how to structure my code as a whole to make use of the info there, because I don't have any background knowledge/training.
I used Problem listing assignments of a student in Google Classroom to come up with my code, but mine is not working and I can't figure out where I'm going wrong.
I also looked at Using Google Apps Script to list assignments through Google Classroom API using course.coursework.list, but when I run the code in the answer, my log says that it's loading, but it never appears to finish.

In this sample script, the courseworks are deleted by searching the coursework names.
Sample script:
Before you use this script, please confirm Classroom API is enabled at Advanced Google services, again.
function deleteCourseworks() {
var courseIds = ['###courseId1###', '###courseId2###',,,];
var courseworkNames = ["###coursework name1###", "###coursework name2###",,,];
for (var i = 0; i < courseIds.length; i++) {
var courseWorks = Classroom.Courses.CourseWork.list(courseIds[i], {courseWorkStates: "PUBLISHED"}).courseWork;
var courseWorkObj = courseWorks.reduce((o, e) => Object.assign(o, {[e.title]: e.id}), {});
for (var j = 0; j < courseworkNames.length; j++) {
var courseWorkId = courseWorkObj[courseworkNames[j]];
console.log(courseIds[i])
console.log(courseWorkId)
var exec = Classroom.Courses.CourseWork.remove(courseIds[i], courseWorkId);
}
}
}
In this case, if you want to delete the courseworks of the state of "DRAFT", please modify courseWorkStates: "PUBLISHED" to courseWorkStates: "DRAFT".
Note:
When an error like "status" : "PERMISSION_DENIED" and The Developer Console project is not permitted to make this request. occurs at Classroom.Courses.CourseWork.remove, the reason of issue can be seen at this thread. Please be careful this.
In that case, for example, it seems that the courseworks created with the GAS project can be deleted. It seems that this is the current specification.
References:
Method: courses.courseWork.list
Method: courses.courseWork.delete
Added:
The following sample script deletes the courseworks by searching the coursework names. But in this case, when the same coursework names are existing, all courseworks of them are deleted. So when you use this, please be careful this.
Sample script:
function deleteCourseworks() {
var courseIds = ['###courseId1###', '###courseId2###',,,];
var courseworkNames = ["###coursework name1###", "###coursework name2###",,,];
for (var i = 0; i < courseIds.length; i++) {
var courseWorks = Classroom.Courses.CourseWork.list(courseIds[i], {courseWorkStates: "PUBLISHED"}).courseWork;
var courseWorkObj = courseWorks.reduce((o, e) => Object.assign(o, {[e.title]: o[e.title] ? o[e.title].concat(e.id) : [e.id]}), {});
for (var j = 0; j < courseworkNames.length; j++) {
var courseWorkIds = courseWorkObj[courseworkNames[j]];
if (courseWorkIds) {
courseWorkIds.forEach(id => {
var exec = Classroom.Courses.CourseWork.remove(courseIds[i], id);
});
}
}
}
}

Related

How to change Topic names Classroom.Courses.Topics.patch()

I'm using Google Apps Script to change the names of a few Topics in several Google Classrooms. I'm using Classroom.Courses.Topics.patch() to change only the 'name' value of the Topics, but my script does not change anything when I look at the Classrooms.
Here is an example: I have two Classrooms (course IDs '100000000000' and '100000000001'). In each Classroom I have three Topics (topic names 'topic1', 'topic2', and 'topic3'). I want to change the name of the first two topics to 'newtopic1' and 'newtopic2' respectively, in both classrooms.
I suspect there could be something off with the way I'm doing the update mask, but I've tried re-ordering things, and I still can't get it to go... Could also be my nested for loops?
function updateTopicNames() {
var courseIds = ['100000000000','100000000001'];
var topicNamesOld = ['topic1','topic2'];
var topicNamesNew = ['newtopic1', 'newtopic2'];
for (var i = 0; i < courseIds.length; i++) {
var topics = Classroom.Courses.Topics.list(courseIds[i]).topic;
var topicObj = topics.reduce((o, e) => Object.assign(o, {[e.name]: e.topicId}), {});
for (var j = 0; j < topicObj.length; j++) {
for (var k = 0; k < topicNamesNew.length; k++) {
var topicId = topicObj[topicNamesOld[j]];
var newName = {'name':topicNamesNew[k]};
var extra = {'updateMask':'name'};
var exec = Classroom.Courses.Topics.patch(newName, topicId, courseIds[i], extra);
}
}
}
}
I checked out the courses.topics.patch API, but there is no example of the update mask implementation for me to extrapolate from.
I tried to bootstrap from code for other .patch() things: StudentSubmissions.Patch UpdateMask Error and How to change course owner using Classroom.Courses.patch() but something is not working when I try to convert these for Topics.patch().
I believe your situation as follows.
The index of topicNamesOld is corresponding to the index of topicNamesNew.
Modification point:
In your script, topicObj is not an array. So you are not required to use the for loop.
When this is reflected to your script, it becomes as follows.
Modified script:
function updateTopicNames() {
var courseIds = ['100000000000','100000000001'];
var topicNamesOld = ['topic1','topic2'];
var topicNamesNew = ['newtopic1', 'newtopic2'];
for (var i = 0; i < courseIds.length; i++) {
var topics = Classroom.Courses.Topics.list(courseIds[i]).topic;
var topicObj = topics.reduce((o, e) => Object.assign(o, {[e.name]: e.topicId}), {});
for (var k = 0; k < topicNamesNew.length; k++) {
var topicId = topicObj[topicNamesOld[k]];
var newName = {'name': topicNamesNew[k]};
var extra = {'updateMask':'name'};
var exec = Classroom.Courses.Topics.patch(newName, courseIds[i], topicId, extra);
}
}
}
Note:
In that case, it seems that the topics created with the same GAS project can be updated. For example, it seems that the topics created by other client cannot be updated. It seems that this is the current specification. Please be careful this.
Reference:
Method: courses.topics.patch

How do I resolve OAuth scopes to GSheets and in call out to a GClassroom function, in order to grab assignment data and post to GSheet?

I don't know JSON, so I'm trying to code this with GScript. I want to combine a call out to this function that gets Classroom info from a working script function that posts array info to a GSheet.
The first time I ran the script below, I triggered the API authentication and got the information I needed, although only in Logger.
var email = "my_email#something.org";
function countWork(email) {
var courseId = "valid_courseId";
var data = ""; // String of resulting information from loop below
var assignments = Classroom.Courses.CourseWork.list(courseId);
var length = assignments.courseWork.length;
// Loop to gather info
for (j = 0; j < length; j++) {
var assignment = assignments.courseWork[j];
var title = assignment.title;
var created = assignment.creationTime;
Logger.log('-->Assignment No. %s -->%s -->(%s)',j+1,title,created);
}
return data;
}
But for some reason, I can't OAuth scopes on this version of the script where I've substituted the array I need for posting to GSheet. I get the error message "Classroom is not defined (line 7...)." What do I need to do so Classroom.Courses.etc will be recognized?
var email = "my_email#something.org";
function extractAssignmentData(email) {
var courseId = "valid_courseId"; //
var data = []; // Array of resulting information from loop below
var assignments = Classroom.Courses.CourseWork.list(courseId); // error: Classroom is not defined (line 7)
var length = assignments.courseWork.length;
// Loop to gather data
for (j = 0; j < length; j++) {
var assignment = assignments.courseWork[j];
// types of information: description, creationTime, updateTime, dueDate, dueTime, workType
var title = assignment.title;
var created = assignment.creationTime;
var info = [j+1,title,created];
data.push(info);
}
return data;
}
Thanks so much, Tanaike, for your helpful responses!
Based on your suggestions, I was able to find this post, which explicitly described how to consult the manifest file, and how to incorporate scopes into the appsscript.json.
I'm still not sure why the first version of the script triggered the scope
"https://www.googleapis.com/auth/classroom.coursework.students"
while the second instead added this one:
"https://www.googleapis.com/auth/classroom.coursework.me.readonly"
But, since I now know how to add what I need and can access the Classroom info I need, it's a mute point. Thanks, again!
(I'm not sure how to mark your comment as the answer to my question -- you should get the points!)

Is it possible to use aliases when assigning a topic for Google Classroom via Google Apps Script?

I'm trying to create drafts of all my assignments via Google Apps script and group them under different topics that are also created when the script is executed. I have about 20 topics and 80 assignments in total. I've already managed to do it by creating separate for loops for each topic where I specify the topicId, but it takes many lines of code. Is there a way it can be simplified by using aliases or the topic name when creating an assignment?
This is a sample of the code I'm using:
function createAssignments() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Fill This Out!');
var course = sheet.getRange(11, 7).getValue(); // Assigns the course ID
var assignments= ss.getSheetByName('Assignments').getRange(1,1,80,3).getValues();
var cTitle = ["Topic 1" "Topic 2", "Topic 20"];
for (var i = 0; i < cTitle.length; i++){
Classroom.Courses.Topics.create({name:cTitle[i]}, course);
}
var getTopics = Classroom.Courses.Topics.list(course); // Gets topic list
var topics = [];
for (var j = 0; j < getTopics.topic.length; j++){
topics.push(getTopics.topic[j].topicId);
}
if (assignments[0][2] = "Arithmetic"){
assignments[0][2] = (topics[0])};
Classroom.Courses.CourseWork.create({ // Creates a draft of the assignment
title: ("Basic Arithmetic Pre-Test"), // Title of the assignment
state: "DRAFT",
materials: [ {
link: {
url: "https://docs.google.com/forms/d/e/yadayada/viewform?usp=sf_link"
}
}
],
workType: "ASSIGNMENT",
topicId: assignment[0][2]
}, course);
}
With this, I can use a multidimensional array to append a topic ID for each assignment, and then create them in a for loop. Is there any easier method though?
Thanks
It's not possible as Alias are only for the Course resource. The only way is iterating over all the Topic list as you already did. I found this post in Issue Tracker, while it's not related to your question, the agent explains a bit how Topic retrieving work.

Getting the body of individual emails from gmail to google sheets

I'm really new at using Google Apps Script, so if what I'm trying doesn't make sense, or just isn't possible please let me know.
Everyday I get several emails that look like the following:
Your Name: FirstName LastName
Phone Number: 555 867 5309
Email Address: FakeEmail#email.com
What do you need help with? Request someone makes.
I'm attempting to automatically send the body of these emails to a new line in a Google Sheet when they come in.
As of right now I have every email get the label "myLabel" when it comes in. I then run the following script, which is a slightly modified version of something I found here:
function myFunction() {
var ss = SpreadsheetApp.getActiveSheet();
var label = GmailApp.getUserLabelByName("MyLabel");
var threads = label.getThreads();
for (var i=0; i<threads.length; i++)
{
var messages = threads[i].getMessages();
for (var j=0; j<messages.length; j++)
{
var msg = messages[j].getBody();
ss.appendRow([msg])
}
threads[i].removeLabel(label);
}
}
I'm attempting to run this code with a timer trigger every 15 minutes. The issue I've run into is that every time the code runs it pulls from every email in the thread. I would like it to just pull from the emails that are new since the last time it ran. Any advice would be greatly appreciated.
Why not mark the messages as read when you finish processing them? Here is a sample from one of my scripts.
var pendingEmailLabel = "MyLabel";
var threads = GmailApp.getUserLabelByName(pendingEmailLabel).getThreads();
for (var t = 0; t < threads.length; ++t) {
var thread = threads[t];
var messages = thread.getMessages();
for (var m = 0; m < messages.length; ++m) {
var message = messages[m];
if (message.isUnread()) {
// INSERT YOUR CODE HERE THAT TAKES ACTION ON THE MESSAGE
message.markRead();
}
}
}
}

Deleting a video from a playlist with YouTube Data API v3 in Google Apps Script

Question: How to use delete of playlistItems in Google Apps Script?
What I tried:
All these give
Missing name after . operator. (line 123, file "Code") error (I have a sense it might be related to JavaScript delete operator, not sure.):
YouTube.PlaylistItems.delete()
YouTube.PlaylistItems.delete("PLi22jkbHFzDjQNWcy4qfLamNjyb0nvkq8")
YouTube.PlaylistItems.delete({id: "PLi22jkbHFzDjQNWcy4qfLamNjyb0nvkq8"})
Apparently, executes fine, but no effect:
var payload =
{
"id" : "PLi22jkbHFzDjQNWcy4qfLamNjyb0nvkq8",
};
var options =
{
"method" : "delete",
"payload" : payload
};
Logger.log(UrlFetchApp.fetch("https://www.googleapis.com/youtube/v3/playlistItems", options));
Any help would be greatly appreciated.
Extra details. The thing I want to do is clear all of the items in a playlist and I already have the following code:
var result = YouTube.PlaylistItems.list('id', {
playlistId: "2L1YG9ktx9sVdo-PMFD2iwCC-UWmkYrgQ-"
});
Logger.log(result.items.length);
var items = result.items;
for (var i = 0; i < items.length; i++) {
Logger.log(items[i].id);
// Deletion of the item with id of "items[i].id is expected to happen here
}
You don't use the videoId, you use the id of the playlistItem...
while (nextPageToken != null) {
var playlistResponse = YouTube.PlaylistItems.list('snippet', {playlistId: playlistId, maxResults: 50,pageToken: nextPageToken});
for (var j = 0; j < playlistResponse.items.length; j++) {
var playlistItem = playlistResponse.items[j];
playlistItemsDelete(playlistItem.id)
//Logger.log('[%s] Title: %s', playlistItem.snippet.resourceId.videoId, playlistItem.snippet.title);
}
...And then...
function playlistItemsDelete(id) {
//var params = {'onBehalfOfContentOwner': 'everythingability'}; // See full sample for function
YouTube.PlaylistItems.remove(id)
}
I think it is not delete() in Apps script. Try YouTube.PlaylistItems.remove(id) instead. I tried adding this method in my script and it automatically populated remove method in the dropdown. There is no delete method.
Hope that helps!