From 48a3be68953ec3267d181ba91a3d4a13223bd33b Mon Sep 17 00:00:00 2001 From: Jon Wayne Parrott Date: Tue, 3 May 2016 11:55:20 -0700 Subject: [PATCH] Adding mailjet samples for standard and flex (#318) Change-Id: I64b2fd1d4e1176e9fcbecf2f75592e78007e6a8a --- appengine/mailjet/.gitignore | 1 + appengine/mailjet/README.md | 11 ++++ appengine/mailjet/app.yaml | 14 +++++ appengine/mailjet/appengine_config.py | 18 ++++++ appengine/mailjet/main.py | 77 +++++++++++++++++++++++ appengine/mailjet/main_test.py | 53 ++++++++++++++++ appengine/mailjet/requirements.txt | 4 ++ appengine/mailjet/templates/index.html | 29 +++++++++ managed_vms/mailjet/README.md | 23 +++++++ managed_vms/mailjet/app.yaml | 13 ++++ managed_vms/mailjet/main.py | 78 ++++++++++++++++++++++++ managed_vms/mailjet/main_test.py | 53 ++++++++++++++++ managed_vms/mailjet/requirements.txt | 4 ++ managed_vms/mailjet/templates/index.html | 29 +++++++++ nox.py | 7 +++ requirements-python2.7-dev.txt | 33 +++++----- requirements-python3.4-dev.txt | 29 ++++----- 17 files changed, 446 insertions(+), 30 deletions(-) create mode 100644 appengine/mailjet/.gitignore create mode 100644 appengine/mailjet/README.md create mode 100644 appengine/mailjet/app.yaml create mode 100644 appengine/mailjet/appengine_config.py create mode 100644 appengine/mailjet/main.py create mode 100644 appengine/mailjet/main_test.py create mode 100644 appengine/mailjet/requirements.txt create mode 100644 appengine/mailjet/templates/index.html create mode 100644 managed_vms/mailjet/README.md create mode 100644 managed_vms/mailjet/app.yaml create mode 100644 managed_vms/mailjet/main.py create mode 100644 managed_vms/mailjet/main_test.py create mode 100644 managed_vms/mailjet/requirements.txt create mode 100644 managed_vms/mailjet/templates/index.html diff --git a/appengine/mailjet/.gitignore b/appengine/mailjet/.gitignore new file mode 100644 index 000000000000..a65b41774ad5 --- /dev/null +++ b/appengine/mailjet/.gitignore @@ -0,0 +1 @@ +lib diff --git a/appengine/mailjet/README.md b/appengine/mailjet/README.md new file mode 100644 index 000000000000..3880c174d4d3 --- /dev/null +++ b/appengine/mailjet/README.md @@ -0,0 +1,11 @@ +# Python Mailjet email sample for Google App Engine Standard + +This sample demonstrates how to use [Mailjet](https://www.mailgun.com) on [Google App Engine Standard](https://cloud.google.com/appengine/docs/). + +## Setup + +Before you can run or deploy the sample, you will need to do the following: + +1. [Create a Mailjet Account](http://www.mailjet.com/google). + +2. Configure your Mailjet settings in the environment variables section in ``app.yaml``. diff --git a/appengine/mailjet/app.yaml b/appengine/mailjet/app.yaml new file mode 100644 index 000000000000..467dd8e55bed --- /dev/null +++ b/appengine/mailjet/app.yaml @@ -0,0 +1,14 @@ +runtime: python27 +threadsafe: yes +api_version: 1 + +handlers: +- url: .* + script: main.app + +# [START env_variables] +env_variables: + MAILJET_API_KEY: your-mailjet-api-key + MAILJET_API_SECRET: your-mailjet-api-secret + MAILJET_SENDER: your-mailjet-sender-address +# [END env_variables] diff --git a/appengine/mailjet/appengine_config.py b/appengine/mailjet/appengine_config.py new file mode 100644 index 000000000000..c903d9a0ac5e --- /dev/null +++ b/appengine/mailjet/appengine_config.py @@ -0,0 +1,18 @@ +# Copyright 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. + +from google.appengine.ext import vendor + +# Add any libraries installed in the "lib" folder. +vendor.add('lib') diff --git a/appengine/mailjet/main.py b/appengine/mailjet/main.py new file mode 100644 index 000000000000..cd7c584e7512 --- /dev/null +++ b/appengine/mailjet/main.py @@ -0,0 +1,77 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +# [START app] +import logging +import os + +from flask import Flask, render_template, request +# [start config] +import mailjet_rest +import requests_toolbelt.adapters.appengine + +# Use the App Engine requests adapter to allow the requests library to be +# used on App Engine. +requests_toolbelt.adapters.appengine.monkeypatch() + +MAILJET_API_KEY = os.environ['MAILJET_API_KEY'] +MAILJET_API_SECRET = os.environ['MAILJET_API_SECRET'] +MAILJET_SENDER = os.environ['MAILJET_SENDER'] +# [END config] + +app = Flask(__name__) + + +# [START send_message] +def send_message(to): + client = mailjet_rest.Client( + auth=(MAILJET_API_KEY, MAILJET_API_SECRET)) + + data = { + 'FromEmail': MAILJET_SENDER, + 'FromName': 'App Engine Flex Mailjet Sample', + 'Subject': 'Example email.', + 'Text-part': 'This is an example email.', + 'Html-part': 'This is an example email.', + 'Recipients': [{'Email': to}] + } + + result = client.send.create(data=data) + + return result.json() +# [END send_message] + + +@app.route('/') +def index(): + return render_template('index.html') + + +@app.route('/send/email', methods=['POST']) +def send_email(): + to = request.form.get('to') + + result = send_message(to) + + return 'Email sent, response:
{}
'.format(result) + + +@app.errorhandler(500) +def server_error(e): + logging.exception('An error ocurred during a request.') + return """ + An internal error occurred:
{}
+ See logs for full stacktrace. + """.format(e), 500 +# [END app] diff --git a/appengine/mailjet/main_test.py b/appengine/mailjet/main_test.py new file mode 100644 index 000000000000..c910f48c544d --- /dev/null +++ b/appengine/mailjet/main_test.py @@ -0,0 +1,53 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +import re + +import pytest +import responses + + +@pytest.fixture +def app(monkeypatch): + monkeypatch.setenv('MAILJET_API_KEY', 'apikey') + monkeypatch.setenv('MAILJET_API_SECRET', 'apisecret') + monkeypatch.setenv('MAILJET_SENDER', 'sender') + + import main + + main.app.testing = True + return main.app.test_client() + + +def test_index(app): + r = app.get('/') + assert r.status_code == 200 + + +@responses.activate +def test_send_email(app): + responses.add( + responses.POST, + re.compile(r'.*'), + body='{"test": "message"}', + content_type='application/json') + + r = app.post('/send/email', data={'to': 'user@example.com'}) + + assert r.status_code == 200 + assert 'test' in r.data.decode('utf-8') + + assert len(responses.calls) == 1 + request_body = responses.calls[0].request.body + assert 'user@example.com' in request_body diff --git a/appengine/mailjet/requirements.txt b/appengine/mailjet/requirements.txt new file mode 100644 index 000000000000..62ae53b1605c --- /dev/null +++ b/appengine/mailjet/requirements.txt @@ -0,0 +1,4 @@ +Flask==0.10.1 +requests==2.10.0 +requests-toolbelt==0.6.0 +mailjet_rest==1.1.1 diff --git a/appengine/mailjet/templates/index.html b/appengine/mailjet/templates/index.html new file mode 100644 index 000000000000..cd1c93ff5b30 --- /dev/null +++ b/appengine/mailjet/templates/index.html @@ -0,0 +1,29 @@ +{# +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. +#} + + + + Mailjet on Google App Engine + + + +
+ + +
+ + + diff --git a/managed_vms/mailjet/README.md b/managed_vms/mailjet/README.md new file mode 100644 index 000000000000..0fb5d38e0b45 --- /dev/null +++ b/managed_vms/mailjet/README.md @@ -0,0 +1,23 @@ +# Python Mailjet email sample for Google App Engine Flexible + +This sample demonstrates how to use [Mailjet](https://www.mailgun.com) on [Google App Engine Flexible](https://cloud.google.com/appengine/docs/flexible/). + +## Setup + +Before you can run or deploy the sample, you will need to do the following: + +1. [Create a Mailjet Account](http://www.mailjet.com/google). + +2. Configure your Mailjet settings in the environment variables section in ``app.yaml``. + +## Running locally + +Refer to the [top-level README](../README.md) for instructions on running and deploying. + +You can run the application locally and send emails from your local machine. You +will need to set environment variables before starting your application: + + $ export MAILGUN_API_KEY=[your-mailgun-api-key] + $ export MAILGUN_API_SECRET=[your-mailgun-secret] + $ export MAILGUN_SENDER=[your-sender-address] + $ python main.py diff --git a/managed_vms/mailjet/app.yaml b/managed_vms/mailjet/app.yaml new file mode 100644 index 000000000000..760c968c4c39 --- /dev/null +++ b/managed_vms/mailjet/app.yaml @@ -0,0 +1,13 @@ +runtime: python +vm: true +entrypoint: gunicorn -b :$PORT main:app + +runtime_config: + python_version: 3 + +# [START env_variables] +env_variables: + MAILJET_API_KEY: your-mailjet-api-key + MAILJET_API_SECRET: your-mailjet-api-secret + MAILJET_SENDER: your-mailjet-sender-address +# [END env_variables] diff --git a/managed_vms/mailjet/main.py b/managed_vms/mailjet/main.py new file mode 100644 index 000000000000..f1ee0d9f3aeb --- /dev/null +++ b/managed_vms/mailjet/main.py @@ -0,0 +1,78 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +# [START app] +import logging +import os + +from flask import Flask, render_template, request +# [start config] +import mailjet_rest + +MAILJET_API_KEY = os.environ['MAILJET_API_KEY'] +MAILJET_API_SECRET = os.environ['MAILJET_API_SECRET'] +MAILJET_SENDER = os.environ['MAILJET_SENDER'] +# [END config] + +app = Flask(__name__) + + +# [START send_message] +def send_message(to): + client = mailjet_rest.Client( + auth=(MAILJET_API_KEY, MAILJET_API_SECRET)) + + data = { + 'FromEmail': MAILJET_SENDER, + 'FromName': 'App Engine Flex Mailjet Sample', + 'Subject': 'Example email.', + 'Text-part': 'This is an example email.', + 'Html-part': 'This is an example email.', + 'Recipients': [{'Email': to}] + } + + result = client.send.create(data=data) + + return result.json() +# [END send_message] + + +@app.route('/') +def index(): + return render_template('index.html') + + +@app.route('/send/email', methods=['POST']) +def send_email(): + to = request.form.get('to') + + result = send_message(to) + + return 'Email sent, response:
{}
'.format(result) + + +@app.errorhandler(500) +def server_error(e): + logging.exception('An error ocurred during a request.') + return """ + An internal error occurred:
{}
+ See logs for full stacktrace. + """.format(e), 500 + + +if __name__ == '__main__': + # This is used when running locally. Gunicorn is used to run the + # application on Google App Engine. See entrypoint in app.yaml. + app.run(host='127.0.0.1', port=8080, debug=True) +# [END app] diff --git a/managed_vms/mailjet/main_test.py b/managed_vms/mailjet/main_test.py new file mode 100644 index 000000000000..c910f48c544d --- /dev/null +++ b/managed_vms/mailjet/main_test.py @@ -0,0 +1,53 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + +import re + +import pytest +import responses + + +@pytest.fixture +def app(monkeypatch): + monkeypatch.setenv('MAILJET_API_KEY', 'apikey') + monkeypatch.setenv('MAILJET_API_SECRET', 'apisecret') + monkeypatch.setenv('MAILJET_SENDER', 'sender') + + import main + + main.app.testing = True + return main.app.test_client() + + +def test_index(app): + r = app.get('/') + assert r.status_code == 200 + + +@responses.activate +def test_send_email(app): + responses.add( + responses.POST, + re.compile(r'.*'), + body='{"test": "message"}', + content_type='application/json') + + r = app.post('/send/email', data={'to': 'user@example.com'}) + + assert r.status_code == 200 + assert 'test' in r.data.decode('utf-8') + + assert len(responses.calls) == 1 + request_body = responses.calls[0].request.body + assert 'user@example.com' in request_body diff --git a/managed_vms/mailjet/requirements.txt b/managed_vms/mailjet/requirements.txt new file mode 100644 index 000000000000..e4b43f039f07 --- /dev/null +++ b/managed_vms/mailjet/requirements.txt @@ -0,0 +1,4 @@ +Flask==0.10.1 +gunicorn==19.4.5 +requests[security]==2.9.1 +mailjet_rest==1.1.1 diff --git a/managed_vms/mailjet/templates/index.html b/managed_vms/mailjet/templates/index.html new file mode 100644 index 000000000000..19993c3547d8 --- /dev/null +++ b/managed_vms/mailjet/templates/index.html @@ -0,0 +1,29 @@ +{# +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. +#} + + + + Mailjet on Google App Engine Flexible + + + +
+ + +
+ + + diff --git a/nox.py b/nox.py index 8321bf4c1066..95ce2bf7cf5a 100644 --- a/nox.py +++ b/nox.py @@ -87,6 +87,7 @@ def session_tests(session, interpreter, extra_pytest_args=None): # allows users to run a particular test instead of all of them. for sample in (session.posargs or collect_sample_dirs('.', SESSION_TESTS_BLACKLIST)): + # Install additional dependencies if they exist dirname = sample if os.path.isdir(sample) else os.path.dirname(sample) for reqfile in list_files(dirname, 'requirements*.txt'): @@ -116,6 +117,12 @@ def session_gae(session, extra_pytest_args=None): pytest_args = COMMON_PYTEST_ARGS + (extra_pytest_args or []) for sample in (session.posargs or collect_sample_dirs('appengine')): + + # Install additional dependencies if they exist + dirname = sample if os.path.isdir(sample) else os.path.dirname(sample) + for reqfile in list_files(dirname, 'requirements*.txt'): + session.install('-r', reqfile) + session.run( 'py.test', sample, *pytest_args, diff --git a/requirements-python2.7-dev.txt b/requirements-python2.7-dev.txt index de342c04cb82..0f7c37da72d6 100644 --- a/requirements-python2.7-dev.txt +++ b/requirements-python2.7-dev.txt @@ -1,30 +1,31 @@ -gcloud==0.13.0 -google-api-python-client==1.5.0 -oauth2client==2.0.2 -requests[security]==2.9.1 beautifulsoup4==4.4.1 coverage==4.1b2 +Django==1.9.5 +flaky==3.1.1 +Flask-Sockets==0.2.0 +Flask-SQLAlchemy==2.1 Flask==0.10.1 funcsigs==1.0.1 +gcloud==0.13.0 +google-api-python-client==1.5.0 itsdangerous==0.24 Jinja2==2.8 MarkupSafe==0.23 mock==2.0.0 +mysql-python==1.2.5 +oauth2client==2.0.2 pbr==1.9.1 +PyCrypto==2.6.1 +pymemcache==1.3.5 +PyMySQL==0.7.2 +pytest-cov==2.2.1 +pytest==2.9.1 PyYAML==3.11 +requests[security]==2.9.1 +responses==0.5.1 +sendgrid==2.2.1 +twilio==6.3.dev0 waitress==0.9.0 WebOb==1.6.0 WebTest==2.0.21 Werkzeug==0.11.9 -Flask-SQLAlchemy==2.1 -PyMySQL==0.7.2 -pymemcache==1.3.5 -PyCrypto==2.6.1 -flaky==3.1.1 -Django==1.9.5 -twilio==6.3.dev0 -sendgrid==2.2.1 -Flask-Sockets==0.2.0 -mysql-python==1.2.5 -pytest==2.9.1 -pytest-cov==2.2.1 diff --git a/requirements-python3.4-dev.txt b/requirements-python3.4-dev.txt index 23ebf37ecbe2..ac09ab406a0c 100644 --- a/requirements-python3.4-dev.txt +++ b/requirements-python3.4-dev.txt @@ -1,28 +1,29 @@ -gcloud==0.13.0 -google-api-python-client==1.5.0 -oauth2client==2.0.2 -requests[security]==2.9.1 beautifulsoup4==4.4.1 coverage==4.1b2 +Django==1.9.5 +flaky==3.1.1 +Flask-SQLAlchemy==2.1 Flask==0.10.1 funcsigs==1.0.1 +gcloud==0.13.0 +google-api-python-client==1.5.0 itsdangerous==0.24 Jinja2==2.8 MarkupSafe==0.23 mock==2.0.0 +oauth2client==2.0.2 pbr==1.9.1 +PyCrypto==2.6.1 +pymemcache==1.3.5 +PyMySQL==0.7.2 +pytest-cov==2.2.1 +pytest==2.9.1 PyYAML==3.11 +requests[security]==2.9.1 +responses==0.5.1 +sendgrid==2.2.1 +twilio==6.3.dev0 waitress==0.9.0 WebOb==1.6.0 WebTest==2.0.21 Werkzeug==0.11.9 -Flask-SQLAlchemy==2.1 -PyMySQL==0.7.2 -pymemcache==1.3.5 -PyCrypto==2.6.1 -flaky==3.1.1 -Django==1.9.5 -twilio==6.3.dev0 -sendgrid==2.2.1 -pytest==2.9.1 -pytest-cov==2.2.1