Get the student´s submission id of a google classroom assignment - google-classroom

I want to return assignments in Google Classrom using
service().courseWork().studentSubmissions().return_(courseId=PASS_HERE_THE_COURSEID, courseWorkId=PASS_HERE_THE_COURSEWORDID, id=PASS_HERE_THE_SUBMISSION_ID)
I have the courseId and the courseWorkId, but don´t know how to get the id=PASS_HERE_THE_SUBMISSION_ID for each student.
Hope someone can help me.

You can use courses.courseWork.studentSubmissions.list to get a list of student submissions. You just need to provide the courseId and courseWorkId as a path parameter. You may also include additional query parameters in your request.
For example, you want to restrict returned student work to those owned by the student with the specified identifier. You need to set a specific identifier to userId as part of your query parameters
Note: You may also loop all the list of student submission to process each submission before returing it using courses.courseWork.studentSubmissions.return
The numeric identifier for the user
The email address of the user
The string literal "me", indicating the requesting user
Sample Response Body (JSON):
{
"studentSubmissions": [
{
object (StudentSubmission)
}
],
"nextPageToken": string
}
StudentSubmission contains all the information related to the student submission for the course work including the courseId, courseWorkId, id and userId.
StudentSubmission Resource (JSON):
{
"courseId": string,
"courseWorkId": string,
"id": string,
"userId": string,
"creationTime": string,
"updateTime": string,
"state": enum (SubmissionState),
"late": boolean,
"draftGrade": number,
"assignedGrade": number,
"alternateLink": string,
"courseWorkType": enum (CourseWorkType),
"associatedWithDeveloper": boolean,
"submissionHistory": [
{
object (SubmissionHistory)
}
],
// Union field content can be only one of the following:
"assignmentSubmission": {
object (AssignmentSubmission)
},
"shortAnswerSubmission": {
object (ShortAnswerSubmission)
},
"multipleChoiceSubmission": {
object (MultipleChoiceSubmission)
}
// End of list of possible types for union field content.
}
(UPDATE)
Regarding the error you have encountered when using courses.courseWork.studentSubmissions.return in Apps Script,
GoogleJsonResponseException: API call to classroom.courses.courseWork.studentSubmissions.return failed with error: #ProjectPermissionDenied The Developer Console project is not permitted to make this request.
It occurred because you are trying to modify a course work which is not created on a Developer Console project. Please refer here.
Sample Code:
var courseId = '2491255xxxxxx';
var courseWorkId = '2524434xxxxx'; // manually created in classroom.google.com
//1st TRY with error
var studentSubmissions = Classroom.Courses.CourseWork.StudentSubmissions.list(courseId, courseWorkId);
Logger.log(studentSubmissions.studentSubmissions[0].id);
//var ret = Classroom.Courses.CourseWork.StudentSubmissions.return({},courseId, courseWorkId, studentSubmissions.studentSubmissions[0].id);
//Logger.log(ret);
var assignment = {
title: "Test Assignment 3",
state: "DRAFT",
assigneeMode: "ALL_STUDENTS",
workType: "ASSIGNMENT"
};
//var newCourseWork = Classroom.Courses.CourseWork.create(assignment, courseId);
//2nd TRY without error
var newCourseWorkId = '2618921xxxxx';
var studentSubmissions2 = Classroom.Courses.CourseWork.StudentSubmissions.list(courseId, newCourseWorkId);
var ret = Classroom.Courses.CourseWork.StudentSubmissions.return({},courseId, newCourseWorkId, studentSubmissions2.studentSubmissions[0].id);
Logger.log(studentSubmissions2);
Logger.log(ret);
Logger.log(Classroom.Courses.CourseWork.get(courseId,newCourseWorkId));
Explanation:
During the first try, I tried to return a student submission course work which was created in https://classroom.google.com/. This case will encounter an error, since I am trying to modify a course work that is not associated with a developer console project. You can check if a course work has an associated developer console project using Classroom.Courses.CourseWork.get(), associatedWithDeveloper property should be true.
On the 2nd try, I created a draft course work first, then modify the created course work in https://classroom.google.com/. Once I finalized the changes and published the course work. I tried to return the student submission course work and it was successful (return should be null/empty). The reason why it succeed is because a developer console project is associated with the course work since I created the course work using Apps Script, hence I could also modify the student submission using Apps Script.

