diff --git a/.github/workflows/appengine-twilio.yaml b/.github/workflows/appengine-twilio.yaml deleted file mode 100644 index 9019416722..0000000000 --- a/.github/workflows/appengine-twilio.yaml +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2023 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -name: appengine-twilio -on: - push: - branches: - - main - paths: - - 'appengine/twilio/**' - - '.github/workflows/appengine-twilio.yaml' - - '.github/workflows/test.yaml' - pull_request: - paths: - - 'appengine/twilio/**' - - '.github/workflows/appengine-twilio.yaml' - - '.github/workflows/test.yaml' - pull_request_target: - types: [labeled] - paths: - - 'appengine/twilio/**' - - '.github/workflows/appengine-twilio.yaml' - - '.github/workflows/test.yaml' - schedule: - - cron: '0 0 * * 0' -jobs: - test: - permissions: - contents: 'read' - id-token: 'write' - if: github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' - uses: ./.github/workflows/test.yaml - with: - name: 'appengine-twilio' - path: 'appengine/twilio' - flakybot: - permissions: - contents: 'read' - id-token: 'write' - if: github.event_name == 'schedule' && always() # always() submits logs even if tests fail - uses: ./.github/workflows/flakybot.yaml - needs: [test] diff --git a/.github/workflows/utils/workflows.json b/.github/workflows/utils/workflows.json index c1ffd9e387..7d5fad553f 100644 --- a/.github/workflows/utils/workflows.json +++ b/.github/workflows/utils/workflows.json @@ -13,7 +13,6 @@ "appengine/static-files", "appengine/storage/flexible", "appengine/storage/standard", - "appengine/twilio", "appengine/typescript", "appengine/websockets", "asset/snippets", diff --git a/appengine/building-an-app/build/app.yaml b/appengine/building-an-app/build/app.yaml index 3781d1712f..7c10aece83 100755 --- a/appengine/building-an-app/build/app.yaml +++ b/appengine/building-an-app/build/app.yaml @@ -1,4 +1,4 @@ -# Copyright 2018, Google, Inc. +# Copyright 2018 Google LLC # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -12,5 +12,7 @@ # limitations under the License. # [START app_yaml] -runtime: nodejs16 +# [START gae_app_yaml] +runtime: nodejs20 +# [END gae_app_yaml] # [END app_yaml] diff --git a/appengine/building-an-app/build/package.json b/appengine/building-an-app/build/package.json index 1261d91729..bbaa1dc1b8 100644 --- a/appengine/building-an-app/build/package.json +++ b/appengine/building-an-app/build/package.json @@ -1,6 +1,6 @@ { "name": "appengine-standard-getting-started-build-apps", - "version": "0.0.1", + "version": "0.1.0", "description": "Node.js getting started sample for building an app on App Engine standard environment.", "private": true, "main": "server.js", @@ -14,12 +14,12 @@ "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git" }, "engines": { - "node": "16.x.x" + "node": "20.x.x" }, "author": "Google Inc.", "license": "Apache-2.0", "dependencies": { - "express": "^4.16.3" + "express": "^4.18.2" }, "devDependencies": { "c8": "^8.0.0", diff --git a/appengine/building-an-app/build/server.js b/appengine/building-an-app/build/server.js index e7b6eae355..6fd176d212 100755 --- a/appengine/building-an-app/build/server.js +++ b/appengine/building-an-app/build/server.js @@ -15,6 +15,7 @@ 'use strict'; // [START app] +// [START gae_app] const express = require('express'); const app = express(); @@ -27,6 +28,7 @@ const PORT = parseInt(process.env.PORT) || 8080; app.listen(PORT, () => { console.log(`Server listening on port ${PORT}...`); }); +// [END gae_app] // [END app] module.exports = app; diff --git a/appengine/building-an-app/build/test/server.test.js b/appengine/building-an-app/build/test/server.test.js index aeb3abcc67..308e73b803 100644 --- a/appengine/building-an-app/build/test/server.test.js +++ b/appengine/building-an-app/build/test/server.test.js @@ -1,8 +1,23 @@ +// Copyright 2018 Google LLC +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + const supertest = require('supertest'); const path = require('path'); const app = require(path.join(__dirname, '../', 'server.js')); -it('should be listening', async () => { - await supertest(app).get('/').expect(200); -}); +describe('gae_app', () => { + it('should be listening', async () => { + await supertest(app).get('/').expect(200); + }); +}) diff --git a/appengine/building-an-app/update/app.yaml b/appengine/building-an-app/update/app.yaml index 3781d1712f..25ee95b89f 100755 --- a/appengine/building-an-app/update/app.yaml +++ b/appengine/building-an-app/update/app.yaml @@ -1,4 +1,4 @@ -# Copyright 2018, Google, Inc. +# Copyright 2018 Google LLC # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -12,5 +12,5 @@ # limitations under the License. # [START app_yaml] -runtime: nodejs16 +runtime: nodejs20 # [END app_yaml] diff --git a/appengine/building-an-app/update/package.json b/appengine/building-an-app/update/package.json index 2c9c88b559..f2e0befe95 100644 --- a/appengine/building-an-app/update/package.json +++ b/appengine/building-an-app/update/package.json @@ -1,6 +1,6 @@ { "name": "appengine-standard-getting-started-update-apps", - "version": "0.0.1", + "version": "0.1.0", "description": "Node.js getting started sample for updating an app on App Engine standard environment.", "private": true, "main": "server.js", @@ -14,12 +14,12 @@ "url": "https://github.com/GoogleCloudPlatform/nodejs-docs-samples.git" }, "engines": { - "node": "16.x.x" + "node": "20.x.x" }, "author": "Google Inc.", "license": "Apache-2.0", "dependencies": { - "express": "^4.16.3" + "express": "^4.18.2" }, "devDependencies": { "c8": "^8.0.0", diff --git a/appengine/building-an-app/update/server.js b/appengine/building-an-app/update/server.js index fc4d4c4898..4eda5078a4 100755 --- a/appengine/building-an-app/update/server.js +++ b/appengine/building-an-app/update/server.js @@ -15,14 +15,17 @@ 'use strict'; // [START app] +// [START gae_update_app] const express = require('express'); const path = require('path'); const app = express(); // [START enable_parser] +// [START gae_enable_parser] // This middleware is available in Express v4.16.0 onwards app.use(express.urlencoded({extended: true})); +// [END gae_enable_parser] // [END enable_parser] app.get('/', (req, res) => { @@ -30,12 +33,15 @@ app.get('/', (req, res) => { }); // [START add_display_form] +// [START gae_add_display_form] app.get('/submit', (req, res) => { res.sendFile(path.join(__dirname, '/views/form.html')); }); +// [END gae_add_display_form] // [END add_display_form] // [START add_post_handler] +// [START gae_add_post_handler] app.post('/submit', (req, res) => { console.log({ name: req.body.name, @@ -43,6 +49,7 @@ app.post('/submit', (req, res) => { }); res.send('Thanks for your message!'); }); +// [END gae_add_post_handler] // [END add_post_handler] // Listen to the App Engine-specified port, or 8080 otherwise @@ -50,6 +57,7 @@ const PORT = parseInt(process.env.PORT) || 8080; app.listen(PORT, () => { console.log(`Server listening on port ${PORT}...`); }); +// [END gae_update_app] // [END app] module.exports = app; diff --git a/appengine/building-an-app/update/test/server.test.js b/appengine/building-an-app/update/test/server.test.js index dcc748801f..0ef0e68cf4 100755 --- a/appengine/building-an-app/update/test/server.test.js +++ b/appengine/building-an-app/update/test/server.test.js @@ -1,4 +1,4 @@ -// Copyright 2018, Google, Inc. +// Copyright 2018 Google LLC // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at @@ -36,16 +36,18 @@ const restoreConsole = function () { beforeEach(stubConsole); afterEach(restoreConsole); -it('should send greetings', async () => { - await requestObj - .get('/') - .expect(200) - .expect(response => { - assert.strictEqual(response.text, 'Hello from App Engine!'); - }); +describe('gae_update_app', () => { + it('should send greetings', async () => { + await requestObj + .get('/') + .expect(200) + .expect(response => { + assert.strictEqual(response.text, 'Hello from App Engine!'); + }); + }); }); -describe('add_display_form', () => { +describe('gae_add_display_form add_display_form', () => { it('should display form', async () => { await requestObj .get('/submit') @@ -61,7 +63,7 @@ describe('add_display_form', () => { }); }); -describe('add_post_handler enable_parser', () => { +describe('gae_add_post_handler add_post_handler gae_enable_parser enable_parser', () => { it('should record message', async () => { await requestObj .post('/submit', { diff --git a/appengine/twilio/README.md b/appengine/twilio/README.md deleted file mode 100644 index 40bdb371e2..0000000000 --- a/appengine/twilio/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Node.js Twilio voice and SMS sample for Google App Engine - -This sample shows how to use [Twilio](https://www.twilio.com) on -[Google App Engine](https://cloud.google.com/appengine) Node.js [standard environment](https://cloud.google.com/appengine/docs/standard/nodejs) -and [flexible environment](https://cloud.google.com/appengine/docs/flexible/nodejs) - -For more information about Twilio, see the -[Twilio Node library](https://www.twilio.com/docs/node/install). - -## Setup - -Before you can run or deploy the sample, you will need to do the following: - -1. [Create a Twilio Account](http://ahoy.twilio.com/googlecloudplatform). Google -App Engine customers receive a complimentary credit for SMS messages and inbound -messages. - -1. Create a number on twilio, and configure the voice request URL to be -`https://.appspot.com/call/receive` and the SMS request URL to -be `https://.appspot.com/sms/receive`. - -1. Configure your Twilio settings in the environment variables section in -`app.yaml`. - -## Running locally - -Refer to the [appengine/README.md](../README.md) file for instructions on -running and deploying. - -You can run the application locally to test the callbacks and SMS sending. You -will need to set environment variables before starting your application: - - export TWILIO_ACCOUNT_SID= - export TWILIO_AUTH_TOKEN= - export TWILIO_NUMBER= - npm start diff --git a/appengine/twilio/app.flexible.yaml b/appengine/twilio/app.flexible.yaml deleted file mode 100644 index 1f0fbe241e..0000000000 --- a/appengine/twilio/app.flexible.yaml +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2015-2016, Google, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -runtime: nodejs -env: flex - -# [START gae_flex_twilio_env] -# The following env variables may contain sensitive information that grants -# anyone access to your Twilio account. Do not add this file to your source -# control. -env_variables: - TWILIO_ACCOUNT_SID: - TWILIO_AUTH_TOKEN: - TWILIO_NUMBER: -# [END gae_flex_twilio_env] diff --git a/appengine/twilio/app.js b/appengine/twilio/app.js deleted file mode 100644 index 9b10658429..0000000000 --- a/appengine/twilio/app.js +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; - -const express = require('express'); -const bodyParser = express.urlencoded({ - extended: false, -}); - -const app = express(); - -const {TWILIO_NUMBER} = process.env; -if (!TWILIO_NUMBER) { - console.log( - 'Please configure environment variables as described in README.md' - ); - throw new Error( - 'Please configure environment variables as described in README.md' - ); -} - -const twilio = require('twilio'); - -const twilioClient = new twilio( - process.env.TWILIO_ACCOUNT_SID, - process.env.TWILIO_AUTH_TOKEN -); - -// [START gae_flex_twilio_receive_call] -app.post('/call/receive', (req, res) => { - const twiml = new twilio.twiml.VoiceResponse(); - - twiml.say('Hello from Google App Engine.'); - - res.status(200).contentType('text/xml').send(twiml.toString()); -}); -// [END gae_flex_twilio_receive_call] - -// [START gae_flex_twilio_send_sms] -app.get('/sms/send', async (req, res, next) => { - const {to} = req.query; - if (!to) { - res - .status(400) - .send('Please provide an number in the "to" query string parameter.'); - return; - } - - try { - await twilioClient.messages.create({ - to: to, - from: TWILIO_NUMBER, - body: 'Hello from Google App Engine', - }); - res.status(200).send('Message sent.'); - } catch (err) { - next(err); - return; - } -}); -// [END gae_flex_twilio_send_sms] - -// [START gae_flex_twilio_receive_sms] -app.post('/sms/receive', bodyParser, (req, res) => { - const sender = req.body.From; - const body = req.body.Body; - - const twiml = new twilio.twiml.MessagingResponse(); - twiml.message(`Hello, ${sender}, you said: ${body}`); - - res.status(200).contentType('text/xml').send(twiml.toString()); -}); -// [END gae_flex_twilio_receive_sms] - -// Start the server -if (module === require.main) { - const PORT = parseInt(process.env.PORT) || 8080; - app.listen(PORT, () => { - console.log(`App listening on port ${PORT}`); - console.log('Press Ctrl+C to quit.'); - }); -} - -exports.app = app; diff --git a/appengine/twilio/app.standard.yaml b/appengine/twilio/app.standard.yaml deleted file mode 100644 index 1b6ec177be..0000000000 --- a/appengine/twilio/app.standard.yaml +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2015-2016, Google, Inc. -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -runtime: nodejs16 - -# [START gae_twilio_env] -# The following env variables may contain sensitive information that grants -# anyone access to your Twilio account. Do not add this file to your source -# control. -env_variables: - TWILIO_ACCOUNT_SID: - TWILIO_AUTH_TOKEN: - TWILIO_NUMBER: -# [END gae_twilio_env] diff --git a/appengine/twilio/package.json b/appengine/twilio/package.json deleted file mode 100644 index a920dd0211..0000000000 --- a/appengine/twilio/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "appengine-twilio", - "description": "Twilio sample for Google App Engine", - "version": "0.0.1", - "private": true, - "license": "Apache Version 2.0", - "author": "Google Inc.", - "engines": { - "node": "16.x.x" - }, - "scripts": { - "start": "node app.js", - "test": "c8 mocha -p -j 2 test/*.test.js" - }, - "dependencies": { - "express": "^4.16.4", - "twilio": "^4.0.0" - }, - "devDependencies": { - "c8": "^8.0.0", - "mocha": "^10.0.0", - "proxyquire": "^2.1.0", - "sinon": "^16.0.0", - "supertest": "^6.0.0" - } -} diff --git a/appengine/twilio/test/app.test.js b/appengine/twilio/test/app.test.js deleted file mode 100644 index 54399cbe9e..0000000000 --- a/appengine/twilio/test/app.test.js +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -'use strict'; -const Supertest = require('supertest'); -const assert = require('assert'); -const sinon = require('sinon'); -const proxyquire = require('proxyquire').noCallThru(); - -process.env.TWILIO_NUMBER = '+15005550006'; -process.env.TWILIO_ACCOUNT_SID = 'test'; -process.env.TWILIO_AUTH_TOKEN = 'test'; - -const getSample = () => { - const twilioMock = { - messages: { - create: sinon.stub().resolves(), - }, - }; - const twilioVoiceRespMock = { - say: sinon.stub().returns(), - }; - const twilioMessagingRespMock = { - message: sinon.stub().returns(), - }; - - const twilioStub = sinon.stub().returns(twilioMock); - twilioStub.twiml = { - VoiceResponse: sinon.stub().returns(twilioVoiceRespMock), - MessagingResponse: sinon.stub().returns(twilioMessagingRespMock), - }; - - const {app} = proxyquire('../app', {twilio: twilioStub}); - - return { - supertest: Supertest(app, { - twilio: twilioStub, - }), - mocks: { - twilio: twilioMock, - twilioVoiceRespMock: twilioVoiceRespMock, - twilioMessagingRespMock: twilioMessagingRespMock, - }, - }; -}; - -describe('gae_flex_twilio_send_sms', () => { - it('should send an SMS message', () => { - const {supertest} = getSample(); - - return supertest - .get('/sms/send') - .query({to: 1234}) - .expect(200) - .expect(response => { - assert.strictEqual(response.text, 'Message sent.'); - }); - }); -}); - -describe('gae_flex_twilio_receive_sms', () => { - it('should receive an SMS message', () => { - const {supertest, mocks} = getSample(); - - return supertest - .post('/sms/receive') - .send({From: 'Bob', Body: 'hi'}) - .type('form') - .expect(200) - .expect(() => { - assert( - mocks.twilioMessagingRespMock.message.calledWith( - 'Hello, Bob, you said: hi' - ) - ); - }); - }); -}); - -describe('gae_flex_twilio_receive_call', () => { - it('should receive a call', () => { - const {supertest, mocks} = getSample(); - - return supertest - .post('/call/receive') - .send() - .expect(200) - .expect(() => { - assert( - mocks.twilioVoiceRespMock.say.calledWith( - 'Hello from Google App Engine.' - ) - ); - }); - }); -});