Developing my first Flutter mobile app, a code snippet to fetch a json from:
'https://my-json-server.typicode.com/typicode/demo/posts'
...successfully responds, decodes, parses, etc. Then when i test with doc uploaded to git as:
'https://raw.githubusercontent.com/rays-github/theirmenu/master/db.json'
...this also works. But when I try to use my own data (Google Web Apps Script publishing a Google Sheets spreadsheet as json):
'https://script.googleusercontent.com/macros/echo?user_content_key=_DZABYr6b6k274bCyLNtzSBd1jtYF_WpuFDYAtNQT-uE6uj0teMefPEiNDxNisIH0ew63RSj757Xh5smCcvouuLLk_VcYyB8m5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnPKmEGJr49ifP_3P8Fcnrtzcwn0zyFgFMfS_we8kf_vIvupeaUN7ec2K60MRzRqUBQ&lib=MNDmyszRDOPMr7WJ3Tg4jKCcl7uh4ZtSK'
...I get errors:
Exception has occurred.
FormatException (FormatException: Unexpected character (at line 2, character 1)
<!DOCTYPE html>
^
)
Here is my Flutter snippet:
import 'dart:convert';
import 'package:theirmenu001pt00/tm_menuitem_model.dart';
import 'package:http/http.dart';
class HttpService {
// final String postsUrl = "https://my-json-server.typicode.com/typicode/demo/posts";
// final String postsUrl = "https://raw.githubusercontent.com/rays-github/theirmenu/master/db.json";
final String postsUrl = "https://script.googleusercontent.com/macros/echo?user_content_key=7zmRRkd__iPae6VZ9oq5TTNjfEm3QQV9EYBvQN-awvPS4-HNw2C4wbUSC8ud0J9rfFuxXvwhWPMjiJj5GUVQvGHDvinAYraCm5_BxDlH2jW0nuo2oDemN9CCS2h10ox_1xSncGQajx_ryfhECjZEnPKmEGJr49ifP_3P8Fcnrtzcwn0zyFgFMfS_we8kf_vIvupeaUN7ec2K60MRzRqUBQ&lib=MNDmyszRDOPMr7WJ3Tg4jKCcl7uh4ZtSK";
Future<List<Post>> getMenuItems() async {
Response res = await get(postsUrl);
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Post> posts =
body.map((dynamic item) => Post.fromJson(item)).toList();
return posts;
} else {
throw "Can't get posts.";
}
}
}
Here is my Google Web App Script:
function doGet(e){
// Sheet url
var ss = SpreadsheetApp.openByUrl("https://docs.google.com/spreadsheets/d/1jsBS-RBNRxYU66WFkJHvrzHLGmNqxBzzQfaHJO6i6UY/edit#gid=446843772");
// Sheet Name
var sheet = ss.getSheetByName("Users");
return getUsers(sheet);
}
function getUsers(sheet){
var jo = {};
var dataArray = [];
// collecting data from 2nd Row , 1st column to last row and last column
var rows = sheet.getRange(2,1,sheet.getLastRow()-1, sheet.getLastColumn()).getValues();
for(var i = 0, l= rows.length; i<l ; i++){
var dataRow = rows[i];
var record = {};
record['userId'] = dataRow[0];
record['id'] = dataRow[1];
record['title'] = dataRow[2];
record['body'] = dataRow[3];
dataArray.push(record);
}
jo = dataArray;
var result = JSON.stringify(jo);
return ContentService.createTextOutput(result).setMimeType(ContentService.MimeType.JSON);
}
SCREENSHOT - MICROSOFT VISUAL STUDIO CODE RUN:
SCREENSHOT - UNAUTHENTICATED REQUEST VIA BROWSER:
Please, advise. Any help is greatly appreciated.
thanks!
Related
I'm new to App scripts and need help with copying the data to spreadsheet from URL.
However, URL is not a website but link which after clicking with directly download csv file into the computer. Also, its not ending with .csv as I have seen in other examples here.
URL basically coming to my inbox at a specific time. I'm trying to use Fetch URL but its not working at all.
Sample URL -
https://docs.google.com/spreadsheets/d/1oPUPPUmy7psliSznUItT0DnHvilXwZHzyrmdyHpHi18/export?format=csv
function ABC () {
const searchQuery = 'XYZ';
const threads = GmailApp.search(searchQuery, 0,1);
const urls = [];
threads.forEach(thread => {
const messages = thread.getMessages();
messages.forEach(message => {
const body = message.getBody();
var re = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'"".,<>?«»“”‘’]))/i;
const match = body.match(re);
if (match) { urls.push(match[1]); }
});
}) ;
Logger.log(urls);
url = urls.toString().replace("[","").replace("]","") ;
Logger.log(url);
function getData() {
var attValue = '';
// making a call to the target website
var response = UrlFetchApp.fetch(url);
//logging response from target website - In Script Editor > View > Logs
Logger.log(response.getContentText());
//parsing the response data from website
//https://developers.google.com/apps-script/reference/url-fetch/http-response
var rawData = response.getContentText();
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[1]);
var cell = sheet.getRange(1, 1);
cell.setValue(rawData);
}
};
Kindly help so that I can copy the data directly into spreadsheet or store the file in Google Drive with filename as combination of text and date.
Thanks
SUGGESTION
You can try the tweaked script below.
In my understanding, here is your goal:
Get your email messages that contain URLs (CSV file) via "XYZ" search terms.
Process the URL using URLFetchApp service
Place the CSV data into your second sheet tab.
Note: If there's anything else missing or something may have been misunderstood, feel free to let me know.
Tweaked Script
function ABC() {
/**TWEAKED: Created a function call method called "getData" */
const url = {
getData: function () {
const searchQuery = 'XYZ';
const threads = GmailApp.search(searchQuery, 0, 1);
const urls = [];
threads.forEach(thread => {
const messages = thread.getMessages();
messages.forEach(message => {
const body = message.getBody();
var re = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'"".,<>?«»“”‘’]))/i;
const match = body.match(re);
if (match) { urls.push(match[1]); }
});
});
Logger.log(urls);
/**TWEAKED: Instead of using the redundant replace method,
* used "regex" inside a single replace method to replace
* all [ and ] characters */
var geturl = urls.toString().replace(/\[|]/gm, "");
console.log(geturl)
return geturl;
}
}
var attValue = '';
/**TWEAKED: Call the "url" variable's "getData" function that will return the URL */
var response = UrlFetchApp.fetch(url.getData.call());
//logging response from target website - In Script Editor > View > Logs
Logger.log(response.getContentText());
//parsing the response data from website
//https://developers.google.com/apps-script/reference/url-fetch/http-response
var rawData = response.getContentText();
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = SpreadsheetApp.setActiveSheet(spreadsheet.getSheets()[1]);
var cell = sheet.getRange(1, 1);
cell.setValue(rawData);
};
Demonstration
After running the ABC() function on the Apps Script editor, the second sheet tab gets populated with the CSV data:
The Apps Script execution log view
References:
JavaScript Function call()
Trying to implement TwitterLib to send tweets from Google Sheets. I am using Google App Scripts, and the following code -
var sheet = SpreadsheetApp.getActive().getSheetByName('View');
var startRowNumber = 1;
var endRowNumber = sheet.getLastRow();
function sendTweets() {
var twitterKeys = {
TWITTER_CONSUMER_KEY: "xxxxxxxxxxxxxxxxxxx",
TWITTER_CONSUMER_SECRET: "xxxxxxxxxxxxxxxxxxx",
TWITTER_ACCESS_TOKEN: "xxxxxxxxxxxxxxxxxxx",
TWITTER_ACCESS_SECRET: "xxxxxxxxxxxxxxxxxxx"
}
var props = PropertiesService.getScriptProperties();
props.setProperties(twitterKeys);
var params = new Array(0);
var service = new Twitterlib.OAuth(props);
var quote;
var identifier;
for (var currentRowNumber = startRowNumber; currentRowNumber <= endRowNumber; currentRowNumber++) {
var row = sheet.getRange(currentRowNumber + ":" + currentRowNumber).getValues();
// check that the second column (Date) is equal to today
if (isToday(row[0][1])) {
quote = row[0][0];
identifier = currentRowNumber - 1;
if (!service.hasAccess()) {
console.log("Authentication Failed");
} else {
console.log("Authentication Successful");
var status = quote + "\n\n" + "#Quotes #Motivation";
try {
var response = service.sendTweet(status, params);
console.log(response);
} catch (e) { console.log(e) }
}
break;
}
}
}
function isToday(date) {
var today = new Date();
var dateFromRow = new Date(date);
return dateFromRow.getDate() == today.getDate() &&
dateFromRow.getMonth() == today.getMonth() &&
dateFromRow.getFullYear() == today.getFullYear()
}
I have signed up for Twitter DEV and have my API Key and Secret (CONSUMER_KEY and CONSUMER_SECRET above) and Access Token and Access Secret as well. I have turned on OAuth 1.0a, Read and write and Direct Message selected, and a Callback URI of (https://script.google.com/macros/s/YOUR_SCRIPT_ID/usercallback) - Replacing YOUR_SCRIPT_ID with the actual one I have.
I am seeing an Authentication Successful message in my Console, but seeing this error when running inside Apps Scripts IDE:
Send tweet failure. Error was: {"name":"Exception"}
Nothing more. I am not sure what else to check to see what I am doing wrong. Any help or resources to read over would greatly be appreciated! Thank you so much!
JJ
This is the json response (from my multiple choice field jsfiddle) that i'm trying to parse:
{"selected":true,"disabled":false,"text":"Ctr","id":"Ctr","title":"","_resultId":"select2-selectcountry-result-je97-Ctr","element":{}},
{"selected":true,"disabled":false,"text":"Title
Part1","id":"TitlePart1","title":"","_resultId":"select2-selectcountry-result-uv7s-TitlePart1","element":{}},
{"selected":false,"disabled":false,"text":"Milan","id":"Milan","_resultId":"select2-selectcountry-result-bmba-Milan","element":{}}]
I need to get: {"id":value},{"id":value},{"id":value} ...
{id:Ctr},{"id":"TitlePart1"},{"id":"Milan} ...
To achieve this result, I'm using this code:
var response = (JSON.stringify($('#selectcountry').select2('data')) );
var json = JSON.parse(response);
var dataSet = json;
var row = [],
data;
for(var i in json){
data = dataSet[i];
row.push({'id': json[i].id})
}
sheet.getRange(6,1).setValue(row);
But in this way I get only the first id:value:
{id:Ctr}
Any help?
Thanks
var s='[{"selected":true,"disabled":false,"text":"Ctr","id":"Ctr","title":"","_resultId":"select2-selectcountry-result-je97-Ctr","element":{}},{"selected":true,"disabled":false,"text":"Title Part1","id":"TitlePart1","title":"","_resultId":"select2-selectcountry-result-uv7s-TitlePart1","element":{}},{"selected":false,"disabled":false,"text":"Milan","id":"Milan","_resultId":"select2-selectcountry-result-bmba-Milan","element":{}}]';
function findId() {
var d=JSON.parse(s);
var ids=[];
d.forEach(function(o){
ids.push(o.id);
});
Logger.log(ids);
//Add this
SpreadsheetApp.getActiveSheet().getRange(1,1,1,3).setValues([ids]);
}
I can't seem to get the getData() function to run on this connector I'm building. Data studio displays my Schema properly, however when I go to 'explore' the data, an error is thrown. Looking in the project executions, the 'getData' function never runs at all.
Data Studio has encountered a system error.
Sorry, we encountered an error and were unable to complete your request.
There's no debug errors shown, and I'm not sure how to continue debugging this.
Here is my code...
var cc = DataStudioApp.createCommunityConnector();
function isAdminUser(){
return true
}
function responseToRows(requestedFields, response){
return response.map(function(item) {
var row = [];
requestedFields.asArray().forEach(function(field){
var id = field.getId()
row.push(item[id])
});
console.log(row);
return { values: row };
});
}
function getAuthType() {
var response = { type: 'NONE' };
return response;
}
function getConfig(){
var json = UrlFetchApp.fetch("<api-url>");
var data = JSON.parse(json);
var config = cc.getConfig();
var tables = data.TableNames
var configElement = config
.newSelectSingle()
.setId('tables')
.setName("Choose your data source")
.setHelpText('Choose your data source');
for(i=0;i<tables.length;i++){
configElement
.addOption(config.newOptionBuilder().setLabel(tables[i]).setValue(tables[i]))
}
return config.build();
}
function getSchema(request){
var fields = cc.getFields();
var types = cc.FieldType;
var table = request.configParams.tables;
var data = UrlFetchApp.fetch("<api-url>"+"?name="+table);
var itemArray = JSON.parse(data);
var singleRow = itemArray["Items"][0];
var keys = Object.keys(singleRow)
for(i=0;i<keys.length;i++){
var nestedKeys = Object.keys(singleRow[keys[i]])
var propName = keys[i];
var dataType = nestedKeys[0]
if(dataType == "S"){
fields.newDimension()
.setId(propName)
.setName(propName)
.setType(types.TEXT)
}else if (dataType == "N"){
fields.newMetric()
.setId(propName)
.setName(propName)
.setType(types.NUMBER)
}
}
console.log(fields.build());
console.log('get schema')
return { schema: fields.build() };
}
function getData(request){
var fields = cc.getFields();
console.log(fields);
console.log('getdata running');
// TODO: Create Schema for requested field
var table = request.configParams.tables;
var requestedFieldIds = request.fields.map(function(field) {
return field.name
});
var requestedFields = fields.forIds(requestedFieldIds);
// TODO: Fetch and Parse data from API
var response = UrlFetchApp.fetch("<api-url>"+"?name="+table);
var parsedResponse = JSON.parse(response)
// TODO: Transform parsed data and filter for requested fields
var rows = responseToRows(requestedFields, parsedResponse)
return {
schema: requestedFields.build(),
rows: rows
}
}
To see debug traces, you could simply log it with console.log() and take a look at your logs in the Google Apps Scripts dashboard :
https://script.google.com/home/executions
I don't know if this is related to your problem, but in my case I was trying to use URL Parameters and getData(request) wouldn't run no matter what values I input - it ended up being that I had to create a production deployment and Publish > Deploy from Manifest and then create an actual published version (not just FROM HEAD).
I have struggling to present available data for selected customer from spreadsheet into app maker form incase staff want to change it or update empty fields.
Client side code:
function getDetails() {
var props = app.currentPage.properties;
var page = app.pages.Search;
var Channel = app.datasources.Update.items;
var Customer = page.descendants.Sheets.value;
props.Loading = true;
props.Error = null;
google.script.run
.withFailureHandler(function(error) {
props.Loading = false;
props.Error = JSON.stringify(error);
console.error(error);
})
.withSuccessHandler(function(Channel) {
props.Loading = false;
page.Channel = Channel;
var items = [];
items = getChannels(props.SelectedSheet);
Channel.items.load(); // this line dosen't work and it doesn't load the data into form
if (Channel && Channel.length > 0) {
page.SelectedSheet = Channel[0];
} })
.getDetails(props.SelectedSheet);
}
Server side code:
function getDetails()(customer){
var spreadSheet = SpreadsheetApp.openById("***").getSheetByName('TRACKER');
var data=spreadSheet.getDataRange().getValues();
var channels = [];
var Name = customer;
var string1 = Name;
var array1 = string1.split(";"); // in here I extract row number belong to customer to get data
var destrow = [];
destrow.push(data[array1[0]][0],data[array1[0]][1],data[array1[0]][2],data[array1[0]][3],data[array1[0]][4],data[array1[0]][5]);
channels.push(destrow);
// return channels;
return channels.map(function(Channel){
return Channel;}); // return array of field data to presented in app maker form
}
Thank you for any answer or suggestion.
Cheers
In theory, this code should throw exception, since Channel is array and array doesn't have load method:
function getDetails() {
...
var Channel = app.datasources.Update.items;
...
// your first Channel variable is never used and is overridden with
// Channel callback parameter
.withSuccessHandler(function(Channel) {
// this line does nothing, since all App Maker objects are sealed
page.Channel = Channel;
// TypeError: load is not a function
Channel.items.load();
...
}
It is not clear from you code, what you are trying to do... Try to debug it and look into browser console more often (F12 or Ctrl + Shift + J).
Further reading:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal