Converting GraphQL mutation to Google Apps Scripts - google-apps-script

I am looking to convert this specific GraphQL code snippet to GAS.
mutation {
createReportExport(input: {
reportId: "XXXX",
fileContentType: CSV,
frequency: ONCE,
reportFilters: [
{
attributeName: "Sale Date",
relativeDateQuery: {
greaterEqual: "P14D"
}
}
]
}) {
reportExport {
id
fileUrl
}
}
}
Below is what I have tried in GAS
var query = 'mutation {createReportExport(input: {reportId: "urn:abc:Report:3318979a-7628-44ab-aa0d-a822f856b908",fileContentType: CSV,frequency: ONCE,reportFilters: [{attributeName: "Sale Date",relativeDateQuery: {greaterEqual: "P10D"}}]}) {reportExport {idfileUrl}}}'
var query2 = {
'operationName': 'Mutation',
'query': {query},
'variables': {}
}
var ql = '{insert URL}';
var content = {
"method": 'POST',
"headers": {"Authorization": httpBasicHeader,
"contentType": "application/json"},
"payload": JSON.stringify(query2)
};
var response = UrlFetchApp.fetch(ql, content);
var data = (response.getContentText());
Logger.log(data);
I have two variables, 'query' and 'query2' that I have tried. I am getting a {"errors":[{"message":"No query document supplied"}]} error message when running it in GAS.
When I run the first code snippet in another environment, it runs successfully. I am looking to keep my project within GAS if possible, since I have figured out the rest of the problems with my project and this is the last thing holding me back.

I think, the query property in query2 should not be wrapped in an object:
var query2 = {
'operationName': 'Mutation',
// no { } here:
'query': query,
'variables': {}
}

Related

No Data in Google Data Studio

I'm trying to show JSON data got from API in Google Data Studio.
so I created community connector and in script verified JSON data from api.
here is script code.
function getFields(request) {
var cc = DataStudioApp.createCommunityConnector();
var fields = cc.getFields();
var types = cc.FieldType;
// var aggregations = cc.AggregationType;
fields.newDimension()
.setId('username')
.setType(types.TEXT);
fields.newMetric()
.setId('version')
.setType(types.NUMBER);
fields.newDimension()
.setId('address')
.setType(types.TEXT);
return fields;
}
function getSchema(request) {
var fields = getFields(request).build();
return { schema: fields };
}
function responseToRows(requestedFields, response) {
// Transform parsed data and filter for requested fields
var row = [];
requestedFields.asArray().forEach(function (field) {
switch (field.getId()) {
case 'username':
return row.push(response.result.user.createdByName);
case 'version':
return row.push(response.result.user.version);
case 'address':
return row.push(response.result.user.address);
default:
return row.push('');
}
});
return { values: row };
}
function getData(request) {
var requestedFieldIds = request.fields.map(function(field) {
return field.name;
});
var requestedFields = getFields().forIds(requestedFieldIds);
// Fetch and parse data from API
var options = {
'method' : 'post',
'contentType': 'application/json',
"headers":{ "api-key": request.configParams.api_key },
"payload": "{username:\""+username+"\", password: \""+password+"\"}",
'muteHttpExceptions': true
};
var response = UrlFetchApp.fetch(url, options);
var parsedResponse = JSON.parse(response);
var rows = responseToRows(requestedFields, parsedResponse);
console.log('getData request', parsedResponse);
return {
schema: requestedFields.build(),
rows: rows
};
}
this is JSON file
{
"result": {
"user": {
"type": "User",
"id": 1073787385,
"address": null,
"version": 1675247127459332096,
"createdBy": 310055,
"createdByName": "Jeirick Hiponia",
}
}
}
Result in data studio.
why don't address show?
And why no data? I think row.push in responseToRows() function is issue.
I'd like to show data like this.

batchUpdate method throws errors while updating Google Slides

