From e39a6cf6b02050227f37c1e4c5d3b683c52082e3 Mon Sep 17 00:00:00 2001 From: sovanna Date: Mon, 6 Apr 2020 21:14:19 +0900 Subject: [PATCH] feat(issue22/server-flask): Adds basic python flask server --- server/.gitignore | 114 +++++++++++++++++++++++++++++++++++++ server/README.md | 0 server/app/__init__.py | 29 ++++++++++ server/app/api/__init__.py | 7 +++ server/app/api/routes.py | 38 +++++++++++++ server/config.py | 21 +++++++ server/main.py | 4 ++ server/requirements.txt | 10 ++++ 8 files changed, 223 insertions(+) create mode 100644 server/.gitignore create mode 100644 server/README.md create mode 100644 server/app/__init__.py create mode 100644 server/app/api/__init__.py create mode 100644 server/app/api/routes.py create mode 100644 server/config.py create mode 100644 server/main.py create mode 100644 server/requirements.txt diff --git a/server/.gitignore b/server/.gitignore new file mode 100644 index 0000000..b87e65c --- /dev/null +++ b/server/.gitignore @@ -0,0 +1,114 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.env-prod +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + + +# misc +build.sh +*.tar.gz +**/*/upldwl/*.jpg + +# nextjs +.next \ No newline at end of file diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..e69de29 diff --git a/server/app/__init__.py b/server/app/__init__.py new file mode 100644 index 0000000..406c603 --- /dev/null +++ b/server/app/__init__.py @@ -0,0 +1,29 @@ +from flask import Flask +from flask_cors import CORS +from flask_mail import Mail +from werkzeug.middleware.proxy_fix import ProxyFix + +import config + + +mail = Mail() + + +def create_app(cfg=config): + app = Flask(__name__) + app.config.from_object(cfg) + app.wsgi_app = ProxyFix(app.wsgi_app) + + mail.init_app(app) + + from app.api import bp as bp_api + + app.register_blueprint(bp_api) + + CORS( + app, + resources={r'/api/*': { + 'origins': '*', + }}) + + return app diff --git a/server/app/api/__init__.py b/server/app/api/__init__.py new file mode 100644 index 0000000..d01fe23 --- /dev/null +++ b/server/app/api/__init__.py @@ -0,0 +1,7 @@ +from flask import Blueprint + + +bp = Blueprint("api", __name__, url_prefix="/api") + + +from app.api import routes # nopep8 diff --git a/server/app/api/routes.py b/server/app/api/routes.py new file mode 100644 index 0000000..bb88fe0 --- /dev/null +++ b/server/app/api/routes.py @@ -0,0 +1,38 @@ +from flask import current_app +from flask import json +from flask import jsonify +from flask import make_response +from flask import request +from flask_mail import Message +from app.api import bp +from app import mail + + +@bp.route("/rfq", methods=["POST"]) +def send_rfq(): + payload = request.json + payload = json.loads(json.htmlsafe_dumps(payload)) + + if "email" not in payload: + resp = jsonify(error="missing email") + return make_response(resp, 400) + + if "body" not in payload: + resp = jsonify(error="missing body") + return make_response(resp, 400) + + recipient = current_app.config["MAIL_RECIPIENT"] + if current_app.debug: + recipient = "sovanna.xyz@gmail.com" + + msg = Message( + "RFQ from %s" % payload['email'], + sender=payload["email"], + recipients=[recipient]) + + msg.body = payload["body"] + msg.html = payload["body"] + + mail.send(msg) + + return jsonify("ok") diff --git a/server/config.py b/server/config.py new file mode 100644 index 0000000..1a10c1b --- /dev/null +++ b/server/config.py @@ -0,0 +1,21 @@ +from os import environ + + +def getenv(env, default=None): + envar = environ.get(env, default) + if envar is None: + raise ValueError('envvar %s is missing' % env) + return envar + + +DEBUG = True if getenv('FLASK_DEBUG') == 'True' else False +SECRET_KEY = getenv('FLASK_SECRET_KEY') + +MAIL_SERVER = getenv("FLASK_MAIL_SERVER") +MAIL_PORT = getenv("FLASK_MAIL_PORT") +MAIL_USE_SSL = getenv("FLASK_MAIL_USE_SSL") +MAIL_DEBUG = DEBUG +MAIL_USERNAME = getenv("FLASK_MAIL_USERNAME") +MAIL_PASSWORD = getenv("FLASK_MAIL_PASSWORD") + +MAIL_RECIPIENT = getenv("FLASK_MAIL_RECIPIENT") diff --git a/server/main.py b/server/main.py new file mode 100644 index 0000000..4d256fe --- /dev/null +++ b/server/main.py @@ -0,0 +1,4 @@ +from app import create_app + + +app = create_app() diff --git a/server/requirements.txt b/server/requirements.txt new file mode 100644 index 0000000..608b84b --- /dev/null +++ b/server/requirements.txt @@ -0,0 +1,10 @@ +blinker==1.4 +click==7.1.1 +Flask==1.1.2 +Flask-Cors==3.0.7 +Flask-Mail==0.9.1 +itsdangerous==1.1.0 +Jinja2==2.11.1 +MarkupSafe==1.1.1 +six==1.14.0 +Werkzeug==1.0.1