Classroom.Courses.Students.create returns error - google-apps-script

I'm writing a script to enroll all my students (2,000) each one in his own classroom.
referring to the Method page I wrote a simple sentence like this:
Classroom.Courses.Students.create({
"courseId": "9898688798",
"profile": {
"name": {
"familyName": "Xxxxxx",
"givenName": "Yyyy"
},
"emailAddress": "myemail#gmail.com"
}
});
but I receive this error:
Exception: Invalid number of arguments provided. Expected 2-3 only
Where did I make a mistake?

Issue:
As the error you are getting says, this method requires two or three parameters, and you're only providing one.
Solution:
If you start typing the method you'll see a popup displaying the required parameters for this method:
resource: referring to the student resource, which is the request body that has to be provided for the API method.
courseId: the identifier of the course to create the student in, which is the path parameter for the API method.
optionalArgs: [OPTIONAL] referring to any additional parameters you'd want to add, like enrollmentCode.
Also, for the first parameter, resource, three of the four fields from the student resource are read-only, so you only have to provide the userId, which can be one of the following:
the numeric identifier for the user
the email address of the user
the string literal "me", indicating the requesting user
Code snippet:
So in your example, you could do this:
const resource = {
"userId": "myemail#gmail.com"
}
const courseId = "9898688798";
Classroom.Courses.Students.create(resource, courseId);

Related

Unable to retrieve Claims in either the id_token or userinfo requests

I'm trying to retrieve the CIF and also the Tax Id of the logged in user following your documentation. When trying to request that information via additional claims via the Consumer API, with the scope of &scope=openid I'm supplying the below claims parameter in my authorization request. Making sure that the External App is configured with the claims access in the Banno portal, I don't get anything in my response id_token. I've also attempted to switch this to the userinfo leveraging the opid/me resource which just returns the user "sub".
Claims readable:
claims={"id_token":{"https://api.banno.com/consumer/claim/customer_identifier":null}}
Here it is url encoded:
claims==%7B%22id_token%22%3A%7B%22https%3A%2F%2Fapi.banno.com%2Fconsumer%2Fclaim%2Fcustomer_identifier%22%3Anull%7D%7D
decoded jwt id_token repsonse:
"id_token": {
"header": {
"alg": "RS256",
"typ": "JWT",
"kid": "sig-rs-0"
},
"body": {
"sub": "sub uuid",
"at_hash": "ShHf2gRtROCBdE-j_5YZkw",
"aud": "aud uuid",
"exp": 1668092577,
"iat": 1668088977,
"iss": "https://api.banno.com/a/consumer/api/v0/oidc"
}
}
using the same example switching the claims key to "userinfo" and making a request to .../a/consumer/api/v0/oidc/me I only get this response:
UserInfo Response:
{"sub":"sub uuid"}
In either scenario, I'm expecting the following example to be in the response:
"https://api.banno.com/consumer/claim/customer_identifier": "AAA1234",
However I don't get anything no matter what I do. What am I missing here?
It looks like there is an extra = in the encoded version. If I take what you've posted in the question, claims==%7B%22id_token%22%3A%7B%22https%3A%2F%2Fapi.banno.com%2Fconsumer%2Fclaim%2Fcustomer_identifier%22%3Anull%7D%7D and decode it, I get claims=={"id_token":{"https://api.banno.com/consumer/claim/customer_identifier":null}}, which has an extra = next to the claims parameter name.
That seems to have the effect of the name of the claim not matching up with what is expected, therefore that claim's value is not included in the Identity Token (and isn't available from the UserInfo endpoint).
The Claims in the Identity Token guide will be helpful to review.

Google script for gmail api watch: No way to get message id for fresh emails?

