mirror of
https://github.com/bellingcat/google-apps-script.git
synced 2026-06-10 20:38:34 +03:00
125 lines
4.6 KiB
JavaScript
125 lines
4.6 KiB
JavaScript
var SheetHelper = class SheetHelper {
|
|
constructor(sheetId, sheetName, headerIndex, load = false, colNamer = (x) => x) {
|
|
this.sheet = SpreadsheetApp.openById(sheetId);
|
|
this.worksheet = this.sheet.getSheetByName(sheetName);
|
|
this.headerIndex = headerIndex;
|
|
this.protection = undefined;
|
|
this.colNamer = colNamer;
|
|
if (load) {
|
|
this._load();
|
|
}
|
|
}
|
|
_load() {
|
|
// get all values + load headers + calculate headerMap
|
|
this.rows = this.worksheet.getDataRange().getDisplayValues();
|
|
// remove irrelevant rows
|
|
this.rows.splice(0, this.headerIndex - 1);
|
|
// retrieve header rows + remove from values
|
|
this.header = this.rows[0];
|
|
this.headerMap = this._indexHeader();// column name => column index
|
|
this.rows.shift();
|
|
}
|
|
/**
|
|
* receives a row 0-index (from the data, excludes the header),
|
|
* a column name, and returns the cell value
|
|
*/
|
|
getCell(rowIndex, colName, useColNamer = true) {
|
|
colName = useColNamer ? this.colNamer(colName) : colName;
|
|
return this.rows[rowIndex][this.headerMap[colName]];
|
|
}
|
|
/**
|
|
* same as {@see getCell} but defaults to empty string and performs a trim
|
|
*/
|
|
getCellOrEmpty(rowIndex, colName) {
|
|
return (this.getCell(rowIndex, colName) || "").trim()
|
|
}
|
|
_indexHeader() {
|
|
// receives list of header names, returns object of ColumnName:ColIndex1
|
|
// colname is lowercased and trimmed
|
|
return this.header.reduce((obj, name, i) => {
|
|
obj[name.trim().toLowerCase()] = i;
|
|
return obj;
|
|
}, {});
|
|
}
|
|
_isEmptyRow(row) {
|
|
// all cols need to be empty
|
|
return row !== undefined && !row.some(cell => cell.length > 0)
|
|
}
|
|
newRowIndex(isEmptyRow = this._isEmptyRow) {
|
|
// finds the next empty row to insert
|
|
let i = this.rows.length - 1;
|
|
while (isEmptyRow(this.rows[i])) {
|
|
i--;
|
|
}
|
|
return i + this.headerIndex + 1 + 1; // 1 for the 1-based, 1 for new row
|
|
}
|
|
getCellAsRange(row, colName, useColNamer = true) {
|
|
colName = useColNamer ? this.colNamer(colName) : colName;
|
|
return this.worksheet.getRange(row, this.headerMap[colName] + 1);
|
|
}
|
|
getCellValue(row, colName, useColNamer = true) {
|
|
colName = useColNamer ? this.colNamer(colName) : colName;
|
|
return this.rows[row][this.headerMap[colName]];
|
|
}
|
|
// offsets the row index by the header, so it is the same as calling getCellAsRange.value()
|
|
getCellValueH(row, colName, useColNamer = true) {
|
|
colName = useColNamer ? this.colNamer(colName) : colName;
|
|
return this.rows[row - this.headerIndex - 1][this.headerMap[colName]];
|
|
}
|
|
updateCell(row, colName, value, useColNamer = true) {
|
|
//console.info(`cell(row=${row}, col=${this.headerMap[colName] + 1} [colName=${colName}]) = ${value}`)
|
|
this.getCellAsRange(row, colName, useColNamer).setNumberFormat('@STRING@').setValue(value)
|
|
}
|
|
hasCol(colName, useColNamer = true) {
|
|
colName = useColNamer ? this.colNamer(colName) : colName;
|
|
return this.headerMap.hasOwnProperty(colName);
|
|
}
|
|
getColValues(colName, useColNamer = true) {
|
|
colName = useColNamer ? this.colNamer(colName) : colName;
|
|
return [].concat.apply([],
|
|
this.rows.map(row => row[this.headerMap[colName]])
|
|
);
|
|
}
|
|
getColAsRange(fromRow, numRows, colName, useColNamer = true){
|
|
colName = useColNamer ? this.colNamer(colName) : colName;
|
|
return this.worksheet.getRange(fromRow, this.headerMap[colName] + 1, numRows)
|
|
}
|
|
setCol(fromRow, colName, matrix, useColNamer = true) {
|
|
if (matrix.length == 0) { return }
|
|
this.getColAsRange(fromRow, matrix.length, colName, useColNamer).setNumberFormat('@STRING@').setValues(matrix);
|
|
}
|
|
resolveColName(colName) {
|
|
return this.colNamer(colName);
|
|
}
|
|
lock(range, lockName) {
|
|
lockName = lockName || 'Sheet is protected by an automated Apps Script'
|
|
this.protection = this.worksheet.getRange(range).protect().setDescription(lockName);
|
|
let me = Session.getEffectiveUser();
|
|
this.protection.removeEditors(this.protection.getEditors());
|
|
this.protection.addEditor(me);
|
|
}
|
|
unlock() {
|
|
if (this.protection !== undefined) {
|
|
this.protection.remove();
|
|
}
|
|
this.protection = undefined;
|
|
}
|
|
/**
|
|
* Returns an object whose keys are description names
|
|
* and values are protection objects
|
|
*/
|
|
getAllProtectedDescriptions() {
|
|
console.time("getAllProtectedDescriptions");
|
|
let descriptionsToProtections = this.sheet.getProtections(SpreadsheetApp.ProtectionType.RANGE)
|
|
.reduce(function (obj, protection) {
|
|
const description = protection.getDescription();
|
|
if (description != null) {
|
|
obj[description] = protection;
|
|
}
|
|
return obj;
|
|
}, {});
|
|
console.timeEnd("getAllProtectedDescriptions");
|
|
return descriptionsToProtections;
|
|
}
|
|
}
|