I am trying to create a presentation and update it on Google Apps Scripts. The creation is successful. However when I try to update the title or add a new shape or text it throws errors.
Is there any other update method? Also is it possible to update the presentation after modifying the texts without updating all of the presentation? I don't want to create an add-on I just want to be able to update the slides with executing the scripts.
Code:
function createAndUpdatePresentation() {
const createdPresentation = Slides.Presentations.create({"title": "MyNewPresentation"});
const link = `https://docs.google.com/presentation/d/${createdPresentation.presentationId}/edit`;
Logger.log(`Created presentation is on: ${link}`);
const request = {
requests: [
{
updateTitle: {
title: 'My Updated Presentation'
}
}
]
};
const updatedPresentation =
Slides.Presentations.batchUpdate(request, createdPresentation.presentationId);
const updatedLink = `https://docs.google.com/presentation/d/${updatedPresentation.presentationId}/edit`;
Logger.log(`Updated presentation is on: ${updatedLink}`);
}
Error: GoogleJsonResponseException: API call to slides.presentations.batchUpdate failed with error: Invalid JSON payload received. Unknown name "updateTitle" at 'requests[0]': Cannot find field.
Here are two ways to edit a new presentation, one using SlidesApp and the second using Slides API.
function newPresentation1() {
try {
let presentation = Slides.Presentations.create({'title': 'MyNewPresentation'});
presentation = SlidesApp.openById(presentation.presentationId);
let slide = presentation.getSlides()[0];
let element = slide.getPageElements()[0];
element.asShape().getText().setText("Hello")
}
catch(err) {
console.log(err)
}
}
function newPresentation2() {
try {
let presentation = Slides.Presentations.create({'title': 'MyNewPresentation'});
let pageElement = presentation.slides[0].pageElements[0].objectId;
let request = { insertText: { objectId: pageElement,
text: "Good bye" }
};
Slides.Presentations.batchUpdate( { requests: [ request ] }, presentation.presentationId );
}
catch(err) {
console.log(err)
}
}
Reference
SlidesApp
Slides API

Sending a Direct Message using Twitter API using Twitter Lib from Google App Script

I am trying to send direct message through twitter api using Twitter-Lib through App-Script. Below is the definition of sendMsg fucntion
function sendMsg(user, tweet) {
var twitterKeys = {
TWITTER_CONSUMER_KEY: "<<>>",
TWITTER_CONSUMER_SECRET: "<<>>",
TWITTER_ACCESS_TOKEN: "<<>>",
TWITTER_ACCESS_SECRET: "<<>>",
}
var props = PropertiesService.getScriptProperties();
// props.deleteAllProperties()
props.setProperties(twitterKeys);
var service = new Twitterlib.OAuth(props);
if ( service.hasAccess() ) {
var user_id = '77773855';
var dm_link = 'https://api.twitter.com/1.1/direct_messages/events/new.json'
var response = service.fetch(dm_link, {
method: "POST",
muteHttpExceptions: true,
data: {"event":
{"type": "message_create",
"message_create": {
"target": {"recipient_id": user_id},
"message_data": {"text": "Hello"}
}
}
}
});
console.log(response.getResponseCode())
}
}
But when I execute this code, the response is always empty and response.getResponseCode() returns 422. Any leads on what I am doing wrong?

Attempting to load list of values in column for Angular Table

