Embedding script for Google Calendar text description - google-calendar-api

I am trying to set the description of a Google Calendar event to have a different selected presenter that is chosen in a rotatory manner (it is a slide deck that needs to be presented by a different person each week). The Python script specifying the rationale would work as the following
import datetime
people = ['Person 1', 'Person 2', 'Person 3']
year, week, day = datetime.date.today().isocalendar()
print(people[week_of_year % len(people)])
the resulting person from this calculation would show up in the calendar event description. Is there any tool to do that?

I was not able to find a way to create a recurrent event with different descriptions for each event.
However, I found a workaround for you using Events: patch. You first create an event using Events: insert, get the ID of the event you created with Events: list, and after that, then get the ID of the recurrences using Events: instances. Lastly, you use Events: patch to add the new description.
It might sound long, but I'm adding a sample with explanations on how to use it.
# impor the libraries that you will use for the calendar API
from __future__ import print_function
import os.path
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
# The scopes that we need to use based on the Google documentation
# I added the information in the reference at the end of the answer
SCOPES = ['https://www.googleapis.com/auth/calendar',
'https://www.googleapis.com/auth/calendar.events']
# creation of the credential, I use as a base the Google Documentation "Python quickstart"
def main():
creds = None
if os.path.exists('token.json'):
creds = Credentials.from_authorized_user_file('token.json', SCOPES)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
creds.refresh(Request())
else:
flow = InstalledAppFlow.from_client_secrets_file(
'credentials.json', SCOPES)
creds = flow.run_local_server(port=0)
with open('token.json', 'w') as token:
token.write(creds.to_json())
try:
service = build('calendar', 'v3', credentials=creds)
# The list of people that will be use in each event
peoples = ['Person 1', 'Person 2', 'Person 3', 'Person 4']
number_week = 0
event = {
# Event title
'summary': 'Testing create description',
# A test description will be replaced later, so you can add anything you want to it.
'description': 'test',
# The start and end dates need to be in ISO-8601 date format
# and the time zone needs to be formatted as an IANA Time Zone Database name, e.g. "Europe/Zurich
'start': {
'dateTime': '2022-10-28T09:00:00-07:00',
'timeZone': 'America/Los_Angeles',
},
'end': {
'dateTime': '2022-10-28T17:00:00-07:00',
'timeZone': 'America/Los_Angeles',
},
'recurrence': [
# You can change the recurrence of the event
# for this example is a weekly event, and it has 4 recurrences
'RRULE:FREQ=WEEKLY;COUNT=4'
],
# The list of attendees
'attendees': [
{'email': 'test#email.xyz'},
{'email': 'test2#email.xyz'},
],
'reminders': {
'useDefault': False,
'overrides': [
{'method': 'email', 'minutes': 24 * 60},
{'method': 'popup', 'minutes': 10},
],
},
}
# We use insert to create the event
event = service.events().insert(calendarId='primary', body=event).execute()
# You can use the print in the next line to see the information about the event while you are testing
# print('Event created: %s' % (event.get('htmlLink')))
page_token = None
# Search for the event, using the method list and the event title q='Testing create description'
# you can use any other search key to get the event ID
events = service.events().list(calendarId='primary', pageToken=page_token, q='Testing create description').execute()
# get the ID of the event
for event in events['items']:
# print(event['id'])
id_event = event['id']
# Will search the ID of the recurrences of the event using the method instances
# e.g. xxxxxxxxxxxxxxxxx_20221028T160000Z
while True:
recurrences_for_events = service.events().instances(calendarId='primary', eventId=id_event,
pageToken=page_token).execute()
# run the dictionary of each iteration
for recurrence_instance in recurrences_for_events['items']:
id_to_update = recurrence_instance['id']
# I used the next print just to review the IDs of each event
# print(id_to_update)
# Create the new body of the event with the name of the people in the list of peoples
# instead of using year, week, day = datetime.date.today().isocalendar(). I use a simple counter to iterate on the list
body = {
'description': peoples[number_week],
}
# update the event description with patch
updated_event = service.events().patch(calendarId='primary', eventId=id_to_update, body=body).execute()
# print(updated_event['description'])
# next patch in case you have a large recurrence of the event
page_token = events.get('nextPageToken')
number_week += 1
# This will reset the counter, in case the number of people is less than the recurrences of the event
if number_week >= len(peoples):
number_week = 0
if not page_token:
break
except HttpError as error:
print('An error occurred: %s' % error)
if __name__ == '__main__':
main()
If the recurrent event has already been created, you only need to use the imports until the number_week = 0, and the part from:
events = service.events().list(calendarId='primary', pageToken=page_token, q='Testing create description').execute()
To the end, you might need to modify the for loop to only run once per recurrence.
Reference:
Python quickstart
Events: insert
Events: list
Events: instances
Events: patch
ISO 8601

