├── External APIs ├── AnyDoAPI.gs ├── ArchiveTrelloCardsWhereFreshdeskTicketIsClosed.gs ├── FreshdeskAPI.gs ├── Plivo.gs ├── Set Slack Status.gs ├── Set Trello FollowUps.gs ├── Todoist.gs ├── TrelloAPI.gs └── Twilio.gs ├── Google Calendar ├── Change Event Color.gs ├── Check for overlapping events.gs ├── Convert Event to All-Day.gs ├── Delete Event From Multiple Calendars.gs ├── Move events to calendar.gs ├── Set Invite Status.gs └── Split Multi-Day Event.gs ├── README.md └── Tasks- Forms- etc └── Any.Do Port.gs /External APIs/AnyDoAPI.gs: -------------------------------------------------------------------------------- 1 | //========================================================================== 2 | // Adapted from https://github.com/davoam/anydo-api. Please expand with other methods as needed! 3 | // Use the login method first to obtain an authToken, then store that authToken as a variable and use in future requests 4 | //========================================================================== 5 | 6 | const API_URL = 'https://sm-prod2.any.do'; 7 | 8 | function login(email, password){ 9 | var json = anyDoPOST("/login", { email, password }); 10 | return json.auth_token; 11 | } 12 | 13 | function sync(authToken){ 14 | var json = anyDoPOST("/api/v2/me/sync", { "models" : syncSample(false, false)}, { "X-Anydo-Auth": authToken }); 15 | return json; 16 | } 17 | 18 | function deleteTask(authToken, taskId){ 19 | anyDoDELETE(`/me/tasks/${taskId}`, { "X-Anydo-Auth": authToken }); 20 | } 21 | 22 | function anyDoPOST(relativeUrl, payload, headers){ 23 | var completeUrl = API_URL + relativeUrl; 24 | var options = { 25 | "method" : "post", 26 | "contentType" : "application/json", 27 | "headers" : headers, 28 | "payload" : JSON.stringify(payload) 29 | }; 30 | 31 | var jsonData = UrlFetchApp.fetch(completeUrl, options); 32 | return JSON.parse(jsonData.getContentText()); 33 | } 34 | 35 | function anyDoDELETE(relativeUrl, headers){ 36 | var completeUrl = API_URL + relativeUrl; 37 | var options = { 38 | "method" : "delete", 39 | "contentType" : "application/json", 40 | "headers" : headers 41 | }; 42 | 43 | UrlFetchApp.fetch(completeUrl, options); 44 | } 45 | 46 | function syncSample(includeDone, includeDeleted){ 47 | return { 48 | category: { 49 | items: [] 50 | }, 51 | task: { 52 | items: [], 53 | config: { includeDone, includeDeleted } 54 | }, 55 | attachment: { 56 | items: [] 57 | }, 58 | sharedMember: { 59 | items: [] 60 | }, 61 | userNotification: { 62 | items: [] 63 | }, 64 | taskNotification: { 65 | items: [] 66 | } 67 | }; 68 | } 69 | -------------------------------------------------------------------------------- /External APIs/ArchiveTrelloCardsWhereFreshdeskTicketIsClosed.gs: -------------------------------------------------------------------------------- 1 | //MAKE SURE YOU ALSO ADD THE FOLLOWING FILES TO YOUR GAS DOCUMENT: 2 | // - https://github.com/derekantrican/Google-Apps-Script-Library/blob/master/External%20APIs/FreshdeskAPI.gs 3 | // - https://github.com/derekantrican/Google-Apps-Script-Library/blob/master/External%20APIs/TrelloAPI.gs 4 | 5 | function closeWhereFDTicketIsClosed() { 6 | var cards = getListCards("LIST_TO_CHECK"); 7 | for (var i = 0; i < cards.length; i++){ 8 | var ticketID = GetFDTicketID(cards[i]); 9 | if (ticketID != null){ 10 | var status = getTicketStatus(ticketID); 11 | 12 | if (status == "CLOSED"){ 13 | archiveCard(cards[i].id); 14 | } 15 | } 16 | } 17 | } 18 | 19 | function GetFDTicketID(trelloCard){ 20 | var regex = RegExp(FRESHDESK_SUB_DOMAIN + "\.freshdesk\.com\/a\/tickets\/(\\d*)","g"); 21 | var match = regex.exec(trelloCard.desc); 22 | if (match == null) 23 | return match; 24 | 25 | return match[1]; 26 | } 27 | -------------------------------------------------------------------------------- /External APIs/FreshdeskAPI.gs: -------------------------------------------------------------------------------- 1 | //========================================================================== 2 | // Use this file to interact with freshdesk.com. Please expand with other methods as needed! 3 | // API documentation: https://developers.freshdesk.com/api/ 4 | //========================================================================== 5 | 6 | var FRESHDESK_API_KEY = "INSERT_YOUR_API_KEY"; 7 | var FRESHDESK_SUB_DOMAIN = "INSERT_YOUR_FRESHDESK_SUB_DOMAIN"; 8 | var FRESHDESK_BASE_URL = "https://" + FRESHDESK_SUB_DOMAIN + ".freshdesk.com/api/v2"; 9 | 10 | function getTicketStatus(ticketID){ 11 | var ticket = freshdeskGET("/tickets/" + ticketID); 12 | if (ticket == null) 13 | return null; 14 | 15 | if (ticket.status == 5) 16 | return "CLOSED"; 17 | else 18 | return "OPEN"; 19 | } 20 | 21 | function freshdeskGET(relativeUrl){ 22 | var options = {"method" : "get", 23 | "contentType": "application/json", 24 | "muteHttpExceptions" : true, 25 | "headers" : {"Authorization" : "Basic " + Utilities.base64Encode(FRESHDESK_API_KEY + ":X")}}; 26 | 27 | var completeUrl = FRESHDESK_BASE_URL + relativeUrl; 28 | var jsonData = UrlFetchApp.fetch(completeUrl, options); 29 | return JSON.parse(jsonData); 30 | } 31 | 32 | function CreateFreshDeskTicket(subject, description, email, name, type){ 33 | var url = FRESHDESK_BASE_URL + "/tickets"; 34 | var authHeader = {"Authorization" : "Basic " + Utilities.base64Encode(FRESHDESK_API_KEY + ":X")}; 35 | 36 | 37 | var payload = {"description" : description, 38 | "subject" : subject, 39 | "email" : email, 40 | "name" : name, 41 | "type" : type, 42 | "status" : 2, 43 | "priority" : 2}; 44 | var options = {"method" : "post", 45 | "contentType": "application/json", 46 | "payload" : JSON.stringify(payload), 47 | "muteHttpExceptions" : true, 48 | "headers" : authHeader}; 49 | 50 | var jsonData = UrlFetchApp.fetch(url, options); 51 | } 52 | -------------------------------------------------------------------------------- /External APIs/Plivo.gs: -------------------------------------------------------------------------------- 1 | function SendSMS(number, message){ 2 | // Get account SID and auth token here: 3 | // https://www.twilio.com/user/account 4 | var authId = /* Get authId from plivo.com*/; 5 | var authToken = /* Get authToken from plivo.com*/; 6 | var url = "https://api.plivo.com/v1/Account/" + authId + "/Message/"; 7 | var options = { 8 | method: "post", 9 | headers: {'Authorization' : 'Basic ' + Utilities.base64Encode(authId + ':' + authToken), 'Content-Type': 'application/json'}, 10 | payload: JSON.stringify({ 11 | src: /*src is one of your Plivo numbers*/, 12 | dst: number, 13 | text: message 14 | }) 15 | }; 16 | var response = UrlFetchApp.fetch(url, options); 17 | Logger.log(response); 18 | } 19 | 20 | function doGet(args){ 21 | var message = args.parameters.Text; 22 | var number = args.parameters.From; 23 | 24 | return ContentService.createTextOutput('').setMimeType(ContentService.MimeType.TEXT); 25 | } 26 | -------------------------------------------------------------------------------- /External APIs/Set Slack Status.gs: -------------------------------------------------------------------------------- 1 | function setStatus() { 2 | //https://api.slack.com/docs/presence-and-status 3 | 4 | var token = /* Get a token at https://api.slack.com/apps */; 5 | var apiEndpoint = "https://slack.com/api/"; 6 | //var method = "users.list"; 7 | var myUserID = "U2GH2RKFT"; 8 | 9 | var method = "users.profile.set"; 10 | var profile = {"status_text": "", "status_emoji" : ""}; 11 | //var profile = {"status_text": "lunch"}; 12 | //var profile = {"first_name": "Derek"}; 13 | var payload = {"token": token, "user" : myUserID, "profile" : JSON.stringify(profile)}; 14 | var payload1 = {"token": token, "user" : myUserID, "profile" : profile}; 15 | Logger.log(payload) 16 | Logger.log(payload1); 17 | return; 18 | //var method = "users.setPresence"; 19 | //var payload = {"token": token, "user" : myUserID, "presence" : "auto"}; //Presence can either be "auto" or "away" 20 | 21 | var completeUrl = apiEndpoint + method; 22 | var jsonData = UrlFetchApp.fetch(completeUrl, {"method" : "post", "payload" : payload}); 23 | var object = JSON.parse(jsonData.getContentText()); 24 | Logger.log(object); 25 | } 26 | 27 | //"{\"channel\":\"channel_test\",\"username\":\"username_test\",\"text\":\"text_test\"}" 28 | -------------------------------------------------------------------------------- /External APIs/Set Trello FollowUps.gs: -------------------------------------------------------------------------------- 1 | //MAKE SURE YOU ALSO ADD THE FOLLOWING FILE TO YOUR GAS DOCUMENT: 2 | // - https://github.com/derekantrican/Google-Apps-Script-Library/blob/master/External%20APIs/TrelloAPI.gs 3 | 4 | function setFollowUpReminders() { 5 | var lists, cards, labels; 6 | var userBoards; 7 | userBoards = getBoardIDsForUser("YOUR_TRELLO_USERNAME"); //This returns a list of board IDs (not boards) 8 | 9 | for (var i = 0; i < userBoards.length; i++){ 10 | cards = getBoardCards(userBoards[i]); 11 | 12 | for (var j = 0; j < cards.length; j++){ 13 | labels = cards[j].labels; 14 | 15 | if (labels.length < 1) 16 | continue; 17 | 18 | for (var k = 0; k < labels.length; k++){ 19 | if (labels[k].name != "" &&labels[k].name.indexOf("@") >= 0){ 20 | GmailApp.sendEmail(labels[k].name, cards[j].name, cards[j].url); 21 | deleteLabelFromBoard(labels[k].id); 22 | } 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /External APIs/Todoist.gs: -------------------------------------------------------------------------------- 1 | //========================================================================== 2 | // Use this file to interact with Todoist.com. Please expand with other methods as needed! 3 | // API documentation: https://developer.todoist.com/rest/ 4 | //========================================================================== 5 | 6 | var TODOIST_API_KEY = "INSERT_YOUR_API_KEY"; 7 | var TODOIST_BASE_URL = "https://api.todoist.com/rest/v1"; 8 | 9 | function getTasks(projectId = null, sectionId = null, label_id = null, filter = null, language = null, ids = []) { 10 | var params = { 11 | "project_id" : projectId, 12 | "section_id" : sectionId, 13 | "label_id" : label_id, 14 | "filter" : filter, 15 | "lang" : language, 16 | "ids" : !ids || ids.length == 0 ? null : ids.join(','), 17 | }; 18 | 19 | return todoistGET("/tasks", Object.keys(params).filter(k => params[k] != null).map(k => `${k}=${encodeURIComponent(params[k])}`).join('&')); 20 | } 21 | 22 | function getTask(taskId) { 23 | return todoistGET(`/tasks/${taskId}`); 24 | } 25 | 26 | function getProjects() { 27 | return todoistGET("/projects"); 28 | } 29 | 30 | function getInboxTasks() { 31 | var inboxProjectId = getProjects().find(p => p.inbox_project).id; 32 | return getTasks(inboxProjectId); 33 | } 34 | 35 | function getLabels() { 36 | return todoistGET("/labels"); 37 | } 38 | 39 | function updateTask(taskId, data) { 40 | todoistPOST(`/tasks/${taskId}`, data); 41 | } 42 | 43 | function createTask(data) { 44 | todoistPOST("/tasks", data); 45 | } 46 | 47 | function completeTask(taskId) { 48 | todoistPOST(`/tasks/${taskId}/close`); 49 | } 50 | 51 | function commentOnTask(taskId, comment) { 52 | return todoistPOST(`/comments`, { 53 | 'task_id' : taskId, 54 | 'content' : comment, 55 | }); 56 | } 57 | 58 | function getCommentsOnTask(taskId) { 59 | return todoistGET('/comments', `task_id=${taskId}`); 60 | } 61 | 62 | function todoistGET(endpoint, additionalParams = ""){ 63 | var completeUrl = TODOIST_BASE_URL + endpoint + "?" + additionalParams; 64 | var options = { 65 | "method" : "get", 66 | "muteHttpExceptions" : true, 67 | "headers" : { 68 | "Authorization" : `Bearer ${TODOIST_API_KEY}` 69 | } 70 | }; 71 | 72 | var jsonData = UrlFetchApp.fetch(completeUrl, options); 73 | if (jsonData.getResponseCode() / 100 == 2 && jsonData.getContentText()) { 74 | return JSON.parse(jsonData.getContentText()); 75 | } 76 | } 77 | 78 | function todoistPOST(endpoint, payload){ 79 | var completeUrl = TODOIST_BASE_URL + endpoint; 80 | var options = { 81 | "method" : "post", 82 | "muteHttpExceptions" : true, 83 | "contentType": "application/json", 84 | "headers" : { 85 | "Authorization" : `Bearer ${TODOIST_API_KEY}`, 86 | }, 87 | "payload" : JSON.stringify(payload) 88 | }; 89 | 90 | var jsonData = UrlFetchApp.fetch(completeUrl, options); 91 | if (jsonData.getContentText()) { 92 | return JSON.parse(jsonData.getContentText()); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /External APIs/TrelloAPI.gs: -------------------------------------------------------------------------------- 1 | //========================================================================== 2 | // Use this file to interact with Trello.com. Please expand with other methods as needed! 3 | // API documentation: https://developers.trello.com/reference/ 4 | //========================================================================== 5 | 6 | var TRELLO_API_KEY = "INSERT_YOUR_API_KEY"; 7 | var TRELLO_BASE_URL = "https://api.trello.com/1"; 8 | var TRELLO_MEMBER_TOKEN = "INSERT_YOUR_MEMBER_TOKEN"; 9 | 10 | function getBoardIDsForUser(username){ 11 | return trelloGET("/members/" + username).idBoards; 12 | } 13 | 14 | function getOpenBoards(username){ 15 | return trelloGET("/members/" + username + "/boards", "&filter=open"); 16 | } 17 | 18 | function getBoardCards(boardID){ 19 | return trelloGET("/boards/" + boardID + "/cards/"); 20 | } 21 | 22 | function getListCards(listID){ 23 | return trelloGET("/list/" + listID + "/cards/"); 24 | } 25 | 26 | function getCard(cardID){ 27 | return trelloGET("/cards/" + cardID); 28 | } 29 | 30 | function addLabelToCard(cardID, labelID){ 31 | trelloPOST("/cards/" + cardID + "/idLabels", {"value" : labelID}); 32 | } 33 | 34 | function deleteLabelFromBoard(labelID){ 35 | trelloDELETE("/labels/" + labelID); 36 | } 37 | 38 | function removeLabelFromCard(cardID, labelID){ 39 | trelloDELETE("/cards/" + cardID + "/idLabels/" + labelID); 40 | } 41 | 42 | function createCard(cardTitle, listID){ 43 | return trelloPOST("/cards", {"name" : cardTitle, "idList" : listID}); 44 | } 45 | 46 | function createChecklist(cardID, checklistName){ 47 | return trelloPOST("/cards/" + cardID + "/checklists", {"name" : checklistName}); 48 | } 49 | 50 | function addItemToChecklist(checklistID, nameOfCheckItem){ 51 | return trelloPOST("/checklists/" + checklistID + "/checkItems", {"name" : nameOfCheckItem}); 52 | } 53 | 54 | function addAttachmentToCard(cardID, urlToAttach){ 55 | return trelloPOST("/cards/" + cardID + "/attachments", {"url" : urlToAttach}); 56 | } 57 | 58 | function removeItemFromChecklist(checklistID, checklistItemID){ 59 | trelloDELETE("/checklists/" + checklistID + "/checkItems/" + checklistItemID); 60 | } 61 | 62 | function getAttachmentsOnCard(cardID){ 63 | return trelloGET("/cards/" + cardID + "/attachments/"); 64 | } 65 | 66 | function getChecklistsOnCard(cardID){ 67 | return trelloGET("/cards/" + cardID + "/checklists/"); 68 | } 69 | 70 | function getCheckItemsOnChecklist(checklistID){ 71 | return trelloGET("/checklists/" + checklistID).checkItems; 72 | } 73 | 74 | function archiveCard(cardID){ 75 | return trelloPUT("/cards/" + cardID, {"closed" : true}); 76 | } 77 | 78 | function unArchiveCard(cardID){ 79 | return trelloPUT("/cards/" + cardID, {"closed" : false}); 80 | } 81 | 82 | function moveCardToTop(cardID){ 83 | return trelloPUT("/cards/" + cardID, {"pos" : "top"}); 84 | } 85 | 86 | function trelloGET(relativeUrl, additionalParams = ""){ 87 | var completeUrl = TRELLO_BASE_URL + relativeUrl + "?key=" + TRELLO_API_KEY + "&token=" + TRELLO_MEMBER_TOKEN + additionalParams; 88 | 89 | var jsonData = UrlFetchApp.fetch(completeUrl); 90 | return JSON.parse(jsonData.getContentText()); 91 | } 92 | 93 | function trelloDELETE(relativeUrl, payload){ 94 | var completeUrl = TRELLO_BASE_URL + relativeUrl + '?key=' + TRELLO_API_KEY + '&token=' + TRELLO_MEMBER_TOKEN; 95 | var options = {"method" : "delete", 96 | "muteHttpExceptions" : true, 97 | "payload" : payload}; 98 | 99 | var jsonData = UrlFetchApp.fetch(completeUrl, options); 100 | return JSON.parse(jsonData.getContentText()).id; 101 | } 102 | 103 | function trelloPOST(relativeUrl, payload){ 104 | var completeUrl = TRELLO_BASE_URL + relativeUrl + '?key=' + TRELLO_API_KEY + '&token=' + TRELLO_MEMBER_TOKEN; 105 | var options = {"method" : "post", 106 | "muteHttpExceptions" : true, 107 | "payload" : payload}; 108 | 109 | var jsonData = UrlFetchApp.fetch(completeUrl, options); 110 | return JSON.parse(jsonData.getContentText()).id; 111 | } 112 | 113 | function trelloPUT(relativeUrl, payload){ 114 | var completeUrl = TRELLO_BASE_URL + relativeUrl + '?key=' + TRELLO_API_KEY + '&token=' + TRELLO_MEMBER_TOKEN; 115 | var options = {"method" : "put", 116 | "muteHttpExceptions" : true, 117 | "payload" : payload}; 118 | 119 | var jsonData = UrlFetchApp.fetch(completeUrl, options); 120 | return JSON.parse(jsonData.getContentText()).id; 121 | } 122 | -------------------------------------------------------------------------------- /External APIs/Twilio.gs: -------------------------------------------------------------------------------- 1 | function sendSms(number, message) { 2 | var accountSid = /* Get SID at https://www.twilio.com/user/account */; 3 | var authToken = /* Get token at https://www.twilio.com/user/account */; 4 | var url = "https://api.twilio.com/2010-04-01/Accounts/" + accountSid + "/Messages"; 5 | var options = { 6 | method: "post", 7 | headers: { 8 | Authorization: "Basic " + Utilities.base64Encode(accountSid + ":" + authToken) 9 | }, 10 | payload: { 11 | From: /*From is one of your Twilio phone numbers*/, 12 | To: number, 13 | Body: message 14 | } 15 | }; 16 | var response = UrlFetchApp.fetch(url, options); 17 | Logger.log(response); 18 | } 19 | 20 | function doGet(args) { 21 | var from = args.parameter.From; 22 | var body = args.parameter.Body; 23 | 24 | return ContentService.createTextOutput('').setMimeType(ContentService.MimeType.TEXT); 25 | } 26 | -------------------------------------------------------------------------------- /Google Calendar/Change Event Color.gs: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * --------------- WARNING!! THIS SCRIPT GETS A BIT ADVANCED (uses the full Google Calendar API in addition to the simple version for Google Apps Script)--------------- 4 | * 5 | * STEPS TO GET THIS WORKING: 6 | * 7 | * 1) Click in the menu "Resources" > "Advanced Google services..." 8 | * 2) In the dialog box that pops up, make sure that for "Calendar API" the switch on the right is switched to "on" 9 | * 3) In that same dialog box, click the "Google Developers Console" link 10 | * 4) On the right side under the category "Google Apps APIs", click "Calendar API" 11 | * 5) At the top under "Overview", click "Enable API" 12 | * 6) You can now close this tab and return to the original script 13 | * 7) In the code, change line 28 to be the name of your calendar (remember to keep the quotes) 14 | * 8) Change line 30 to reflect what date the events start on and change "PST" to your timezone (keep the same formatting) 15 | * 9) Change line 32 to be a keyword you want to match or "" to select all the events in the calendar after the date in line 8 (remember this is a case-sensitive match) 16 | * 10) Change line 34 to be "0" or "1" depending on whether you want to search for the keyword in the title (0) or in the description (1) of events 17 | * 11) Change line 36 to be the color to change to (all lower-case). This is defined by the tool tip shown when editing an event (e.g.http://i.imgur.com/hlHCW3x.png) 18 | * 12) Finally, once you're all set with the above steps, click in the menu "Run" > "myFunction" (you may have to authorize the script to modify your calendar the first time) 19 | * 20 | * ------------------------------------------------------------------------------ 21 | */ 22 | 23 | function myFunction() { 24 | 25 | //---------ONLY EDIT BELOW HERE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING--------- 26 | 27 | 28 | var calendar = "Test"; //The name of the calendar you want to modify (WITH quotes) 29 | 30 | var startDate = new Date("Jan 10 PST 2016"); //The start of the time range in which the events exist 31 | 32 | var keyword = "Blue"; //The keyword to search for in the event title (WITH quotes; IS case-sensitive) 33 | 34 | var where = 1; //Where to search for events (0 = title; 1 = description) 35 | 36 | var color = "blue"; //The color to change the events to (WITH the quotes) 37 | 38 | 39 | //---------ONLY EDIT ABOVE HERE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING--------- 40 | 41 | var calendarId = CalendarApp.getCalendarsByName(calendar)[0].getId(); 42 | 43 | var optionalArgs = { 44 | timeMin: startDate.toISOString(), 45 | showDeleted: false, 46 | singleEvents: true, 47 | orderBy: 'startTime' 48 | }; 49 | 50 | var service = Calendar.Events; 51 | var response = Calendar.Events.list(calendarId, optionalArgs); 52 | var events = response.items; 53 | 54 | for (i = 0; i < events.length; i++) { 55 | Logger.log(events[i].summary); 56 | 57 | if (where == 0) 58 | var searchResult = events[i].summary.search(keyword); 59 | else if (where == 1){ 60 | if (events[i].description == undefined) 61 | continue; 62 | 63 | var searchResult = events[i].description.search(keyword); 64 | } 65 | 66 | if (searchResult > -1){ 67 | 68 | if (color == "bold blue") 69 | events[i].colorId = 9; 70 | else if (color == "blue") 71 | events[i].colorId = 1; 72 | else if (color == "turquoise") 73 | events[i].colorId = 7; 74 | else if (color == "green") 75 | events[i].colorId = 2; 76 | else if (color == "bold green") 77 | events[i].colorId = 10; 78 | else if (color == "yellow") 79 | events[i].colorId = 5; 80 | else if (color == "orange") 81 | events[i].colorId = 6; 82 | else if (color == "red") 83 | events[i].colorId = 4; 84 | else if (color == "bold red") 85 | events[i].colorId = 11; 86 | else if (color == "purple") 87 | events[i].colorId = 3; 88 | else if (color == "gray") 89 | events[i].colorId = 8; 90 | 91 | try{ 92 | service.update(events[i], calendarId, events[i].id); 93 | } 94 | catch(e){ 95 | Logger.log(e); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Google Calendar/Check for overlapping events.gs: -------------------------------------------------------------------------------- 1 | //---------ONLY EDIT BELOW HERE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING--------- 2 | var calendars = ""; //Calendar names. Comma-separated (eg "Calendar1,Calendar2,This is also a calendar") 3 | var filterKeywords = ""; //Filter keywords blacklist (ie an event won't be "overlapping" if it contains one of these keywords). Comma-separated. Case-insensitive 4 | var email = ""; //Email to send results of overlapping events to 5 | //---------ONLY EDIT ABOVE HERE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING--------- 6 | 7 | function myFunction() { 8 | calendars = calendars.split(","); 9 | calendars = cleanArray(calendars); //Remove empty entries 10 | 11 | var finalArray = []; 12 | var now = new Date(); 13 | var oneMonth = new Date(now.getTime() + (30 * 24 * 60 * 60 * 1000)); 14 | 15 | for (var i = 0; i < calendars.length; i++){ 16 | var calendar = CalendarApp.getCalendarsByName(calendars[i].trim())[0]; 17 | var events = calendar.getEvents(now, oneMonth); 18 | 19 | for (var j = 0; j < events.length; j++){ 20 | //Todo: need support for All-day events 21 | var currentEventArray = [events[j].getTitle(), events[j].getStartTime(), events[j].getEndTime(), events[j].getId()]; 22 | finalArray.push(currentEventArray); 23 | } 24 | } 25 | 26 | processArray(finalArray); 27 | } 28 | 29 | function processArray(array){ 30 | var results = []; 31 | 32 | for (var i = 0; i < array.length; i++){ 33 | var detailsForCurrentEvent = array[i]; 34 | 35 | var currentResult = checkAgainstEvents(detailsForCurrentEvent, array.slice(i)); 36 | if (currentResult == "pass") 37 | continue; 38 | else 39 | results.push(currentResult); 40 | } 41 | 42 | if (results.length == 0) 43 | return; 44 | 45 | var body = "Here are some conflicting events that were found on your calendar:\n"; 46 | for (var i = 0; i < results.length; i++) 47 | body += "\n" + results[i]; 48 | 49 | MailApp.sendEmail(email, "Conflicting Events", body); 50 | } 51 | 52 | function checkAgainstEvents(myEventDetails, fullArray){ 53 | var myTitle = myEventDetails[0]; 54 | var myStartTime = new Date(myEventDetails[1]); 55 | var myEndTime = new Date(myEventDetails[2]); 56 | var found = false; 57 | 58 | for (var i = 0; i < fullArray.length; i++){ 59 | var detailsForCurrentEvent = fullArray[i]; 60 | var startTimeToCheck = detailsForCurrentEvent[1]; 61 | var endTimeToCheck = detailsForCurrentEvent[2]; 62 | var eventTitleToCheck = detailsForCurrentEvent[0]; 63 | 64 | if (myEventDetails[3] == detailsForCurrentEvent[3]){ //This is the same event (the ids are the same) 65 | found = true; 66 | continue; 67 | } 68 | else if (myEndTime <= startTimeToCheck) //No conflict. myEvent is entirely before eventToCheck 69 | continue; 70 | else if (myStartTime >= endTimeToCheck) //No conflict. myEvent is entirely after eventToCheck 71 | continue; 72 | else if (keywordMatch(eventTitleToCheck) || keywordMatch(myTitle)) //Either event contains a filter keyword 73 | continue; 74 | else //There is a conflict (either entirely overlapping or partially overlapping) 75 | return '"' + myEventDetails[0] + "\" conflicts with \"" + detailsForCurrentEvent[0] + "\" on " + myStartTime.toDateString(); 76 | } 77 | 78 | return "pass"; //There are no conflicts with myEvent 79 | } 80 | 81 | function keywordMatch(inputString){ 82 | var keywordArray = filterKeywords.split(","); 83 | keywordArray = cleanArray(keywordArray); //Remove empty entries 84 | 85 | for (var i = 0; i < keywordArray.length; i++){ 86 | if (inputString.toUpperCase().includes(keywordArray[i].toUpperCase())) 87 | return true; 88 | } 89 | 90 | return false; 91 | } 92 | 93 | String.prototype.includes = function(phrase){ 94 | return this.indexOf(phrase) > -1; 95 | } 96 | 97 | function cleanArray(actual) { 98 | //Credit: https://stackoverflow.com/a/281335 99 | var newArray = new Array(); 100 | for (var i = 0; i < actual.length; i++) { 101 | if (actual[i]) { 102 | newArray.push(actual[i]); 103 | } 104 | } 105 | return newArray; 106 | } 107 | -------------------------------------------------------------------------------- /Google Calendar/Convert Event to All-Day.gs: -------------------------------------------------------------------------------- 1 | function myFunction() { 2 | //---------ONLY EDIT BELOW HERE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING--------- 3 | 4 | var calendar = "Test"; //The name of the calendar you want to modify (WITH quotes) 5 | 6 | var startDate = new Date("Jan 10 PST 2017"); //The start of the time range in which the events exist 7 | 8 | var endDate = new Date ("Dec 31 PST 2017"); //The end of the time range in which the events exist 9 | 10 | var keyword = ""; //The keyword to search for in the event title (WITH quotes; IS case-sensitive) 11 | 12 | //---------ONLY EDIT ABOVE HERE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING--------- 13 | 14 | var calendar = CalendarApp.getCalendarsByName(calendar)[0]; 15 | var events = calendar.getEvents(startDate, endDate); 16 | 17 | Logger.log("Found " + events.length + " events"); 18 | 19 | for (var i = 0; i < events.length; i++){ 20 | if (keyword != "" && keyword != null && events[i].getTitle().indexOf(keyword) > -1) 21 | events[i].setAllDayDate(events[i].getStartTime()); 22 | else if (keyword == ""){ 23 | events[i].setAllDayDate(events[i].getStartTime()); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Google Calendar/Delete Event From Multiple Calendars.gs: -------------------------------------------------------------------------------- 1 | function myFunction() { 2 | 3 | //---------------------------EDIT THIS ONLY------------------------- 4 | 5 | //Name of the calendars to delete events from 6 | var calendarNames = ["calendar1", 7 | "calendar2", 8 | "calendar3"]; 9 | 10 | var startTime = new Date("Feb 11 PST 2017"); //The start of the time range in which the events exist 11 | 12 | var endTime = new Date("Feb 19 PST 2017"); //The end of the time range in which the events exist 13 | 14 | var keyword = ""; //Keyword to search for in the event's title (Leave as "" to not use keyword search) 15 | 16 | //To see what happened, click in the menu "View" > "Logs" 17 | //------------------------------------------------------------------ 18 | 19 | for (var i = 0; i < calendarNames.length; i++){ 20 | var calendar = CalendarApp.getCalendarsByName(calendarNames[i])[0]; 21 | 22 | var events = calendar.getEvents(startTime, endTime); 23 | 24 | for (var j = 0; j < events.length; j++){ 25 | //Get the info from the event on the old calendar 26 | var title = events[j].getTitle(); 27 | 28 | if (keyword != "" && title.indexOf(keyword) < 0) 29 | continue; 30 | 31 | //Delete the event from the calendar 32 | events[j].deleteEvent(); 33 | Logger.log("Deleted \"" + title + "\" from " + calendar.getName()); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Google Calendar/Move events to calendar.gs: -------------------------------------------------------------------------------- 1 | function myFunction() { 2 | 3 | //---------------------------EDIT THIS ONLY------------------------- 4 | 5 | var oldCal = "work"; //Name of the calendar to copy events from 6 | 7 | var newCal = "personal"; //Name of the calendar to copy events to 8 | 9 | var startTime = new Date("Aug 25 PST 2015"); //The start of the time range in which the events exist 10 | 11 | var endTime = new Date("Aug 31 PST 2015"); //The end of the time range in which the events exist 12 | 13 | var deleteEvent = "N"; //Should the old event be deleted? "Y" or "N" 14 | 15 | var keyword = "test"; //Keyword to search for in the event's title (Leave as "" to not use keyword search) 16 | 17 | //To see what happened, click in the menu "View" > "Logs" 18 | //------------------------------------------------------------------ 19 | 20 | var calendar1=CalendarApp.getCalendarsByName(oldCal)[0]; 21 | var calendar2=CalendarApp.getCalendarsByName(newCal)[0]; 22 | 23 | var events = calendar1.getEvents(startTime, endTime); 24 | 25 | for (var i = 0; i < events.length; i++){ 26 | //Get the info from the event on the old calendar 27 | var title = events[i].getTitle(); 28 | 29 | if (keyword != "" && title.indexOf(keyword) < 0) 30 | continue; 31 | 32 | var desc = events[i].getDescription(); 33 | var loc = events[i].getLocation(); 34 | var start = events[i].getStartTime(); 35 | var end = events[i].getEndTime(); 36 | Logger.log(start); 37 | //Create the new event on the new calendar 38 | var newEvent = calendar2.createEvent(title, start, end, {description: desc, location: loc}); 39 | Logger.log("Moved \"" + title + "\" from " + calendar1.getName() + " to " + calendar2.getName()); 40 | 41 | if (events[i].isAllDayEvent()){ 42 | start = new Date(start.getTime() + (24 * 60 * 60 * 1000)); //Add a day to the date because of this error: https://goo.gl/gYF7dm 43 | newEvent.setAllDayDate(start); 44 | } 45 | 46 | //Delete the old event from the old calendar 47 | if (deleteEvent == "Y") 48 | events[i].deleteEvent(); 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /Google Calendar/Set Invite Status.gs: -------------------------------------------------------------------------------- 1 | function myFunction() { 2 | //---------ONLY EDIT BELOW HERE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING--------- 3 | 4 | var startDate = new Date("July 26 PST 2016"); //Required: The start of the time range in which the events exist 5 | 6 | var endDate = new Date("July 30 PST 2016"); //Required: The end of the time range in which the events exist 7 | 8 | var calendar = ""; //Optional: calendar to search on (Leave as "" for all calendars. IS case-sensitive) 9 | 10 | var keyword = ""; //Optional: keyword to search for in the title of the event (WITH quotes. One phrase at a time & IS case-sensitive. If you don't want to limit to events that match the keyword, leave as "") 11 | 12 | var status = "YES"; //Required: Status to set (Options: "YES", "NO", "MAYBE", "INVITED". IS case-sensitive) 13 | 14 | //---------ONLY EDIT ABOVE HERE UNLESS YOU REALLY KNOW WHAT YOU'RE DOING--------- 15 | 16 | if (calendar == "") 17 | var calendars = CalendarApp.getAllCalendars(); 18 | else 19 | var calendars = CalendarApp.getCalendarsByName(calendar); 20 | 21 | for (var i = 0; i < calendars.length; i++){ 22 | var events = calendars[i].getEvents(startDate, endDate); 23 | 24 | for (var j = 0; j < events.length; j++){ 25 | if (keyword != "" && events[j].getTitle().indexOf(keyword) < 0) 26 | continue; 27 | 28 | Logger.log("Before status for \"" + events[j].getTitle() + "\" (" + calendars[i].getName() + "): " + events[j].getMyStatus()); 29 | 30 | if (events[j].getMyStatus() == CalendarApp.GuestStatus.OWNER){ 31 | Logger.log("You are already the owner for this event"); 32 | continue; 33 | } 34 | else if (events[j].getMyStatus() == null){ 35 | Logger.log("A response cannot be set on this event"); 36 | continue; 37 | } 38 | 39 | if (status == "YES") 40 | events[j].setMyStatus(CalendarApp.GuestStatus.YES); 41 | else if (status == "NO") 42 | events[j].setMyStatus(CalendarApp.GuestStatus.NO); 43 | else if (status == "MAYBE") 44 | events[j].setMyStatus(CalendarApp.GuestStatus.MAYBE); 45 | else if (status == "INVITED") 46 | events[j].setMyStatus(CalendarApp.GuestStatus.INVITED); 47 | 48 | Logger.log("After status for \"" + events[j].getTitle() + "\" (" + calendars[i].getName() + "): " + events[j].getMyStatus()); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /Google Calendar/Split Multi-Day Event.gs: -------------------------------------------------------------------------------- 1 | function myFunction() { 2 | //Currently events greater than 24-hours are shown in the "all-day" section. This program breaks up those events so that they exist in the main calendar section 3 | 4 | var now = new Date(); 5 | var oneMonth = new Date(now.getTime() + (30 * 24 * 60 * 60 * 1000)); 6 | var calendars = ["derekantrican@gmail.com"]; 7 | 8 | for (var i = 0; i < calendars.length; i++){ 9 | var calendar = CalendarApp.getCalendarsByName(calendars[i])[0]; 10 | 11 | var events = calendar.getEvents(now, oneMonth); 12 | 13 | for (var j = 0; j < events.length; j++){ 14 | var duration = (events[j].getEndTime() - events[j].getStartTime()) / (1000 * 60 * 60); 15 | Logger.log(events[j].getTitle()); 16 | Logger.log("Duration: " + duration + " hours"); 17 | 18 | if (duration >= 24){ 19 | var finalStart = events[j].getStartTime(); 20 | var finalEnd = events[j].getEndTime(); 21 | 22 | for (var k = 0; k <= Math.floor(duration/24); k++){ 23 | var curStart; 24 | var curEnd; 25 | var newEvent; 26 | 27 | if (k == 0){ //First iteration 28 | curEnd = new Date(finalStart.getYear(), finalStart.getMonth(), finalStart.getDate(), 23, 59); 29 | newEvent = calendar.createEvent(events[j].getTitle(), finalStart, curEnd); 30 | } 31 | else if (k == Math.floor(duration/24)){ //Last iteration 32 | curStart = new Date(finalEnd.getYear(), finalEnd.getMonth(), finalEnd.getDate(), 0, 0); 33 | newEvent = calendar.createEvent(events[j].getTitle(), curStart, finalEnd); 34 | newEvent.removeAllReminders(); 35 | } 36 | else{ 37 | curStart = new Date(finalStart.getYear(), finalStart.getMonth(), finalStart.getDate() + k, 0, 0); 38 | curEnd = new Date(finalStart.getYear(), finalStart.getMonth(), finalStart.getDate() + k, 23, 59); 39 | newEvent = calendar.createEvent(events[j].getTitle(), curStart, curEnd); 40 | newEvent.removeAllReminders(); 41 | } 42 | 43 | newEvent.setLocation(events[j].getLocation()); 44 | newEvent.setDescription(events[j].getDescription()); 45 | } 46 | 47 | GmailApp.sendEmail("derekantrican@gmail.com", "Events were adjusted", "The event " + events[j].getTitle() + " was just adjusted on your calendar"); 48 | events[j].deleteEvent(); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GoogleAppsScriptLibrary 2 | 3 | This repository is a collection of documents written in [Google Apps Script](https://developers.google.com/apps-script/). Google Apps Script allows you to write scripts in Google Drive (very similar to how you might make a document in Google Drive) that interacts natively with a variety of Google services (e.g. Sheets, Docs, Drive, Gmail, Calendar, Contacts, etc). Not only that, but there are also ways to have your script interact with full APIs of those services (e.g. YouTube, Maps, etc) or even external services (in this repository I have examples for [Trello](https://trello.com/), [Plivo](https://www.plivo.com/), & [Twilio](https://www.twilio.com/)) 4 | 5 | For developing in Google Apps Script, I definitely recommend extensions listed here: https://github.com/derekantrican/Google-Apps-Script-Library/wiki/Developing-in-Google-Apps-Script 6 | 7 | Please use the [issues page](https://github.com/derekantrican/Google-Apps-Script-Library/issues) here to report issues with these scripts. You can also contact me at derekantrican@gmail.com and I can help you troubleshoot a problem 8 | 9 | ----------- 10 | 11 | ### Programs Overviews: 12 | 13 | External APIs 14 | 15 | - *Plivo.gs:* An example of how to use Google Apps Script to send & recieve text messages through [Plivo](https://www.plivo.com/) 16 | - *Set Slack Status.gs:* An example of how to set Slack status (i.e. https://api.slack.com/docs/presence-and-status#custom_status) 17 | - *Set Trello FollowUps.gs:* With this example, you can create a new label on any card on any board (that you have access to) in Trello with the [FollowUpThen](fut.io) format (e.g. `1hour@fut.io`). This script is designed to run on a time basis (e.g. every 15 minutes) and will create a FollowUpThen reminder for those cards and delete that temporary label from the board 18 | - *Twilio.gs:* An example of how to use Google Apps Script to send & recieve text messages through [Twilio](https://www.twilio.com/) 19 | 20 | Google Calendar 21 | 22 | - *Change Event Color.gs:* This script uses the **Official** Google Calendar API to change the color of events in Google Calendar 23 | - *Check for overlapping events.gs:* This script will check multiple Google Calendars and check for conflicting (overlapping) events and alert the user to any such cases 24 | - *Convert Event to All-Day.gs:* This script will simply convert any event into an all-day event 25 | - *Delete Event From Multiple Calendars.gs:* The title is pretty self-explanatory here 26 | - *Move events to calendar.gs:* Can move (or just copy) events from one calendar to another 27 | - *Set Invite Status.gs:* This script will set your status on events you are invited to (`YES`/`NO`/`MAYBE`/`INVITED`) 28 | - *Split Multi-Day Event.gs:* The purpose of this script is to split events that last more than 24 hrs into sections no more than 24 hrs (the reason being that Google Calendar shows events >24hrs in the "all-day section" at the top of the calendar - making them harder to spot). This makes it easier to see when a large event is planned. **This script still has some development work to be done and has issues** 29 | 30 | *ICS-ICAL Sync:* https://github.com/derekantrican/GAS-ICS-Sync 31 | 32 | Tasks- Forms- etc 33 | 34 | - *Any.Do Port.gs:* **This script was never fully working and should only be used for reference on how to create Google Forms and interact with Google Tasks** This was an attempt to recreate the [Moment](https://support.any.do/hc/en-us/articles/202781361-What-is-the-Any-do-Moment-) function of the task manager [Any.Do](https://www.any.do/) 35 | 36 | ---------- 37 | ### Interesting libraries/articles 38 | 39 | Here are a variety of articles, libraries, tools, etc I have found related to Google Apps Script: 40 | 41 | - Continuous integration (building/testing/publishing/etc) with Travis CI: https://github.com/faresd/google-apps-script_travis-ci 42 | - A library for updating a manifest file (`appsscript.json`) programatically: https://github.com/tanaikech/ManifestsApp 43 | - An extension for adding git commands (push/pull, etc) to the GAS IDE: https://chrome.google.com/webstore/detail/google-apps-script-github/lfjcgcmkmjjlieihflfhjopckgpelofo 44 | - A dark-theme for the GAS IDE: https://chrome.google.com/webstore/detail/appsscript-color/ciggahcpieccaejjdpkllokejakhkome 45 | - Using VS Code on your computer to develop GAS: 46 | - https://www.labnol.org/internet/google-apps-script-developers/32305/ 47 | - https://yagisanatode.com/2019/04/01/working-with-google-apps-script-in-visual-studio-code-using-clasp/ 48 | -------------------------------------------------------------------------------- /Tasks- Forms- etc/Any.Do Port.gs: -------------------------------------------------------------------------------- 1 | /* 2 | TO DO: 3 | 4 | - Post-meeting functionality 5 | 6 | */ 7 | 8 | function anyDoMoment() { 9 | 10 | var now = new Date(); 11 | var todaySimple = Utilities.formatDate(now, Session.getScriptTimeZone(), "MM-dd"); 12 | var thisYear = Utilities.formatDate(now, Session.getScriptTimeZone(), "YYYY"); 13 | var tomorrow = new Date(Utilities.formatDate(now, Session.getScriptTimeZone(), "MMM") + " " + todaySimple.split("-")[1] + " 23:00 GMT -5:00 " + thisYear); 14 | var files = DriveApp.getFilesByName("Google Tasks \"Moment\""); 15 | var exists = false; 16 | 17 | if (files.hasNext()){ 18 | exists = true; 19 | var file = files.next(); 20 | var date = file.getLastUpdated(); 21 | var dateSimple = Utilities.formatDate(date, Session.getScriptTimeZone(), "MM-dd"); 22 | 23 | if (dateSimple != todaySimple){ 24 | file.setTrashed(true); 25 | exists = false; 26 | } 27 | 28 | var url = file.getUrl(); 29 | var form = FormApp.openByUrl(url); 30 | } 31 | else{ 32 | 33 | moveToDateList(); //Make sure the tasks that were set for "tomorrow" yesterday are moved up to today before executing this function 34 | 35 | var defaultList = Tasks.Tasks.list("@default"); 36 | var items = defaultList.items; //Google tasks 37 | 38 | var triggers = ScriptApp.getProjectTriggers(); 39 | for (var i = 0; i < triggers.length; i++) { //Delete any existing triggers 40 | try{ 41 | if (ScriptApp.getProjectTriggers()[i].getHandlerFunction() == "anyDoMoment") 42 | ScriptApp.deleteTrigger(triggers[i]); 43 | } 44 | catch(e){ 45 | Logger.log("ERROR: " + e); 46 | Logger.log("TRIGGER: " + ScriptApp.getProjectTriggers()[i]); 47 | } 48 | } 49 | 50 | if (items.length <= 0){ 51 | ScriptApp.newTrigger("anyDoMoment").timeBased().at(tomorrow).create(); //Trigger itself again tomorrow 52 | return; 53 | } 54 | else if (items.length == 1 && items[0].title == ""){ 55 | ScriptApp.newTrigger("anyDoMoment").timeBased().at(tomorrow).create(); //Trigger itself again tomorrow 56 | return; 57 | } 58 | 59 | var form = FormApp.create('Google Tasks \"Moment\"'); 60 | form.setDescription("When do you expect to complete the tasks below?"); 61 | 62 | for (var i = 0; i < items.length; i++){ //Create a multiple choice for each google task 63 | var when = form.addMultipleChoiceItem(); 64 | when.setRequired(true); 65 | when.setTitle(items[i].title) 66 | .setChoices([ 67 | when.createChoice('Today'), 68 | when.createChoice('Tomorrow'), 69 | when.createChoice('Someday') 70 | ]); 71 | } 72 | 73 | var url = form.getPublishedUrl(); 74 | url = shortenUrl(url); 75 | GmailApp.sendEmail("derekantrican@gmail.com", "Any.Do Moment", "Fill out when you plan to complete today's tasks: " + url); 76 | ScriptApp.newTrigger("anyDoMoment").timeBased().everyMinutes(1).create(); //Trigger itself every minute until the script runs through and deletes all its triggers 77 | } 78 | 79 | if (exists){ 80 | 81 | var title = "Default List"; 82 | var allLists = Tasks.Tasklists.list().getItems(); 83 | for (var n in allLists) { 84 | if (title == allLists[n].getTitle()) 85 | var defaultID = allLists[n].getId(); 86 | } 87 | 88 | title = "Tomorrow"; 89 | for (var n in allLists) { 90 | if (title == allLists[n].getTitle()) 91 | var tomorrowID = allLists[n].getId(); 92 | } 93 | 94 | if (typeof tomorrowID == 'undefined'){ 95 | var tomorrowList = Tasks.newTaskList().setTitle("Tomorrow"); 96 | var tomorrowInsert = Tasks.Tasklists.insert(tomorrowList); 97 | var tomorrowID = tomorrowInsert.getId(); 98 | } 99 | 100 | title = "Someday"; 101 | for (var n in allLists) { 102 | if (title == allLists[n].getTitle()) 103 | var somedayID = allLists[n].getId(); 104 | } 105 | 106 | if (typeof somedayID == 'undefined'){ 107 | var somedayList = Tasks.newTaskList().setTitle("Someday"); 108 | var somedayInsert = Tasks.Tasklists.insert(somedayList); 109 | var somedayID = somedayInsert.getId(); 110 | } 111 | 112 | var formResponses = form.getResponses(); 113 | 114 | if (formResponses.length > 0){ 115 | 116 | for (var i = 0; i < formResponses.length; i++) { 117 | var formResponse = formResponses[i]; 118 | var itemResponses = formResponse.getItemResponses(); 119 | for (var j = 0; j < itemResponses.length; j++) { 120 | var itemResponse = itemResponses[j]; 121 | 122 | var newtask = Tasks.newTask().setTitle(itemResponse.getItem().getTitle()); 123 | 124 | if (itemResponse.getResponse() == "Tomorrow") 125 | var ID = tomorrowID; 126 | else if (itemResponse.getResponse() == "Someday") 127 | var ID = somedayID; 128 | else 129 | continue; 130 | 131 | var inserted = Tasks.Tasks.insert(newtask, ID); 132 | 133 | var defaultList = Tasks.Tasks.list("@default"); 134 | var items = defaultList.items; 135 | Logger.log(itemResponse.getItem().getTitle()); 136 | 137 | for (var n = 0; n < items.length; n++){ 138 | Logger.log(items[n].title); 139 | if (items[n].title == itemResponse.getItem().getTitle()){ 140 | var toDeleteID = items[n].getId(); 141 | break; 142 | } 143 | } 144 | try{ 145 | Tasks.Tasks.remove(defaultID, toDeleteID); //Delete the task from the original list 146 | } 147 | catch(e){ 148 | GmailApp.sendEmail("derekantrican@gmail.com", "ERROR in Any.Do", "ERROR: " + e); 149 | } 150 | } 151 | } 152 | 153 | var triggers = ScriptApp.getProjectTriggers(); 154 | for (var i = 0; i < triggers.length; i++) { //Delete any existing triggers 155 | if (ScriptApp.getProjectTriggers()[i].getHandlerFunction() == "anyDoMoment") 156 | ScriptApp.deleteTrigger(triggers[i]); 157 | } 158 | ScriptApp.newTrigger("anyDoMoment").timeBased().at(tomorrow).create(); //Trigger itself again tomorrow 159 | DriveApp.getFilesByName("Google Tasks \"Moment\"").next().setTrashed(true); //Delete the form after getting the responses 160 | } 161 | else 162 | Logger.log("No responses"); 163 | } 164 | } 165 | 166 | function clearCompleted(){ 167 | //Clear completed tasks 168 | 169 | //var defaultList = Tasks.Tasks.list("@default"); 170 | //var items = defaultList.items; //Google tasks 171 | var now = new Date(); 172 | var today = Utilities.formatDate(now, Session.getScriptTimeZone(), "MM-dd"); 173 | today = Utilities.formatDate(now, Session.getScriptTimeZone(), "yyyy-MM-dd"); 174 | 175 | var allLists = Tasks.Tasklists.list().getItems(); 176 | 177 | 178 | for (var n = 0; n < allLists.length; n++){ 179 | var id = allLists[n].getId(); 180 | Logger.log(id); 181 | var items = Tasks.Tasks.list(id).items; 182 | Logger.log(allLists[n].getTitle()); 183 | 184 | if (typeof items == 'undefined') 185 | continue; 186 | 187 | for (var i = 0; i < items.length; i++){ 188 | Logger.log(items[i].title); 189 | 190 | if (typeof items[i].completed != 'undefined'){ 191 | Logger.log("!!!" + items[i].title + ' is marked as completed'); 192 | var toDeleteID = items[i].getId(); 193 | gamifyAddToFavor(1); 194 | 195 | Logger.log("This is due at : " + items[i].due); 196 | 197 | if (typeof items[i].due != 'undefined' && items[i].due.split('T')[0] == today) 198 | gamifyAddToFavor(24); 199 | 200 | Tasks.Tasks.remove(id, toDeleteID); 201 | } 202 | } 203 | } 204 | } 205 | 206 | function moveToDateList(){ 207 | Logger.clear(); 208 | //Format today and tomorrow date like this: YYYY-MM-DDT23:60:00.00-05:00 209 | var now = new Date(); 210 | var today = Utilities.formatDate(now, Session.getScriptTimeZone(), "MM-dd"); 211 | var thisYear = Utilities.formatDate(now, Session.getScriptTimeZone(), "YYYY"); 212 | var tomorrow = new Date(Utilities.formatDate(now, Session.getScriptTimeZone(), "MMM") + " " + today.split("-")[1] + " 24:00 GMT -5:00 " + thisYear); 213 | tomorrow = Utilities.formatDate(tomorrow, Session.getScriptTimeZone(), "yyyy-MM-dd"); 214 | today = Utilities.formatDate(now, Session.getScriptTimeZone(), "yyyy-MM-dd"); 215 | Logger.log(today); 216 | Logger.log(tomorrow); 217 | 218 | var title = "Default List"; 219 | var allLists = Tasks.Tasklists.list().getItems(); 220 | for (var n in allLists) { 221 | if (title == allLists[n].getTitle()) 222 | var defaultID = allLists[n].getId(); 223 | } 224 | 225 | title = "Tomorrow"; 226 | for (var n in allLists) { 227 | if (title == allLists[n].getTitle()) 228 | var tomorrowID = allLists[n].getId(); 229 | } 230 | 231 | title = "Someday"; 232 | for (var n in allLists) { 233 | if (title == allLists[n].getTitle()) 234 | var somedayID = allLists[n].getId(); 235 | } 236 | 237 | var listIDs = [defaultID,tomorrowID,somedayID]; 238 | 239 | for (var i = 0; i < listIDs.length; i++){ 240 | var item = Tasks.Tasks.list(listIDs[i]).items; 241 | 242 | if (typeof item == 'undefined') 243 | continue; 244 | 245 | for (var j = 0; j < item.length; j++){ 246 | 247 | if (i != 1 && typeof item[j].due == 'undefined') 248 | continue; 249 | 250 | if (i == 1 || item[j].due.split('T')[0] == today){ 251 | Logger.log(item[j].title + " is due today"); 252 | var newtask = Tasks.newTask().setTitle(item[j].title); 253 | Tasks.Tasks.insert(newtask, defaultID); 254 | var toDeleteID = item[j].getId(); 255 | Tasks.Tasks.remove(listIDs[i], toDeleteID); 256 | } 257 | else if (item[j].due.split('T')[0] == tomorrow){ 258 | Logger.log(item[j].title + " is due tomorrow"); 259 | var newtask = Tasks.newTask().setTitle(item[j].title); 260 | Tasks.Tasks.insert(newtask, tomorrowID); 261 | var toDeleteID = item[j].getId(); 262 | Tasks.Tasks.remove(listIDs[i], toDeleteID); 263 | } 264 | } 265 | } 266 | } 267 | --------------------------------------------------------------------------------