Google Classroom, delete teacher from course backend Error 500 - google-apis-explorer

I'm able to delete a teacher from a course but in this particular case I get this error (In Classroom API Reference ):
{
"error": {
"code": 500,
"message": "Internal error encountered.",
"status": "INTERNAL"
}
}
From my NodeJS app:
{ code: 500,
message: 'Internal error encountered.',
errors:
[ { message: 'Internal error encountered.',
domain: 'global',
reason: 'backendError' } ],
status: 'INTERNAL' }
The code (NodeJS app):
let classroom = google.classroom('v1');
let data = {
auth : auth,
courseId : idCurso,
userId : emailDocente
};
classroom.courses.teachers.delete(data, (err, response) => {
//...code
});
I get this error from the UI.
More Info:
There are two teachers in the course: myemail#mydomain.com and
admin#mydomain.com admin#mydomain.com is the owner.
I need to remove myemail#mydomain.com The user is active and exists in GSuite Admin
SDK.
courseState is ACTIVE

The error was caused by: the teacher was the owner of the google drive's folder. I had to delete from drive and the trash too. Developers should validate this and show a more clear message or delete the drive folder before deleting the teacher. Hope you guys update this. Thanks.
Update: I haven't been able to transfer ownership using drive API due to the fact that the user which I'm using to connect to the API doesn't have permission to change ownership I cannot have the real user to log in and change ownership because it's an automated process which runs every x minutes. I have to assign ownership of the drive folder to the user I connect to the API -not the real user- otherwise this will not work. I hope Google devs fix this.

Related

Use appscript to track user installs of google marketplace app

