Exporting Gcal with Colours - colors

Is there any way to export colours from Goggle Calander and post them into Goggle Sheets - I've seen posts from 2019 from various sites saying that this functionality was impossible, but I use colours to break up my calendar and I would love to bring colours over to help with my stats.

You can follow this guide:
Create a new Google Sheet
Create a new Bound Script via Extensions > Apps Script
Activate Advanced Service for accesing Calendar API Colors
Copy this code in:
const sS = SpreadsheetApp.getActiveSheet()
function bringCalendarToSheet() {
// Getting the colors for the Calendar and Events
const colors = Calendar.Colors.get()
const colorsCalendar = colors.calendar
const colorsEvents = colors.event
// Parsing and setting the data for the Calendar Colors
const A1 = sS.getRange('A1').setValue('Calendar Colors')
const colorsCalendarLength = Object.keys(colorsCalendar).length
const rCC = sS.getRange(2, 1, 1, colorsCalendarLength).setBackgrounds([Object.keys(colorsCalendar).map(k => {
return colorsCalendar[k].background
})])
// Parsing and setting the data for the Event Colors
const A3 = sS.getRange('A3').setValue('Event Colors')
const colorsEventsLength = Object.keys(colorsEvents).length
const rEC = sS.getRange(4, 1, 1, colorsEventsLength).setBackgrounds(
[Object.keys(colorsEvents).map(k => {
return colorsEvents[k].background
})]
)
}
This will show all Calendar available colors:
Result:

Related

How can I send image attachment to email