been using google script to trigger action when new mail comes in.
This is my doPost function
function doPost(e) {
var contents = JSON.parse(e.postData.contents);
var message = contents.message;
var data = JSON.parse(Utilities.newBlob(Utilities.base64Decode(message.data)).getDataAsString());
var historyId = data.historyId;
}
With this, I have access to historyId,... but to get the message object, or at least the message id of the mail, I will be needing to show the history. so:
Gmail.Users.History.list("me", {"startHistoryId": historyId});
The expected result of the code above would be:
{ historyId: '######', history: [ { messages: [Object], id: '#####' } ] }
This is is true for mails that have threads or histories already.
BUT, this isn't the case for new mails. It only shows the historyId { historyId: '######' }
My question is, is there really no way to get the message object for new mails? If not, how?
Gmail.Users.Message.list() returns:
An email message.
JSON representation
{
"id": string,
"threadId": string,
"labelIds": [
string
],
"snippet": string,
"historyId": string,
"internalDate": string,
"payload": {
object (MessagePart)
},
"sizeEstimate": integer,
"raw": string
}
The reason why the history.list method is just returning the ID is explained in its documentation
Returns history records after the specified startHistoryId. The supplied startHistoryId should be obtained from the historyId of a message, thread, or previous list response. History IDs increase chronologically but are not contiguous with random gaps in between valid IDs. (...) If you receive no nextPageToken in the response, there are no updates to retrieve and you can store the returned historyId for a future request.
This means that you will only get the messages after the specified History ID, so if you're tracking changes to the User's most recent History ID you will get blank responses.
To get the message objects you can use messages.list instead. And based on the quote above it seems that there's no easy way to get a list of all History IDs so they expect you to store the current ID when a change occurs and when you detect another change you can use the stored ID instead of the new one to get the most recent messages.

ADF V2 - Web POST method using Dynamic Content and Variable