We've developed a Google Marketplace app using AppsScript which we've now made live on the marketplace (https://workspace.google.com/marketplace/app/report_connector_for_salesforce_beta/977246938879). However, we're struggling to work out how to use the Google Marketplace API (https://developers.google.com/workspace/marketplace/example-calls-marketplace-api) to access the license data. Has anyone else successfully managed this?
Has anyone else managed to get this working? It would be great if there was an app for this by the way on the marketplace!
Many thanks
Andy
So far, we've created a separate Google Sheet (in the same domain as our app), and we've written a simple API call function as follows:
function getUsers() {
const options = {
muteHttpExceptions: true,
headers: {
Authorization: `Bearer ${ScriptApp.getOAuthToken()}`
}
};
let response = UrlFetchApp.fetch("https://appsmarket.googleapis.com/appsmarket/v2/licenseNotification/<our app Id>",options);
Logger.log("Refresh Response:"+response);
}
We've created a new project in the GCP, and have enabled:
Google Workspace Marketplace API
Google Workspace Marketplace SDK
We've added the following scopes to the project:
Connect to an external service https://www.googleapis.com/auth/script.external_request
View your installed application's licensing information https://www.googleapis.com/auth/appsmarketplace.license
But, when we run the code, we just keep getting the following:
Info Refresh Response:{
"error": {
"code": 403,
"message": "Not authorized to access the application ID",
"errors": [
{
"message": "Not authorized to access the application ID",
"domain": "global",
"reason": "forbidden"
}
]
}
}
This worked for me, but I needed to add "https://*.googleapis.com/" in the urlFetchWhitelist.
Is your App Id correct? Check it out at https://console.cloud.google.com/apis/api/appsmarket-component.googleapis.com/googleapps_sdk?project=*projectName*

Using custom libraries from apps script in App Maker: Authorization problem

I am using this code in Apps script
function getUserObjByEmail(email){
// Same as using AdminDirectory class.
var apiUrl = "https://www.googleapis.com/admin/directory/v1/users/"+email+"?fields=id";
var token = ScriptApp.getOAuthToken();
var header = {"Authorization":"Bearer " + token};
var options = {
"method": "GET",
"headers": header
};
var response = JSON.parse(UrlFetchApp.fetch(apiUrl, options));
return response;
}
which I run as a function from App Maker project. Things go smoothly when I use the app since I have an admin role( I guess, not sure ) but the problem arises when other normal users in our domain start using the deployed app maker app. I checked the server logs and its full of this message:
Exception: Request failed for
https://www.googleapis.com/admin/directory/v1/users/email#domain.com?fields=id
returned code 403.
Truncated server response: { "error": { "errors": [ { "domain": "global",
"reason": "forbidden", "message": "Not Authorized to access this
resource/api" ... (use muteHttpExceptions option to examine full response)
Any idea how to fix this? I have manually added the required scopes for the apps script library, I added the following:
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/admin.directory.user"
The reason this happens is because YOU have admin rights, otherwise you'd be getting the same error message. The other users don't have admin rights hence they get the error. To solve this problem, you can either deploy the application running it as the developer or you can use a service account to impersonate an admin and do the process.
Regarding the first approach, you can find more info here https://developers.google.com/appmaker/security/identity.
Regarding the second approach, you can use the following app script library https://github.com/gsuitedevs/apps-script-oauth2#using-service-accounts
Moreover, if you do not require to get custom schemas information, then you can simply use a directory model and that should work for all users. Check the reference here: https://developers.google.com/appmaker/models/directory

How can I trigger a Google Apps Script function from the Google API PHP Client with the authentication I have set already?

I'm struggling to trigger a Google Apps Script Function which builds many dropdowns of a Google Spreadsheet.
I need this data to be updated daily on this Google Spreadsheet so I must call the function.
Seems like I'm required to have a client-side authentication which I'm reluctant to force it to happen.
I have set already the Google API PHP Client which does batch updates, get requests and control users and its roles.
Here's how the code looks like:
public function updateTemplate ()
{
$client = $this->getClient();
$service = new Google_Service_Script($client);
$scriptId = $this->gScriptId;
// Create an execution request object.
$request = new Google_Service_Script_ExecutionRequest();
$request->setFunction('SetUpNewSpreadsheet');
try {
// Make the API request.
$response = $service->scripts->run($scriptId, $request);
echo "here<pre>";
print_r($response);
exit;
I'm getting the following response error:
Caught exception: {
"error": {
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [ {
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"domain": "global",
"reason": "unauthorized"
} ]
, "status": "UNAUTHENTICATED"
}
}
I've checked the message errors and docs already. I'm wondering if maybe I'm missing something or if I can find a way to execute that request without forcing a client-side login?
Has anyone been through it?

Is it possible to integrate Amazon QuickSight dashboard graphs to a web application?

I need to display live interactive graphs based on customer data present in MySQL,for generating the graphs, I am planning to use Amazon Quick Sight but i would like to know whether the generated graphs can be integrated with my web application UI ?
Datasource MYSQL is hosted in AWS.
Any other better design solution is also most welcome :)
I don't think so. Even if you want to share the dashboard to
someone, you need to create a user in QuickSight. Any more than 1
user will be charged by AWS.
The dashboard cannot be public and you need to login to view the
dashboard. If it was public, you could have embedded it in your
webpage as an iframe. But you cannot.
So, I think you are having limited options here, when it comes to
QuickSight.
You can always using D3 or Google Charts to display the data by
exposing REST services for your data in MySQL.
If you have a huge database, you may want to consider indexing the
data to Elasticsearch and perform queries on it.
Check if Kibana + Elasticsearch works out of the box for you.
Good luck!
Update: Dec 28 2018
Amazon announced in Nov 2018, that Amazon QuickSight dashboards can now be embedded in applications. Read more here at this AWS QuickSight Update.
AWS has enabled the embedding of the Dashboards into web apps. The feature was released on 27th Nov 2018. Here are a few helpful links:
1. https://aws.amazon.com/blogs/big-data/embed-interactive-dashboards-in-your-application-with-amazon-quicksight/
2. https://docs.aws.amazon.com/quicksight/latest/user/embedded-dashboards-setup.html
Note: This answer is applicable only if you are using AWS Cognito
In order to generate Quicksight secure dashboard URL, follow the below steps:
Step 1: Create a new Identity Pool. Go to https://console.aws.amazon.com/cognito/home?region=u-east-1 , click ‘Create new Identity Pool’
Give an appropriate name.
Go to the Authentication Providers section, select Cognito.
Give the User Pool ID(your User pool ID) and App Client ID (go to App
Clients in user pool and copy id).
Click ‘Create Pool’. Then click ‘Allow’ to create roles of the
identity pool in IAM.
Step 2: Assign Custom policy to the Identity Pool Role
Create a custom policy with the below JSON.
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "quicksight:RegisterUser",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "quicksight:GetDashboardEmbedUrl",
"Resource": "*",
"Effect": "Allow"
},
{
"Action": "sts:AssumeRole",
"Resource": "*",
"Effect": "Allow"
}
]
}
Note: if you want to restrict the user to only one dashboard, replace the * with the dashboard ARN name in quicksight:GetDashboardEmbedUrl,
then goto the roles in IAM.
select the IAM role of the Identity pool and assign the custom policy
to the role.
Step 3: Configuration for generating the temporary IAM(STS) user
Login to your application with the user credentials.
For creating temporary IAM user, we use Cognito credentials.
When user logs in, Cognito generates 3 token IDs - IDToken,
AccessToken, RefreshToken. These tokens will be sent to your application server.
For creating a temporary IAM user, we use Cognito Access Token and credentials will look like below.
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId:"Identity pool ID",
Logins: {
'cognito-idp.us-east-1.amazonaws.com/UserPoolID': AccessToken
}
});
For generating temporary IAM credentials, we call sts.assume role
method with the below parameters.
var params = {
RoleArn: "Cognito Identity role arn",
RoleSessionName: "Session name"
};
sts.assumeRole(params, function (err, data) {
if (err) console.log( err, err.stack); // an error occurred
else {
console.log(data);
})
You can add additional parameters like duration (in seconds) for the
user.
Now, we will get the AccessKeyId, SecretAccessKey and Session
Token of the temporary user.
Step 4: Register the User in Quicksight
With the help of same Cognito credentials used in Step 3, we will
register the user in quicksight by using the quicksight.registerUser
method with the below parameters
var params = {
AwsAccountId: “account id”,
Email: 'email',
IdentityType: 'IAM' ,
Namespace: 'default',
UserRole: ADMIN | AUTHOR | READER | RESTRICTED_AUTHOR | RESTRICTED_READER,
IamArn: 'Cognito Identity role arn',
SessionName: 'session name given in the assume role creation',
};
quicksight.registerUser(params, function (err, data1) {
if (err) console.log("err register user”); // an error occurred
else {
// console.log("Register User1”);
}
});
Now the user will be registered in quicksight.
Step5: Update AWS configuration with New credentials.
Below code shows how to configure the AWS.config() with new
credentials generated Step 3.
AWS.config.update({
accessKeyId: AccessToken,
secretAccessKey: SecretAccessKey ,
sessionToken: SessionToken,
"region": Region
});
Step6: Generate the EmbedURL for Dashboards:
By using the credentials generated in Step 3, we will call the
quicksight.getDashboardEmbedUrl with the below parameters
var params = {
AwsAccountId: "account ID",
DashboardId: "dashboard Id",
IdentityType: "IAM",
ResetDisabled: true,
SessionLifetimeInMinutes: between 15 to 600 minutes,
UndoRedoDisabled: True | False
}
quicksight.getDashboardEmbedUrl(params,
function (err, data) {
if (!err) {
console.log( data);
} else {
console.log(err);
}
}
);
Now, we will get the embed url for the dashboard.
Call the QuickSightEmbedding.embedDashboard from front end with the
help of the above generated url.
The result will be the dashboard embedded in your application with
filter controls.
I know this is a very late reply, but just in case someone else stumbles across this question... We use periscopedata.com to embed BI dashboards in our SaaS app. All that's needed is knowledge of SQL (to create the charts/dashboards) and enough dev knowledge to call their API endpoint to display the dash in your own app.

Google Drive Transfer Ownership fails on file from Windows Google Drive App

Same problem as Transfer ownership of file uploaded using Google drive API - seems like no solution there. I've added my own question a) for different language, and b) simpler code, with two methods tried. I've tried one of the answers from that, and don't think the other applies.
I need to transfer ownership of a Google Drive file or folder from me to someone else. If the file was created in Google Drive (web) then it works fine. If the file was created by the API (eg through Google Drive Windows app) then it fails with Insufficient permissions for this file [403]
I'm not using Google Apps for Work, so can't impersonate or use the Admin tool.
I've tried:
public bool ChangeItemOwnership(DriveService service, string fileId, string myPermissionId, string toPermissionId)
{
try
{
Permission permission = service.Permissions.Get(fileId, myPermissionId).Execute();
if (permission.Role == "owner")
{
permission = service.Permissions.Get(fileId, toPermissionId).Execute();
permission.Role = "owner";
PermissionsResource.UpdateRequest updatePermission = service.Permissions.Update(permission, fileId, toPermissionId);
updatePermission.TransferOwnership = true;
permission = updatePermission.Execute();
}
}
catch
{
return false;
}
return true;
}
and
public bool ChangeItemOwnership(DriveService service, string fileId, string myPermissionId, string toPermissionId)
{
try
{
Permission permission = service.Permissions.Get(fileId, myPermissionId).Execute();
if (permission.Role == "owner")
{
Permission patchedPermission = new Permission();
patchedPermission.Role = "owner";
PermissionsResource.PatchRequest patchPermission = service.Permissions.Patch(patchedPermission, fileId, toPermissionId);
patchPermission.TransferOwnership = true;
patchPermission.Execute();
}
}
catch
{
return false;
}
return true;
}
FYI, I authorise with:
static string[] Scopes = { DriveService.Scope.Drive };
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(_resourceStream).Secrets,
Scopes,
"user",
CancellationToken.None,
new FileDataStore(credPath, true)).Result;
I wondered whether the problem might be the "user" above but I haven't seen any other answer to what that should read - I tried putting my email address but same result. Also considered different scopes but can't see any that might apply.
It even fails on Google's API pages:
https://developers.google.com/drive/v2/reference/permissions/update
fileId = a file's Id - try one created through Google Drive Windows app
permissionId = from https://developers.google.com/drive/v2/reference/permissions/getIdForEmail
transferOwnership = true
Request body: role = owner
Really stuck on this. Can anyone help?
EDIT: As requested, the permissions relating to me, my user, on the file. I've hidden some things which might be better hidden (not sure). The only differences are the ETag and the SelfLink.
I get fromPermissionId by:
About about = service.About.Get().Execute();
fromPermissionId = about.PermissionId;
Below is permission from after the line:
Permission permission = service.Permissions.Get(fileId, fromPermissionId).Execute();
FILE FOR WHICH OWNERSHIP CANNOT BE HANDED OVER:
permission
{Google.Apis.Drive.v2.Data.Permission}
AdditionalRoles: null
AuthKey: null
Domain: "gmail.com"
EmailAddress: "***********#gmail.com"
ETag: "\"fbeGFVkC******djp1CYyuwDABw/aPlNOCkOt******X9klsSp45w\""
Id: "1726185******1763882"
Kind: "drive#permission"
Name: "James Carlyle-Clarke"
PhotoLink: null
Role: "owner"
SelfLink: "https://www.googleapis.com/drive/v2/files/0B******DI_IeTk9z******ZTRkk/permissions/1726185******1763882"
Type: "user"
Value: null
WithLink: null
FILE FOR WHICH OWNERSHIP CAN BE HANDED OVER:
permission
{Google.Apis.Drive.v2.Data.Permission}
AdditionalRoles: null
AuthKey: null
Domain: "gmail.com"
EmailAddress: "***********#gmail.com"
ETag: "\"fbeGFVkC******djp1CYyuwDABw/cT4fcr2Tka******EpimOAHa4hw\""
Id: "1726185******1763882"
Kind: "drive#permission"
Name: "James Carlyle-Clarke"
PhotoLink: null
Role: "owner"
SelfLink: "https://www.googleapis.com/drive/v2/files/1Uyg0o******hZKvIRS-ghAi0GeJ******7029Eofr1o/permissions/1726185******1763882"
Type: "user"
Value: null
WithLink: null
SECOND UPDATE:
Found a post suggesting using Insert() - Google Drive API ownership of files uploaded from service account
Tried it. It failed, with error Bad Request. User message: "You can't change the owner of this item yet. (We're working on it.)" [400]
Interestingly the old methods above still give the same 403 error.
Still looking for a solution, but I'm hoping someone from Google has been lurking and is now working on fixing it.
THIRD UPDATE:
Tried PropertyList properties = service.Properties.List(fileId).Execute();
There are no properties at all on either of the files (the one I can change ownership of, and the one I can't change ownership of).
If you need more then let me know.