Related

does FullCalendar 5 still allow for defining a custom dayName array?

Is it possible to define custom day names, short day names, month names etc. in FullCalendar version 5? I believe most of the localization is now done natively using javascript's Intl object. But I need to define latin names, which are not to be found in the Intl object. Can it be done with a custom locale file or maybe upon initialization of the calendar by passing in a property? From my tests neither of the two are working but maybe I'm just not doing it right?
let calendar = new FullCalendar.Calendar(calendarEl, {
dayMaxEvents: true,
events: $events,
locale: 'la',
dayNames: ['Dies Solis','Dies Lunae','Dies Martis','Dies Mercurii','Dies Iovis','Dies Veneris','Dies Saturni'],
dayNamesShort: ['Sol','Lun','Mart','Merc','Iov','Ven','Sat']
});
and the locale file la.js :
FullCalendar.globalLocales.push(function () {
'use strict';
var la = {
code: "la",
week: {
dow: 1, // Monday is the first day of the week.
doy: 4 // The week that contains Jan 4th is the first week of the year.
},
buttonText: {
prev: "Prior",
next: "Prox",
today: "Hodie",
month: "Mensis",
week: "Hebdomada",
day: "Dies",
list: "Agenda"
},
weekText: "Hb",
allDayText: "Tota die",
moreLinkText: function(n) {
return "+alii " + n;
},
noEventsText: "Rei gestae non sunt"
};
return la;
}());
(which I am loading via a script tag: <script src='../lib/locales/la.js'></script>).
Some things are picked up from the locale file, for example I see hodie instead of today.
I've tried defining dayNames and dayNamesShort in the locale file but doesn't seem to work either.

Update all rows with dependency defined (Duration and Predecessors)

In Smartsheets I have these columns Duration, Predecessors, Start and End Date, When I change my base Start date all my rows for EndDate and StartDate are then populated. I am trying to achieve the same functionality by api but when I update that base cell with start date value it gets updated but not the other rows for the same column. Do I have to manually calculate all dates based on predecessor and duration and update all rows (if using via api)?
const sheetId = <some_sheet_id>;
const rows = [{
"id": <row_id>, "cells": [{
"columnId": <column_id>,
// option 1 with value (either one)
"value": new Date("2020-03-15"),
// option 2 with objectvalue (either one)
"objectValue": {"objectType": "ABSTRACT_DATETIME", "value": new Date("2020-03-15")},
}]
}];
const options = { sheetId, body: rows };
await smartClient.sheets.updateRow(options);
// response is success

How to get document _id from Meteor cursor?