I'm struggling with trying to figure out what I'm doing wrong, mostly down to not having a good understanding of AngularJS due to being new. The main goal is that I'm trying to list out all the values in the additionalText list out on the front-end, but it seems to be causing issue with this error:
Error: [$http:badreq] Http request configuration url must be a string or a $sce trusted object. Received: []
Context:
I have table in my application that relies on the API, this variable contains a list and outputs the following:
{
"name": "TEST",
"description": "TEST",
"additionalText": [
{
"name": "TEST",
"description": "TEST",
"lockId": 0
}
{
"name": "TEST",
"description": "TEST",
"lockId": 0
}
],
"lockId": 0
}
The API is working as expected, I can carry out all the necessary REST calls successfully. So I'm not struggling with that, the front-end is where I am having some difficulty.
HTML:
<td data-title="'additionalTexts'" sortable="'additionalTexts'">
<span ng-repeat="additionalText in additionalTextList[entity.name]">
<i>{{additionalText.name}}</i><br>
</span>
</td>
AngularJS:
$scope.refreshTextTable= function() {
SpringDataRestService.query(
{
collection: "APIURL"
},
function (response) {
var additionalTextRoles = response;
$scope.textTableOptions = new NgTableParams({}, {
dataset: additionalTextRoles,
counts: [],
});
// Also populate a list of all linked roles
for (var i = 0; i < additionalTextRoles.length; i++) {
var additionalTextRole = additionalTextRoles[i];
// This approach allows you to inject data into the callback
$http.get(additionalTextRole.additionalText).then((function (additionalTextRole) {
return function(response) {
$scope.additionalTextList[additionalTextRole.name] = response.additionalText;
};
})(additionalTextRole));
}
},
function (response) {
// TODO: Error Handling
}
);
};
Any help would be greatly appreciated, I'm really struggling with this one.
Can you try this below code:
$scope.refreshTextTable = function() {
SpringDataRestService.query({
collection: "APIURL"
},
function(response) {
var additionalTextRoles = response;
$scope.textTableOptions = new NgTableParams({}, {
dataset: additionalTextRoles,
counts: [],
});
// Also populate a list of all linked roles
for (var i = 0; i < additionalTextRoles.length; i++) {
var additionalTextRole = additionalTextRoles[i];
// This approach allows you to inject data into the callback
$http.get(additionalTextRole.additionalText).then((function(additionalTextRole) {
return function(response) {
$scope.additionalTextList = response.additionalText;
};
})(additionalTextRole));
}
},
function(response) {
// TODO: Error Handling
}
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.0.3/angular.min.js"></script>
<td data-title="'additionalTexts'" sortable="'additionalTexts'">
<span ng-repeat="additionalText in additionalTextList">
<i>{{additionalText.name}}</i><br>
</span>
</td>
The error message says the url must be a string.
For debugging purposes, console.log the URL:
for (var i = 0; i < additionalTextRoles.length; i++) {
var additionalTextRole = additionalTextRoles[i];
// This approach allows you to inject data into the callback
var url = additionalTextRole.additionalText;
console.log(i, url);
$http.get(url).then((function (additionalTextRole) {
return function(response) {
$scope.additionalTextList[additionalTextRole.name] = response.additionalText;
};
})(additionalTextRole));
}
Also note that the response object returned by the $http service does not have a property named additionalText. So it is likely that the intention is response.data.additionalText. To avoid the IIFE, use the forEach method:
additionalTextRoles.forEach( role => {
var url = role.additionalText;
console.log(url);
$http.get(url).then((function(response) {
$scope.additionalTextList[role.name] = response.data.additionalText;
});
});

Internal Server Error when changing chart font name via API

I am trying to update formatting of the charts using Sheets API's UpdateChartSpec request.
However, the script returns the error:
"API call to sheets.spreadsheets.batchUpdate failed with error: Internal error encountered"
Here's the snippet of my code that raises the exception:
var request = [{
'updateChartSpec': {
'chartId': chart_id,
'spec': {
'fontName': 'Arial',
'basicChart': { //to update font name, it seems that chart type should be provided
'chartType': 'BAR'
}
}
}
}];
Sheets.Spreadsheets.batchUpdate({'requests': request}, spreadsheet_id);
Can anybody tell, what's wrong with the request, if anything?
Per the "Samples" section on the Google Sheets API description, you cannot perform a partial chart specification update - you must replace the existing spec with a whole new spec.
If you just want to change a small bit of the current spec, then the simplest approach is to
Query the current chartSpec
Change the necessary bits
Issue the update with the (whole) modified spec.
In Apps Script this might be implemented as such:
function getChartSpecs(wkbkId) {
const fields = "sheets(charts(chartId,spec),properties(sheetId,title))";
var resp = Sheets.Spreadsheets.get(wkbkId, { fields: fields });
// return an object mapped by chartId, storing the chart spec and the host sheet.
return resp.sheets.reduce(function (obj, sheet) {
if (sheet.charts) {
sheet.charts.forEach(function (chart) {
obj[chart.chartId] = {
spec: chart.spec,
sheetName: sheet.properties.title,
sheetId: sheet.properties.sheetId
};
});
}
return obj;
}, {});
}
function makeChartUpdateRequest(chartId, newSpec) {
return {
updateChartSpec: {
chartId: chartId,
spec: newSpec
}
};
}
function setNewFontOnChart(newFontName, chartId, chartSpecs) {
const wb = SpreadsheetApp.getActive();
const wbId = wb.getId();
if (!chartSpecs)
chartSpecs = getChartSpecs(wbId);
var requests = [];
if (!chartId) { // Update all charts
requests = Object.keys(chartSpecs).map(function (id) {
var chart = chartSpecs[id];
chart.spec.fontName = newFontName;
return makeChartUpdateRequest(id, chart.spec);
});
} else if (chartSpecs[chartId]) { // Update just one chart.
chartSpecs[chartId].spec.fontName = newFontName;
requests.push(makeChartUpdateRequest(chartId, chartSpecs[chartId].spec));
} else {
// oops, the given chartId is not valid.
}
if (requests.length) {
Sheets.Spreadsheets.batchUpdate({ requests: requests }, wbId);
}
}
Useful links:
Partial Responses / "Fields"
APIs Explorer - spreadsheets#get
APIs Explorer - spreadsheets#batchUpdate
Array#map
Array#forEach
Array#reduce