Related

How to automatically update the UI after user updates a userProperty in Google Apps Script Workspace Add-ons for Google Sheets?

I want to automagically update the UI with a new user setting after the user updates that setting by submitting a user input from.
Currently, I am attempting to use the updateCard() method from the CardService as shown in the below code. The docs are here but they do not contain any example code.
I expect that after the user provides the input and submits it, the current card will be replaced by an updated card that will contain the new setting.
However, what’s actually happening is that the card I expect to update is not updating automatically. To see the change, the user has to manually refresh the app homepage. After, and only after, a manual refresh, does the homepage card update with the new setting.
How do I update the homepage automatically without requiring a manual refresh?
Code.gs
const changedProperty = PropertiesService.getUserProperties().getProperty( MY_SETTING );
const newNavigation = CardService.newNavigation();
const cardPoppedToRoot = newNavigation.popToRoot();
const homepageCard = getCardFromUiConfig( HOMEPAGE_UI_CONFIG, );
const updatedCard = cardPoppedToRoot.updateCard( homepageCard, );
return updatedCard;
I also tried the following code per this answer and the results are exactly the same as with the above code.
Code.gs
return CardService.newActionResponseBuilder()
.setNavigation(
CardService.newNavigation()
.popToRoot()
.updateCard( homepageCard, )
).build();
When I try to configure my appsscript.json file as shown in the answer as follows:
appsscript.json
"homepageTrigger": {
"runFunction": "onHomepage"
},
"contextualTriggers":[
{
"unconditional":{},
"onTriggerFunction": "onHomepage"
}
]
I get the following error:
"appsscript.json" has errors: Invalid manifest: unknown fields: [addOns.common.contextualTriggers]
I think that that is only possible for Gmail add-ons.
contextualTriggers can't be child of common.
From https://developers.google.com/apps-script/manifest/addons#common (links not included):
Common
The manifest configuration for parameters that are common for every host application. Some values defined here are used as a default when specific values for a particular host are omitted.
{
"homepageTrigger": {
object (HomepageTrigger)
},
"layoutProperties": {
object (LayoutProperties)
},
"logoUrl": string,
"name": string,
"openLinkUrlPrefixes": [
string
],
"universalActions": [
{
object (UniversalAction)
}
],
"useLocaleFromApp": boolean
}
AFAIK contextualTriggers can only be used with Gmail add-ons. From https://developers.google.com/apps-script/manifest/gmail-addons (links not included):
Gmail
The Google Workspace add-on manifest configuration for Gmail extensions. See Extending Gmail with Google Workspace add-ons for more information.
{
"authorizationCheckFunction": string,
"composeTrigger": {
object (ComposeTrigger)
},
"contextualTriggers": [
{
object (ContextualTrigger)
}
],
"homepageTrigger": {
object (HomepageTrigger)
}
}
Related
How to fully refresh Google Addon Card (Google Sheets) which includes a drop down menu populated using sheet data when data changes?

How to get query sys_id of current.sys_id Service Portal (ServiceNow)

