我们正在从一个谷歌应用域迁移到另一个域。为了让我的用户生活更轻松,我想设置一个他们可以运行的脚本,该脚本将复制他们的日历。我有复制事件的代码,并且有效,但是我需要执行与用户获得的“复制到我的日历”选项等效的代码,因为我们将关闭旧的谷歌应用程序域,我担心他们会失去所有这些事件在外部(已删除)日历上。
所以在谷歌应用程序脚本中 - 你如何复制日历事件,成为新域中的实际事件,而不是从旧域复制的事件?
很难解释!
乔治
我们正在从一个谷歌应用域迁移到另一个域。为了让我的用户生活更轻松,我想设置一个他们可以运行的脚本,该脚本将复制他们的日历。我有复制事件的代码,并且有效,但是我需要执行与用户获得的“复制到我的日历”选项等效的代码,因为我们将关闭旧的谷歌应用程序域,我担心他们会失去所有这些事件在外部(已删除)日历上。
所以在谷歌应用程序脚本中 - 你如何复制日历事件,成为新域中的实际事件,而不是从旧域复制的事件?
很难解释!
乔治
您可以通过 Google Apps 脚本日历服务完成的工作有一些限制:
这是一个完成复制日历事件的大部分工作的函数。这是一个要点的摘录,其中包括用于电子表格菜单/用户界面和错误检查的附加代码。有关安装和使用脚本的更多信息,请访问要点。
/**
* Copy all events in given date range. Returns number of unique events
* that were copied.
*/
function copyEvents(fromCal, toCal, startDate, endDate) {
var copiedEvents = [];
var date = new Date(startDate);
var endD = new Date(endDate);
Logger.log("startDate="+startDate+", date="+date+", endDate="+endDate);
while (date <= endD) {
Logger.log(date);
var events = fromCal.getEventsForDay(date);
for (var event=0; event < events.length; event++) {
var src = events[event];
var srcId = src.getId();
if (copiedEvents.indexOf(srcId) >= 0) continue; // Multi-day events only need to be copied once
copiedEvents.push(srcId);
var newEvent;
if (src.isAllDayEvent()) {
newEvent = toCal.createAllDayEvent(src.getTitle(), src.getAllDayStartDate())
.setTime(src.getAllDayStartDate(), src.getAllDayEndDate());
}
else {
newEvent = toCal.createEvent(src.getTitle(), src.getStartTime(), src.getEndTime());
}
// Set additional attributes, common for all day & single events
var desc = src.getDescription();
if (!src.isOwnedByMe()) { // Prepend Email address of creator to description, if not "me"
var creators = src.getCreators();
if (creators.length > 0)
desc = creators[0].concat(desc);
}
try {
newEvent.setDescription(desc);
} catch (e) {
// Work around http://code.google.com/a/google.com/p/apps-api-issues/issues/detail?id=3425
};
newEvent.setLocation(src.getLocation());
// Email Reminders
var reminders = src.getEmailReminders();
for (var rem=0; rem < reminders.length; rem++) {
src.addEmailReminder(reminders[rem]);
}
// Popup Reminders
reminders = src.getPopupReminders();
for (var rem=0; rem < reminders.length; rem++) {
src.addPopupReminder(reminders[rem]);
}
// SMS Reminders
reminders = src.getSmsReminders();
for (var rem=0; rem < reminders.length; rem++) {
src.addSmsReminder(reminders[rem]);
}
}
date.setDate(date.getDate() + 1);
}
return copiedEvents.length;
}
一种可能的方法是-
在旧域中编写您的应用程序脚本,即容器绑定(可能是 Google 文档)并部署为作为触发器运行,以特定频率调整(最少为 1 分钟)。将此 Google Doc 复制到旧域中的所有用户,并让他们授权和调用脚本。此脚本将读取一定数量的事件,因此它不会遇到此处所述的使用限制,然后使用Apps 脚本中的日历 API在新域中创建事件 [我没有尝试过,但是,我认为应该是可能,因为它基于 REST 并支持 OAuth]。这是一个与 Twitter API 集成的示例和另一个与Salesforce API集成的示例
您可能遇到的主要问题可能是由于日历服务的相对缓慢。
即使 Mogsdad 代码编写得很好并且可能尽可能高效,由于 5' 的时间限制,它也无法在一批中复制大量事件。
我一直在处理日历很长一段时间,这一直是一个真正的问题......
所以我的想法是分两次处理这个过程,一个将所有事件写入电子表格进行存储的“备份”,这相当简单明了……还有一个“恢复”功能,可以读取电子表格并将事件复制到日历。
不错的技巧是您可以将这些日历数据复制到另一个日历,这就是您的用例变得有趣的地方!只要您有写入权限,您确实可以恢复任何其他域日历中的所有事件。
该脚本已用于非常大的数据集(一年内超过 3000 个事件)并且运行良好。我用它来复制日历,所以我有“测试副本”,我可以在不接触“真实的”的情况下进行各种其他实验。
该脚本很长,并且没有很好的文档记录(我不是为这篇文章编写的;-),但可以通过将其添加到电子表格中来尝试一下。UI 是法语的(这个论坛的另一个坏主意,对此感到抱歉),但任何翻译人员都会在必要时帮助您以您的方式自定义它(如果您决定使用它)。无论如何,它使用非常简单的单词,我相信任何人都会毫不费力地理解它。
这是:( 请注意,您可以在备份过程中选择多个日历)
var FUS1=new Date().toString().substr(25,6)+":00";
var tz = SpreadsheetApp.getActiveSpreadsheet().getSpreadsheetTimeZone();
function onOpen() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var menuEntries = [
{name: "Backup des agendas", functionName: "backup"},
{name: "Restauration d'un agenda", functionName: "restore"},
];
ss.addMenu("Fonction Tech.", menuEntries);
}
function backup() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var app = UiApp.createApplication().setTitle("Sauvegarde des agendas en feuilles Google");
app.setHeight(325).setWidth(420);
// Create a grid with 3 text boxes and corresponding labels
var grid = app.createGrid(4, 2);
var wait = app.createImage('https://dl.dropboxusercontent.com/u/211279/loading3.gif').setVisible(false);
grid.setWidget(0, 0, app.createLabel("Nom des agendas à sauvegarder :"));
var list = app.createListBox(true).setVisibleItemCount(5);
list.setName('calendar');
grid.setWidget(0, 1, list);
var calendars = CalendarApp.getAllCalendars();
for (var i = 0; i < calendars .length; i++) {
list.a
list.addItem(calendars[i].getName());
}
grid.setWidget(1, 0, app.createLabel('Date début :'))
.setWidget(2, 0, app.createDateBox().setId("start").setValue(new Date('2013/09/01')))
.setWidget(1, 1, app.createLabel('Date fin :'))
.setWidget(2, 1, app.createDateBox().setId("end").setValue(new Date('2014/07/30')))
var button = app.createButton('Confirmer');
var handler = app.createServerClickHandler('bkpToSheet');
handler.addCallbackElement(grid);
var cHandler = app.createClientHandler().forTargets(wait).setVisible(true);
button.addClickHandler(handler).addClickHandler(cHandler);
grid.setWidget(3, 0,button).setWidget(3, 1, wait);
app.add(grid);
doc.show(app);
}
function bkpToSheet(e){
var app = UiApp.getActiveApplication();
var calNames = e.parameter.calendar.split(',');
var name = 'BACKUP-AGENDAS-DU-'+Utilities.formatDate(new Date(), FUS1, 'dd-MM-yyyy@HH/mm').replace('/','h')+'-'+calNames.join('&');
var ss = SpreadsheetApp.create(name)
ss.setSpreadsheetTimeZone(tz);
var ssId = ss.getId();
try{var bkpFolder = DocsList.getFolder('Backup agendas')}
catch(err){var bkpFolder = DocsList.createFolder('Backup agendas')}
DocsList.getFileById(ssId).addToFolder(bkpFolder);
DocsList.getFileById(ssId).removeFromFolder(DocsList.getRootFolder());
for(n=0;n<calNames.length;++n){
var sh = ss.insertSheet(calNames[n]);
//Logger.log(calNames[n])
var eventArray = [];
var startDate = new Date(e.parameter.start);
var endDate = new Date(e.parameter.end);
var Calendar = CalendarApp.getCalendarsByName(calNames[n]);
var events = Calendar[0].getEvents(startDate , endDate);
if (events[0]){
var line = new Array();
for (i = 0; i < events.length; i++) {
line = new Array();
var guestList = events[i].getGuestList(false);
var guests = [];
var guestsName = []
for(g=0;g<guestList.length;++g){
guests.push(guestList[g].getEmail());
guestsName.push(guestList[g].getName());
}
FUS1=events[i].getStartTime().toString().substr(25,6)+":00";
var title = events[i].getTitle()
line.push(title);
line.push(Utilities.formatDate(events[i].getStartTime(), FUS1, 'yyyy/MM/dd HH:mm:ss'));
line.push(Utilities.formatDate(events[i].getEndTime(), FUS1, 'yyyy/MM/dd HH:mm:ss'));
line.push(events[i].getLocation());
line.push(events[i].getCreators());
line.push(guests.join(','))
line.push(guestsName.join(','))
line.push((events[i].getEndTime() - events[i].getStartTime()) / 3600000);
line.push(events[i].getDescription())
eventArray.push(line);
}
}
var titre = ["Backup de l'Agenda de "+calNames[n],'Début ','Fin','Lieu/ressources','Créateur','invités (lien)','invités (nom)','durée','description'];
eventArray.unshift(titre);
sh.getRange(1,1,eventArray.length,eventArray[0].length).setValues(eventArray);
}
ss.setActiveSheet(ss.getSheets()[0]);
var delSheet = ss.deleteActiveSheet(); // delete first empty sheet
var app = UiApp.getActiveApplication();
app.close();
return app;
}
function restore(){
ScriptProperties.setProperty('restorePointers',[0,0].join('@'))
var app = UiApp.createApplication().setTitle("Restauration d'agenda à partir des BACKUPS Google Spreadsheets");
app.setHeight(225).setWidth(780);
var doc = SpreadsheetApp.getActiveSpreadsheet();
var waitR = app.createImage('https://dl.dropboxusercontent.com/u/211279/loading3T.gif').setId('waitR').setVisible(false);
var wait = app.createImage('https://dl.dropboxusercontent.com/u/211279/loading3.gif').setId('wait').setVisible(false);
var handlerContinueRestore = app.createServerHandler('continueRestore');
var handlerCancelRestore = app.createServerHandler('cancelRestore');
var cliHandlerContinue = app.createClientHandler().forEventSource().setEnabled(false).setHTML('Merci, reprise de la restauration').forTargets(waitR).setVisible(true);
var cont = app.createButton('continuer la restauration',handlerContinueRestore).setId('continue')
.setStyleAttributes({'fontSize':'12px', padding:'5px', borderRadius:'4px 4px 4px 4px',borderColor:'#ff0000',borderWidth:'2px'}).addClickHandler(cliHandlerContinue);
var cancel = app.createButton("Annuler la restauration.", handlerCancelRestore).setId('cancel')
.setStyleAttributes({'fontSize':'12px', padding:'5px', borderRadius:'4px 4px 4px 4px',borderColor:'#ff0000',borderWidth:'2px'});
var msgHTML = app.createHTML().setId('msgHTML').setStyleAttributes({'fontSize':'12px', 'padding':'25px', 'borderRadius':'4px 4px 4px 4px','borderColor':'#ff0000','borderWidth':'2px'});
var popPanel = app.createVerticalPanel().setPixelSize(587,137).setId('popPanel').setStyleAttributes({background:'#ffffcc',padding:'25px', borderRadius:'12px 12px 12px 12px',borderColor:'#ff0000',borderWidth:'1px'}).setVisible(false);
var popGrid = app.createGrid(2,3).setWidth('500');
popPanel.add(msgHTML).add(popGrid);
popGrid.setWidget(0,0,cont).setWidget(0,1,cancel).setWidget(0, 2, waitR);
var cHandler = app.createClientHandler().forTargets(wait).setVisible(true);
var wHandler = app.createClientHandler();
var grid = app.createGrid(5, 2).setId('grid').addClickHandler(wHandler);
var dateHandler = app.createServerHandler('restoreDate').addCallbackElement(grid);
var chkGrid = app.createGrid(1, 7);
chkGrid.setText(0, 0, 'ressources/invités à restaurer :')
.setWidget(0, 1, app.createCheckBox('@salles').setName('salles'))
.setWidget(0, 2, app.createCheckBox('#cours').setName('cours'))
.setWidget(0, 3, app.createCheckBox('profs').setName('profs'))
.setWidget(0, 4, app.createCheckBox('Dates partielles').setName('dates').addClickHandler(dateHandler).addClickHandler(cHandler));
var list = app.createListBox().setName('bkpname').addItem('- - -');
var listS = app.createListBox().setName('sourceCal').addItem('- - -');
var listD = app.createListBox().setName('targetCal').addItem('- - -');
grid.setText(0, 0, "Backup à utiliser :");
grid.setWidget(0, 1, list);
grid.setText(1, 0, "Agenda de la feuille (source) :");
grid.setWidget(1, 1, listS);
grid.setText(2, 0, "Agenda cible(destination) :");
grid.setWidget(2, 1, listD);
var bkps = DocsList.find('BACKUP-AGENDAS-DU-');
var bkpList = [];
for(n=0;n<bkps.length;++n){
//Logger.log(bkps[n].getName()+' '+bkps[n].getId())
if(bkps[n].getName().indexOf('BACKUP-AGENDAS-DU-')>-1){
list.addItem(bkps[n].getName(),bkps[n].getId())
}
}
var calendars = CalendarApp.getAllCalendars();
for (var i = 0; i < calendars .length; i++) {
listS.addItem(calendars[i].getName(),calendars[i].getId());
listD.addItem(calendars[i].getName(),calendars[i].getId());
}
var dateDeb = app.createListBox().setId('dateDeb').setName('dateDeb').setVisible(false).addChangeHandler(dateHandler).addItem('première date disponible','xxxxxxxxxx');
var dateFin = app.createListBox().setId('dateFin').setName('dateFin').setVisible(false).addChangeHandler(dateHandler).addItem('dernière date disponible','xxxxxxxxxx');
var button = app.createButton('Confirmer').setId('button');
var msg = app.createButton("cette opération peut être longue... veuillez patienter et attendre la disparition de cette fenêtre<BR>Vous pouvez voir la progression dans le bas de l'écran (date et nombre / total) "
+"<BR>ou interrompre la restauration en cliquant ici.",handlerCancelRestore).setVisible(false).setId('msg').setStyleAttributes({'fontSize':'12px', padding:'25px',background:'#ffffff',borderWidth:'0px'});
var handler = app.createServerClickHandler('restoreCal');
handler.addCallbackElement(grid);
var cHandler = app.createClientHandler().forEventSource().setVisible(false).forTargets(wait,msg).setVisible(true).forTargets(dateDeb,dateFin).setEnabled(false);
// var msgHandler = app.createClientHandler().forTargets(msg).setVisible(true).forTargets(dateDeb,dateFin).setEnabled(false);
button.addClickHandler(handler).addClickHandler(cHandler).setEnabled(false);
grid.setWidget(3, 0,button).setWidget(3, 1, chkGrid);
grid.setWidget(4, 0,dateDeb).setWidget(4, 1, dateFin);
var warning = app.createLabel("Veuillez d'abord sélectionner un document et les noms des agendas").setId('warning');
wHandler.validateNotMatches(list, '- - -').validateNotMatches(listS, '- - -').validateNotMatches(listD, '- - -')
.forTargets(button).setEnabled(true).forTargets(warning).setVisible(false);
app.add(grid).add(warning).add(msg).add(popPanel).add(wait);
cHandler.forTargets(grid).setVisible(false);
doc.show(app);
}
function continueRestore(e){
var app = UiApp.getActiveApplication();
var popAlert = app.getElementById('popPanel');
var grid = app.getElementById('grid');
var msg = app.getElementById('msg').setVisible(false);
ScriptProperties.setProperty('startrestore',new Date().getTime().toString());
// recover pointers to continue restore
var restoreData = ScriptProperties.getProperty('restoreData');
e = Utilities.jsonParse(restoreData);
return restoreCal(e)
}
function cancelRestore(e){
var app = UiApp.getActiveApplication();
ScriptProperties.setProperty('restoreData','')
ScriptProperties.setProperty('restorePointers','canceled');
SpreadsheetApp.getActiveSpreadsheet().toast(' ','restauration annulée');
app.close();
return app;
}
function restoreDate(e){
var app = UiApp.getActiveApplication();
var wait = app.getElementById('wait');
var sourceCalId = e.parameter.sourceCal;
var sourceCal = CalendarApp.getCalendarById(sourceCalId);
var sourceCalName = sourceCal.getName();
var ssId = e.parameter.bkpname;
if(!SpreadsheetApp.openById(ssId).getSheetByName(sourceCalName)){Browser.msgBox('pas de backup correspondant à cet agenda dans ce document');return app}
var data = SpreadsheetApp.openById(ssId).getSheetByName(sourceCalName).getDataRange().getValues();
var deb = [];
var fin = [];
for(n=1;n<data.length;++n){
deb.push([Utilities.formatDate(new Date(data[n][1]),tz,'dd-MM-yyyy'),n-1]);
fin.push([Utilities.formatDate(new Date(data[n][2]),tz,'dd-MM-yyyy'),n-1]);
}
//Logger.log(deb)
var dateDeb = [];
var dateFin = [];
for(n=deb.length-1;n>0;n--){if(deb[n][0]!=deb[n-1][0]){dateDeb.push(deb[n])}};
for(n=fin.length-1;n>0;n--){if(fin[n][0]!=fin[n-1][0]){dateFin.push(fin[n])}};
var debList = app.getElementById('dateDeb');
debList.setVisible(true);
var finList = app.getElementById('dateFin');
finList.setVisible(true);
if(e.parameter.dates=='false'){debList.setVisible(false);finList.setVisible(false)}
dateDeb.push(['première date disponible','xxxxxxxxxx']);
dateDeb.reverse();
dateFin.unshift(['dernière date disponible','xxxxxxxxxx']);
if(e.parameter.dateDeb=='xxxxxxxxxx'){
debList.clear();
for(n=0;n<dateDeb.length;++n){debList.addItem(dateDeb[n][0],dateDeb[n][1])}
}
if(e.parameter.dateFin=='xxxxxxxxxx'){
finList.clear();
for(n=0;n<dateFin.length;++n){finList.addItem(dateFin[n][0],dateFin[n][1])}
}
wait.setVisible(false);
var cHandler = app.createClientHandler().forTargets(wait).setVisible(true);
app.getElementById('button').addClickHandler(cHandler);
return app;
}
function restoreCal(e){
var lock = LockService.getPublicLock();
var success = lock.tryLock(5000);
if (!success) {
Logger.log('tryLock failed to get the lock');
return
}
ScriptProperties.setProperty('startrestore',new Date().getTime().toString())
if(ScriptProperties.getProperty('restoreData')==''||ScriptProperties.getProperties().toString().indexOf('restoreData')==-1)
{ScriptProperties.setProperty('restoreData',Utilities.jsonStringify(e))
}
var app = UiApp.getActiveApplication();
var alert = app.getElementById('alert')
var ssId = e.parameter.bkpname;
var targetCalId = e.parameter.targetCal;
var targetCal = CalendarApp.getCalendarById(targetCalId);
var targetCalName = targetCal.getName();
var sourceCalId = e.parameter.sourceCal;
var sourceCal = CalendarApp.getCalendarById(sourceCalId);
var sourceCalName = sourceCal.getName();
var salles = e.parameter.salles =='true';
var cours = e.parameter.cours == 'true';
var profs = e.parameter.profs == 'true';
var partiel = e.parameter.dates =='true';
//Logger.log(SpreadsheetApp.openById(ssId).getNumSheets()+' '+sourceCalName + salles+cours+profs)
if(!SpreadsheetApp.openById(ssId).getSheetByName(sourceCalName)){Browser.msgBox('pas de backup correspondant à cet agenda dans ce document');lock.releaseLock(); return app}
var data = SpreadsheetApp.openById(ssId).getSheetByName(sourceCalName).getDataRange().getValues();
var headers = data.shift();
//Logger.log(headers)
//Logger.log(ssId+' '+targetCal)
// [Agendas de BaAC1, Début , Fin, Lieu/ressources, Créateur, invités(liens),invités(nom), durée, description]
// date format = 23/09/2013 12:45:00
var pointers = ScriptProperties.getProperty('restorePointers');
if(pointers=='0@0'){
if(partiel){
//Logger.log(partiel+' '+e.parameter.dateDeb+' '+e.parameter.dateFin)
if(e.parameter.dateDeb.length < 5){var dStart = Number(e.parameter.dateDeb)}else{dStart=0};
if(e.parameter.dateFin.length < 5){var dEnd = Number(e.parameter.dateFin)}else{dEnd=data.length};
}else{
var dStart=0;dEnd=data.length;
}
}else{
dStart = Number(pointers.split('@')[0]);
dEnd = Number(pointers.split('@')[1]);
}
if(dStart>dEnd){dStart=dEnd}
//Logger.log(partiel+' de '+dStart+' à '+dEnd)
// main loop ------------------------
for(var ee=dStart;ee<dEnd;++ee){
var ccc = ScriptProperties.getProperty('restorePointers');
if(ccc=='canceled'){ app.close() ; return app };
if(new Date().getTime()-Number(ScriptProperties.getProperty('startrestore'))>260000){ ;// normal = 260000 mS
ScriptProperties.setProperty('restorePointers',[ee,dEnd].join('@'));
var popPanel = app.getElementById('popPanel').setVisible(true);
var msgHTML = app.getElementById('msgHTML').setHTML("la restauration n'est pas terminée...( encore "+(dEnd-ee)
+" éléments à restaurer sur "+dEnd+" )<BR> veuillez cliquer ici et le processus reprendra là où il s'était arrêté");
var msg = app.getElementById('msg').setVisible(false);
var wait = app.getElementById('wait').setVisible(false);
var waitR = app.getElementById('waitR').setVisible(false);
var cont = app.getElementById('continue').setEnabled(true).setHTML('continuer la restauration');
var grid = app.getElementById('grid').setVisible(false);
lock.releaseLock();
return app
}
var guests = '';
var types = data[ee][6].split(',');
var typesLink = data[ee][5].split(',');
for(t=0;t<types.length;++t){
if(types[t].indexOf('@')>-1 && salles){guests+=typesLink[t]+','; continue}
if(types[t].indexOf('#')>-1 && cours){guests+=typesLink[t]+','; continue}
if(profs){guests+=typesLink[t]+','}
}
if(guests.length>0){guests = guests.substring(0,guests.length-1)}
//Logger.log(targetCal.getName()+' '+ee+' '+ guests)
var options = {'guests':guests,'location':data[ee][3],'description':data[ee][8]}
try{
targetCal.createEvent(data[ee][0], new Date(data[ee][1]), new Date(data[ee][2]), options);
Utilities.sleep(30);
}catch(error){
app.add(app.createLabel('erreur du serveur :'+Utilities.jsonStringify(error)+ ' le processus devrait néanmoins continuer sans intervention de vore part'));
}
//Logger.log(ee+' '+data[ee][0]+' '+new Date(data[ee][1])+' '+ new Date(data[ee][2])+' '+guests)
if((ee%10==0)&&ee>0){SpreadsheetApp.getActiveSpreadsheet().toast(ee+' événements crées sur '+dEnd,Utilities.formatDate(new Date(data[ee][1]),tz,'dd-MMM-yyyy'))}
}
// end of main loop-----------------
ScriptProperties.setProperty('restoreData','')
ScriptProperties.setProperty('restorePointers',0+'@'+0);
SpreadsheetApp.getActiveSpreadsheet().toast(dEnd+' événements crées sur '+dEnd,'restauration terminée');
app.close();
lock.releaseLock();
return app;
}