├── PubsubAppREADME.pdf ├── README.md ├── examples ├── Async-Response-Processing │ ├── Form-Collector │ │ ├── code.gs │ │ └── index.html │ └── Form-Processor │ │ └── code.gs └── Gmail-Notifications │ └── GmailNotifications.gs └── src ├── PublishingApp.gs ├── PubsubApp.gs ├── SubscriptionApp.gs └── policyBuilder.gs /PubsubAppREADME.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spencer-Easton/Apps-Script-PubSubApp-Library/babfae1a8771e49f9cf45b89f312b9730804f452/PubsubAppREADME.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Apps-Script-PubSubApp-Library 2 | An Apps Script library for the Google Cloud Pub/Sub Service 3 | View the documentation [here](https://drive.google.com/open?id=0B_j9_-NbJQQDdm9BMWtVeDNhM28) 4 | -------------------------------------------------------------------------------- /examples/Async-Response-Processing/Form-Collector/code.gs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015 Spencer Easton 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | function doGet(e) { 18 | return HtmlService.createHtmlOutputFromFile('index').setSandboxMode(HtmlService.SandboxMode.IFRAME); 19 | } 20 | 21 | 22 | function handleResponse(response){ 23 | try{ 24 | PubSubApp.setTokenService(getTokenService()); 25 | var pub = PubSubApp.PublishingApp('api-project-665...208'); 26 | var message = pub.newMessage(); 27 | message.data = Utilities.base64Encode(response); 28 | pub.getTopic('response').publish(message); 29 | return true; 30 | }catch(e){throw new Error(e)} 31 | 32 | } 33 | 34 | 35 | function getTokenService(){ 36 | var jsonKey = JSON.parse(PropertiesService.getScriptProperties().getProperty("jsonKey")); 37 | var privateKey = jsonKey.private_key; 38 | var serviceAccountEmail = jsonKey.client_email; 39 | var sa = GSApp.init(privateKey, ['https://www.googleapis.com/auth/pubsub'], serviceAccountEmail); 40 | sa.addUser(serviceAccountEmail) 41 | .requestToken(); 42 | return sa.tokenService(serviceAccountEmail); 43 | } 44 | -------------------------------------------------------------------------------- /examples/Async-Response-Processing/Form-Collector/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |
7 | Enter your name:
8 | 9 |
10 | 11 |
12 | 13 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /examples/Async-Response-Processing/Form-Processor/code.gs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015 Spencer Easton 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | function doPost(e) { 18 | var postBody = JSON.parse(e.postData.getDataAsString()); 19 | var messageData = Utilities.newBlob(Utilities.base64Decode(postBody.message.data)).getDataAsString(); 20 | Utilities.sleep(10000); 21 | var ss = SpreadsheetApp.openById('1DGHH-j8MaHx1UijIxHZcffLpMG_NDkf_LsGKL0GVWR8').getSheetByName("Log"); 22 | ss.appendRow([new Date(), messageData, JSON.stringify(postBody,undefined,2)]) 23 | return 200; 24 | } 25 | -------------------------------------------------------------------------------- /examples/Gmail-Notifications/GmailNotifications.gs: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2015 Spencer Easton 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | var PROJECTID = 'api-project-3...9'; 18 | var WEBHOOK_URL = 'https://script.google.com/a/macros/ccsknights.org/s/AKfycbw_RzzP6WiptJ9T9EQKiW9I5AaZfhXAiWYrkcx9OOvc11s0_J8e/exec' 19 | 20 | function doPost(e){ 21 | var postBody = JSON.parse(e.postData.getDataAsString()); 22 | var messageData = Utilities.newBlob(Utilities.base64Decode(postBody.message.data)).getDataAsString(); 23 | var ss = SpreadsheetApp.openById('1URu5nXCHLHYz5bEhMoRSb3reFdvrfb5Sl3zP0Rc00s8').getSheetByName("Log"); 24 | ss.appendRow([new Date(), messageData, JSON.stringify(postBody,undefined,2)]) 25 | return 200; 26 | } 27 | 28 | function setupPubSub(){ 29 | var newTopic = CreateTopic("mailTrigger"); 30 | newTopic.setIamPolicy(addGmailPolicy()); 31 | Logger.log(newTopic.getName()); 32 | var newSub = CreateSubscription("mailTrigger",newTopic.getName(),WEBHOOK_URL); 33 | } 34 | 35 | function enrollEmail(){ 36 | PubSubApp.setTokenService(getTokenService()) 37 | var topicName = PubSubApp.PublishingApp(PROJECTID).getTopicName("mailTrigger") 38 | Logger.log(watchEmail(topicName,{labelIds:["INBOX"]})); 39 | } 40 | 41 | function disEnrollEmail(){ 42 | var res = UrlFetchApp.fetch("https://www.googleapis.com/gmail/v1/users/me/stop",{method:"POST",headers:{authorization:"Bearer "+ScriptApp.getOAuthToken()}}); 43 | Logger.log(res.getContentText()); 44 | } 45 | 46 | 47 | function addGmailPolicy(Policy){ 48 | return PubSubApp.policyBuilder() 49 | [(Policy)?"editPolicy":"newPolicy"](Policy) 50 | .addPublisher("SERVICEACCOUNT", 'gmail-api-push@system.gserviceaccount.com') 51 | .getPolicy(); 52 | } 53 | 54 | function addDomainSubs(Domain,Policy){ 55 | return PubSubApp.policyBuilder() 56 | [(Policy)?"editPolicy":"newPolicy"](Policy) 57 | .addPublisher("DOMAIN", Domain) 58 | .getPolicy(); 59 | } 60 | 61 | function getSubscriptionPolicy(){ 62 | return PubSubApp.policyBuilder() 63 | .newPolicy() 64 | .addSubscriber("DOMAIN","ccsknights.org") 65 | } 66 | 67 | function watchEmail(fullTopicName,watchOptions){ 68 | var options = {email:"me",token:ScriptApp.getOAuthToken(),labelIds:[]}; 69 | 70 | for(var option in watchOptions){ 71 | if(option in options){ 72 | options[option] = watchOptions[option]; 73 | } 74 | } 75 | Logger.log(options); 76 | var url = "https://www.googleapis.com/gmail/v1/users/"+options.email+"/watch" 77 | 78 | var payload = { 79 | topicName: fullTopicName, 80 | labelIds: options.labelIds 81 | } 82 | 83 | var params = { 84 | method:"POST", 85 | contentType: "application/json", 86 | payload: JSON.stringify(payload), 87 | headers:{Authorization: "Bearer "+ options.token 88 | }, 89 | muteHttpExceptions:true 90 | } 91 | 92 | var results = UrlFetchApp.fetch(url, params); 93 | 94 | if(results.getResponseCode() != 200){ 95 | throw new Error(results.getContentText()) 96 | }else{ 97 | return JSON.parse(results.getContentText()); 98 | } 99 | 100 | } 101 | 102 | function CreateTopic(topicName) { 103 | var topic; 104 | PubSubApp.setTokenService(getTokenService()); 105 | var pubservice = PubSubApp.PublishingApp(PROJECTID); 106 | try{topic = pubservice.newTopic(topicName)} 107 | catch(e){topic = pubservice.getTopic(topicName);} 108 | return topic; 109 | } 110 | 111 | function CreateSubscription(subscriptionName,topicName,webhookUrl){ 112 | var sub; 113 | PubSubApp.setTokenService(getTokenService()); 114 | var subService = PubSubApp.SubscriptionApp(PROJECTID); 115 | try{sub = subService.newSubscription(subscriptionName,topicName,webhookUrl)} 116 | catch(e){sub = subService.getSubscription(subscriptionName,topicName,webhookUrl)} 117 | return sub; 118 | } 119 | 120 | 121 | function getTokenService(){ 122 | var jsonKey = JSON.parse(PropertiesService.getScriptProperties().getProperty("jsonKey")); 123 | var privateKey = jsonKey.private_key; 124 | var serviceAccountEmail = jsonKey.client_email; 125 | var sa = GSApp.init(privateKey, ['https://www.googleapis.com/auth/pubsub'], serviceAccountEmail); 126 | sa.addUser(serviceAccountEmail) 127 | .requestToken(); 128 | return sa.tokenService(serviceAccountEmail); 129 | } 130 | 131 | 132 | function requestGmailScope_(){GmailApp.getAliases()} 133 | -------------------------------------------------------------------------------- /src/PublishingApp.gs: -------------------------------------------------------------------------------- 1 | /* 2 | PubSubApp - PublishingApp.gs 3 | 4 | Copyright (c) 2015 Spencer Easton 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | /*global tokenService_*/ 20 | /*global CALLPAGE_*/ 21 | /*global CALL_*/ 22 | 23 | 24 | /******************************************** 25 | * The constructor for the PublishingApp service 26 | * @param {string} projectId The API project ID of the pub/sub service. 27 | * @return {object} The PublishingApp service 28 | *********************************************/ 29 | function PublishingApp(projectId) { 30 | return new ProjectTopic_(projectId); 31 | } 32 | 33 | 34 | /******************************************** 35 | *********************************************/ 36 | function ProjectTopic_(projectId) { 37 | 38 | if (!tokenService_) { 39 | throw new Error("You must set a token service first"); 40 | } 41 | var self = this; 42 | self.project = projectId; 43 | 44 | 45 | /******************************************** 46 | *********************************************/ 47 | self.getTopics = function() { 48 | var path = 'projects/' + self.project + '/topics', 49 | options = { 50 | method: "GET" 51 | }, 52 | topics = CALLPAGE_(path, options, "topics"); 53 | return topics; 54 | }; 55 | 56 | /******************************************** 57 | *********************************************/ 58 | self.getTopicName = function(topic) { 59 | var path = "projects/" + self.project + "/topics/" + topic, 60 | options = { 61 | method: "GET" 62 | }, 63 | topicName = CALL_(path, options).name; 64 | return topicName; 65 | }; 66 | 67 | /******************************************** 68 | *********************************************/ 69 | self.getTopic = function(topic) { 70 | return new Topic(self.getTopicName(topic)); 71 | }; 72 | 73 | /******************************************** 74 | *********************************************/ 75 | self.newTopic = function(topic) { 76 | 77 | // check for valid topic naming 78 | var expression = new RegExp(/^(?!goog)[a-z][a-z0-9-_\.~+%]{2,254}$/i); 79 | if (!expression.test(topic)) { 80 | throw new Error("Invalid Topic Name"); 81 | } 82 | 83 | var path = 'projects/' + self.project + '/topics/' + topic, 84 | options = { 85 | method: "PUT" 86 | }, 87 | topicName = CALL_(path, options).name; 88 | return new Topic(topicName); 89 | }; 90 | 91 | /******************************************** 92 | *********************************************/ 93 | 94 | self.deleteTopic = function(topic) { 95 | var topicName = self.getTopicName(topic), 96 | path = 'projects/' + self.project + '/topics/' + topicName, 97 | options = { 98 | method: "DELETE" 99 | }; 100 | CALL_(path, options); 101 | return self; 102 | }; 103 | 104 | /******************************************** 105 | * 106 | *********************************************/ 107 | function Topic(topicName) { 108 | var topicObj = this; 109 | topicObj.topicName_ = topicName; 110 | 111 | 112 | /******************************************** 113 | *********************************************/ 114 | topicObj.setIamPolicy = function(policyResource) { 115 | var postBody = JSON.stringify({ 116 | policy: policyResource 117 | }), 118 | path = topicObj.topicName_ + ":setIamPolicy", 119 | options = { 120 | method: "POST", 121 | payload: postBody 122 | }; 123 | return CALL_(path, options); 124 | }; 125 | 126 | /******************************************** 127 | *********************************************/ 128 | topicObj.getIamPolicy = function() { 129 | var path = topicObj.topicName_ + ":getIamPolicy", 130 | options = { 131 | method: "GET" 132 | }; 133 | return CALL_(path, options); 134 | }; 135 | 136 | /******************************************** 137 | *********************************************/ 138 | topicObj.testIamPolicy = function(permissionsArray) { 139 | 140 | var path = topicObj.topicName_ + ":testIamPermissions", 141 | options = { 142 | method: "POST", 143 | payload: JSON.stringify({ 144 | "permissions": permissionsArray 145 | }) 146 | }; 147 | 148 | return CALL_(path, options); 149 | }; 150 | /******************************************** 151 | *********************************************/ 152 | topicObj.getSubscriptions = function() { 153 | var path = topicObj.topicName_ + "/subscriptions", 154 | options = { 155 | method: "GET" 156 | }, 157 | subscriptions = CALLPAGE_(path, options, "subscriptions"); 158 | return subscriptions; 159 | }; 160 | 161 | /******************************************** 162 | *********************************************/ 163 | topicObj.publish = function(Message) { 164 | 165 | var postBody = JSON.stringify({ 166 | messages: [Message] 167 | }), 168 | path = topicObj.topicName_ + ":publish", 169 | options = { 170 | method: "POST", 171 | payload: postBody 172 | }; 173 | return CALL_(path, options); 174 | }; 175 | 176 | /******************************************** 177 | *********************************************/ 178 | topicObj.getName = function() { 179 | return topicObj.topicName_ 180 | }; 181 | return topicObj; 182 | } 183 | 184 | /******************************************** 185 | *********************************************/ 186 | self.newMessage = function() { 187 | var message = {}; 188 | message.data = ""; 189 | message.attributes = {}; 190 | return JSON.parse(JSON.stringify(message)); 191 | }; 192 | return self; 193 | } -------------------------------------------------------------------------------- /src/PubsubApp.gs: -------------------------------------------------------------------------------- 1 | /* 2 | PubSubApp - PubSubApp.gs 3 | 4 | Copyright (c) 2015 Spencer Easton 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | 20 | 21 | var BASEURL_ = 'https://pubsub.googleapis.com/v1/'; 22 | var tokenService_; 23 | 24 | /* 25 | * Stores the function passed that is invoked to get a OAuth2 token; 26 | * @param {function} service The function used to get the OAuth2 token; 27 | * 28 | */ 29 | function setTokenService(service) { 30 | tokenService_ = service; 31 | } 32 | 33 | 34 | function CALL_(path, options) { 35 | var fetchOptions = { 36 | method: "", 37 | muteHttpExceptions: true, 38 | contentType: "application/json", 39 | headers: { 40 | Authorization: "Bearer " + tokenService_() 41 | } 42 | }, 43 | url = BASEURL_ + path; 44 | 45 | for (var option in options) { 46 | fetchOptions[option] = options[option]; 47 | } 48 | 49 | /*global UrlFetchApp*/ 50 | var response = UrlFetchApp.fetch(url, fetchOptions); 51 | if (response.getResponseCode() != 200) { 52 | throw new Error(response.getContentText()); 53 | } 54 | else { 55 | return JSON.parse(response.getContentText()); 56 | } 57 | } 58 | 59 | function CALLPAGE_(path, options, returnParamPath) { 60 | var fetchOptions = { 61 | method: "", 62 | muteHttpExceptions: true, 63 | contentType: "application/json", 64 | headers: { 65 | Authorization: "Bearer " + tokenService_() 66 | } 67 | }; 68 | for (var option in options) { 69 | fetchOptions[option] = options[option]; 70 | } 71 | 72 | var url = BASEURL_ + path, 73 | returnArray = [], 74 | nextPageToken; 75 | do { 76 | if (nextPageToken) { 77 | url += "?pageToken=" + nextPageToken; 78 | } 79 | var results = UrlFetchApp.fetch(url, fetchOptions); 80 | if (results.getResponseCode() != 200) { 81 | throw new Error(results.getContentText()); 82 | } 83 | else { 84 | var resp = JSON.parse(results.getContentText()); 85 | nextPageToken = resp.nextPageToken; 86 | returnArray = returnArray.concat(resp[returnParamPath]); 87 | } 88 | 89 | } while (nextPageToken); 90 | return returnArray; 91 | } -------------------------------------------------------------------------------- /src/SubscriptionApp.gs: -------------------------------------------------------------------------------- 1 | /* 2 | PubSubApp - SubscriptionApp.gs 3 | 4 | Copyright (c) 2015 Spencer Easton 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | /*global tokenService_*/ 20 | /*global CALLPAGE_*/ 21 | /*global CALL_*/ 22 | 23 | /******************************************** 24 | * Construtor for the SubscriptionApp service 25 | * @param {string} projectId The API project ID of the pub/sub service 26 | * @return {object} The SubscriptionApp service 27 | *********************************************/ 28 | function SubscriptionApp(projectId) { 29 | return new ProjectSubscription_(projectId) 30 | } 31 | 32 | /******************************************** 33 | *********************************************/ 34 | function ProjectSubscription_(projectId) { 35 | var self_ = this; 36 | self_.project = projectId; 37 | 38 | /******************************************** 39 | *********************************************/ 40 | self_.getSubscriptions = function() { 41 | var path = 'projects/' + self_.project + '/subscriptions', 42 | options = { 43 | method: "GET" 44 | }, 45 | subscriptions = CALLPAGE_(path, options, "subscriptions"); 46 | return subscriptions; 47 | }; 48 | 49 | /******************************************** 50 | *********************************************/ 51 | self_.getSubscription = function(subscriptionName) { 52 | var path = "projects/" + self_.project + "/subscriptions/" + subscriptionName, 53 | options = { 54 | method: "GET" 55 | }, 56 | subResource = CALL_(path, options); 57 | return new Subscription(subResource); 58 | }; 59 | 60 | /******************************************** 61 | *********************************************/ 62 | self_.deleteSubscription = function(subscriptionName) { 63 | var path = "projects/" + self_.project + "/subscriptions/" + subscriptionName, 64 | options = { 65 | method: "DELETE" 66 | }; 67 | CALL_(path, options); 68 | return self_; 69 | }; 70 | 71 | /******************************************** 72 | *********************************************/ 73 | self_.newSubscription = function(subscriptionName, topicName, endPoint) { 74 | var expression = new RegExp(/^(?!goog)[a-z][a-z0-9\-_\.~+%]{2,254}$/i); 75 | if (!expression.test(subscriptionName)) { 76 | throw new Error("Invalid Subscription Name"); 77 | } 78 | var path = "projects/" + self_.project + "/subscriptions/" + subscriptionName, 79 | subOptions = { 80 | topic: topicName, 81 | pushConfig: {}, 82 | ackDeadlineSeconds: 30 83 | }; 84 | 85 | if (endPoint) { 86 | subOptions.pushConfig.pushEndpoint = endPoint; 87 | } 88 | var options = { 89 | method: "PUT", 90 | payload: JSON.stringify(subOptions) 91 | }, 92 | subResource = CALL_(path, options); 93 | return new Subscription(subResource); 94 | }; 95 | 96 | /******************************************** 97 | *********************************************/ 98 | function Subscription(subResource) { 99 | var selfSub = this; 100 | selfSub.resource = subResource; 101 | 102 | /******************************************/ 103 | /******************************************/ 104 | selfSub.getResource = function() { 105 | return selfSub.resource 106 | }; 107 | 108 | /******************************************/ 109 | /******************************************/ 110 | selfSub.setIamPolicy = function(policyResource) { 111 | var path = selfSub.resource.name + ":setIamPolicy", 112 | options = { 113 | method: "POST", 114 | payload: JSON.stringify({ 115 | policy: policyResource 116 | }) 117 | }; 118 | return CALL_(path, options); 119 | }; 120 | 121 | /******************************************/ 122 | /******************************************/ 123 | selfSub.getIamPolicy = function() { 124 | var path = selfSub.resource.name + ":getIamPolicy", 125 | options = { 126 | method: "GET" 127 | }; 128 | return CALL_(path, options); 129 | }; 130 | 131 | /******************************************/ 132 | /******************************************/ 133 | selfSub.testIamPolicy = function(permissionsArray) { 134 | var path = selfSub.resource.name + ":testIamPermissions", 135 | options = { 136 | method: "POST", 137 | payload: JSON.stringify({ 138 | "permissions": permissionsArray 139 | }) 140 | }; 141 | return CALL_(path, options); 142 | }; 143 | 144 | /******************************************/ 145 | /******************************************/ 146 | selfSub.pull = function(maxCount, autoAck) { 147 | var autoAck = autoAck !== false, 148 | returnMessages = [], 149 | ackIds = [], 150 | maxCount = maxCount || 1, 151 | payload = { 152 | "returnImmediately": true, 153 | "maxMessages": maxCount, 154 | }, 155 | path = selfSub.resource.name + ":pull", 156 | options = { 157 | method: "POST", 158 | payload: JSON.stringify(payload) 159 | }, 160 | messages = CALL_(path, options).receivedMessages; 161 | if (autoAck) { 162 | for (var i in messages) { 163 | ackIds.push(messages[i].ackId); 164 | } 165 | if (ackIds.length > 0) { 166 | selfSub.ack(ackIds); 167 | } 168 | } 169 | return messages; 170 | }; 171 | 172 | /******************************************/ 173 | /******************************************/ 174 | selfSub.modifyAckDeadline = function(ackIds, seconds) { 175 | var payload = { 176 | ackIds: ackIds, 177 | "ackDeadlineSeconds": seconds 178 | }, 179 | path = selfSub.resource.name + ":modifyAckDeadline", 180 | options = { 181 | method: "POST", 182 | payload: JSON.stringify(payload) 183 | }; 184 | CALL_(path, options); 185 | return selfSub; 186 | }; 187 | 188 | /******************************************/ 189 | /******************************************/ 190 | selfSub.ack = function(ackIds) { 191 | var payload = { 192 | ackIds: ackIds 193 | }, 194 | path = selfSub.resource.name + ":acknowledge", 195 | options = { 196 | method: "POST", 197 | payload: JSON.stringify(payload) 198 | }; 199 | CALL_(path, options); 200 | return selfSub; 201 | }; 202 | } 203 | return self_; 204 | } -------------------------------------------------------------------------------- /src/policyBuilder.gs: -------------------------------------------------------------------------------- 1 | /* 2 | PubSubApp - policyBuilder.gs 3 | 4 | Copyright (c) 2015 Spencer Easton 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | /******************************************** 20 | * The constructor of the policyBuilder service 21 | * @return {object} The policyBuilder service 22 | *********************************************/ 23 | function policyBuilder() { 24 | return new policyBuilder_(); 25 | } 26 | 27 | function policyBuilder_() { 28 | var policyBuilder = this, 29 | POLICY = JSON.stringify({ 30 | bindings: [] 31 | }), 32 | ROLES = Object.freeze({ 33 | Viewer: "roles/viewer", 34 | Editor: "roles/editor", 35 | Owner: "roles/owner", 36 | Publisher: "roles/pubsub.publisher", 37 | Subscriber: "roles/pubsub.subscriber" 38 | }), 39 | MEMBERTYPE = Object.freeze({ 40 | ALLUSERS: "allAuthenticatedUsers", 41 | USER: "user:", 42 | SERVICEACCOUNT: "serviceAccount:", 43 | GROUP: "group:", 44 | DOMAIN: "domain:" 45 | }); 46 | 47 | 48 | /******************************************** 49 | * Creates a Policy object from an existing IAM policy resource 50 | * @param {object} policyResource The policy resource to edit 51 | * @return {object} new Policy object 52 | *********************************************/ 53 | policyBuilder.editPolicy = function(policyResource) { 54 | var policyMap = {}, 55 | policy = policyResource.bindings; 56 | for (var i in policy) { 57 | if (!(policy[i].role in policyMap)) { 58 | policyMap[policy[i].role] = []; 59 | } 60 | for (var ii in policy[i].members) { 61 | policyMap[policy[i].role].push(policy[i].members[ii]); 62 | } 63 | } 64 | return new Policy_(policyMap); 65 | }; 66 | 67 | /******************************************** 68 | * Creates a new Policy object 69 | * @return {object} new Policy object 70 | *********************************************/ 71 | policyBuilder.newPolicy = function() { 72 | return new Policy_(); 73 | }; 74 | 75 | function Policy_(policyMap) { 76 | var policyMapper = policyMap || {}; 77 | var thisPolicy = this; 78 | 79 | for (var role in ROLES) { 80 | /******************************************** 81 | * Add member to policy role 82 | * @param {string} memberRole The role defined in MEMBERTYPE object 83 | * @param {string} Name The name, usually the email, of the user 84 | * @return {object} this Policy object 85 | *********************************************/ 86 | thisPolicy["add" + role] = (function(myRole) { 87 | return function(memberType, Name) { 88 | addMember_(myRole, memberType.toUpperCase(), Name); 89 | return thisPolicy; 90 | }; 91 | })(role); 92 | 93 | /******************************************** 94 | * remove member from policy role 95 | * @param {string} Name The name, usually the email, of the user 96 | * @return {object} this Policy object 97 | *********************************************/ 98 | thisPolicy["remove" + role] = (function(myRole) { 99 | return function(Name) { 100 | removeMember_(myRole, Name); 101 | return thisPolicy; 102 | }; 103 | })(role); 104 | 105 | } 106 | 107 | /******************************************/ 108 | /******************************************/ 109 | function addMember_(role, memberType, name) { 110 | var name = name || ""; 111 | if (!(ROLES[role] in policyMapper)) { 112 | policyMapper[ROLES[role]] = []; 113 | } 114 | policyMapper[ROLES[role]].push(MEMBERTYPE[memberType] + name); 115 | } 116 | 117 | /******************************************/ 118 | /******************************************/ 119 | function removeMember_(role, name) { 120 | var name = name || ""; 121 | for (var i = 0; i < policyMapper[ROLES[role]].length; i++) { 122 | if (policyMapper[ROLES[role]][i].indexOf(name) != -1) { 123 | policyMapper[ROLES[role]].splice(i, 1); 124 | } 125 | } 126 | } 127 | /******************************************** 128 | * Return this poliocy as a IAM PolicyResource 129 | * @return {object} IAM policy resource object 130 | *********************************************/ 131 | thisPolicy.getPolicy = function() { 132 | var returnPolicy = JSON.parse(POLICY), 133 | members; 134 | for (var policy in policyMapper) { 135 | returnPolicy.bindings.push({ 136 | role: policy, 137 | members: policyMapper[policy] 138 | }); 139 | } 140 | return returnPolicy; 141 | }; 142 | return thisPolicy; 143 | } 144 | return policyBuilder; 145 | } --------------------------------------------------------------------------------