I have a question regarding a small issue that I'm having. I've created a widget that will live on the Service Portal to allow an admin to Accept or Reject requests.
The data for the widget is pulling from the Approvals (approval_approver) table. Under my GlideRecord, I have a query that checks for the state as requested. (Ex. addQuery('state', 'requested'))
To narrow down the search, I tried entering addQuery('sys_id', current.sys_id). When I use this query, my script breaks and I get an error on the Service Portal end.
Here's a sample of the GlideRecord script I've written to Accept.
[//Accept Request
if(input && input.action=="acceptApproval") {
var inRec1 = new GlideRecord('sysapproval_approver');
inRec1.addQuery('state', 'requested');
//inRec1.get('sys_id', current.sys_id);
inRec1.query();
if(inRec1.next()) {
inRec1.setValue('state', 'Approved');
inRec1.setValue('approver', gs.getUserID());
gs.addInfoMessage("Accept Approval Processed");
inRec1.update();
}
}][1]
I've research the web, tried using $sp.getParameter() as a work-around and no change.
I would really appreciate any help or insight on what I can do different to get script to work and filter the right records.
If I understand your question correctly, you are asking how to get the sysId of the sysapproval_approver record from the client-side in a widget.
Unless you have defined current elsewhere in your server script, current is undefined. Secondly, $sp.getParameter() is used to retrieve URL parameters. So unless you've included the sysId as a URL parameter, that will not get you what you are looking for.
One pattern that I've used is to pass an object to the client after the initial query that gets the list of requests.
When you're ready to send input to the server from the client, you can add relevant information to the input object. See the simplified example below. For the sake of brevity, the code below does not include error handling.
// Client-side function
approveRequest = function(sysId) {
$scope.server.get({
action: "requestApproval",
sysId: sysId
})
.then(function(response) {
console.log("Request approved");
});
};
// Server-side
var requestGr = new GlideRecord();
requestGr.addQuery("SOME_QUERY");
requestGr.query(); // Retrieve initial list of requests to display in the template
data.requests = []; // Add array of requests to data object to be passed to the client via the controller
while(requestsGr.next()) {
data.requests.push({
"number": requestsGr.getValue("number");
"state" : requestsGr.getValue("state");
"sysId" : requestsGr.getValue("sys_id");
});
}
if(input && input.action=="acceptApproval") {
var sysapprovalGr = new GlideRecord('sysapproval_approver');
if(sysapprovalGr.get(input.sysId)) {
sysapprovalGr.setValue('state', 'Approved');
sysapprovalGr.setValue('approver', gs.getUserID());
sysapprovalGr.update();
gs.addInfoMessage("Accept Approval Processed");
}
...

how to define BusinessNetworkConnection in hyperledger-composer transaction processor?

In my hyperledger-composer app, I have a transaction processor:
async function doSomething(transaction) {
//some code
// the following line results in error message:
const connection = new BusinessNetworkConnection();
await connection.connect('admin#tmy-network');
const result = await connection.query(selectPatientByEmail, { inputValue: email });
//some more code
}
However, the line
const connection = new BusinessNetworkConnection();
causes the following error messsage:
ReferenceError: BusinessNetworkConnection is not defined
How can I define the BusinessNetworkConnection?
*******************************UPDATE**************************************
Following the comment by Paul O'Mahony, I used the following line of code in my transaction processor function (in order to get the patient with the email address 'adam#gmail.com'):
let result = await query('selectPatientByEmail', {
"email": "adam#gmail.com"
});
The query is defined in the queries.qry file as follows:
query selectPatientByEmail {
description: "Select the patient with the given email address"
statement:
SELECT org.comp.app.Patient
WHERE (email == _$email)
}
However, the query returns "undefined" (i.e. variable "result" is undefined) .
What for god's sake is wrong with the code? I just can't see what might be the causing this behaviour.
***************************Update2*****************************************
I have to correct myself ... the query returns something ... but when I want to access the id of the returned patient, this is not possible. That is,
result.id is "undefined"
How can I access the id of the patient returned?
this is because you are (above) writing client code inside a native transaction function - you don't need to set these. Transaction processor functions are automatically invoked by the runtime when transactions are submitted (eg using the BusinessNetworkConnection API under the covers, but it is already part of the transaction - you don't need to specify) . See https://hyperledger.github.io/composer/latest/reference/js_scripts for more info - and the sample networks for common use cases and examples -> https://github.com/hyperledger/composer-sample-networks/tree/master/packages/

