This should be easy and pretty standard, but I haven't found it anywhere.
So there is this webpage with lots of events I'd like to have on my gCal. But I don't want to simply import them once, as they are routinely updated, but rather to subscribe to an ical feed based on them.
So I've successfully parsed the page into a gSheet using the IMPORTXML function, and published it as csv, using the very same headers and formatting gCal demands for importing csv files.
Now all I need to do is convert csv to ical, since gCal imports but doesn't subscribe to csv (why?!). There are a bunch of csv-to-ical converters out there, and some even online, but they all require you to upload the csv file, rather than taking an url (let alone as an argument, rather than as a POST query).
If only there was a Google Apps Script to do it… is that possible? How?
So I wrote one, which is generating the ics file, which seems to be in order, as I formatted the fields in gSheets accordingly, but gCal, while taking the subscription without error, shows no events. I suspect it may be a related problem to this.
csv2ical.gs:
function doGet() {
return
ContentService
.createTextOutput(HtmlService.createTemplateFromFile('template')
.evaluate().getContent()).setMimeType(ContentService.MimeType.ICAL);
}
template.html
<? var url = 'https://docs.google.com/spreadsheets/d/e/2PACX-1vQevL9qR46RxyhcmHrp8ekoElMLctUjazcuYlKsIkFeRsEQe0XOiYrJSF1OIyfRfshzUGncfdh12kst/pub?gid=709766031&single=true&output=csv'; ?>
BEGIN:VCALENDAR
VERSION:2.0
<? var events = Utilities.parseCsv(UrlFetchApp.fetch(url).getContentText()); ?>
<? for(var i=1;i<events.length;i++){ ?>
BEGIN:VEVENT
SUBJECT:<?= events[i][0] ?>
DESCRIPTION:<?= events[i][1] ?>
DTSTART:<?= events[i][2] ?>
DTEND:<?= events[i][3] ?>
LOCATION:<?= events[i][4] ?>
STATUS:CONFIRMED
END:VEVENT
<? } ?>
END:VCALENDAR
Related
As of 04/20/2015 the Google Documents API v3.0 is deprecated, and will no longer function function on and after this date. So anyone using this API must switch to use the Google Drive API.
I have integrated the Google Drive API into my PHP application, but I can not find how to get a EDIT url for a file I have created or uploaded. Previously in the Google Documents API after uploading a file, the response would return a edit url that would be a direct url to edit the file.
I am using a service account that uses a generated key by my google developers account at https://console.developers.google.com. This means my application is making calls on behalf of my service account the developer account has created for me. A google drive service account CAN NOT be accesses by the Drive UI, because as a user you can not login to the account as you would a personal google account.
What I have done is shared my documents I have uploaded or created with my personal account, and the url google returns in the call is named "alternateLink" and it is formatted as such:
https://docs.google.com/file/d/0B0nkjw07ekP9LUpuZG4tOHcxdkE/edit?usp=drivesdk
However when logged into the account I shared the above file with, it just goes to a viewer and not the "Google Docs Editor"
How can I get a file's edit link with Google Drive API?
The link you are using is correct, so that's not the issue.
The main problem was you have to set convert true in the time of upload. Without converting the file google will give you the link to view not to edit.
Here you will get file upload detials. Please check the below code i have only added the convert field:-
$file = new Google_Service_Drive_DriveFile();
$file->setTitle($title);
$file->setDescription($description);
$file->setMimeType($mimeType);
// Set the parent folder.
if ($parentId != null) {
$parent = new Google_Service_Drive_ParentReference();
$parent->setId($parentId);
$file->setParents(array($parent));
}
try {
$data = file_get_contents($filename);
$createdFile = $service->files->insert($file, array(
'data' => $data,
'mimeType' => $mimeType,
'convert' => true // To convert you file
));
return $createdFile;
} catch (Exception $e) {
print "An error occurred: " . $e->getMessage();
}
The AlternateLink is the edit url, and my issue was the uploadType value and the mime-type for the document type when attempting to upload or create the document with the google drive api.
The file edit URL can be found under the WebViewLink file property. You can retrieve it by doing something like:
$sheetsList = $drive_service->files->listFiles([
'fields' => 'files(id, name, webViewLink, webContentLink)',
]);
// You could be using $seetList->getFiles() to loop through the files.
// Here we're just picking the current one (any file) to get the WebViewLink for.
print $sheetsList->current()->getWebViewLink();
In order to adjust file permissions you can use:
$permissions = new \Google_Service_Drive_Permission();
$permissions->setRole('writer');
$permissions->setType('anyone');
$drive_service->permissions->create($file_id, $permissions);
Possible values for setRole() and setType() can be found here: https://developers.google.com/drive/api/v3/reference/permissions/create
I want to implement a workflow where users submit data via a Google Form, and their responses are automatically posted to a pre-existing PDF form.
I have a couple of PDF forms that I use frequently. I have created a Google Form to gather all of the information necessary to complete the PDF. Now I am trying to find a way to map the answers to the original PDF.
How can I accomplish that?
There is an article on patentbytes.com, Automatically Completing Your PDF Forms, which goes into some detail about this topic, and which is the inspiration for this answer.
With Google Apps Script, you cannot modify existing PDF forms. However, you can leverage the existing Import capabilities in applications such as Adobe Acrobat and Acrobat Reader, by scripting the generation of form data in a way that is easily imported.
Here's the idea:
Have users fill out Google Form. Use the form settings to ensure required questions are answered.
On form submission, have a spreadsheet-contained trigger function generate an XML file with the user's answers. It's simple to use text-substitution to complete this, but we'll use an alternative approach using Google's XmlService.
Transmit the XML-formatted answers to the administrator. This may be done via email, or by placing a file in Google Drive.
Use Adobe Acrobat or Reader to import the XML file into the pdf form. (If needed.)
Before proceeding, your PDF form needs to have specific characteristics:
It must be a fillable form.
It must include support for Export and Import of form data. (In Adobe Reader, you will see an "Extended" menu, as in this screen shot.)
We'll use the example form from the previously mentioned article as an example. It works, although it needs cleaning up.
Export a sample of XML form data
Using Acrobat Reader (or similar), fill out a sample form completely, and Export the form data as XML. (It simplifies future steps if you fill the form out using camelCase terms that will be used for the HTML template - for example inventionTitle.)
Create HTML template from exported XML
In the Apps Script editor, use File-New to create a new html file in the project, and name it "formXml". Paste the text content of the exported xml file into formXml.html.
The XML declaration needs to be in our final output, but will cause the HtmlService to crash if left in the template. Remove it from the template; we'll add it back in our code.
<?xml version="1.0" encoding="UTF-8"?>
(Optional) Prettify the XML, to make it easier to avoid introducing errors. (freeformatter.com has a useful xml formatter. I found that a first pass with "compact mode" followed by a second pass at 2 spaces per indent produced good results.
(Optional) Reorder the fields logically.
For each input field, replace the example text with valid printing scriplets.
inventionTitle becomes <?= inventionTitle ?>
formXml.html
Here is what your form XML template should end up like. We have only 5 of the form fields represented in this example.
<fields xmlns:xfdf="http://ns.adobe.com/xfdf-transition/">
<TitleofInvention xfdf:original="Title of Invention"><?= inventionTitle ?></TitleofInvention>
<Inventorone xfdf:original="Inventor one"><?= inventor1name ?></Inventorone>
<Citizenof xfdf:original="Citizen of"><?= inventor1citizenship ?></Citizenof>
<Inventortwo xfdf:original="Inventor two"><?= inventor2name ?></Inventortwo>
<Citizenof_2 xfdf:original="Citizen of_2"><?= inventor2citizenship ?></Citizenof_2>
</fields>
Code.gs
Here's the form submission trigger function. Each time a user fills out your on-line google form, this spreadsheet form submission trigger will process their responses, and save a timestamped xml file on your google drive, ready to be imported into a PDF form.
function formSubmission(eventData) {
// Get a handle on the xml template
var formXml = HtmlService.createTemplateFromFile('formXml');
// Replace templated values with user's input
formXml.inventionTitle = eventData.namedValues['Invention Title'];
formXml.inventor1name = eventData.namedValues['Inventor 1 Name'];
formXml.inventor1citizenship = eventData.namedValues['Inventor 1 Citizenship'];
formXml.inventor2name = eventData.namedValues['Inventor 2 Name'];
formXml.inventor2citizenship = eventData.namedValues['Inventor 2 Citizenship'];
// Evaluate the template with substitutions
var xml = formXml.evaluate();
// Get the evaluated template as text, prepend the XML Declaration
var formXmlText = '<?xml version="1.0" encoding="UTF-8"?>'
+ xml.getContent();
// Save user's input as an xml file on our Google Drive
var fileName = 'Form ' + eventData.namedValues['Timestamp'];
var xmlFile = DriveApp.createFile(fileName, formXmlText, MimeType.XML);
}
Form & Spreadsheet
The namedValues in the eventData object processed by the trigger function come from the Form Responses sheet, which are directly from the Form questions. (That's a good reason to keep the questions short, and rely on the Help Text to elaborate!)
I'm making standalone web app in Google Apps Script. I have somekind of task flow in the app. First search something from spreadsheet, then do some selections what to do with the collected data and after that fill spreadsheet row with some userinputs. So I need to run between few states.
I'm fairly sure I don't know enough about web tech so this might be very stupid question but here it goes.
I know that the e.parameters comes from the url like this www.google.com&value=helloworld
, e.parameters.value returns helloworld.
So now the problem: How do I set parameter e values in doGet(e) and call this same page or even different page/script in same script project? In otherwords how do I call self&value=helloworld ?
Is there some other way to do this? In GWT I just store everything to database and keep session in cookies. But cookies are not allowed so how to keep the state of the webapp in google apps script?
EDIT: This is how I pass the parameters for doGet(e).
function doGet(e) {
var app = UiApp.createApplication();
var newValue = 0;
if(e.parameter == undefined || e.parameter.value == undefined){
newValue = 1;
}else{
newValue = 1+parseInt(e.parameter.value);
}
var link = 'https://script.google.com/a/macros/domain.com/s/<insertidhere>/dev';
var anchor = app.createAnchor('Next',link+'?&value='+newValue);
anchor.setTarget('_self');
app.add(anchor);
var label = app.createLabel(newValue);
app.add(label);
return app;
}
The link format has changed a bit so instead of concatenate &value=... you need to add ? first like this ?&value1=helloworld&value2=....
Failing to use ? led me to think that there is bug and I need to use old format for the link and using that old format forbit any other than the script owner using it.
Hopefully this helps somebody to solve similar problems.
You've almost answered yourself. Append the URL paramenters to the end of your web app's URL and you can access them in your script.
Let's say you have a URL like
http://script.google.com/.../exec
When you hit the URL
http://script.google.com/.../exec?value=helloworld
,
inside doGet, you can read these URL parameters as
e.parameter.value;
IMO - instead of using ? to separate multiple parameters try keeping all the values in a single anchor with some other character separator of your choice such as # since after the first ? its possibly ignoring the other one and everything afterwards. Would be great to hear back on what you find.
I have a ruby file namely sample.rb. I want to execute that from my form and, actually my ruby code when executed will write to a html file. So what i need to do is when i click on the button in the form it should execute the ruby code and then it has to open the html file that comes from execution in one of the frame in my form. Is it is possible? If possible! how to do?
What i have tried is
<?php
exec("./sample.rb")
?>
But what it does is. It simply took the url of the api that i have used in ruby code and it returns the json from that api.
May be you should use rails for that http://rubyonrails.org
You are invoking sample.rb as an external command, just like any other shell script. Therefore you have to capture and process its output yourself.
You say that "it returns the JSON from the api". That's fine, you can extract the data you are interested in, e.g.:
<?php
$json = exec("./sample.rb");
$data = json_decode($json);
$url = $data->url; # assuming there is an URL field
?>
Now you can for example output a link:
click
or generate some JavaScript:
<script>
window.location.href="<?php echo $url ?>";
</script>
or redirect the user via a HTTP header:
<?php
header("Location: $url");
?>
I am working on my blog again, but I want to make an online text editor where you click a button and it saves it to their computer, and if you click the load button it loads a file from their computer. Does anyone know how to do that?
Thanks in Advance!
There is currently no way to write to the filesystem of the client. This is for security reasons.
However, with JavaScript you can store some data (up to 5MB) in the localStorage object and retrieve it from there later on. localStorage #MDN
The localStorage can only store strings in its key-value store, so you might have to serialize your objects before storing them.
Storing
window.localStorage.setItem( 'yourId', JSON.stringfy( yourData ) );
Retrieving
var yourData = JSON.parse( window.localStorage.getItem( 'yourId' ) );
I'm unsure why there is so strong an it's impossible current with client-side storage: all you have to do is export the file as whatever format you want (even plain-text) and have the user download it -- akin to Save As. To load the file, have the user upload it again -- akin to Open.
This can be accomplished by posting the contents of the textarea to a php script, for example.
This is no more steps than using Save As... and Open dialogs in any other local word processing application.
The only reason you might want a user to do this, though, is to allow them to edit the file locally while they were disconnected from your blogging platform. So a more elegant alternative, unless you want the user to actually edit the file locally, is to save draft versions on the server (like StackExchange does).
Loading can be implemented like this in a form (sending to a PHP-script for example):
<input name="usedFile" type="file" class="file" size="50"
accept="text/csv,text/plain" />
This allows for example loading of text- and csv-files.
I think saving is not possible like this.
#comment
It really depends on what you want to do with the file. Here is a simple loading function:
if (!empty($_FILES['usedFile']['tmp_name'])) {
load_uploaded_file($_FILES['usedFile']['tmp_name'], $my_loaded_data);
}
// ...
function load_uploaded_file($filename, &$data) {
if (!file_exists($filename)) {
return False;
}
$data = array();
$rowCount = 0;
$handle = fopen($filename, 'r');
while (($line = fgets($handle, 4096)) !== False) {
$data[$rowCount] = $line;
$rowCount++;
}
fclose($handle);
return True;
}