As I have created list of qr codes to scan and then I want to send this images to email by using Google app script.
current result
image is not sent to gmail.
codes
function sendEmail(sheetName = "emails") {
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName).activate();
var spreedsheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
var lastRow = spreedsheet.getLastRow();
//var ssa = SpreadSheetApp().getSheetByName(sheetName); // spread sheet object
const messageBody = "Dear receiver, We would like to invite you on upcoming seminar please use this link {actual link} and show receiptionis this bar code {actual code}"
const subjectText = "Seminar invitation"
// loop rows or spread sheet
for (var i=2; i<= lastRow; i++) {
var receiverName = spreedsheet.getRange(i, 1).getValue();
var receiverEmail = spreedsheet.getRange(i, 2).getValue();
var seminarLink = spreedsheet.getRange(i, 3).getValue();
var barcode = spreedsheet.getRange(i, 4).getBlob();
var msgBdy = messageBody.replace("receiver",receiverName).replace("{actual link}", seminarLink);
var photoBlob = barcode
MailApp.sendEmail({
to: receiverEmail,
subject: subjectText,
htmlBody: messageBody + "<br /><img src='cid:qrCode'>",
inlineImages: { qrCode: photoBlob }
});
}
}
From your following reply,
images are created from =IMAGE("chart.googleapis.com/…) with that google sheet excel
In this case, I thought that your goal can be achieved using Google Apps Script.
When I saw your script, getValue() is used in a loop. In this case, the process cost will become high. In this modification, this issue is also modified.
Modified script:
function sendEmail(sheetName = "emails") {
var spreedsheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
var lastRow = spreedsheet.getLastRow();
const messageBody = "Dear receiver, We would like to invite you on upcoming seminar please use this link {actual link} and show receiptionis this bar code {actual code}";
const subjectText = "Seminar invitation";
const range = spreedsheet.getRange("A2:D" + lastRow);
const values = range.getValues();
const formulas = range.getFormulas();
values.forEach(([receiverName, receiverEmail, seminarLink], i) => {
const url = formulas[i][3].split('"')[1];
const photoBlob = UrlFetchApp.fetch(url).getBlob();
var msgBdy = messageBody.replace("receiver", receiverName).replace("{actual link}", seminarLink);
MailApp.sendEmail({
to: receiverEmail,
subject: subjectText,
htmlBody: messageBody + "<br /><img src='cid:qrCode'>",
inlineImages: { qrCode: photoBlob }
});
});
}
When this script is run, the values are retrieved from "A2:D" of the sheet. And, each value is retrieved from each row. In the case of the column "D", the URL is retrieved from the formula, and the image blob is retrieved using UrlFetchApp. And, those values are put as the email.
References
forEach()
fetch(url, params)
Update 2
As said in the comments, replace this line:
var barcode = spreedsheet.getRange(i, 4).getBlob();
To:
var barcode = UrlFetchApp.fetch(spreedsheet.getRange(i, 4).getFormula().match(/\"(.*?)\"/)[1]).getAs('image/png')
Update
As you are inserting the image via a IMAGE Formula, you can easily parse the value, obtain the URL and get the Blob via UrlFetchApp
Sample:
const sS = SpreadsheetApp.getActive()
function testSendImage() {
const img = sS.getRange('A1').getFormula()
const urlImg = img.match(/\"(.*?)\"/)[1]
const fetchImage = UrlFetchApp.fetch(urlImg).getAs('image/png')
MailApp.sendEmail({
to: "some#gmail.com",
subject: "QR",
htmlBody: 'Check this QR <img src="cid:fetchImage" />',
inlineImages: { fetchImage: fetchImage } })
}
In the current state, there is no method for extrancting the image from a cell, however there is a Feature Request on Google's Issue Tracker, you can click here to review it.
Remember to click in the top right if you want this feature to be implemented.
In any case, you review this StackOverflow question for workarounds or alternative methods.

Meteor Tabular not reacting to ReactiveDict's values changing

I'm using the great Tabular package. https://github.com/Meteor-Community-Packages/meteor-tabular.
I'm making use of the client-side selector helper to Reactively change my table by having Server modify the query for my dataset.
I have multiple HTML inputs that act as filters and am populating a ReactiveDict with the values. A search-button click event triggers the ReactiveDict to get populated with an Object using .set
Initialization of ReactiveDict
Template.tbl.onCreated(function () {
const self = this;
self.filters = new ReactiveDict({});
});
Population of ReactiveDict
'click #search-button'(e, template) {
//clear to 'reset' fields in ReactiveDict that could've been cleared by User
template.filters.clear();
const searchableFields = getSearchableFields();
//Initialize standard JS Obj that ReactiveDict will then be set to
const filterObj = {};
//Loop through search fields on DOM and populate into Obj if they have a val
for (let field of searchableFields) {
const value = $(`#${field}-filter`).val();
if (value) {
filterObj[field] = new RegExp(escapeStringRegex(value.trim()), 'i');
}
}
if (Object.keys(filterObj).length) {
template.filters.set(filterObj);
}
},
Selector Helper
selector: () => {
const filters = Template.instance().filters.all();
const selector = { SOME_DEFAULT_OBJ, ...filters };
return selector;
},
I'm noticing the server doesn't notice any changes from a ReactiveDict if all keys remain the same.
I'm testing this by logging in the serve-side's changeSelector md and verifying that my logging does not occur if just a value in selector has changed.
Is there a solution to this?
I.e. {foo:'foo'} to {foo:'bar'} should reactively trigger the server to re-query but it does not. But {foo:'foo'} to {bar:'bar'} would get triggered.
Is this an issue with how I'm using the ReactiveDict or is this on the Tabular side?
Thanks

Leaderboards level system discord js

I have this xp system and I save each id in a json with a name.
How can I display a top 5 people?
Is there a way to retrieve the data and display 5 at a time?
I would try to sort and after creating a forum to display fixed 5 but I don't know exactly how I could do that.
Any ideas?
const xp = require("../../xp.json")
if(!xp[message.author.id]) {
xp[message.author.id] = {
xp: 0,
level:1
};
}
let curxp = xp[message.author.id].xp;
let curlvl = xp[message.author.id].level;
let nxtLevelXp = curlvl * 300;
let difference = nxtLevelXp - curxp;
For example, this is how I retrieve the data for display
Use the Object.entries , here is an example -
const xp = require("../../xp.json");
var top5 = Object.entries(xp).sort((a,b)=>b[1].level - a[1].level).splice(0,5);
Try mapping them

How to set multiple values into a client side people picker

i have a list with a people picker column which takes multiple inputs.I have a form created using content editor web part in which i have a client side people picker how to set multiple values into a client side people picker using jsom
Normally you define client people control in HTML:
<div id="control" title="Users" spclientpeoplepicker="true"></div>
Then you need to initialize it.
To initialize it properly you need to assure that these javascripts files are loaded: autofill.js, clienttemplates.js, clientforms.js, clientpeoplepicker.js
JavaScript set control value code:
Entities are validate automatically with function AddUserKeys
var userField = $("input[id$='ClientPeoplePicker_EditorInput']").get(0); // simplified user control search, real word scenario, first search proper row in your form
var peoplepicker = SPClientPeoplePicker.PickerObjectFromSubElement(userField);
peoplepicker.AddUserKeys("Login1"); // or display name
peoplepicker.AddUserKeys("Login2");
JavaScript init control code:
SP.SOD.loadMultiple(['autofill.js', 'clienttemplates.js', 'clientforms.js', 'clientpeoplepicker.js'], registerControls);
function registerControls() {
initPeoplePicker('control');
}
function initPeoplePicker (id, user) {
// Create a schema to store picker properties, and set the properties.
var schema = {};
schema['PrincipalAccountType'] = 'User'; //,DL,SecGroup,SPGroup';
schema['SearchPrincipalSource'] = 15;
schema['ResolvePrincipalSource'] = 15;
schema['AllowMultipleValues'] = true;
schema['MaximumEntitySuggestions'] = 50;
schema['Width'] = '311px';
// use code below to init controls with selected user
/*
var users = new Array(1);
var defaultUser = {};
defaultUser.AutoFillDisplayText = user.Value;
defaultUser.AutoFillKey = user.get_loginName();
defaultUser.Description = user.get_email();
defaultUser.DisplayText = user.get_title();
defaultUser.EntityType = "User";
defaultUser.IsResolved = true;
defaultUser.Key = user.get_loginName();
defaultUser.Resolved = true;
users[0] = defaultUser;
*/
// Render and initialize the picker.
// Pass the ID of the DOM element that contains the picker, an array of initial
// PickerEntity objects to set the picker value, and a schema that defines
// picker properties.
SPClientPeoplePicker_InitStandaloneControlWrapper(id, null/*users*/, schema);
}

Google Apps Script - Exporting events from Google Sheets to Google Calendar - how can I stop it from removing my spreadsheet formulas?

I've been trying to create a code that takes info from a Google Spreadsheet, and creates Google Calendar events. I'm new to this, so bear with my lack of in-depth coding knowledge!
I initially used this post to create a code:
Create Google Calendar Events from Spreadsheet but prevent duplicates
I then worked out that it was timing out due to the number of rows on the spreadsheet, and wasn't creating eventIDs to avoid the duplicates. I got an answer here to work that out!
Google Script that creates Google Calendar events from a Google Spreadsheet - "Exceeded maximum execution time"
And now I've realised that it's over-writing the formulas, I have in the spreadsheet, auto-completing into each row, as follows:
Row 12 - =if(E4="","",E4+1) // Row 13 - =if(C4="","",C4+1) // Row 18 - =if(B4="","","WHC - "&B4) // Row 19 - =if(B4="","","Docs - "&B4)
Does anyone have any idea how I can stop it doing this?
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the exportEvents() function.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet();
var entries = [{
name : "Export WHCs",
functionName : "exportWHCs"
},
{
name : "Export Docs",
functionName : "exportDocs"
}];
sheet.addMenu("Calendar Actions", entries);
};
/**
* Export events from spreadsheet to calendar
*/
function exportWHCs() {
// check if the script runs for the first time or not,
// if so, create the trigger and PropertiesService.getScriptProperties() the script will use
// a start index and a total counter for processed items
// else continue the task
if(PropertiesService.getScriptProperties().getKeys().length==0){
PropertiesService.getScriptProperties().setProperties({'itemsprocessed':0});
ScriptApp.newTrigger('exportWHCs').timeBased().everyMinutes(5).create();
}
// initialize all variables when we start a new task, "notFinished" is the main loop condition
var itemsProcessed = Number(PropertiesService.getScriptProperties().getProperty('itemsprocessed'));
var startTime = new Date().getTime();
var sheet = SpreadsheetApp.getActiveSheet();
var headerRows = 4; // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getValues();
var calId = "flightcentre.com.au_pma5g2rd5cft4lird345j7pke8#group.calendar.google.com";
var cal = CalendarApp.getCalendarById(calId);
for (i in data) {
if (i < headerRows) continue; // Skip header row(s)
var row = data[i];
var date = new Date(row[12]); // First column
var title = row[18]; // Second column
var tstart = new Date(row[15]);
tstart.setDate(date.getDate());
tstart.setMonth(date.getMonth());
tstart.setYear(date.getYear());
var tstop = new Date(row[16]);
tstop.setDate(date.getDate());
tstop.setMonth(date.getMonth());
tstop.setYear(date.getYear());
var id = row[17]; // Sixth column == eventId
// Check if event already exists, update it if it does
try {
var event = cal.getEventSeriesById(id);
}
catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
if (!event) {
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"));
var newEvent = cal.createEvent(title, tstart, tstop).addEmailReminder(5).getId();
row[17] = newEvent; // Update the data array with event ID
}
else {
event.setTitle(title);
}
if(new Date().getTime()-startTime > 240000){ // if > 4 minutes
var processed = i+1;// save usefull variable
PropertiesService.getScriptProperties().setProperties({'itemsprocessed':processed});
range.setValues(data);
MailApp.sendEmail(Session.getEffectiveUser().getEmail(),'progress sheet to cal','item processed : '+processed);
return;
}
debugger;
}
// Record all event IDs to spreadsheet
range.setValues(data);
}
/**
* Export events from spreadsheet to calendar
*/
function exportDocs() {
// check if the script runs for the first time or not,
// if so, create the trigger and PropertiesService.getScriptProperties() the script will use
// a start index and a total counter for processed items
// else continue the task
if(PropertiesService.getScriptProperties().getKeys().length==0){
PropertiesService.getScriptProperties().setProperties({'itemsprocessed':0});
ScriptApp.newTrigger('exportDocs').timeBased().everyMinutes(5).create();
}
// initialize all variables when we start a new task, "notFinished" is the main loop condition
var itemsProcessed = Number(PropertiesService.getScriptProperties().getProperty('itemsprocessed'));
var startTime = new Date().getTime();
var sheet = SpreadsheetApp.getActiveSheet();
var headerRows = 4; // Number of rows of header info (to skip)
var range = sheet.getDataRange();
var data = range.getValues();
var calId = "flightcentre.com.au_pma5g2rd5cft4lird345j7pke8#group.calendar.google.com";
var cal = CalendarApp.getCalendarById(calId);
for (i in data) {
if (i < headerRows) continue; // Skip header row(s)
var row = data[i];
var date = new Date(row[13]); // First column
var title = row[19]; // Second column
var tstart = new Date(row[15]);
tstart.setDate(date.getDate());
tstart.setMonth(date.getMonth());
tstart.setYear(date.getYear());
var tstop = new Date(row[16]);
tstop.setDate(date.getDate());
tstop.setMonth(date.getMonth());
tstop.setYear(date.getYear());
var id = row[20]; // Sixth column == eventId
// Check if event already exists, update it if it does
try {
var event = cal.getEventSeriesById(id);
}
catch (e) {
// do nothing - we just want to avoid the exception when event doesn't exist
}
if (!event) {
//cal.createEvent(title, new Date("March 3, 2010 08:00:00"), new Date("March 3, 2010 09:00:00"));
var newEvent = cal.createEvent(title, tstart, tstop).addEmailReminder(5).getId();
row[20] = newEvent; // Update the data array with event ID
}
else {
event.setTitle(title);
}
if(new Date().getTime()-startTime > 240000){ // if > 4 minutes
var processed = i+1;// save usefull variable
PropertiesService.getScriptProperties().setProperties({'itemsprocessed':processed});
range.setValues(data);
MailApp.sendEmail(Session.getEffectiveUser().getEmail(),'progress sheet to cal','item processed : '+processed);
return;
}
debugger;
}
// Record all event IDs to spreadsheet
range.setValues(data);
}
You have to ways to solve that problem.
First possibility : update your sheet with array data only on columns that have no formulas, proceeding as in this other post but in your case (with multiple columns to skip) it will rapidly become tricky
Second possibility : (the one I would personally choose because I 'm not a "formula fan") is to do what your formulas do in the script itself, ie translate the formulas into array level operations.
following your example =if(E4="","",E4+1) would become something like data[n][4]=data[n][4]==''?'':data[n+1][4]; if I understood the logic (but I'm not so sure...).
EDIT
There is actually a third solution that is even simpler (go figure why I didn't think about it in the first place...) You could save the ranges that have formulas, for example if col M has formulas you want to keep use :
var formulM = sheet.getRange('G1:G').getFormulas();
and then, at the end of the function (after the global setValues()) rewrite the formulas using :
sheet.getRange('G1:G').setFormulas(formulM);
to restore all the previous formulas... as simple as that, repeat for every column where you need to keep the formulas.

Resources