I have rewritten this question as i now understand my problem a bit more. The answers below remain relevant.
I have the following query which returns a record.
Template.game.helpers({
Game: function () {
var myGame = Games.findOne(
{
game_minutes: {$gt: MinutesSinceMidnightNow},
court_id: court,
game_date: {$gt: lastMidnight}
},
{
sort: {game_minutes: 1}
}
); // find
console.log(myGame);
console.log(myGame._id);
return myGame;
} // game function
}); //template scoreboard.helpers
Meteor.startup(function () {
Meteor.call('removeGames', court, MinutesSinceMidnightNow);
for(var i=0;i<incomingGames.length;i++){
var game = incomingGames[i];
var gameTime = game.game_time;
if ( MinutesSinceMidnightGameTime(gameTime) > MinutesSinceMidnightNow ) {
console.log("game # " + i + ' game time ' + MinutesSinceMidnightGameTime(gameTime) + ' now' + ' ' + MinutesSinceMidnightNow);
Meteor.call('insertGame', game);
} // if
} // for
// game = Meteor.call("nextGame", MinutesSinceMidnightNow, court, lastMidnight);
console.log(MinutesSinceMidnightNow + ', ' + court + ', ' + lastMidnight);
}); // startup
The first console.log shows a game object which includes the _id property. The second console log throws an error. How can I get the _id value?
On thinking more about this, the code may actually work. Console log eventually displays nthe id number. The strange thing is the error occurs before the game inserts in server startup. I guess the client started before the server and then reactively aligned with the real data once the server started? This is hard to get my head around coming from traditional web development.
Here is the console output
undefined scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:118
Exception in template helper: TypeError: Cannot read property '_id' of undefined
at Object.Template.game.helpers.Game (http://localhost:3000/client/scoreboard/scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:122:19)
at http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:2693:16
at http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:1602:16
at Object.Spacebars.call (http://localhost:3000/packages/spacebars.js?3c496d2950151d744a8574297b46d2763a123bdf:169:18)
at Template.game.HTML.DIV.Spacebars.With.HTML.SPAN.class (http://localhost:3000/client/scoreboard/template.scoreboard.js?0ad2de4b00dfdc1e702345d82ba32c20d943ac63:16:22)
at null.<anonymous> (http://localhost:3000/packages/spacebars.js?3c496d2950151d744a8574297b46d2763a123bdf:261:18)
at http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:1795:16
at Object.Blaze._withCurrentView (http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:2029:12)
at viewAutorun (http://localhost:3000/packages/blaze.js?88aac5d3c26b7576ac55bb3afc5324f465757709:1794:18)
at Tracker.Computation._compute (http://localhost:3000/packages/tracker.js?192a05cc46b867dadbe8bf90dd961f6f8fd1574f:288:36) debug.js:41
game # 0 game time 1395 now 549 scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:148
game # 1 game time 1110 now 549 scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:148
game # 2 game time 1185 now 549 scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:148
game # 3 game time 1260 now 549 scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:148
549, 1, Wed Oct 22 2014 00:00:00 GMT+0930 (CST) scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:157
Object {_id: "scYEdthygZFHgP2G9", court_id: 1, game_date: Wed Oct 22 2014 09:09:50 GMT+0930 (CST), court_name: "Court 1", game_time: "18:30"…} scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:118
scYEdthygZFHgP2G9
I cannot comment on the accepted answer, so I'll put the explaination as to why you see the log error here.
Your code runs just fine, the problem is (and reason for your log error) that you don't take into account that your collection of games isn't populated with any data yet. The first line in your log output reads:
undefined scoreboard.js?c19ff4a1d16ab47e5473a6e43694b3c42ec1cc22:118
which corresponds to
console.log(myGame);
The first time Meteor renders your templates, you simply don't have any data in the Games collection - it's on the wire on the way to your client. Meteor then automatically reruns your templates when data has arrived, explaining the subsequent console outputs.
So basically, the only thing that is wrong with your code at this moment, is the console log that tries to output the _id, since the during the first evaluation there is no game (thus you trying to access the property "_id" of the object "undefined" - the log error message). Remove that line and you should be ready to go!
If the parameter being passed to the function is an array, you can use Array.every. If it's a cursor, you'd need to fetch the results first.
UPDATE
I've just seen your comment. If you're looking for the first game after timenow, just do:
game = Games.findOne({game_minutes: {$gt: timenow}, [ANY OTHER FILTER]}, {sort: {game_minutes: 1}});
I've assumed the collection is called Games, and obviously you need to substitute in any other filter details to get the right set of games to look through, but it should work.
If you can access the game collection, I prefer adding selector and options to your query:
next_game = Games.find(
{
game_minutes: {$gt: timenow}
},
{
sort: {game_minutes: 1},
limit: 1
});
If not, fetch, filter, and then get the minimum one.
new_games = games.fetch().filter(function(game){
return game.game_minutes > timenow;
});
next_game = _.min(new_games, function(game){
return game.game_minutes;
});

Basic data binding in Go walk

I am trying to understand how data binding works in Go walk.
I have reviewed the somewhat complex data binding example, but I am having difficulties implementing a simple, one field data binding.
The code below demonstrates more or less what I am trying to achieve - I want the text label to be bound to the message variable (i.e., to be synchronized with its content) - of course, without the need for me to push changes to the label itself.
package main
import (
"github.com/lxn/walk"
. "github.com/lxn/walk/declarative"
"strconv"
"time"
)
func main() {
var messageLabel *walk.Label
var message string = "Hello"
// Change `message` over 5 seconds
go func() {
for i := 1; i < 6; i++ {
time.Sleep(time.Second)
message = "Counting: " + strconv.Itoa(i)
// I want to make it work
// without this line below
messageLabel.SetText(message)
}
}()
// Build a simple window with a text label
// that is supposed to be bound to the
// contents of the `message` variable
MainWindow{
Title: "Binding Test",
MinSize: Size{300, 50},
Layout: VBox{},
Children: []Widget{
Label{
AssignTo: &messageLabel,
Text: message,
// Text: BindTo{message} // Objective
},
},
}.Run()
}
I didn't see any Databinder code in your snapshot.
In that exanple you mentioned,these code below makes databinding work
DataBinder: DataBinder{
AssignTo: &db,
Name: "animal",
DataSource: animal,
ErrorPresenter: ToolTipErrorPresenter{},
},
It binds the data who calls Bind("Name") to the field with the same name in Datasource which is animal in that example.

Associating child to it's parent's parent?

In OpenERP I have 3 models, A, B and C. If you start on the form for A, there is a tree list of children B. when you click on one of those B children that form has a tree list of children C. I need the C children to be associated to both parents A and B but they will only associate themselves with B despite having many2one fields for both A and B. How can I force this association?
I have looked at solutions using active_id and default_get without success. The context object seems useful for this but I see no way of dynamically setting it with ids for both parent objects as I drill down from A to C navigating through the forms. I don't understand why context is not normally used for holding the context in this manner like in various web frameworks.
To clarify, when I edit object A and from it's edit form create an instance of B and from B's edit form create an instance of C how do I make the C associated to A and B?
Should I just execute a simple update with subselect query in C's create method to make this happen or will that break the ORM?
Looking at the transaction data when I save a new C instance (document) I see that everything I need in terms of ids is within the transaction but I don't know how to access and manipulate the values as I need to e.g.
{
"jsonrpc":"2.0",
"method":"call",
"params":{
"model":"dbe.vendor",
"method":"write",
"args":[
[
3
],
{
"application":[
[
4,
2,
false
],
[
1,
21,
{
"documents":[
[
4,
37,
false
],
[
4,
35,
false
],
[
4,
46,
false
],
[
4,
36,
false
],
[
0,
false,
{
"state":"new",
"name":"order of precendence test",
"description":"TESTING",
"type_of":7,
"locked":false,
"note":false,
"datas":false,
"datas_fname":false,
"type":"binary",
"application_id":false,
"certification_id":false,
"vendor_id":3,
"message_follower_ids":false,
"message_ids":false
}
]
]
}
]
]
}
],
"kwargs":{
"context":{
"lang":"en_US",
"tz":"EST",
"uid":7
}
},
"session_id":"303ae4c1bd9d49079c4efc9e06e0184f",
"context":{
"lang":"en_US",
"tz":"EST",
"uid":7
}
},
"id":"r138"
}
NOTE: I manually inserted vendor_id because it is a required field but it is the field I want to automatically populated.
Perhaps I am not literate enough with OpenERP to make this association happen properly or there isn't enough relevant documentation or the ORM isn't designed for this use (or any combinations of these) but I need this to work as per my requirements and now it does. I apologize if it is offensive in any manner. Criticisms and advice always welcome.
def create(self, cr, uid, vals, context=None):
"""Creates a new dbe.document instance. Called by both internal app and client.
documents are associated to dbe.vendor, dbe.application and dbe.certification.
#param vals: All dbe.document field values as a dictionary.
#return ID of new dbe.document instance.
"""
if context is None:
context={}
doc_id = None
association_id = None
# vendor_id is passed with vals when documents are created from the client side.
new_vendor_id = vals.get('vendor_id',False)
if new_vendor_id:
doc_id = super(dbe_document,self).create(cr, uid, vals, context=context)
_logger.debug("<CREATE> DBE Document (%d) created for vendor #%d by user %d", doc_id, new_vendor_id, uid)
else: # within OpenERP we cannot get vendor_id from context so we do it caveman style.
doc_id = super(dbe_document,self).create(cr, uid, vals, context=context)
association_id = self.read(cr, uid, doc_id, ['application_id', 'certification_id'], context=context)
if association_id['application_id']:
application_id = association_id['application_id']
application_obj = self.pool.get('dbe.application')
application = application_obj.browse(cr, uid, application_id)
new_vendor_id = application.vendor_id.id
elif association_id['certification_id']: # since there is no application maybe its a certification related doc....
certification_id = association_id['certification_id'][0]
certification_obj = self.pool.get('dbe.certification')
certification = certification_obj.browse(cr, uid, certification_id)
new_vendor_id = certification.vendor_id.id
else:
raise osv.except_osv(_('ValidateError'), _('<CREATE> A DBE Document cannot be created without an application or certification - Association Missing!'))
if new_vendor_id: # brute-force association to dbe.vendor.
vals.update({'vendor_id': new_vendor_id})
self.write(cr, uid, doc_id, vals, context)
_logger.debug("<CREATE> DBE Document (%d) created for vendor #%d by user %d", doc_id, new_vendor_id, uid)
else: # too bad - no vendor, no doc.
_logger.debug("<CREATE> DBE Document (%d) removed because vendor_id missing for user %d", doc_id, uid)
raise osv.except_osv(_('ValidateError'), _('<CREATE> A DBE Document cannot be created without selecting a Vendor - Vendor Id Missing!'))
return doc_id
better to use fields.related to make such association where you can do refer "A" from "B" in form of "C".

Resources