Very short version
How do I include an ADF Variable inside a JSON POST request, in a Web Activity within ADF?
I feel like this should be a very simple string concatenation, but i can't get it to work
Detail
We have a requirement to run a query / SProc from within ADF, which will return a string containing an error message. That string is to then be passed via the Web Activity in ADF to a Logic App, in order to fire off an email, containing the error.
The setup of the logic app is copied from here:
https://www.mssqltips.com/sqlservertip/5718/azure-data-factory-pipeline-email-notification--part-1/
and then here (part 2)
https://www.mssqltips.com/sqlservertip/5962/send-notifications-from-an-azure-data-factory-pipeline--part-2/
In ADF, I used the Lookup activity, to run a query, which brings back the error (appears to work, the preview returns the correct string)
Then I use the Set Variable activity, to take the output of the lookup and store it in a variable.
Last Step is to fire off the POST using the Web Activity.
With this code (tweaked slightly to remove personal details) in my Web Activity, everything works fine and I receive an email
{
"DataFactoryName": "#{pipeline().DataFactory}",
"PipelineName": "#{pipeline().Pipeline}",
"Subject": "Pipeline finished!",
"ErrorMessage": "Everything is okey-dokey!",
"EmailTo": "me#myEmail.com"
}
But any attempt to put the contents of the Variable into the Subject part has failed.
This (for example) sends me an email with the subject literally being #variables('EmailSubject')
{
"DataFactoryName": "#{pipeline().DataFactory}",
"PipelineName": "#{pipeline().Pipeline}",
"Subject": "#variables('EmailSubject')",
"ErrorMessage": "Everything is okey-dokey!",
"EmailTo": "me#myEmail.com"
}
But I've also attempted various other solutions that result in errors or the email subject just containing the literal thing that I put in there (e.g. + #variables('EmailSubject') +).
I also tried storing the entire JSON in the Variable, and then having the Web activity use only the variable, that returned no errors, but also did not send an email.
This attempt:
{
"DataFactoryName": "#{pipeline().DataFactory}",
"PipelineName": "#{pipeline().Pipeline}",
"Subject": "#{variables('EmailSubject')}",
"ErrorMessage": "Everything is okey-dokey!",
"EmailTo": "me#myEmail.com"
}
Resulted in this input into the web activity - which actually includes the text of the error, which is a bonus ... (text = Job Duration Warning):
{
"url": "https://azureLogicAppsSiteHere",
"method": "POST",
"headers": {
"Content-Type": "application/json"
},
"body": "{\n \"DataFactoryName\": \"DFNAMEHERE\",\n \"PipelineName\": \"pipeline1\",\n \"Subject\": \"{\"firstRow\":{\"\":\"Job Duration Warning\"},\"effectiveIntegrationRuntime\":\"DefaultIntegrationRuntime (West Europe)\",\"billingReference\":{\"activityType\":\"PipelineActivity\",\"billableDuration\":[{\"meterType\":\"AzureIR\",\"duration\":0.016666666666666666,\"unit\":\"DIUHours\"}]},\"durationInQueue\":{\"integrationRuntimeQueue\":0}}\",\n \"ErrorMessage\": \"Everything is okey-dokey!\",\n \"EmailTo\": \"me#myEmail.com\"\n}\t"
}
But then resulted in this error:
{
"errorCode": "2108",
"message": "{\"error\":{\"code\":\"InvalidRequestContent\",\"message\":\"The request content is not valid and could not be deserialized: 'After parsing a value an unexpected character was encountered: f. Path 'Subject', line 4, position 17.'.\"}}",
"failureType": "UserError",
"target": "Web1",
"details": []
}
[Edit] The PREVIEW from the Lookup Activity is the text: Job Duration Warning BUT when I debug the pipeline, it lets me see the actual Output, which is this:
{
"count": 1,
"value": [
{
"": "Job Duration Warning"
}
],
"effectiveIntegrationRuntime": "DefaultIntegrationRuntime (West Europe)",
"billingReference": {
"activityType": "PipelineActivity",
"billableDuration": [
{
"meterType": "AzureIR",
"duration": 0.016666666666666666,
"unit": "DIUHours"
}
]
},
"durationInQueue": {
"integrationRuntimeQueue": 0
}
}
So it appears that the problem is that the Lookup Output isn't what I thought it was, so the variable can't be used in the Web Activity, as it contains unsupported characters or something along those lines.
I just tested this and it worked ok:
Create a String Parameter with the value Job Duration Warning
Set the Variable value to be #pipeline().parameters.ParamSubject
Include the variable in the web activity with an # in front of it
I then receive my expected email with the right subject. I just don't know how to get the string output of my query, into a variable / parameter, so that i can use it in the web activity.
I don't know how well this applies to other people's issues, but I found a solution that has worked for me.
In the SELECT query within the Lookup Activity - name the output (in my case, I called that column 'Subject'- i.e. SELECT xyz AS Subject
In the Lookup Activity, turn on the setting 'First Row Only'
In the Set Variable Activity, use the code: #activity('Lookup1').output.firstRow.subject
(where 'Lookup1' is the name of your Lookup Activity and Subject is the name of the column you are outputting)
In the Web Activity, reference the variable as follows:
{
"DataFactoryName": "#{pipeline().DataFactory}",
"PipelineName": "#{pipeline().Pipeline}",
"Subject": "#{variables('EmailSubject')}",
"ErrorMessage": "Everything is okey-dokey!",
"EmailTo": "me#myEmail.com"
}

Gmail.Users.Threads.get with metadata scope and metadata format not working

I'm sure it's a pretty stupid thing I'm missing, but I can't quite see it.
My Google Apps Script only needs mail headers so it has a very restrictive scope:
"https://www.googleapis.com/auth/gmail.metadata". I really don't want to change this scope because it provides just what I need.
Because of this restrictive scope, many API calls will force you to select the METADATA format instead of the default FULL. This can be checked using the API explorer (https://developers.google.com/gmail/api/v1/reference/users/threads/get). Remember to Select JUST the metadata scope, otherwise it will work! :-)
{
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Metadata scope doesn't allow format FULL"
}
],
"code": 403,
"message": "Metadata scope doesn't allow format FULL"
}
}
Then, from the format drop down menu select "metadata" run again and it will work.
This simple code is enough to replicate the issue:
Code.gs
function getThread() {
// get the most recent thread
var thread = Gmail.Users.Threads.list('me', {maxResults: 1});
Logger.log('thread: %s', thread);
thread = JSON.parse(thread);
var threadId = thread.threads[0].id;
Logger.log('threadId: %s', threadId);
// scope "https://www.googleapis.com/auth/gmail.metadata"
// requires me to specify the metadata format
// next line will error: Metadata scope doesn't allow format FULL
var thread = Gmail.Users.Threads.get('me', {id: threadId, format: 'metadata'});
}
appsscript.json (View -> Show manifest file)
{
"oauthScopes": ["https://www.googleapis.com/auth/gmail.metadata"],
"dependencies": {
"enabledAdvancedServices": [{
"userSymbol": "Gmail",
"serviceId": "gmail",
"version": "v1"
}]
},
"exceptionLogging": "STACKDRIVER"
}
When getThread() function is run, it produces this error:
Metadata scope doesn't allow format FULL (line 10, file "Code.gs")
Gmail API, in particular Gmail.Users.Thread.get documentation (https://developers.google.com/gmail/api/v1/reference/users/threads/get) states:
Optional query parameters
format string The format to return the messages in.
Acceptable values are:
"full": Returns the parsed email message content in the payload field and the raw field is not used. (default)
"metadata": Returns email headers with message metadata such as identifiers and labels.
"minimal": Only returns email message metadata such as identifiers and labels, it does not return the email headers, body, or payload.
So it's not clear to me how this API call should be written:
var thread = Gmail.Users.Threads.get('me', {id: threadId, format: 'metadata'});
I've tried all the possible combinations of quotes (single, double and no quotes) with case (upper and lower) and nothing has worked. It seems it's being ignored... :-(
I'm stumped... please help! :-)
Thanks!!
Per the API documentation, Gmail.Users.Threads.get() requires 2 parameters, and has an optional 2 (the format object you indicate):
Path parameters
id string The ID of the thread to retrieve.
userId string The user's email address. The special value me can be used to indicate the authenticated user.
Optional query parameters
format string The format to return the messages in. Acceptable values are:
- "full": Returns the parsed email message content in the payload field and the raw field is not used. (default)
- "metadata": Returns email headers with message metadata such as identifiers and labels.
- "minimal": Only returns email message metadata such as identifiers and labels, it does not return the email headers, body, or payload.
metadataHeaders[] list When given and format is METADATA, only include headers specified.
In Apps Script's Advanced Services Gmail client library, 2 signatures are provided:
The parameters here should be:
userId - the user to request (for your case, "me")
id - the ID of the thread you want to obtain
your optional parameter object

Response custom error when key not satisfies the exact value in couchbase view

I have a document like -
{
"fullUserName": "xxyz",
"userFirstName": "xx",
"userLastName": "xx",
"primaryRole": "xy",
"actualRole": "rrr",
"userId": "abcd1234",
"password":"c28f5c7cb675d41c7763ab0c42d",
"type":"login",
"channels":"*"
}
and view -
function (doc, meta) {
if(doc.userId,doc.password,doc.type){
emit([doc.userId,doc.password,doc.type],doc);
}
}
When the key matches with the docment's property it return the document otherwise it return empty JSON like -
{"total_rows":2,"rows":[
]
}
Now I want to response the error message in JSON format when the key does not match for example-
{
"Error-Code":"400",
"Error-Msg":"user id and password does not match"
}
Is there any way to do so,Please correct if I am moving in the wrong direction.
Thanks in advance.
You shouldn't directly expose the view query result to your users but interpret it instead.
So make a view request, look at the response and do the business logic of checking there. For example:
"if result is empty it can only be because the user is unknown or the password hash didn't match the user, so return a business-specific error message, otherwise carry on with login"
There's no way you can change the behavior and response format of the server, and that doesn't make much sense to do so anyway. This is the API and contract of how you interact with the server. You should add your own business logic in a layer in between.