I'm to setting up web-based cron jobs through cron-jobs.org to my site with Moodle installation. When I do the cron job through command line way, /usr/bin/php path/to/moodle/admin/cli/cron.php, I don't have trouble with execution and results; but in cron-jobs status of my cron task appear like "Response too big".
What can I do?
Alternatively, you can use Google Apps scripts: https://developers.google.com/apps-script
1 - Create a Google SpreadSheet
2 - Click Tools > Script Editor
3 - Copy and paste code below: (replace url)
function runCron() {
var url = "http://yourmoodle.com.br/moodle/admin/cron.php";
var options = {
'method': 'get',
//muteHttpExceptions: true,
};
var maxRows= 1440;
try{
var response = UrlFetchApp.fetch(url, options).getContentText().substring(0,50000);
Logger.log(response);
} catch (e) {
Logger.log(e);
var response = e;
}
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
// This logs the value in the very last cell of this sheet
sheet.insertRowAfter(1);
sheet.getRange('A2').setValue(new Date()).setNumberFormat("MM/dd/yyyy hh:mm");
sheet.getRange('B2').setValue(response);
var lastRow = sheet.getLastRow();
if(lastRow>maxRows){
sheet.deleteRow(lastRow);
}
}
4 - Save and edit your project's name
5 - Click Edit > Current project's trigger
6 - Add a new trigger
7 - Set event source to Time-driven and type of time based trigger to Minutes timer
8 - Save and sign in to grant permission for your project.
If you have a choice, do not use the web based cron. It is likely to be removed in a future Moodle version.
...it is recommended to only run the cron from the command line or set a cron password for remote access.
Reference:
https://docs.moodle.org/38/en/Cron#The_web_based_Moodle_cron_command
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app
https://developers.google.com/apps-script/guides/sheets
The solution is to find another web cron provider which does not have the limitations cron-job.org does.
See this one: https://www.easycron.com/
It's still free but can handle larger amount of data being returned.
Related
I have a working script in one of my google sheets projects, but now I want it to be triggered when I hit the submit button on a Google Form I have. Basically, the data from my Google Form gets exported to my Sheets form, but then I have a script to analyze the data entered. For some reason, it seems like it's doing nothing when the onSubmitForm() function is triggered. It's clear there's a problem because my logger test line displays for the onSubmitForm function but not for the EvaluateResults function.
The code in my Google Form is simple:
function onSubmitForm(){
Logger.log("onSubmitForm Running");
a.EvaluateResults();
}
The code in the Google Sheets is simple as well:
function EvaluateResults(){
Logger.log("evaluation running");
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet_results = ss.getSheetByName("Sheet2");
var sheet_userForm = ss.getSheetByName("Form Responses 1");
sheet_results.getRange("C24").setValue((sheet_userForm.getRange("A2").getValue());
}
You should write the entire function in Google form script itself. You can collect the response from Google form as soon as the submit is hit.
function onSubmitForm(e){
Logger.log("onSubmitForm Running");
var itemResponses = e.response.getItemResponses();
var emailAddress = itemResponses[1].getResponse(); // Response of second question
Logger.log(emailAddress)
var ss = SpreadsheetApp.openById("SS ID"); // Replace with your Spreadsheet Id
var sheet_results = ss.getSheetByName("Sheet2");
sheet_results.getRange("C24").setValue(emailAddress);
}
Within our Google Apps Org, I would like to setup a shared contact list that anyone inside our company can access and add/edit the contacts so we have all the same information. What is the best way to go about this?
I would create an application in App Engine that uses the Google APIs to edit the Shared Contacts list. That way you can restrict access to your domain users and also audit the activity that is occurring. There are third party tools out there that can edit the shared contact list but this is typically locked down to avoid situations where users delete contacts they should not be able to. Don't forget that the Shared Contacts list that appears in Gmail's type-ahead has a 24 hour delay.
Hey for anyone out there we used a Google Sheet, now anyone can update the sheet and you can either set an automated trigger to upload them on a schedule or manually push them into the Google Directory.
gsheet:
First we pull all the contacts from the directory then you can add/update/delete existing or new contacts.
Then push them to the Directory using the menu.
We made setup super simple so it auto grabs the user info and domain etc without the user having to do anything
var SHEET_NAME = 'google';
var ERROR_RECIPIENT_MAIL= Session.getActiveUser().getEmail();
var DOMAIN = ERROR_RECIPIENT_MAIL.replace(/.*#/, "");
Then we call the Domain Shared Contacts API to get all the data and put it into an array:
function getAllContacts(){
var contacts = ContactsApp.getContacts();
var lastRow = SpreadsheetApp.getActiveSpreadsheet().
getSheetByName(SHEET_NAME).getLastRow();
if (lastRow >2) SpreadsheetApp.getActiveSpreadsheet().
getSheetByName(SHEET_NAME).deleteRows(3, lastRow*1-2);
var contacts = ContactsApp.getContacts();
var params = {
method : "get",
contentType : "application/atom+xml",
headers : {"Authorization": "Bearer " +
ScriptApp.getOAuthToken(),"GData-Version": "3.0"},
muteHttpExceptions : true
};
var startIndex=1;
var data,respCode,resp;
resp = UrlFetchApp.fetch("//www.google.com/m8/feeds/contacts/"
+DOMAIN+"/full?alt=json&start-index="+startIndex, params);
respCode=resp.getResponseCode();
//SpreadsheetApp.getActiveSpreadsheet().
// getSheetByName(SHEET_NAME).getRange("A10").setValue(resp);
data = JSON.parse(resp.getContentText());
From there it's then put in the correct fields on the sheet for the user to update. Then the user selects the action from the drop down which calls the appropriate function when the script is run to update.
Example of delete function:
function deleteContact(contactID,rowNumber){
var params = {
method : "delete",
contentType : "application/json",
headers : {"Authorization": "Bearer " + ScriptApp.getOAuthToken(),"GData-Version": "3.0","If-Match":"*"}
};
var resp = UrlFetchApp.fetch(contactID, params);
var respCode=resp.getResponseCode();
if (respCode=='201' || respCode=='200') {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).deleteRow(rowNumber*1);
}
else{
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME).getRange(rowNumber*1, 15, 1, 1).setValue('ERROR');
ERROR_COUNT=ERROR_COUNT.toString()+rowNumber;
}
}
It's pretty cool, and now we are working on bulk data entry as it seems to stall or stop after about 700 contacts in a single run. Also some of the contacts don't get synced and have an error which we'll work on shortly to get the user more info and even store the missed contact to be fixed and updated after. Anyway hope that helps and gives you some ideas.
Ours is located here for anyone interested.
I'm trying to add an autocomplete feature (a Ui in a popup window in a spreadsheet) in my Google Spreadsheet using this Google Apps Script suggest box library from Romain Vialard and James Ferreira's book (modified):
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "my_sheet" ) { //checks that we're on the correct sheet
var r = s.getActiveCell();
if( r.getColumn() == 1) {
var names = ["Adam", "Peter", "Benjamin", "Ceaser", "Prometheus", "Gandi", "Gotama", "Mickey Mouse"];
var app = UiApp.createApplication();
var suggestBox = SuggestBoxCreator.createSuggestBox(app, 'contactPicker', 200, names);
app.add(suggestBox);
SpreadsheetApp.getActive().show(app);
var dataCell0 = r.offset(0, 1);
var dataCell0 = r.offset(0, 1);
if( dataCell0.getValue() == '' )
otherTestTunction();
}
}
}
But when I start editing column 1 of "my_sheet" and the Ui box appears, this autorization error happens (In my language it says: "you must have permission to perform this action"):
The documentation says that onEdit() trigger "They cannot access any services that require authentication as that user. For example, the Google Translate service is anonymous and can be accessed by the simple triggers. Google Calendar, Gmail, and Sites are not anonymous and the simple triggers cannot access those services."
Since I'm not using ContactsApp, I suppose that the suggest box library require authorization.
How could I set up an installable on Edit trigger that will ask for authorization? (Could you give me some code sample?)
Here is my test spreadsheet: https://docs.google.com/spreadsheet/ccc?key=0AtHEC6UUJ_rsdFBWMkhfWUQ0MEs2ck5OY1BsYjRSLXc&usp=drive_web#gid=0
Out of curiosity about what you suggested on authorizations needed by the library I made a test on a new sheet, the exact code below asks for spreadsheet access, nothing more.
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
var names = ["Adam", "Peter", "Benjamin", "Ceaser", "Prometheus", "Gandi", "Gotama", "Mickey Mouse"];
var app = UiApp.createApplication();
var suggestBox = SuggestBoxCreator.createSuggestBox(app, 'contactPicker', 200, names);
app.add(suggestBox);
SpreadsheetApp.getActive().show(app);
var dataCell0 = r.offset(0, 1);
}
To handle that you just have to ask your user to run one function in your script (no matter what function) and they will get the following popup :
After this initial step your function will work as expected, ie the Ui will show up.
Beside that, I'm not sure I understand what you want to achieve is feasible, the onEdit trigger fires when the edit is done, meaning after you hit ENTER, then the value in the suggestBox is not taken into account... moreover you have to handler in the UI to do anything so I'm still wondering what do you really expect to do with this code ? (what would be ideal is an onClick event in spreadsheetApp but unfortunately it doesn't exist so far...)
But maybe I missed something obvious.
About installable onEdit that you mention also in your post, you should note that it doesn't need to be authorized by the end user since it would run as YOU, the person that creates the trigger and not the user accessing the SS , therefor accessing your own data and not the user's ones... That might be a non negligible restriction (as Zig mentioned in a comment earlier...)
I have a set of published dashboards that are linked to from a google site. The dashboards are all pulling data from a google spreadsheet, they are fairly basic - filterable datatables mostly. It is a pretty large spreadsheet with a lot of vlookups and a few importrange, a few filter formulas, some query formulas...there is a lot going on...often you get the "some formulas are taking a while to process message"
The dashboards work great if you have the spreadsheet open. Or if someone else has it open. But, if you close out of the spreadsheet, and wait a while, and try and run the dashboards when the spreadsheet is closed, often the dashboards don't pull in any data.
I'm suspicious that I need to allow the dashboards to wait for the data to load a little longer, or somehow open the spreadsheet in the "background" if that is possible. Any thoughts? Here's an example dashboard I have:
function doGet() {
var ss = SpreadsheetApp.openById("0Aq2VphSIvT4NdE1IRTlzV0NyWF9XZ1hsX2hXZG0xdHc");
var lastrow = ss.getSheetByName('CIC Student Aggregate').getLastRow();
var data = ss.getSheetByName('CIC Student Aggregate').getRange(1, 1, lastrow, 13);
var StudentFilter = Charts.newStringFilter()
.setFilterColumnLabel("Student Name")
.build();
var TotalsFilter = Charts.newNumberRangeFilter()
.setFilterColumnLabel("Total Interactions")
.build();
var tablechart = Charts.newTableChart()
.setDimensions(680, 550)
.setDataViewDefinition(Charts.newDataViewDefinition()
.setColumns([0,1,7,8,9,10,11,12]))
.build();
var piechart = Charts.newPieChart()
.setDimensions(330, 350)
.setDataViewDefinition(Charts.newDataViewDefinition()
.setColumns([0,12]))
.build();
var dashboard = Charts.newDashboardPanel()
.setDataTable(data)
.bind([StudentFilter,TotalsFilter], [tablechart,piechart])
.build();
var uiApp = UiApp.createApplication()
.setTitle("Interactions Totals")
.setWidth(980)
.setHeight(600);
dashboard.add(uiApp.createVerticalPanel()
.add(StudentFilter).add(TotalsFilter)
.setSpacing(1)
.add(uiApp.createHorizontalPanel()
.add(uiApp.createVerticalPanel())
.add(tablechart).add(piechart)
));
uiApp.add(dashboard);
return uiApp;
}
do you still have your problem ?
If it is the case, do you have some 'importrange' in your dashboard ?
If you read data with appscript on a range where the data is generated via importrange, it will return nothing if the spreadsheet is closed.
In fact, 'importrange' is triggered only when a user open a spreadsheet. Appscript doesn't trigger the 'importrange' on Spreadsheet opening.
I have an Alfresco document reference; what I'm looking for is a way to access workflow attached to that document and finish it (or progress it to the next transition) through Javascript.
Almost every example on the web shows how to start workflow, and from the dashlet I could call task command processor (/alfresco/command/task/end/[/transition]) if I knew the task ID, but how do I do the same thing from server-side web script starting only from the document reference?
There must be a way to access workflows from document and manage them programatically.
From a document nodeRef you can signal the current task like this:
var docNodeRef = "workspace://SpacesStore/<GUID HERE>";
var transitionId = "some action";
var theDocument = search.findNode(docNodeRef);
foreach (currWorkflow in theDocument.activeWorkflows)
{
var path = currWorkflow.paths[currWorkflow.paths.length-1];
var task = path.tasks[0];
for (var transitionKey in task.transitions)
{
if (task.transitions[transitionKey] == transitionId)
{
path.signal(transitionId);
break;
}
}
}
If you want to signal the default transition you can skip the inner loop and just do this:
var docNodeRef = "workspace://SpacesStore/<GUID HERE>";
var transitionId = "some action";
var theDocument = search.findNode(docNodeRef);
foreach (currWorkflow in theDocument.activeWorkflows)
{
var path = currWorkflow.paths[currWorkflow.paths.length-1];
var task = path.tasks[0];
// Signal default transition
path.signal(null);
}
Well, I still don't know how to transition, but there are a couple of things I found out.
First, I can access workflows document participates in and cancel it:
for each (workflow in document.activeWorkflows) {
workflow.cancel();
}
However, I'm still not quite sure how to progress tasks. I can get to the task and do something with it:
var task = workflow.getTask(taskId);
task.endTask(transitionId);
...but I still have no idea how to get to taskId or transitionId, either programmatically or through Alfresco.
EDIT: figured it out, transitionId is actually transition name as defined in workflow processdefinition XML:
<transition name="SomeTransitionId" to="end">
Also, to get list of tasks from the workflow you can iterate through paths (workflow.getPaths()) and then through tasks with path.getTasks().