Alexa skills kit, trouble getting session attributes to persist

I have been working on a skill where I am using Login With Amazon account linking so I can grab the user email address and name to use in my skill. I am doing something similar to the scoreKeeper sample, using the eventHandlers.js and the storage.js for saving items to a database. In the eventHandlers.onLaunch I am successfully getting the profile name and email address from Amazon and I save it to the session.attributes like this:
var profile = JSON.parse(body);
speechOutput="Hello, " + profile.name.split(" ")[0] + ".";
var sessionAttributes = {};
sessionAttributes = { name: profile.name, email: profile.email };
session.attributes = sessionAttributes;
console.log("Name in session:", session.attributes.name);
The console log shows the name so I know it is being saved in the session.attributes, but when I try to access the session.attributes in my storage.js or intentHandlers.js, it shows it as being empty. What am I missing? Thanks in advance. This has been driving me crazy.
I got this working by adding session to the callback of the response.ask function, like this:
ask: function (speechOutput, repromptSpeech, _session) {
this._context.succeed(buildSpeechletResponse({
session: _session,
output: speechOutput,
reprompt: repromptSpeech,
shouldEndSession: false
}));
},
It had session: this._session for saving the session, but that didn't seem to be working for me. Passing it as a variable did.
Let's say you want to obtain city name from the user and be able to access that value later in the Alexa session:
1) Pre-define your key/value pairs in the JSON response:
def build_response(session_attributes, speechlet_response):
return {
'version': '1.0',
'sessionAttributes': {
"session_attributes": {
'NameOfCity': city_name,
}
},
'response': speechlet_response
}
2) In global scope, declare the variable as an empty string:
city_name = "",
3) Whenever you update that variable within a function, make sure you reference that variable as global. For example:
def set_city_name_in_session(intent, session):
card_title = intent['name']
session_attributes = {}
should_end_session = False
if 'CityIntent' in intent['slots']:
global city_name
city_name = intent['slots']['CityIntent']['value']
4) When creating a function that needs to access this variable, pass the global variable as an argument into the function then, within the function, expose all session key/pair values like so:
def access_variables(intent, session, city_name):
card_title = intent['name']
session_attributes = {}
should_end_session = False
exposed_attributes = session['attributes']['session_attributes']
city_name_attribute_value = exposed_attributes.get('NameOfCity')
if (some_kind_of_condition):
do something awesome with city_name_attribute_value
To test, enter sample utterances into Service Simulator then check if values are persisting in your Lambda JSON response.

Getting Parse Objects via pointers

I am trying to get a Reservation object which contains a pointer to Restaurant.
In Parse Cloud code, i am able to get the restaurants objects associated with Reservations via query.include('Restaurant') in log just before response.success. However, the Restaurants reverted back to pointer when i receive the response on client app.
I tried reverted JSSDK version to 1.4.2 & 1.6.7 as suggested in some answers, but it doesn't work for me.
Parse.Cloud.define('getreservationsforuser', function(request, response) {
var user = request.user
console.log(user)
var query = new Parse.Query('Reservations')
query.equalTo('User', user)
query.include('Restaurant')
query.find({
success : function(results) {
console.log(JSON.stringify(results))
response.success(results)
},
error : function (error) {
response.error(error)
}
})
})
response :
..."restaurant":{"__type":"Pointer",
"className":"Restaurants",
"objectId":"kIIYe7Z0tD"},...
You can't directly send the pointer objects back from cloud code even though you have included it. You need to manually copy the content of that pointer object to a javascript object. Like below:
var restaurant = {}
restaurant["id"] = YOUR_POINTER_OBJECT.id;
restaurant["createdAt"] = YOUR_POINTER_OBJECT.createdAt;
restaurant["custom_field"] = YOUR_POINTER_OBJECT.get("custom_field");
ps: in your code you seem do nothing else other than directly send the response back. I think parse REST api might be a better choice in that case.
It turned out that my code implementation was correct.

Resources