Create assignment with file drive using google apps script - javascript

I'm a new developer, I want to add an assignment in Google Classroom using a script. Here is the code that was created:
function assignmentWithDriveFile(){
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('ASSIGNMENT (Drive File)');
const courseId = sheet.getRange('B1').getValue();
const topicId = sheet.getRange('B2').getValue.toString();
var assignment = {
topicId: topicId,
title: sheet.getRange('B3').getValue().toString(),
description: sheet.getRange('B4').getValue().toString(),
materials :[{
driveFile: {
driveFile: {
id: sheet.getRange('B5').getValue.toString(),
title: sheet.getRange('B6').getValue.toString()
},
shareMode: "STUDENT_COPY"
}
}],
maxPoints : sheet.getRange('B7').getValue().toString(),
state: "PUBLISHED",
workType: "ASSIGNMENT"
};
const newCourseAssignment = Classroom.Courses.CourseWork.create(assignment, courseId);
const assId = newCourseAssignment.id;
sheet.getRange('D1').setValue(assId);
}
after running I get a notification in my spreadsheet that is "GoogleJsonResponseException: API call to classroom.courses.courseWork.create failed with error: #AttachmentNotVisible The item referenced by an attachment was not found or not visible to the user."
well what should i do?
I really wait for your answer and I appreciate it```
Do I have to change the drive ID?

Modification points:
About the error of The item referenced by an attachment was not found or not visible to the user., in this case, when the file ID is the invalid file ID, such an error occurs. When I saw your showing script, I thought that at id: sheet.getRange('B5').getValue.toString(),, getValue should be getValue(). This can be also seen at title: sheet.getRange('B6').getValue.toString(). If your file ID is correct, I thought that the reason for your issue might be due to this.
In your situation, I think that the values can be retrieved from cells B1:B7 by one call.
When these points are reflected in your script, how about the following modification?
Modified script:
function assignmentWithDriveFile() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName('ASSIGNMENT (Drive File)');
const [[courseId], [topicId], [title], [description], [driveFileId], [driveFileTitle], [maxPoints]] = sheet.getRange("B1:B7").getDisplayValues();
var assignment = {
topicId,
title,
description,
materials: [{
driveFile: {
driveFile: {
id: driveFileId, title: driveFileTitle
},
shareMode: "STUDENT_COPY"
}
}],
maxPoints: maxPoints,
state: "PUBLISHED",
workType: "ASSIGNMENT"
};
const newCourseAssignment = Classroom.Courses.CourseWork.create(assignment, courseId);
const assId = newCourseAssignment.id;
sheet.getRange('D1').setValue(assId);
}
I think that when these values of [[courseId], [topicId], [title], [description], [driveFileId], [driveFileTitle], [maxPoints]] are correct values, this script works.

Related

How to find a row by value and update it's content from Google Sheets API in javascript nodejs

I am working on an Nextjs application that uses a Google Spreadsheet as a database. The application should GET, APPEND and UPDATE values in a spreadsheet, using the Sheets API v4.I have difficulties updating a specific row. I need to find a row that has a specific value in it's first column ("ID") and update all the cells in this row.
I want to mark attendance for the Students
This is how my spreadsheet looks like.
id
name
Attendance
30336547
Burhanuddin
Present
30336548
Alexandra
30336549
Andrew
30336550
Anna
30336551
Becky
30336552
Benjamin
30336553
Carl
I have tried removing all values and looping the array and getting the key of the matching value. I want to use and search or find options from google sheet API.
I tried the implement google sheet API to use batchUpdateByDataFilter()
import { google } from "googleapis";
const auth = new google.auth.GoogleAuth({
credentials: {
client_email:
"example#example.iam.gserviceaccount.com", //Placeholder client_email value
private_key:
"-----BEGIN PRIVATE KEY-----\n-----END PRIVATE KEY-----\n", //Placeholder private_key value
},
scopes: [
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/drive.file",
"https://www.googleapis.com/auth/spreadsheets",
],
});
const sheets = google.sheets({
auth,
version: "v4",
});
const sourceSheet = await sheets.spreadsheets.values.batchUpdateByDataFilter({
spreadsheetId: "", //Placeholder private_key value
requestBody: {
valueInputOption: "USER_ENTERED",
data: [
{
dataFilter: {
developerMetadataLookup: {
locationType: "COLUMN",
metadataKey: "id",
metadataValue: "30336547",
visibility: "DOCUMENT",
metadataLocation: {
locationType: "COLUMN",
spreadsheet: false,
},
metadataId: 0,
},
},
values: [["Present"]],
},
],
},
});
res.status(200).json({
success: true,
msg: sourceSheet,
});
I believe your goal is as follows.
You want to search for a value from column "A" of Google Spreadsheet and want to update column "C".
You want to achieve this using googleapis for node.js.
Modification points:
In the current stage, the values cannot be directly searched with REST Resource: spreadsheets.developerMetadata.
In this case, it is required to do the following flow.
Retrieve values from Spreadsheet.
Check the values.
Update the Spreadsheet.
When this flow is reflected in your script, how about the following modification? In this modification, the script for using Sheets API is modified.
Modified script:
const sheets = google.sheets({auth, version: "v4"}); // This is from your showing script.
const spreadsheetId = "###"; // Please set your Spreadsheet ID.
const sheetName = "Sheet1"; // Please set your sheet name.
const inputValues = ["30336551", "30336553"]; // This is a sample input value.
const { data: { values }} = await sheets.spreadsheets.values.get({ spreadsheetId, range: sheetName });
await sheets.spreadsheets.values.update({
spreadsheetId,
range: sheetName,
resource: {values: values.map((r) => inputValues.includes(r[0]) ? [r[0], r[1], "Present"] : r)},
valueInputOption: "USER_ENTERED",
});
When this script is run, the rows of ["30336551", "30336553"] (These values are from your question.) in column "A" are updated. A value of "Present" is put into the column "C".
References:
Method: spreadsheets.values.get
Method: spreadsheets.values.update

ValidationException: The provided key element does not match the schema with primary key and sort key

Using "aws-sdk": "^2.1063.0" and nodejs 12
Inside my lambda I am doing an update to a dynamodb table.
My table has a Primary key: JobUID type string and a Sort key type string.
My parameters look like this:
var params = {
TableName: tableName,
Key: {
"JobUID": payload.JobUID,
"TimeStamp": payload.TimeStamp
},
UpdateExpression:
"set #HasResponse = :v_HasResponse, #ResponseTimeStamp = :v_ResponseTimeStamp, #Recommendation = :v_Recommendation, #ThreadRepComment = :v_ThreadRepComment",
ExpressionAttributeNames: {
"#HasResponse": payload.HasResponse,
"#ResponseTimeStamp": payload.ResponseTimeStamp,
"#Recommendation": payload.Recommendation,
"#ThreadRepComment": payload.ThreadRepComment,
},
ExpressionAttributeValues: {
":v_HasResponse": payload.HasResponse,
":v_ResponseTimeStamp": payload.ResponseTimeStamp,
":v_Recommendation": payload.Recommendation,
":v_ThreadRepComment": payload.ThreadRepComment,
},
// returns only the affected attributes, as they appeared after the update
ReturnValues: "UPDATED_NEW"
};
I have printed out the payload.JobUID and payload.TimeStamp in the log so I know they are what expect.
The latest row in the table has JobUID and TimeStamp exactly as I printed them out.
I want to update the 4 properties in the expression attribute names.
I am getting the error "ValidationException: The provided key element does not match the schema"
I have looked on the web and in SOF at examples of updates and I cannot seem to get this to work.
what is wrong with my key values.
The update call looks like this. Super simple
var returnValue = await dynamo.update(params).promise();
I also tried
Key: {
JobUID: {"S": payload.JobUID},
TimeStamp: {"S":payload.TimeStamp}
},
So this is what I found works:
var params = {
TableName: tableName,
Key: {
JobUID: payload.JobUID,
TimeStamp: payload.TimeStamp
},
UpdateExpression:
"set HasResponse = :v_HasResponse, ResponseTimeStamp = :v_ResponseTimeStamp, Recommendation = :v_Recommendation, ThreadRepComment = :v_ThreadRepComment",
ExpressionAttributeValues: {
":v_HasResponse": payload.HasResponse,
":v_ResponseTimeStamp": payload.ResponseTimeStamp,
":v_Recommendation": payload.Recommendation,
":v_ThreadRepComment": payload.ThreadRepComment || "",
},
// returns only the affected attributes, as they appeared after the update
ReturnValues: "UPDATED_NEW"
};
var returnValue = await dynamo.update(params).promise();
If there is a property is is null or empty, in my case the ThreadRepComment could be null or empty so you need to handle that.

Find google sheet id from sheet name using nodejs and Google Sheets API v4

I would like to find a google sheet id (as in the .../edit#gid="SHEET_ID" query parameter) from the sheet name using nodejs and the Google Sheets v4 API. If I understand correctly the following code should work, but the response does not contain any "sheetIds" at all. Any idea what I've maybe missed?
const request = {
spreadsheetId: GS_ID,
ranges: [sheetName],
includeGridData: false
};
let res = await GS.spreadsheets.get(request);
console.log(res.data.properties.sheetId);
I only get this data, so the sheets properties seem to be missing
{ spreadsheetId: '###',
properties:
{ title: '###',
locale: 'en_US',
autoRecalc: 'ON_CHANGE',
timeZone: 'Asia/Tokyo',
defaultFormat: {...},
sheets: [ { properties: [Object] } ],
spreadsheetUrl: 'https://docs.google.com/spreadsheets/d/###/edit' }
Explanation:
The ranges parameter needs to be in A1 notation to retrieve sheet information from the response. To retrieve sheet information, iterate through the sheets array and get the sheetID from a particular sheet name:
Sample:
const rangeName = 'A1:B1';
const sheetName = 'Sheet1';
const GS_ID = <insert spreadsheet ID here>;
const request = {
spreadsheetId: GS_ID,
ranges: rangeName,
includeGridData: false
};
let res = await GS.spreadsheets.get(request);
for (i = 0; i < res.sheets.length; i++) {
if (res.sheets[i].title === sheetName) {
console.log(res.sheets[i].sheetId); // get sheet ID here
}
}
References:
Sheets API | Spreadsheets.get
Object Spreadsheet
Object Sheet

Is there a way to create an XLSX with multiple sheets using alaSql?

What i´m trying to do is generating an xlsx file with multiple sheets by using alaSql . They only need to have the columns and no data at all (it´s going to be used as a template available for download)
var tasksData = [{
UserName:"",
Application:"",
Module:""
}];
var objectsData = [{
UserName:"",
Application:"",
Module:""
}];
var conflictsData = [{
UserName:"",
Application:"",
Module:""
}];
var opts = [{
sheetid: 'TasksData',
headers: false
}, {
sheetid: 'ObjectsData',
headers: false
}, {
sheetid: 'ConflictsData',
headers: false
}];
alasql('SELECT * INTO XLSX("MatrixSODTemplate.xlsx",?) FROM ?',[opts,[tasksData,objectsData,conflictsData]]);
i need the output to be a single xlsx file with 3 sheets. And no data in it, only the columns.
Sheet TaskData:
-UserName
-Application
-Module
Sheet ObjectsData:
-UserName
-Application
-Module
Sheet ConflictsData:
-UserName
-Application
-Module
So i found out what was going on. I had an old version of alasql in my project. So i upgrade it and then i found this helpfull link where the developers explain how to do it.
var data1 = [{a:1,b:10},{a:2,b:20}];
var data2 = [{a:100,b:10},{a:200,b:20}];
var opts = [{sheetid:'One',header:true},{sheetid:'Two',header:false}];
var res = alasql('SELECT INTO XLSX("restest344b.xlsx",?) FROM ?',[opts,[data1,data2]],
function(){
done();
});
https://github.com/agershun/alasql/wiki/How-to-create-multiple-worksheets-into-a-workbook
Hope it helps someone

How to add more metrics on the country_map in Apache-superset?

I am using country_map in apache-superset for visualization purposes. When zooming in on a polygon, information from the columns appears inside of the polygon, like so:
There is only one available metric option to display:
Code for the metric update is found on this path:
superset/assets/src/visualizations/CountryMap/CountryMap.js
Code:
const updateMetrics = function (region) {
if (region.length > 0) {
resultText.text(format(region[0].metric));
}
};
The metrics are defined in controls.jsx:
/superset/static/assets/src/explore/controls.jsx
const metrics = {
type: 'MetricsControl',
multi: true,
label: t('Metrics'),
validators: [v.nonEmpty],
default: (c) => {
const metric = mainMetric(c.savedMetrics);
return metric ? [metric] : null;
},
mapStateToProps: (state) => {
const datasource = state.datasource;
return {
columns: datasource ? datasource.columns : [],
savedMetrics: datasource ? datasource.metrics : [],
datasourceType: datasource && datasource.type,
};
},
description: t('One or many metrics to display'),
};
const metric = {
...metrics,
multi: false,
label: t('Metric'),
default: props => mainMetric(props.savedMetrics),
};
Country map is using metric, which doesn't allow multiple metrics to be selected, Code found here:
superset/assets/src/explore/controlPanels/CountryMap.js
controlPanelSections: [
{
label: t('Query'),
expanded: true,
controlSetRows: [
['entity'],
['metric'],
['adhoc_filters'],
],
},
{
label: t('Options'),
expanded: true,
controlSetRows: [
['select_country', 'number_format'],
['linear_color_scheme'],
],
},
],
The python class of country_map is located at viz.py:
class CountryMapViz(BaseViz):
"""A country centric"""
viz_type = 'country_map'
verbose_name = _('Country Map')
is_timeseries = False
credits = 'From bl.ocks.org By john-guerra'
def query_obj(self):
qry = super(CountryMapViz, self).query_obj()
qry['metrics'] = [
self.form_data['metric']]
qry['groupby'] = [self.form_data['entity']]
return qry
Changing the code in CountryMap.js and viz.py from metric to metrics results in the following error:
Traceback (most recent call last):
File "/Documents/superset/superset/superset/viz.py", line 410, in get_df_payload
df = self.get_df(query_obj)
File "/Documents/superset/superset/superset/viz.py", line 213, in get_df
self.results = self.datasource.query(query_obj)
File "/Documents/superset/superset/superset/connectors/sqla/models.py", line 797, in query
sql = self.get_query_str(query_obj)
File "/Documents/superset/superset/superset/connectors/sqla/models.py", line 471, in get_query_str
qry = self.get_sqla_query(**query_obj)
File "/Documents/superset/superset/superset/connectors/sqla/models.py", line 585, in get_sqla_query
elif m in metrics_dict:
TypeError: unhashable type: 'list'
How can I add more metrics to display inside the polygon?
The direct cause of the error TypeError: unhashable type: 'list' is your modification to file "viz.py":
self.form_data['metric']] to self.form_data['metrics']], in the query_obj(self) method.
As you can see in the source code here, form data metrics is a list object that contains metric, where metric is probably a string or other hashable object. In python language, a list object is not hashable. Because you replace a hashable object (metric) with an unhashable one (metrics), an unhashable type error is then raised.
The correct way to modify CoutryMapViz.query_obj() to accept metrics query can be found in the other Viz classes. The code section here is a very nice example:
class CalHeatmapViz(BaseViz):
"""Calendar heatmap."""
...
def query_obj(self):
d = super(CalHeatmapViz, self).query_obj()
fd = self.form_data
d['metrics'] = fd.get('metrics')
return d
Finally, the CoutryMapViz.query_obj() method should look like this:
class CountryMapViz(BaseViz):
...
def query_obj(self):
qry = super(CountryMapViz, self).query_obj()
qry['metrics'] = fd.get('metrics')
qry['groupby'] = [self.form_data['entity']]
return qry

Categories