├── Chapter-12 ├── tests │ └── __init__.py ├── webapp │ ├── static │ │ └── .keep │ ├── api │ │ ├── blog │ │ │ ├── __init__.py │ │ │ └── fields.py │ │ └── __init__.py │ ├── translations │ │ ├── __init__.py │ │ └── pt │ │ │ └── LC_MESSAGES │ │ │ ├── messages.mo │ │ │ └── messages.po │ ├── templates │ │ ├── footer.html │ │ ├── 404.html │ │ ├── admin │ │ │ ├── second_page.html │ │ │ ├── custom.html │ │ │ └── post_edit.html │ │ ├── blog │ │ │ ├── home.html │ │ │ ├── tag.html │ │ │ ├── user.html │ │ │ ├── rightbody.html │ │ │ └── new.html │ │ ├── head.html │ │ └── messages.html │ ├── main │ │ ├── __init__.py │ │ └── controllers.py │ ├── blog │ │ ├── __init__.py │ │ └── forms.py │ ├── babel │ │ ├── controllers.py │ │ └── __init__.py │ └── admin │ │ ├── forms.py │ │ ├── __init__.py │ │ └── controllers.py ├── Flask-YouTube │ ├── MANIFEST.in │ ├── flask_youtube │ │ ├── templates │ │ │ └── youtube │ │ │ │ └── video.html │ │ └── __init__.py │ └── setup.py ├── babel │ ├── babel.cfg │ └── messages.pot ├── install_flask_youtube.sh ├── nginx.conf ├── main.py ├── README.md ├── requirements.txt ├── run_test_server.py ├── celery_runner.py └── init.sh ├── Chapter-13 ├── tests │ └── __init__.py ├── webapp │ ├── static │ │ └── .keep │ ├── api │ │ ├── blog │ │ │ ├── __init__.py │ │ │ └── fields.py │ │ └── __init__.py │ ├── translations │ │ ├── __init__.py │ │ └── pt │ │ │ └── LC_MESSAGES │ │ │ ├── messages.mo │ │ │ └── messages.po │ ├── templates │ │ ├── footer.html │ │ ├── 404.html │ │ ├── admin │ │ │ ├── second_page.html │ │ │ ├── custom.html │ │ │ └── post_edit.html │ │ ├── blog │ │ │ ├── home.html │ │ │ ├── tag.html │ │ │ ├── user.html │ │ │ ├── rightbody.html │ │ │ └── new.html │ │ ├── head.html │ │ └── messages.html │ ├── main │ │ ├── __init__.py │ │ └── controllers.py │ ├── blog │ │ ├── __init__.py │ │ └── forms.py │ ├── babel │ │ ├── controllers.py │ │ └── __init__.py │ └── admin │ │ ├── forms.py │ │ ├── __init__.py │ │ └── controllers.py ├── .landscape.yml ├── Procfile ├── Flask-YouTube │ ├── MANIFEST.in │ ├── flask_youtube │ │ ├── templates │ │ │ └── youtube │ │ │ │ └── video.html │ │ └── __init__.py │ └── setup.py ├── deploy │ ├── supervisor_worker.conf │ ├── Jenkins │ │ ├── Dockerfile │ │ └── run.sh │ ├── uwsgi.ini │ └── docker │ │ ├── prod.env │ │ ├── Dockerfile_worker │ │ ├── Dockerfile_frontend │ │ ├── docker-compose.yml │ │ └── worker_entrypoint.sh ├── install_flask_youtube.sh ├── .gitignore ├── .dockerignore ├── babel │ ├── babel.cfg │ └── messages.pot ├── heroku-uwsgi.ini ├── wsgi.py ├── README.md ├── main.py ├── .ebextensions │ ├── 11_celery_start.config │ ├── 01_env.config │ └── 10_post_deploy.config ├── .travis.yml ├── application.py ├── requirements.txt ├── run_test_server.py ├── celery_runner.py └── init.sh ├── Chapter-10 ├── webapp │ ├── static │ │ └── .keep │ ├── api │ │ ├── blog │ │ │ ├── __init__.py │ │ │ ├── fields.py │ │ │ └── parsers.py │ │ └── __init__.py │ ├── translations │ │ ├── __init__.py │ │ └── pt │ │ │ └── LC_MESSAGES │ │ │ ├── messages.mo │ │ │ └── messages.po │ ├── templates │ │ ├── footer.html │ │ ├── 404.html │ │ ├── admin │ │ │ ├── second_page.html │ │ │ ├── custom.html │ │ │ └── post_edit.html │ │ ├── blog │ │ │ ├── home.html │ │ │ ├── tag.html │ │ │ ├── user.html │ │ │ ├── rightbody.html │ │ │ ├── new.html │ │ │ └── edit.html │ │ ├── head.html │ │ └── messages.html │ ├── main │ │ ├── __init__.py │ │ └── controllers.py │ ├── blog │ │ ├── __init__.py │ │ └── forms.py │ ├── babel │ │ ├── controllers.py │ │ └── __init__.py │ └── admin │ │ ├── forms.py │ │ ├── __init__.py │ │ └── controllers.py ├── babel │ ├── babel.cfg │ └── messages.pot ├── README.md ├── main.py ├── requirements.txt ├── docker-compose.yml ├── celery_runner.py ├── init.sh └── config.py ├── Chapter-11 ├── webapp │ ├── static │ │ └── .keep │ ├── api │ │ ├── blog │ │ │ ├── __init__.py │ │ │ └── fields.py │ │ └── __init__.py │ ├── translations │ │ ├── __init__.py │ │ └── pt │ │ │ └── LC_MESSAGES │ │ │ ├── messages.mo │ │ │ └── messages.po │ ├── templates │ │ ├── footer.html │ │ ├── 404.html │ │ ├── admin │ │ │ ├── second_page.html │ │ │ ├── custom.html │ │ │ └── post_edit.html │ │ ├── blog │ │ │ ├── home.html │ │ │ ├── tag.html │ │ │ ├── user.html │ │ │ ├── rightbody.html │ │ │ └── new.html │ │ ├── head.html │ │ └── messages.html │ ├── main │ │ ├── __init__.py │ │ └── controllers.py │ ├── blog │ │ ├── __init__.py │ │ └── forms.py │ ├── babel │ │ ├── controllers.py │ │ └── __init__.py │ └── admin │ │ ├── forms.py │ │ ├── __init__.py │ │ └── controllers.py ├── Flask-YouTube │ ├── MANIFEST.in │ ├── flask_youtube │ │ ├── templates │ │ │ └── youtube │ │ │ │ └── video.html │ │ └── __init__.py │ └── setup.py ├── babel │ ├── babel.cfg │ └── messages.pot ├── install_flask_youtube.sh ├── README.md ├── main.py ├── Flask-GZip │ ├── setup.py │ └── flask_gzip │ │ └── __init__.py ├── requirements.txt ├── celery_runner.py ├── init.sh └── config.py ├── Chapter-5 ├── webapp │ ├── blog │ │ ├── __init__.py │ │ └── forms.py │ ├── main │ │ ├── __init__.py │ │ └── controllers.py │ ├── templates │ │ ├── footer.html │ │ ├── 404.html │ │ ├── blog │ │ │ ├── home.html │ │ │ ├── tag.html │ │ │ ├── user.html │ │ │ └── rightbody.html │ │ ├── head.html │ │ ├── messages.html │ │ └── navbar.html │ └── __init__.py ├── requirements.txt ├── main.py ├── README.md ├── manage.py ├── config.py └── init.sh ├── Chapter-9 ├── webapp │ ├── static │ │ └── .keep │ ├── api │ │ ├── blog │ │ │ ├── __init__.py │ │ │ └── fields.py │ │ └── __init__.py │ ├── templates │ │ ├── footer.html │ │ ├── 404.html │ │ ├── blog │ │ │ ├── home.html │ │ │ ├── tag.html │ │ │ ├── user.html │ │ │ ├── rightbody.html │ │ │ ├── new.html │ │ │ └── edit.html │ │ ├── head.html │ │ └── messages.html │ ├── main │ │ ├── __init__.py │ │ └── controllers.py │ ├── blog │ │ ├── __init__.py │ │ └── forms.py │ └── __init__.py ├── Dockerfile ├── main.py ├── requirements.txt ├── manage.py ├── README.md ├── celery_runner.py ├── init.sh └── config.py ├── Chapter-8 ├── webapp │ ├── api │ │ ├── blog │ │ │ ├── __init__.py │ │ │ ├── fields.py │ │ │ └── parsers.py │ │ └── __init__.py │ ├── templates │ │ ├── footer.html │ │ ├── 404.html │ │ ├── blog │ │ │ ├── home.html │ │ │ ├── tag.html │ │ │ ├── user.html │ │ │ ├── rightbody.html │ │ │ ├── new.html │ │ │ └── edit.html │ │ ├── head.html │ │ └── messages.html │ ├── main │ │ ├── __init__.py │ │ └── controllers.py │ ├── blog │ │ ├── __init__.py │ │ ├── forms.py │ │ └── models.py │ └── __init__.py ├── main.py ├── requirements.txt ├── README.md ├── manage.py ├── config.py └── init.sh ├── Chapter-1 ├── requirements.txt ├── config.py ├── .gitignore ├── Dockerfile ├── README.md ├── init.sh └── main.py ├── Chapter-3 ├── alembic │ ├── README │ └── script.py.mako ├── templates │ ├── footer.html │ ├── home.html │ ├── head.html │ ├── tag.html │ ├── user.html │ ├── messages.html │ ├── rightbody.html │ └── navbar.html ├── requirements.txt ├── manage.py ├── README.md ├── config.py ├── init.sh └── alembic.ini ├── Chapter-2 ├── requirements.txt ├── manage.py ├── config.py ├── README.md └── init.sh ├── Chapter-4 ├── templates │ ├── blog │ │ ├── footer.html │ │ ├── home.html │ │ ├── head.html │ │ ├── tag.html │ │ ├── user.html │ │ ├── messages.html │ │ ├── rightbody.html │ │ └── navbar.html │ ├── 404.html │ └── generic_list.html ├── requirements.txt ├── manage.py ├── README.md ├── config.py └── init.sh ├── Chapter-6 ├── webapp │ ├── templates │ │ ├── footer.html │ │ ├── 404.html │ │ ├── blog │ │ │ ├── home.html │ │ │ ├── tag.html │ │ │ ├── user.html │ │ │ ├── rightbody.html │ │ │ ├── new.html │ │ │ └── edit.html │ │ ├── head.html │ │ └── messages.html │ ├── blog │ │ ├── __init__.py │ │ ├── forms.py │ │ └── models.py │ ├── main │ │ ├── __init__.py │ │ └── controllers.py │ └── __init__.py ├── requirements.txt ├── main.py ├── README.md ├── manage.py ├── config.py └── init.sh ├── Chapter-7 ├── webapp │ ├── templates │ │ ├── footer.html │ │ ├── 404.html │ │ ├── blog │ │ │ ├── home.html │ │ │ ├── tag.html │ │ │ ├── user.html │ │ │ ├── rightbody.html │ │ │ ├── new.html │ │ │ └── edit.html │ │ ├── head.html │ │ └── messages.html │ ├── blog │ │ ├── __init__.py │ │ ├── forms.py │ │ └── models.py │ ├── main │ │ ├── __init__.py │ │ └── controllers.py │ ├── __init__.py │ └── auth │ │ └── models.py ├── requirements.txt ├── init.sh ├── main.py ├── README.md ├── manage.py └── config.py ├── .gitignore ├── README.md └── NOTES.txt /Chapter-12/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-13/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-10/webapp/static/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-11/webapp/static/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-12/webapp/static/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-13/webapp/static/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-5/webapp/blog/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-5/webapp/main/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-9/webapp/static/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-10/webapp/api/blog/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-11/webapp/api/blog/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-12/webapp/api/blog/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-13/webapp/api/blog/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-8/webapp/api/blog/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-9/webapp/api/blog/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-10/webapp/translations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-11/webapp/translations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-12/webapp/translations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-13/webapp/translations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-1/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==0.12.4 2 | 3 | -------------------------------------------------------------------------------- /Chapter-3/alembic/README: -------------------------------------------------------------------------------- 1 | Generic single-database configuration. -------------------------------------------------------------------------------- /Chapter-3/templates/footer.html: -------------------------------------------------------------------------------- 1 | Hands on Web development with Flask - 2018 -------------------------------------------------------------------------------- /Chapter-2/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | Flask-sqlalchemy 3 | Flask-Migrate 4 | -------------------------------------------------------------------------------- /Chapter-4/templates/blog/footer.html: -------------------------------------------------------------------------------- 1 | Hands on Web development with Flask - 2018 -------------------------------------------------------------------------------- /Chapter-13/.landscape.yml: -------------------------------------------------------------------------------- 1 | ignore-paths: 2 | - migrations 3 | - deploy 4 | - babel 5 | -------------------------------------------------------------------------------- /Chapter-13/Procfile: -------------------------------------------------------------------------------- 1 | web: uwsgi heroku-uwsgi.ini 2 | celery: celery worker -A celery_runner 3 | -------------------------------------------------------------------------------- /Chapter-11/Flask-YouTube/MANIFEST.in: -------------------------------------------------------------------------------- 1 | prune *.pyc 2 | recursive-include flask_youtube/templates * 3 | -------------------------------------------------------------------------------- /Chapter-12/Flask-YouTube/MANIFEST.in: -------------------------------------------------------------------------------- 1 | prune *.pyc 2 | recursive-include flask_youtube/templates * 3 | -------------------------------------------------------------------------------- /Chapter-13/Flask-YouTube/MANIFEST.in: -------------------------------------------------------------------------------- 1 | prune *.pyc 2 | recursive-include flask_youtube/templates * 3 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Hands on Web development with Flask - 2018 3 |
-------------------------------------------------------------------------------- /Chapter-11/webapp/templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Hands on Web development with Flask - 2018 3 |
-------------------------------------------------------------------------------- /Chapter-12/webapp/templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Hands on Web development with Flask - 2018 3 |
-------------------------------------------------------------------------------- /Chapter-13/webapp/templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Hands on Web development with Flask - 2018 3 |
-------------------------------------------------------------------------------- /Chapter-5/webapp/templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Hands on Web development with Flask - 2018 3 |
-------------------------------------------------------------------------------- /Chapter-6/webapp/templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Hands on Web development with Flask - 2018 3 |
-------------------------------------------------------------------------------- /Chapter-7/webapp/templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Hands on Web development with Flask - 2018 3 |
-------------------------------------------------------------------------------- /Chapter-8/webapp/templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Hands on Web development with Flask - 2018 3 |
-------------------------------------------------------------------------------- /Chapter-9/webapp/templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | Hands on Web development with Flask - 2018 3 |
-------------------------------------------------------------------------------- /Chapter-13/deploy/supervisor_worker.conf: -------------------------------------------------------------------------------- 1 | [program:celery] 2 | command=celery worker -A celery_runner 3 | directory=/srv/app 4 | 5 | -------------------------------------------------------------------------------- /Chapter-13/install_flask_youtube.sh: -------------------------------------------------------------------------------- 1 | DIR=./Flask-YouTube 2 | cd $DIR 3 | python3 setup.py build 4 | python3 setup.py install 5 | 6 | -------------------------------------------------------------------------------- /Chapter-5/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask 2 | Flask-SQLAlchemy==2.3.2 3 | Flask-Migrate==2.1.1 4 | Flask-WTF==0.14.2 5 | Faker==0.8.13 6 | -------------------------------------------------------------------------------- /Chapter-3/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==0.12.4 2 | Flask-SQLAlchemy==2.3.2 3 | Flask-Migrate==2.1.1 4 | Flask-WTF==0.14.2 5 | Faker==0.8.13 6 | -------------------------------------------------------------------------------- /Chapter-4/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "blog/base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-4/requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==0.12.4 2 | Flask-SQLAlchemy==2.3.2 3 | Flask-Migrate==2.1.1 4 | Flask-WTF==0.14.2 5 | Faker==0.8.13 6 | 7 | -------------------------------------------------------------------------------- /Chapter-5/webapp/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-6/webapp/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-7/webapp/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-8/webapp/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-9/webapp/templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 |

Ups, Page not found!

4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /Chapter-13/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Elastic Beanstalk Files 3 | .elasticbeanstalk/* 4 | !.elasticbeanstalk/*.cfg.yml 5 | !.elasticbeanstalk/*.global.yml 6 | -------------------------------------------------------------------------------- /Chapter-13/.dockerignore: -------------------------------------------------------------------------------- 1 | venv 2 | venv3 3 | htmlcov 4 | init.sh 5 | run_test_server.py 6 | Dockerfile 7 | docker-compose.yml 8 | database.db 9 | 10 | -------------------------------------------------------------------------------- /Chapter-10/babel/babel.cfg: -------------------------------------------------------------------------------- 1 | [python: webapp/**.py] 2 | [jinja2: webapp/templates/**.html] 3 | encoding = utf-8 4 | extensions=jinja2.ext.autoescape,jinja2.ext.with_ 5 | -------------------------------------------------------------------------------- /Chapter-11/babel/babel.cfg: -------------------------------------------------------------------------------- 1 | [python: webapp/**.py] 2 | [jinja2: webapp/templates/**.html] 3 | encoding = utf-8 4 | extensions=jinja2.ext.autoescape,jinja2.ext.with_ 5 | -------------------------------------------------------------------------------- /Chapter-12/babel/babel.cfg: -------------------------------------------------------------------------------- 1 | [python: webapp/**.py] 2 | [jinja2: webapp/templates/**.html] 3 | encoding = utf-8 4 | extensions=jinja2.ext.autoescape,jinja2.ext.with_ 5 | -------------------------------------------------------------------------------- /Chapter-12/install_flask_youtube.sh: -------------------------------------------------------------------------------- 1 | DIR=./Flask-YouTube 2 | cd $DIR 3 | pip3 uninstall flask-youtube 4 | python3 setup.py build 5 | python3 setup.py install 6 | 7 | -------------------------------------------------------------------------------- /Chapter-13/babel/babel.cfg: -------------------------------------------------------------------------------- 1 | [python: webapp/**.py] 2 | [jinja2: webapp/templates/**.html] 3 | encoding = utf-8 4 | extensions=jinja2.ext.autoescape,jinja2.ext.with_ 5 | -------------------------------------------------------------------------------- /Chapter-13/deploy/Jenkins/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM jenkinsci/blueocean 2 | 3 | USER root 4 | RUN apk add build-base python3-dev mariadb-dev libffi-dev 5 | 6 | EXPOSE 8080 7 | -------------------------------------------------------------------------------- /Chapter-13/heroku-uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | http-socket = :$(PORT) 3 | die-on-term = true 4 | wsgi-file = wsgi.py 5 | callable = app 6 | processes = 4 7 | threads = 2 8 | -------------------------------------------------------------------------------- /Chapter-10/webapp/main/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import main_blueprint 4 | app.register_blueprint(main_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-11/webapp/main/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import main_blueprint 4 | app.register_blueprint(main_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-12/webapp/main/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import main_blueprint 4 | app.register_blueprint(main_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-13/webapp/main/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import main_blueprint 4 | app.register_blueprint(main_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-6/webapp/blog/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import blog_blueprint 4 | app.register_blueprint(blog_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-6/webapp/main/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import main_blueprint 4 | app.register_blueprint(main_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-7/webapp/blog/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import blog_blueprint 4 | app.register_blueprint(blog_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-7/webapp/main/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import main_blueprint 4 | app.register_blueprint(main_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-8/webapp/main/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import main_blueprint 4 | app.register_blueprint(main_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-9/webapp/main/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | def create_module(app, **kwargs): 3 | from .controllers import main_blueprint 4 | app.register_blueprint(main_blueprint) 5 | -------------------------------------------------------------------------------- /Chapter-1/config.py: -------------------------------------------------------------------------------- 1 | class Config(object): 2 | pass 3 | 4 | class ProdConfig(Config): 5 | pass 6 | 7 | class DevConfig(Config): 8 | DEBUG = True 9 | 10 | -------------------------------------------------------------------------------- /Chapter-8/webapp/blog/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def create_module(app, **kwargs): 4 | from .controllers import blog_blueprint 5 | app.register_blueprint(blog_blueprint) 6 | 7 | -------------------------------------------------------------------------------- /Chapter-1/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pem 3 | *.pub 4 | *.tar.gz 5 | *.zip 6 | *.sql 7 | *.db 8 | secrets.txt 9 | ./tmp 10 | ./build/* 11 | .idea/* 12 | .idea 13 | env 14 | venv 15 | 16 | -------------------------------------------------------------------------------- /Chapter-1/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.6.5 2 | 3 | WORKDIR /app 4 | 5 | ADD . /app 6 | 7 | RUN pip install -r requirements.txt 8 | 9 | EXPOSE 5000 10 | CMD ["python", "main.py"] 11 | 12 | -------------------------------------------------------------------------------- /Chapter-10/webapp/translations/pt/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Web-Development-with-Flask/HEAD/Chapter-10/webapp/translations/pt/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /Chapter-11/webapp/translations/pt/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Web-Development-with-Flask/HEAD/Chapter-11/webapp/translations/pt/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /Chapter-12/webapp/translations/pt/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Web-Development-with-Flask/HEAD/Chapter-12/webapp/translations/pt/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /Chapter-13/webapp/translations/pt/LC_MESSAGES/messages.mo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PacktPublishing/Hands-On-Web-Development-with-Flask/HEAD/Chapter-13/webapp/translations/pt/LC_MESSAGES/messages.mo -------------------------------------------------------------------------------- /Chapter-7/requirements.txt: -------------------------------------------------------------------------------- 1 | blinker 2 | Flask==1.0.2 3 | Flask-MongoEngine 4 | Flask-Login==0.4.1 5 | Flask-WTF==0.14.2 6 | flask-bcrypt 7 | flask-openid 8 | flask-dance 9 | Faker==0.8.13 10 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/admin/second_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | This is the second page! 5 | 6 | Link 7 | {% endblock %} -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/admin/second_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | This is the second page! 5 | 6 | Link 7 | {% endblock %} -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/admin/second_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | This is the second page! 5 | 6 | Link 7 | {% endblock %} -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/admin/second_page.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | This is the second page! 5 | 6 | Link 7 | {% endblock %} -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/admin/custom.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | This is the custom view! 5 | 6 | Link 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/admin/post_edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/model/edit.html' %} 2 | {% block tail %} 3 | {{ super() }} 4 | 5 | {% endblock %} -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/admin/custom.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | This is the custom view! 5 | 6 | Link 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/admin/post_edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/model/edit.html' %} 2 | {% block tail %} 3 | {{ super() }} 4 | 5 | {% endblock %} -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/admin/custom.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | This is the custom view! 5 | 6 | Link 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/admin/post_edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/model/edit.html' %} 2 | {% block tail %} 3 | {{ super() }} 4 | 5 | {% endblock %} -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/admin/custom.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block body %} 4 | This is the custom view! 5 | 6 | Link 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/admin/post_edit.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/model/edit.html' %} 2 | {% block tail %} 3 | {{ super() }} 4 | 5 | {% endblock %} -------------------------------------------------------------------------------- /Chapter-1/README.md: -------------------------------------------------------------------------------- 1 | Chapter 1 - Getting Started 2 | =========================== 3 | 4 | To run the application 5 | ---------------------- 6 | 7 | ``` 8 | ./init.sh 9 | export FLASK_APP=main.py 10 | flask run 11 | ``` 12 | -------------------------------------------------------------------------------- /Chapter-3/manage.py: -------------------------------------------------------------------------------- 1 | from main import app, db, User, Post, Tag, migrate 2 | 3 | 4 | @app.shell_context_processor 5 | def make_shell_context(): 6 | return dict(app=app, db=db, User=User, Post=Post, Tag=Tag, migrate=migrate) 7 | -------------------------------------------------------------------------------- /Chapter-4/manage.py: -------------------------------------------------------------------------------- 1 | from main import app, db, User, Post, Tag, migrate 2 | 3 | 4 | @app.shell_context_processor 5 | def make_shell_context(): 6 | return dict(app=app, db=db, User=User, Post=Post, Tag=Tag, migrate=migrate) 7 | -------------------------------------------------------------------------------- /Chapter-6/requirements.txt: -------------------------------------------------------------------------------- 1 | blinker 2 | Flask==1.0.2 3 | Flask-Login==0.4.1 4 | Flask-SQLAlchemy==2.3.2 5 | Flask-Migrate==2.1.1 6 | Flask-WTF==0.14.2 7 | flask-bcrypt 8 | flask-openid 9 | flask-dance 10 | Faker==0.8.13 11 | -------------------------------------------------------------------------------- /Chapter-9/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rabbitmq:3-management 2 | 3 | ENV RABBITMQ_ERLANG_COOKIE "SWQOKODSQALRPCLNMEQG" 4 | ENV RABBITMQ_DEFAULT_USER "rabbitmq" 5 | ENV RABBITMQ_DEFAULT_PASS "rabbitmq" 6 | ENV RABBITMQ_DEFAULT_VHOST "/" 7 | 8 | -------------------------------------------------------------------------------- /Chapter-2/manage.py: -------------------------------------------------------------------------------- 1 | from main import app, db, User, Post, Tag, migrate 2 | 3 | 4 | @app.shell_context_processor 5 | def make_shell_context(): 6 | return dict(app=app, db=db, User=User, Post=Post, Tag=Tag, migrate=migrate) 7 | 8 | 9 | -------------------------------------------------------------------------------- /Chapter-7/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | pip install -r requirements.txt 9 | -------------------------------------------------------------------------------- /Chapter-13/deploy/Jenkins/run.sh: -------------------------------------------------------------------------------- 1 | docker run \ 2 | --rm \ 3 | -u root \ 4 | -p 8080:8080 \ 5 | -v jenkins-data:/var/jenkins_home \ 6 | -v /var/run/docker.sock:/var/run/docker.sock \ 7 | -v "$HOME":/home \ 8 | jenkinsci/blueocean 9 | -------------------------------------------------------------------------------- /Chapter-13/wsgi.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from webapp.cli import register 4 | 5 | env = os.environ.get('WEBAPP_ENV', 'dev') 6 | application = create_app('config.%sConfig' % env.capitalize()) 7 | register(application) 8 | -------------------------------------------------------------------------------- /Chapter-5/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | 4 | env = os.environ.get('WEBAPP_ENV', 'dev') 5 | app = create_app('config.%sConfig' % env.capitalize()) 6 | 7 | 8 | if __name__ == '__main__': 9 | app.run() 10 | -------------------------------------------------------------------------------- /Chapter-6/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | 4 | env = os.environ.get('WEBAPP_ENV', 'dev') 5 | app = create_app('config.%sConfig' % env.capitalize()) 6 | 7 | 8 | if __name__ == '__main__': 9 | app.run() 10 | -------------------------------------------------------------------------------- /Chapter-7/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | 4 | env = os.environ.get('WEBAPP_ENV', 'dev') 5 | app = create_app('config.%sConfig' % env.capitalize()) 6 | 7 | 8 | if __name__ == '__main__': 9 | app.run() 10 | -------------------------------------------------------------------------------- /Chapter-8/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | 4 | env = os.environ.get('WEBAPP_ENV', 'dev') 5 | app = create_app('config.%sConfig' % env.capitalize()) 6 | 7 | 8 | if __name__ == '__main__': 9 | app.run() 10 | -------------------------------------------------------------------------------- /Chapter-9/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | 4 | env = os.environ.get('WEBAPP_ENV', 'dev') 5 | app = create_app('config.%sConfig' % env.capitalize()) 6 | 7 | 8 | if __name__ == '__main__': 9 | app.run() 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .coverage 2 | *.egg-info 3 | .eggs/ 4 | *.egg 5 | *.pyc 6 | *.db 7 | *.rdb 8 | */tmp 9 | build/ 10 | dist/ 11 | */docs/_build/ 12 | .idea 13 | .idea/ 14 | env 15 | venv 16 | venv3 17 | *.sublime* 18 | migrations 19 | htmlcov 20 | -------------------------------------------------------------------------------- /Chapter-3/README.md: -------------------------------------------------------------------------------- 1 | Chapter 3 - Creating Views with template 2 | ======================================== 3 | 4 | To run the application 5 | ---------------------- 6 | 7 | ``` 8 | ./init.sh 9 | export FLASK_APP=main.py 10 | flask run 11 | ``` 12 | -------------------------------------------------------------------------------- /Chapter-11/install_flask_youtube.sh: -------------------------------------------------------------------------------- 1 | DIR=/Users/daniel.gaspar/workspace/python/mastering_flask_v2/New_Code/Chapter_11/chapter_11/Flask-YouTube 2 | pushd $DIR 3 | pip uninstall flask-youtube 4 | python setup.py build 5 | python setup.py install 6 | popd 7 | 8 | -------------------------------------------------------------------------------- /Chapter-6/README.md: -------------------------------------------------------------------------------- 1 | Chapter 6 - Securing your app 2 | ============================= 3 | 4 | To run the application 5 | ---------------------- 6 | 7 | ``` 8 | ./init.sh 9 | source venv/bin/activate 10 | export FLASK_APP=main.py 11 | flask run 12 | ``` 13 | -------------------------------------------------------------------------------- /Chapter-11/Flask-YouTube/flask_youtube/templates/youtube/video.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-12/Flask-YouTube/flask_youtube/templates/youtube/video.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-13/Flask-YouTube/flask_youtube/templates/youtube/video.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Chapter-13/README.md: -------------------------------------------------------------------------------- 1 | Chapter 13 - Deploying Flask Apps 2 | ================================= 3 | 4 | To run the application 5 | ---------------------- 6 | 7 | ``` 8 | ./init.sh 9 | source venv/bin/activate 10 | export FLASK_APP=main.py 11 | flask run 12 | ``` 13 | -------------------------------------------------------------------------------- /Chapter-2/config.py: -------------------------------------------------------------------------------- 1 | class Config(object): 2 | SQLALCHEMY_TRACK_MODIFICATIONS = False 3 | 4 | 5 | class ProdConfig(Config): 6 | pass 7 | 8 | 9 | class DevConfig(Config): 10 | DEBUG = True 11 | SQLALCHEMY_DATABASE_URI = 'sqlite:///database.db' 12 | -------------------------------------------------------------------------------- /Chapter-3/templates/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | 6 | {{ macros.render_posts(posts) }} 7 | {{ macros.render_pagination(posts, 'home') }} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Chapter-4/README.md: -------------------------------------------------------------------------------- 1 | Chapter 4 - Creating Controllers with blueprints 2 | ================================================ 3 | 4 | To run the application 5 | ---------------------- 6 | 7 | ``` 8 | ./init.sh 9 | export FLASK_APP=main.py 10 | flask run 11 | ``` 12 | -------------------------------------------------------------------------------- /Chapter-7/README.md: -------------------------------------------------------------------------------- 1 | Chapter 7 - Using NoSQL with Flask 2 | ================================== 3 | 4 | To run the application 5 | ---------------------- 6 | 7 | ``` 8 | ./init.sh 9 | source venv/bin/activate 10 | export FLASK_APP=main.py 11 | flask run 12 | ``` 13 | -------------------------------------------------------------------------------- /Chapter-8/requirements.txt: -------------------------------------------------------------------------------- 1 | blinker 2 | Flask==1.0.2 3 | Flask-Login==0.4.1 4 | Flask-SQLAlchemy==2.3.2 5 | Flask-Migrate==2.1.1 6 | Flask-WTF==0.14.2 7 | flask-restful 8 | flask-jwt-extended 9 | flask-bcrypt 10 | flask-openid 11 | flask-dance 12 | Faker==0.8.13 13 | -------------------------------------------------------------------------------- /Chapter-3/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

Welcome to the blog!

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-8/README.md: -------------------------------------------------------------------------------- 1 | Chapter 8 - Building RESTful APIs 2 | ================================= 3 | 4 | To run the application 5 | ---------------------- 6 | 7 | ``` 8 | ./init.sh 9 | source venv/bin/activate 10 | export FLASK_APP=main.py 11 | flask run 12 | ``` 13 | 14 | -------------------------------------------------------------------------------- /Chapter-10/README.md: -------------------------------------------------------------------------------- 1 | Chapter 10 - Useful Flask Extensions 2 | ==================================== 3 | 4 | 5 | To run the application 6 | ---------------------- 7 | 8 | ``` 9 | ./init.sh 10 | source venv/bin/activate 11 | export FLASK_APP=main.py 12 | flask run 13 | ``` 14 | -------------------------------------------------------------------------------- /Chapter-12/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | root /usr/share/nginx/html; 4 | location / { 5 | try_files $uri @wsgi; 6 | } 7 | location @wsgi { 8 | include uwsgi_params; 9 | uwsgi_pass backend:3031; 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /Chapter-4/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | 6 | {{ macros.render_posts(posts) }} 7 | {{ macros.render_pagination(posts, 'blog.home') }} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Chapter-1/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ ! -d "venv" ]; then 4 | echo -------------------- 5 | echo Creating virtualenv 6 | echo -------------------- 7 | virtualenv venv 8 | fi 9 | source venv/bin/activate 10 | 11 | pip install -r requirements.txt 12 | -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | {{ macros.render_posts(posts) }} 6 | {{ macros.render_pagination(posts, 'blog.home') }} 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | {{ macros.render_posts(posts) }} 6 | {{ macros.render_pagination(posts, 'blog.home') }} 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | {{ macros.render_posts(posts) }} 6 | {{ macros.render_pagination(posts, 'blog.home') }} 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /Chapter-4/templates/blog/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

Welcome to the blog!

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-5/README.md: -------------------------------------------------------------------------------- 1 | Chapter 5 - Advanced application structure 2 | ========================================== 3 | 4 | To run the application 5 | ---------------------- 6 | 7 | ``` 8 | ./init.sh 9 | source venv/bin/activate 10 | export FLASK_APP=main.py 11 | flask run 12 | ``` 13 | -------------------------------------------------------------------------------- /Chapter-5/webapp/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | 6 | {{ macros.render_posts(posts) }} 7 | {{ macros.render_pagination(posts, 'blog.home') }} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Chapter-5/webapp/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

Welcome to the blog!

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-6/webapp/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | 6 | {{ macros.render_posts(posts) }} 7 | {{ macros.render_pagination(posts, 'blog.home') }} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Chapter-6/webapp/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

Welcome to the blog!

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-7/webapp/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | 6 | {{ macros.render_posts(posts) }} 7 | {{ macros.render_pagination(posts, 'blog.home') }} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Chapter-7/webapp/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

Welcome to the blog!

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-8/webapp/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | 6 | {{ macros.render_posts(posts) }} 7 | {{ macros.render_pagination(posts, 'blog.home') }} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Chapter-8/webapp/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

Welcome to the blog!

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-9/webapp/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | 6 | {{ macros.render_posts(posts) }} 7 | {{ macros.render_pagination(posts, 'blog.home') }} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Chapter-9/webapp/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

Welcome to the blog!

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-10/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from webapp.cli import register 4 | 5 | env = os.environ.get('WEBAPP_ENV', 'dev') 6 | app = create_app('config.%sConfig' % env.capitalize()) 7 | register(app) 8 | 9 | if __name__ == '__main__': 10 | app.run() 11 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/blog/home.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | {% block title %}Home{% endblock %} 4 | {% block leftbody %} 5 | 6 | {{ macros.render_posts(posts) }} 7 | {{ macros.render_pagination(posts, 'blog.home') }} 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /Chapter-11/README.md: -------------------------------------------------------------------------------- 1 | Chapter 11 - Building Your Own Extension 2 | ========================================= 3 | 4 | 5 | To run the application 6 | ---------------------- 7 | 8 | ``` 9 | ./init.sh 10 | source venv/bin/activate 11 | export FLASK_APP=main.py 12 | flask run 13 | ``` 14 | -------------------------------------------------------------------------------- /Chapter-11/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from webapp.cli import register 4 | 5 | env = os.environ.get('WEBAPP_ENV', 'dev') 6 | app = create_app('config.%sConfig' % env.capitalize()) 7 | register(app) 8 | 9 | if __name__ == '__main__': 10 | app.run() 11 | -------------------------------------------------------------------------------- /Chapter-12/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from webapp.cli import register 4 | 5 | env = os.environ.get('WEBAPP_ENV', 'dev') 6 | app = create_app('config.%sConfig' % env.capitalize()) 7 | register(app) 8 | 9 | if __name__ == '__main__': 10 | app.run() 11 | -------------------------------------------------------------------------------- /Chapter-13/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from webapp.cli import register 4 | 5 | env = os.environ.get('WEBAPP_ENV', 'dev') 6 | app = create_app('config.%sConfig' % env.capitalize()) 7 | register(app) 8 | 9 | if __name__ == '__main__': 10 | app.run() 11 | -------------------------------------------------------------------------------- /Chapter-2/README.md: -------------------------------------------------------------------------------- 1 | Chapter 2 - Creating Models with SQLAlchemy 2 | =========================================== 3 | 4 | To run the application 5 | ---------------------- 6 | 7 | ``` 8 | ./init.sh 9 | source venv/bin/activate 10 | export FLASK_APP=main.py 11 | flask run 12 | ``` 13 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

{{_('Welcome to this Blog')}}

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

{{_('Welcome to this Blog')}}

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

{{_('Welcome to this Blog')}}

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/head.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |

My Blog

5 |

{{_('Welcome to this Blog')}}

6 |
7 |
8 | -------------------------------------------------------------------------------- /Chapter-13/deploy/uwsgi.ini: -------------------------------------------------------------------------------- 1 | [uwsgi] 2 | chdir = /srv/app 3 | wsgi-file=/srv/app/wsgi.py 4 | 5 | socket = /tmp/uwsgi.sock 6 | chown-socket = nginx:nginx 7 | chmod-socket = 664 8 | 9 | processes = 30 10 | 11 | vacuum = true 12 | max-requests = 5000 13 | harakiri = 30 14 | buffer-size=32768 15 | -------------------------------------------------------------------------------- /Chapter-9/requirements.txt: -------------------------------------------------------------------------------- 1 | blinker 2 | Flask==1.0.2 3 | Flask-Login==0.4.1 4 | Flask-SQLAlchemy==2.3.2 5 | Flask-Migrate==2.1.1 6 | Flask-WTF==0.14.2 7 | flask-restful 8 | flask-jwt-extended 9 | Faker==0.8.13 10 | flask-bcrypt 11 | flask-openid 12 | flask-dance 13 | celery 14 | flask-celery-helper 15 | -------------------------------------------------------------------------------- /Chapter-13/webapp/main/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for 2 | 3 | main_blueprint = Blueprint( 4 | 'main', 5 | __name__, 6 | template_folder='../templates/main' 7 | ) 8 | 9 | 10 | @main_blueprint.route('/') 11 | def index(): 12 | return redirect(url_for('blog.home')) 13 | -------------------------------------------------------------------------------- /Chapter-10/webapp/main/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, render_template 2 | 3 | main_blueprint = Blueprint( 4 | 'main', 5 | __name__, 6 | template_folder='../templates/main' 7 | ) 8 | 9 | 10 | @main_blueprint.route('/') 11 | def index(): 12 | return redirect(url_for('blog.home')) 13 | -------------------------------------------------------------------------------- /Chapter-11/webapp/main/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, render_template 2 | 3 | main_blueprint = Blueprint( 4 | 'main', 5 | __name__, 6 | template_folder='../templates/main' 7 | ) 8 | 9 | 10 | @main_blueprint.route('/') 11 | def index(): 12 | return redirect(url_for('blog.home')) 13 | -------------------------------------------------------------------------------- /Chapter-12/webapp/main/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, render_template 2 | 3 | main_blueprint = Blueprint( 4 | 'main', 5 | __name__, 6 | template_folder='../templates/main' 7 | ) 8 | 9 | 10 | @main_blueprint.route('/') 11 | def index(): 12 | return redirect(url_for('blog.home')) 13 | -------------------------------------------------------------------------------- /Chapter-5/webapp/main/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, render_template 2 | 3 | main_blueprint = Blueprint( 4 | 'main', 5 | __name__, 6 | template_folder='../templates/main' 7 | ) 8 | 9 | 10 | @main_blueprint.route('/') 11 | def index(): 12 | return redirect(url_for('blog.home')) 13 | -------------------------------------------------------------------------------- /Chapter-6/webapp/main/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, render_template 2 | 3 | main_blueprint = Blueprint( 4 | 'main', 5 | __name__, 6 | template_folder='../templates/main' 7 | ) 8 | 9 | 10 | @main_blueprint.route('/') 11 | def index(): 12 | return redirect(url_for('blog.home')) 13 | -------------------------------------------------------------------------------- /Chapter-7/webapp/main/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, render_template 2 | 3 | main_blueprint = Blueprint( 4 | 'main', 5 | __name__, 6 | template_folder='../templates/main' 7 | ) 8 | 9 | 10 | @main_blueprint.route('/') 11 | def index(): 12 | return redirect(url_for('blog.home')) 13 | -------------------------------------------------------------------------------- /Chapter-8/webapp/main/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, render_template 2 | 3 | main_blueprint = Blueprint( 4 | 'main', 5 | __name__, 6 | template_folder='../templates/main' 7 | ) 8 | 9 | 10 | @main_blueprint.route('/') 11 | def index(): 12 | return redirect(url_for('blog.home')) 13 | -------------------------------------------------------------------------------- /Chapter-9/webapp/main/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, redirect, url_for, render_template 2 | 3 | main_blueprint = Blueprint( 4 | 'main', 5 | __name__, 6 | template_folder='../templates/main' 7 | ) 8 | 9 | 10 | @main_blueprint.route('/') 11 | def index(): 12 | return redirect(url_for('blog.home')) 13 | -------------------------------------------------------------------------------- /Chapter-1/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from config import DevConfig 3 | 4 | app = Flask(__name__) 5 | app.config.from_object(DevConfig) 6 | 7 | # Changed to show the git diff command 8 | @app.route('/') 9 | def home(): 10 | return '

Hello world

' 11 | 12 | if __name__ == '__main__': 13 | app.run(host='0.0.0.0') 14 | -------------------------------------------------------------------------------- /Chapter-13/.ebextensions/11_celery_start.config: -------------------------------------------------------------------------------- 1 | commands: 2 | celery_start: 3 | command: | 4 | #!/usr/bin/env bash 5 | cd /opt/python/current/app 6 | . /opt/python/current/env 7 | source /opt/python/run/venv/bin/activate 8 | celery multi start worker1 -A celery_runner 9 | -------------------------------------------------------------------------------- /Chapter-13/webapp/blog/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import event 2 | from .models import Reminder 3 | from .tasks import on_reminder_save 4 | 5 | 6 | def create_module(app, **kwargs): 7 | event.listen(Reminder, 'after_insert', on_reminder_save) 8 | from .controllers import blog_blueprint 9 | app.register_blueprint(blog_blueprint) 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hands-On-Web-Development-with-Flask 2 | Hands-On Web Development with Flask_Published by Packt 3 | 4 | # The code for this repository is under development :construction_worker: 5 | 6 | This is an example Blog application that includes: 7 | 8 | - Authentication using DB, Oauth and OpenID 9 | - Role based access control 10 | 11 | -------------------------------------------------------------------------------- /Chapter-10/webapp/blog/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import event 2 | from .models import db, Reminder 3 | from .tasks import on_reminder_save 4 | 5 | 6 | def create_module(app, **kwargs): 7 | event.listen(Reminder, 'after_insert', on_reminder_save) 8 | from .controllers import blog_blueprint 9 | app.register_blueprint(blog_blueprint) 10 | -------------------------------------------------------------------------------- /Chapter-11/webapp/blog/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import event 2 | from .models import db, Reminder 3 | from .tasks import on_reminder_save 4 | 5 | 6 | def create_module(app, **kwargs): 7 | event.listen(Reminder, 'after_insert', on_reminder_save) 8 | from .controllers import blog_blueprint 9 | app.register_blueprint(blog_blueprint) 10 | -------------------------------------------------------------------------------- /Chapter-12/webapp/blog/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import event 2 | from .models import db, Reminder 3 | from .tasks import on_reminder_save 4 | 5 | 6 | def create_module(app, **kwargs): 7 | event.listen(Reminder, 'after_insert', on_reminder_save) 8 | from .controllers import blog_blueprint 9 | app.register_blueprint(blog_blueprint) 10 | -------------------------------------------------------------------------------- /Chapter-13/.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "3.5" 4 | - "3.3" 5 | - "2.7" 6 | install: 7 | - "pip install --upgrade" 8 | - "pip -V" 9 | - "pip install -r requirements.txt" 10 | - "pip install coveralls" 11 | script: 12 | - coverage run --source webapp --branch -m unittest discover 13 | after_success: 14 | coveralls 15 | -------------------------------------------------------------------------------- /Chapter-8/webapp/api/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_restful import Api 2 | from .blog.controllers import PostApi 3 | 4 | rest_api = Api() 5 | 6 | 7 | def create_module(app, **kwargs): 8 | 9 | rest_api.add_resource( 10 | PostApi, 11 | '/api/post', 12 | '/api/post/', 13 | ) 14 | rest_api.init_app(app) 15 | -------------------------------------------------------------------------------- /Chapter-13/.ebextensions/01_env.config: -------------------------------------------------------------------------------- 1 | 2 | option_settings: 3 | aws:elasticbeanstalk:application:environment: 4 | WEBAPP_ENV: Prod 5 | DB_URI: mysql://admin:password@myblog.c4pdwhkmbyqm.eu-central-1.rds.amazonaws.com:3306/myblog 6 | CELERY_BROKER_URL: sqs://sqs.us-east-1.amazonaws.com/arn:aws:sqs:eu-central-1:633393569065:myblog-sqs/myblog-sqs 7 | -------------------------------------------------------------------------------- /Chapter-9/webapp/blog/__init__.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import event 2 | from .models import db, Reminder 3 | from .tasks import on_reminder_save 4 | 5 | 6 | def create_module(app, **kwargs): 7 | event.listen(Reminder, 'after_insert', on_reminder_save) 8 | from .controllers import blog_blueprint 9 | app.register_blueprint(blog_blueprint) 10 | 11 | 12 | -------------------------------------------------------------------------------- /Chapter-10/webapp/babel/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, session, redirect, url_for 2 | 3 | babel_blueprint = Blueprint( 4 | 'babel', 5 | __name__, 6 | url_prefix="/babel" 7 | ) 8 | 9 | 10 | @babel_blueprint.route('/') 11 | def index(locale): 12 | session['locale'] = locale 13 | return redirect(url_for('blog.home')) 14 | -------------------------------------------------------------------------------- /Chapter-11/webapp/babel/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, session, redirect, url_for 2 | 3 | babel_blueprint = Blueprint( 4 | 'babel', 5 | __name__, 6 | url_prefix="/babel" 7 | ) 8 | 9 | 10 | @babel_blueprint.route('/') 11 | def index(locale): 12 | session['locale'] = locale 13 | return redirect(url_for('blog.home')) 14 | -------------------------------------------------------------------------------- /Chapter-12/webapp/babel/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, session, redirect, url_for 2 | 3 | babel_blueprint = Blueprint( 4 | 'babel', 5 | __name__, 6 | url_prefix="/babel" 7 | ) 8 | 9 | 10 | @babel_blueprint.route('/') 11 | def index(locale): 12 | session['locale'] = locale 13 | return redirect(url_for('blog.home')) 14 | -------------------------------------------------------------------------------- /Chapter-13/webapp/babel/controllers.py: -------------------------------------------------------------------------------- 1 | from flask import Blueprint, session, redirect, url_for 2 | 3 | babel_blueprint = Blueprint( 4 | 'babel', 5 | __name__, 6 | url_prefix="/babel" 7 | ) 8 | 9 | 10 | @babel_blueprint.route('/') 11 | def index(locale): 12 | session['locale'] = locale 13 | return redirect(url_for('blog.home')) 14 | -------------------------------------------------------------------------------- /Chapter-7/manage.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import mongo, create_app 3 | from webapp.blog.models import User, Post 4 | 5 | 6 | env = os.environ.get('WEBAPP_ENV', 'dev') 7 | app = create_app('config.%sConfig' % env.capitalize()) 8 | 9 | 10 | @app.shell_context_processor 11 | def make_shell_context(): 12 | return dict(app=app, mongo=mongo, User=User, Post=Post) 13 | -------------------------------------------------------------------------------- /Chapter-5/manage.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import db, migrate, create_app 3 | from webapp.blog.models import User, Post, Tag 4 | 5 | 6 | env = os.environ.get('WEBAPP_ENV', 'dev') 7 | app = create_app('config.%sConfig' % env.capitalize()) 8 | 9 | 10 | @app.shell_context_processor 11 | def make_shell_context(): 12 | return dict(app=app, db=db, User=User, Post=Post, Tag=Tag, migrate=migrate) 13 | -------------------------------------------------------------------------------- /Chapter-5/webapp/blog/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm as Form 2 | from wtforms import StringField, TextAreaField 3 | from wtforms.validators import DataRequired, Length 4 | 5 | 6 | class CommentForm(Form): 7 | name = StringField( 8 | 'Name', 9 | validators=[DataRequired(), Length(max=255)] 10 | ) 11 | text = TextAreaField(u'Comment', validators=[DataRequired()]) 12 | -------------------------------------------------------------------------------- /Chapter-3/templates/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-4/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-10/webapp/admin/forms.py: -------------------------------------------------------------------------------- 1 | from wtforms import ( 2 | widgets, 3 | TextAreaField 4 | ) 5 | 6 | 7 | class CKTextAreaWidget(widgets.TextArea): 8 | def __call__(self, field, **kwargs): 9 | kwargs.setdefault('class_', 'ckeditor') 10 | return super(CKTextAreaWidget, self).__call__(field, **kwargs) 11 | 12 | 13 | class CKTextAreaField(TextAreaField): 14 | widget = CKTextAreaWidget() 15 | -------------------------------------------------------------------------------- /Chapter-11/webapp/admin/forms.py: -------------------------------------------------------------------------------- 1 | from wtforms import ( 2 | widgets, 3 | TextAreaField 4 | ) 5 | 6 | 7 | class CKTextAreaWidget(widgets.TextArea): 8 | def __call__(self, field, **kwargs): 9 | kwargs.setdefault('class_', 'ckeditor') 10 | return super(CKTextAreaWidget, self).__call__(field, **kwargs) 11 | 12 | 13 | class CKTextAreaField(TextAreaField): 14 | widget = CKTextAreaWidget() 15 | -------------------------------------------------------------------------------- /Chapter-12/webapp/admin/forms.py: -------------------------------------------------------------------------------- 1 | from wtforms import ( 2 | widgets, 3 | TextAreaField 4 | ) 5 | 6 | 7 | class CKTextAreaWidget(widgets.TextArea): 8 | def __call__(self, field, **kwargs): 9 | kwargs.setdefault('class_', 'ckeditor') 10 | return super(CKTextAreaWidget, self).__call__(field, **kwargs) 11 | 12 | 13 | class CKTextAreaField(TextAreaField): 14 | widget = CKTextAreaWidget() 15 | -------------------------------------------------------------------------------- /Chapter-13/webapp/admin/forms.py: -------------------------------------------------------------------------------- 1 | from wtforms import ( 2 | widgets, 3 | TextAreaField 4 | ) 5 | 6 | 7 | class CKTextAreaWidget(widgets.TextArea): 8 | def __call__(self, field, **kwargs): 9 | kwargs.setdefault('class_', 'ckeditor') 10 | return super(CKTextAreaWidget, self).__call__(field, **kwargs) 11 | 12 | 13 | class CKTextAreaField(TextAreaField): 14 | widget = CKTextAreaWidget() 15 | -------------------------------------------------------------------------------- /Chapter-7/webapp/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-11/Flask-GZip/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='Flask-GZip', 5 | version='0.1', 6 | license='MIT', 7 | description='Flask extension to allow easy GZip compressing of web pagess', 8 | author='Jack Stouffer', 9 | author_email='example@gmail.com', 10 | platforms='any', 11 | install_requires=['Flask'], 12 | packages=find_packages() 13 | ) 14 | -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-3/templates/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-5/webapp/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-6/webapp/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-8/webapp/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-9/webapp/templates/blog/tag.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ tag.title }}{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts With Tag {{ tag.title }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-4/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-5/webapp/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-6/manage.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import db, migrate, create_app 3 | from webapp.auth.models import User 4 | from webapp.blog.models import Post, Tag 5 | 6 | 7 | env = os.environ.get('WEBAPP_ENV', 'dev') 8 | app = create_app('config.%sConfig' % env.capitalize()) 9 | 10 | 11 | @app.shell_context_processor 12 | def make_shell_context(): 13 | return dict(app=app, db=db, User=User, Post=Post, Tag=Tag, migrate=migrate) 14 | -------------------------------------------------------------------------------- /Chapter-6/webapp/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-7/webapp/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-8/manage.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import db, migrate, create_app 3 | from webapp.auth.models import User 4 | from webapp.blog.models import Post, Tag 5 | 6 | 7 | env = os.environ.get('WEBAPP_ENV', 'dev') 8 | app = create_app('config.%sConfig' % env.capitalize()) 9 | 10 | 11 | @app.shell_context_processor 12 | def make_shell_context(): 13 | return dict(app=app, db=db, User=User, Post=Post, Tag=Tag, migrate=migrate) 14 | -------------------------------------------------------------------------------- /Chapter-8/webapp/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-9/webapp/templates/blog/user.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% import 'macros.html' as macros %} 3 | 4 | {% block title %}{{ user.username }}'s Posts{% endblock %} 5 | {% block leftbody %} 6 |
7 |
8 |

Posts By {{ user.username }}

9 |
10 |
11 | {{ macros.render_posts(posts, pagination=False) }} 12 | 13 | {% endblock %} 14 | -------------------------------------------------------------------------------- /Chapter-13/deploy/docker/prod.env: -------------------------------------------------------------------------------- 1 | WEBAPP_ENV=Prod 2 | DB_HOST=db 3 | DB_URI=mysql://myblog:password@db:3306/myblog 4 | CELERY_BROKER_URL=amqp://rabbitmq:rabbitmq@rmq:5672// 5 | REDIS_HOST=redis 6 | MYSQL_ROOT_PASSWORD=rootpassword 7 | MYSQL_DATABASE=myblog 8 | MYSQL_USER=myblog 9 | MYSQL_PASSWORD=password 10 | RABBITMQ_ERLANG_COOKIE=SWQOKODSQALRPCLNMEQG 11 | RABBITMQ_DEFAULT_USER=rabbitmq 12 | RABBITMQ_DEFAULT_PASS=rabbitmq 13 | RABBITMQ_DEFAULT_VHOST=/ 14 | -------------------------------------------------------------------------------- /Chapter-3/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-12/README.md: -------------------------------------------------------------------------------- 1 | Chapter 12 - Testing Flask Apps 2 | ================================ 3 | 4 | 5 | To run the application 6 | ---------------------- 7 | 8 | ``` 9 | ./init.sh 10 | source venv/bin/activate 11 | export FLASK_APP=main.py 12 | flask run 13 | ``` 14 | 15 | Run the tests and coverage 16 | -------------------------- 17 | 18 | ``` 19 | python run_test_server.py & 20 | coverage run --source webapp --branch -m unittest discover 21 | ``` 22 | 23 | -------------------------------------------------------------------------------- /Chapter-4/templates/blog/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-4/templates/generic_list.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block body %} 3 | 4 |
5 | 6 | {% for obj in objects %} 7 | 8 | {% for col in columns %} 9 | 12 | {% endfor %} 13 | 14 | {% endfor %} 15 |
10 | {{col}} {{ obj[col] }} 11 |
16 |
17 | 18 | {% endblock %} 19 | -------------------------------------------------------------------------------- /Chapter-9/manage.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import db, migrate, create_app, celery 3 | from webapp.auth.models import User 4 | from webapp.blog.models import Post, Tag 5 | 6 | 7 | env = os.environ.get('WEBAPP_ENV', 'dev') 8 | app = create_app('config.%sConfig' % env.capitalize()) 9 | 10 | 11 | @app.shell_context_processor 12 | def make_shell_context(): 13 | return dict(app=app, db=db, User=User, Post=Post, Tag=Tag, migrate=migrate, celery=celery) 14 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-5/webapp/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-6/webapp/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-7/webapp/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-8/webapp/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-9/webapp/templates/messages.html: -------------------------------------------------------------------------------- 1 | {% with messages = get_flashed_messages(with_categories=true) %} 2 | {% if messages %} 3 | {% for category, message in messages %} 4 | 8 | {% endfor %} 9 | {% endif %} 10 | {% endwith %} 11 | -------------------------------------------------------------------------------- /Chapter-10/requirements.txt: -------------------------------------------------------------------------------- 1 | click 2 | blinker 3 | enum 4 | redis 5 | Flask==1.0.2 6 | Flask-Login==0.4.1 7 | Flask-SQLAlchemy==2.3.2 8 | Flask-Migrate==2.1.1 9 | Flask-WTF==0.14.2 10 | flask-restful 11 | flask-jwt-extended 12 | flask-debugtoolbar 13 | flask-admin 14 | Flask-Caching 15 | Flask-Babel==0.11.1 16 | Flask-Mail 17 | Faker==0.8.13 18 | Flask-Assets 19 | cssmin 20 | jsmin 21 | flask-bcrypt 22 | flask-openid 23 | flask-dance 24 | celery 25 | flask-celery-helper 26 | -------------------------------------------------------------------------------- /Chapter-11/requirements.txt: -------------------------------------------------------------------------------- 1 | click 2 | blinker 3 | enum 4 | redis 5 | Flask==1.0.2 6 | Flask-Login==0.4.1 7 | Flask-SQLAlchemy==2.3.2 8 | Flask-Migrate==2.1.1 9 | Flask-WTF==0.14.2 10 | flask-restful 11 | flask-jwt-extended 12 | flask-debugtoolbar 13 | flask-admin 14 | Flask-Caching 15 | Flask-Babel==0.11.1 16 | Flask-Mail 17 | Faker==0.8.13 18 | Flask-Assets 19 | cssmin 20 | jsmin 21 | flask-bcrypt 22 | flask-openid 23 | flask-dance 24 | celery 25 | flask-celery-helper 26 | -------------------------------------------------------------------------------- /Chapter-13/deploy/docker/Dockerfile_worker: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | RUN apt-get update && \ 3 | apt-get install -y supervisor python3-pip python3-dev libmysqlclient-dev mysql-client 4 | RUN mkdir /srv/app 5 | WORKDIR /srv/app 6 | COPY . . 7 | RUN pip3 install -r requirements.txt 8 | RUN sh install_flask_youtube.sh 9 | 10 | COPY ./deploy/supervisor_worker.conf /etc/supervisor/conf.d/celery_worker.conf 11 | COPY ./deploy/docker/worker_entrypoint.sh . 12 | ENTRYPOINT ["sh", "./worker_entrypoint.sh"] 13 | -------------------------------------------------------------------------------- /Chapter-10/webapp/api/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_restful import Api 2 | from .blog.controllers import PostApi, ReminderApi 3 | 4 | rest_api = Api() 5 | 6 | 7 | def create_module(app, **kwargs): 8 | 9 | rest_api.add_resource( 10 | PostApi, 11 | '/api/post', 12 | '/api/post/', 13 | ) 14 | rest_api.add_resource( 15 | ReminderApi, 16 | '/api/reminder', 17 | '/api/reminder/', 18 | ) 19 | rest_api.init_app(app) 20 | -------------------------------------------------------------------------------- /Chapter-11/webapp/api/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_restful import Api 2 | from .blog.controllers import PostApi, ReminderApi 3 | 4 | rest_api = Api() 5 | 6 | 7 | def create_module(app, **kwargs): 8 | 9 | rest_api.add_resource( 10 | PostApi, 11 | '/api/post', 12 | '/api/post/', 13 | ) 14 | rest_api.add_resource( 15 | ReminderApi, 16 | '/api/reminder', 17 | '/api/reminder/', 18 | ) 19 | rest_api.init_app(app) 20 | -------------------------------------------------------------------------------- /Chapter-12/webapp/api/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_restful import Api 2 | from .blog.controllers import PostApi, ReminderApi 3 | 4 | rest_api = Api() 5 | 6 | 7 | def create_module(app, **kwargs): 8 | 9 | rest_api.add_resource( 10 | PostApi, 11 | '/api/post', 12 | '/api/post/', 13 | ) 14 | rest_api.add_resource( 15 | ReminderApi, 16 | '/api/reminder', 17 | '/api/reminder/', 18 | ) 19 | rest_api.init_app(app) 20 | -------------------------------------------------------------------------------- /Chapter-13/application.py: -------------------------------------------------------------------------------- 1 | # Used for AWS ElasticBeanstalk deploy 2 | 3 | import os 4 | from webapp import create_app 5 | from webapp.cli import register 6 | from dotenv import load_dotenv 7 | 8 | # Patch for elasticbeanstalk not loading env vars 9 | EB_ENV_FILE='/opt/python/current/env' 10 | if os.path.isfile(EB_ENV_FILE): 11 | load_dotenv(EB_ENV_FILE) 12 | 13 | env = os.environ.get('WEBAPP_ENV', 'dev') 14 | application = create_app('config.%sConfig' % env.capitalize()) 15 | register(application) 16 | -------------------------------------------------------------------------------- /Chapter-13/webapp/api/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_restful import Api 2 | from .blog.controllers import PostApi, ReminderApi 3 | 4 | rest_api = Api() 5 | 6 | 7 | def create_module(app, **kwargs): 8 | 9 | rest_api.add_resource( 10 | PostApi, 11 | '/api/post', 12 | '/api/post/', 13 | ) 14 | rest_api.add_resource( 15 | ReminderApi, 16 | '/api/reminder', 17 | '/api/reminder/', 18 | ) 19 | rest_api.init_app(app) 20 | -------------------------------------------------------------------------------- /Chapter-9/webapp/api/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_restful import Api 2 | from .blog.controllers import PostApi, ReminderApi 3 | 4 | rest_api = Api() 5 | 6 | 7 | def create_module(app, **kwargs): 8 | 9 | rest_api.add_resource( 10 | PostApi, 11 | '/api/post', 12 | '/api/post/', 13 | ) 14 | rest_api.add_resource( 15 | ReminderApi, 16 | '/api/reminder', 17 | '/api/reminder/', 18 | ) 19 | rest_api.init_app(app) 20 | -------------------------------------------------------------------------------- /Chapter-12/requirements.txt: -------------------------------------------------------------------------------- 1 | mysqlclient 2 | click 3 | blinker 4 | redis 5 | enum 6 | Flask==1.0.2 7 | Flask-Login==0.4.1 8 | Flask-SQLAlchemy==2.3.2 9 | Flask-Migrate==2.1.1 10 | Flask-WTF==0.14.2 11 | flask-restful 12 | flask-jwt-extended 13 | flask-debugtoolbar 14 | flask-admin 15 | Flask-Caching 16 | Flask-Babel==0.11.1 17 | Flask-Mail 18 | Faker==0.8.13 19 | Flask-Assets 20 | cssmin 21 | jsmin 22 | flask-bcrypt 23 | flask-openid 24 | flask-dance 25 | celery 26 | flask-celery-helper 27 | selenium 28 | coverage 29 | -------------------------------------------------------------------------------- /Chapter-13/requirements.txt: -------------------------------------------------------------------------------- 1 | mysqlclient 2 | click 3 | blinker 4 | redis 5 | Flask==0.12.4 6 | Flask-Login>0.3.0 7 | Flask-SQLAlchemy==2.3.2 8 | Flask-Migrate==2.1.1 9 | Flask-WTF==0.14.2 10 | flask-restful 11 | flask-jwt-extended 12 | flask-debugtoolbar 13 | flask-admin 14 | Flask-Caching 15 | Flask-Babel==0.11.1 16 | Flask-Mail 17 | Faker==0.8.13 18 | Flask-Assets 19 | cssmin 20 | jsmin 21 | flask-bcrypt 22 | flask-openid 23 | flask-dance 24 | celery 25 | flask-celery-helper 26 | selenium 27 | python-dotenv 28 | 29 | -------------------------------------------------------------------------------- /Chapter-12/run_test_server.py: -------------------------------------------------------------------------------- 1 | from webapp import create_app 2 | from webapp import db 3 | from webapp.auth.models import User, Role 4 | 5 | app = create_app('config.TestConfig') 6 | 7 | db.app = app 8 | db.create_all() 9 | 10 | default = Role("default") 11 | poster = Role("poster") 12 | db.session.add(default) 13 | db.session.add(poster) 14 | db.session.commit() 15 | 16 | test_user = User("test") 17 | test_user.set_password("test") 18 | test_user.roles.append(poster) 19 | db.session.add(test_user) 20 | db.session.commit() 21 | 22 | app.run() 23 | -------------------------------------------------------------------------------- /Chapter-13/deploy/docker/Dockerfile_frontend: -------------------------------------------------------------------------------- 1 | FROM tiangolo/uwsgi-nginx:python3.6 2 | 3 | # Create and set directory where the code will live 4 | RUN mkdir /srv/app 5 | WORKDIR /srv/app 6 | 7 | # Copy our code 8 | COPY . . 9 | # Install all python packages required 10 | RUN pip install -r requirements.txt 11 | RUN sh install_flask_youtube.sh 12 | 13 | # Setup NGINX and uWSGI 14 | COPY ./deploy/uwsgi.ini /etc/uwsgi/uwsgi.ini 15 | ENV NGINX_WORKER_OPEN_FILES 2048 16 | ENV NGINX_WORKER_CONNECTIONS 2048 17 | ENV LISTEN_PORT 80 18 | 19 | EXPOSE 80 20 | -------------------------------------------------------------------------------- /Chapter-13/run_test_server.py: -------------------------------------------------------------------------------- 1 | from webapp import create_app 2 | from webapp import db 3 | from webapp.auth.models import User, Role 4 | 5 | app = create_app('config.TestConfig') 6 | 7 | db.app = app 8 | db.create_all() 9 | 10 | default = Role("default") 11 | poster = Role("poster") 12 | db.session.add(default) 13 | db.session.add(poster) 14 | db.session.commit() 15 | 16 | test_user = User("test") 17 | test_user.set_password("test") 18 | test_user.roles.append(poster) 19 | db.session.add(test_user) 20 | db.session.commit() 21 | 22 | app.run() 23 | -------------------------------------------------------------------------------- /Chapter-3/config.py: -------------------------------------------------------------------------------- 1 | class Config(object): 2 | POSTS_PER_PAGE = 10 3 | 4 | 5 | class ProdConfig(Config): 6 | SECRET_KEY = '\xcb\xd7\x8a.\x82\x9c1Lu\xf1&2\xf6i\xfa\x8e\xb1\xc9t^\xccW\xdbw' 7 | SQLALCHEMY_TRACK_MODIFICATIONS = False 8 | SQLALCHEMY_DATABASE_URI = 'sqlite:///database.db' 9 | 10 | 11 | class DevConfig(Config): 12 | DEBUG = True 13 | SECRET_KEY = '\xa8\xcc\xeaP+\xb3\xe8 |\xad\xdb\xea\xd0\xd4\xe8\xac\xee\xfaW\x072@O3' 14 | SQLALCHEMY_TRACK_MODIFICATIONS = True 15 | SQLALCHEMY_DATABASE_URI = 'sqlite:///database.db' 16 | -------------------------------------------------------------------------------- /Chapter-4/config.py: -------------------------------------------------------------------------------- 1 | class Config(object): 2 | POSTS_PER_PAGE = 10 3 | 4 | 5 | class ProdConfig(Config): 6 | SECRET_KEY = '\xcb\xd7\x8a.\x82\x9c1Lu\xf1&2\xf6i\xfa\x8e\xb1\xc9t^\xccW\xdbw' 7 | SQLALCHEMY_TRACK_MODIFICATIONS = False 8 | SQLALCHEMY_DATABASE_URI = 'sqlite:///database.db' 9 | 10 | 11 | class DevConfig(Config): 12 | DEBUG = True 13 | SECRET_KEY = '\xa8\xcc\xeaP+\xb3\xe8 |\xad\xdb\xea\xd0\xd4\xe8\xac\xee\xfaW\x072@O3' 14 | SQLALCHEMY_TRACK_MODIFICATIONS = True 15 | SQLALCHEMY_DATABASE_URI = 'sqlite:///database.db' 16 | -------------------------------------------------------------------------------- /Chapter-10/webapp/babel/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import has_request_context, session 2 | from flask_babel import Babel 3 | 4 | babel = Babel() 5 | 6 | 7 | @babel.localeselector 8 | def get_locale(): 9 | if has_request_context(): 10 | locale = session.get('locale') 11 | if locale: 12 | return locale 13 | session['locale'] = 'en' 14 | return session['locale'] 15 | 16 | 17 | def create_module(app, **kwargs): 18 | babel.init_app(app) 19 | from .controllers import babel_blueprint 20 | app.register_blueprint(babel_blueprint) 21 | -------------------------------------------------------------------------------- /Chapter-11/webapp/babel/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import has_request_context, session 2 | from flask_babel import Babel 3 | 4 | babel = Babel() 5 | 6 | 7 | @babel.localeselector 8 | def get_locale(): 9 | if has_request_context(): 10 | locale = session.get('locale') 11 | if locale: 12 | return locale 13 | session['locale'] = 'en' 14 | return session['locale'] 15 | 16 | 17 | def create_module(app, **kwargs): 18 | babel.init_app(app) 19 | from .controllers import babel_blueprint 20 | app.register_blueprint(babel_blueprint) 21 | -------------------------------------------------------------------------------- /Chapter-12/webapp/babel/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import has_request_context, session 2 | from flask_babel import Babel 3 | 4 | babel = Babel() 5 | 6 | 7 | @babel.localeselector 8 | def get_locale(): 9 | if has_request_context(): 10 | locale = session.get('locale') 11 | if locale: 12 | return locale 13 | session['locale'] = 'en' 14 | return session['locale'] 15 | 16 | 17 | def create_module(app, **kwargs): 18 | babel.init_app(app) 19 | from .controllers import babel_blueprint 20 | app.register_blueprint(babel_blueprint) 21 | -------------------------------------------------------------------------------- /Chapter-13/webapp/babel/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import has_request_context, session 2 | from flask_babel import Babel 3 | 4 | babel = Babel() 5 | 6 | 7 | @babel.localeselector 8 | def get_locale(): 9 | if has_request_context(): 10 | locale = session.get('locale') 11 | if locale: 12 | return locale 13 | session['locale'] = 'en' 14 | return session['locale'] 15 | 16 | 17 | def create_module(app, **kwargs): 18 | babel.init_app(app) 19 | from .controllers import babel_blueprint 20 | app.register_blueprint(babel_blueprint) 21 | -------------------------------------------------------------------------------- /Chapter-9/README.md: -------------------------------------------------------------------------------- 1 | Chapter 9 - Creating Asynchronous Tasks with Celery 2 | =================================================== 3 | 4 | 5 | To run the application 6 | ---------------------- 7 | 8 | ``` 9 | ./init.sh 10 | source venv/bin/activate 11 | export FLASK_APP=main.py 12 | flask run 13 | ``` 14 | 15 | 16 | Run RabbitMQ 17 | ------------ 18 | 19 | ``` 20 | docker build -t blog-rmq . 21 | docker run -d -p 15672:15672 -p 5672:5672 blog-rmq 22 | ``` 23 | 24 | 25 | Run celery worker 26 | ----------------- 27 | 28 | ``` 29 | celery -A celery_runner worker -l info 30 | ``` 31 | -------------------------------------------------------------------------------- /Chapter-6/webapp/blog/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm as Form 2 | from wtforms import StringField, TextAreaField 3 | from wtforms.validators import DataRequired, Length 4 | 5 | 6 | class CommentForm(Form): 7 | name = StringField( 8 | 'Name', 9 | validators=[DataRequired(), Length(max=255)] 10 | ) 11 | text = TextAreaField(u'Comment', validators=[DataRequired()]) 12 | 13 | class PostForm(Form): 14 | title = StringField('Title', [ 15 | DataRequired(), 16 | Length(max=255) 17 | ]) 18 | text = TextAreaField('Content', [DataRequired()]) 19 | -------------------------------------------------------------------------------- /Chapter-10/webapp/blog/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm as Form 2 | from wtforms import StringField, TextAreaField 3 | from wtforms.validators import DataRequired, Length 4 | 5 | 6 | class CommentForm(Form): 7 | name = StringField( 8 | 'Name', 9 | validators=[DataRequired(), Length(max=255)] 10 | ) 11 | text = TextAreaField(u'Comment', validators=[DataRequired()]) 12 | 13 | 14 | class PostForm(Form): 15 | title = StringField('Title', [ 16 | DataRequired(), 17 | Length(max=255) 18 | ]) 19 | text = TextAreaField('Content', [DataRequired()]) 20 | -------------------------------------------------------------------------------- /Chapter-7/webapp/blog/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm as Form 2 | from wtforms import StringField, TextAreaField 3 | from wtforms.validators import DataRequired, Length 4 | 5 | 6 | class CommentForm(Form): 7 | name = StringField( 8 | 'Name', 9 | validators=[DataRequired(), Length(max=255)] 10 | ) 11 | text = TextAreaField(u'Comment', validators=[DataRequired()]) 12 | 13 | 14 | class PostForm(Form): 15 | title = StringField('Title', [ 16 | DataRequired(), 17 | Length(max=255) 18 | ]) 19 | text = TextAreaField('Content', [DataRequired()]) 20 | -------------------------------------------------------------------------------- /Chapter-8/webapp/blog/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm as Form 2 | from wtforms import StringField, TextAreaField 3 | from wtforms.validators import DataRequired, Length 4 | 5 | 6 | class CommentForm(Form): 7 | name = StringField( 8 | 'Name', 9 | validators=[DataRequired(), Length(max=255)] 10 | ) 11 | text = TextAreaField(u'Comment', validators=[DataRequired()]) 12 | 13 | 14 | class PostForm(Form): 15 | title = StringField('Title', [ 16 | DataRequired(), 17 | Length(max=255) 18 | ]) 19 | text = TextAreaField('Content', [DataRequired()]) 20 | -------------------------------------------------------------------------------- /Chapter-9/webapp/blog/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm as Form 2 | from wtforms import StringField, TextAreaField 3 | from wtforms.validators import DataRequired, Length 4 | 5 | 6 | class CommentForm(Form): 7 | name = StringField( 8 | 'Name', 9 | validators=[DataRequired(), Length(max=255)] 10 | ) 11 | text = TextAreaField(u'Comment', validators=[DataRequired()]) 12 | 13 | 14 | class PostForm(Form): 15 | title = StringField('Title', [ 16 | DataRequired(), 17 | Length(max=255) 18 | ]) 19 | text = TextAreaField('Content', [DataRequired()]) 20 | -------------------------------------------------------------------------------- /Chapter-10/docker-compose.yml: -------------------------------------------------------------------------------- 1 | rabbit1: 2 | container_name: rabbitmq 3 | image: "rabbitmq:3-management" 4 | hostname: "rabbit1" 5 | environment: 6 | RABBITMQ_ERLANG_COOKIE: "SWQOKODSQALRPCLNMEQG" 7 | RABBITMQ_DEFAULT_USER: "rabbitmq" 8 | RABBITMQ_DEFAULT_PASS: "rabbitmq" 9 | RABBITMQ_DEFAULT_VHOST: "/" 10 | ports: 11 | - "15672:15672" 12 | - "5672:5672" 13 | labels: 14 | NAME: "blog-rmq" 15 | redis: 16 | container_name: redis 17 | image: redis 18 | ports: 19 | - "6379:6379" 20 | volumes: 21 | - ../data/redis:/data 22 | restart: always 23 | 24 | -------------------------------------------------------------------------------- /Chapter-5/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | basedir = os.path.abspath(os.path.dirname(__file__)) 4 | 5 | 6 | class Config(object): 7 | SECRET_KEY = '736670cb10a600b695a55839ca3a5aa54a7d7356cdef815d2ad6e19a2031182b' 8 | POSTS_PER_PAGE = 10 9 | 10 | 11 | class ProdConfig(Config): 12 | SQLALCHEMY_TRACK_MODIFICATIONS = False 13 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 14 | 15 | 16 | class DevConfig(Config): 17 | DEBUG = True 18 | SQLALCHEMY_TRACK_MODIFICATIONS = True 19 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 20 | -------------------------------------------------------------------------------- /Chapter-3/alembic/script.py.mako: -------------------------------------------------------------------------------- 1 | """${message} 2 | 3 | Revision ID: ${up_revision} 4 | Revises: ${down_revision | comma,n} 5 | Create Date: ${create_date} 6 | 7 | """ 8 | 9 | # revision identifiers, used by Alembic. 10 | revision = ${repr(up_revision)} 11 | down_revision = ${repr(down_revision)} 12 | branch_labels = ${repr(branch_labels)} 13 | depends_on = ${repr(depends_on)} 14 | 15 | from alembic import op 16 | import sqlalchemy as sa 17 | ${imports if imports else ""} 18 | 19 | def upgrade(): 20 | ${upgrades if upgrades else "pass"} 21 | 22 | 23 | def downgrade(): 24 | ${downgrades if downgrades else "pass"} 25 | -------------------------------------------------------------------------------- /Chapter-11/webapp/blog/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm as Form 2 | from wtforms import StringField, TextAreaField 3 | from wtforms.validators import DataRequired, Length 4 | 5 | 6 | class CommentForm(Form): 7 | name = StringField( 8 | 'Name', 9 | validators=[DataRequired(), Length(max=255)] 10 | ) 11 | text = TextAreaField(u'Comment', validators=[DataRequired()]) 12 | 13 | 14 | class PostForm(Form): 15 | title = StringField('Title', [DataRequired(),Length(max=255)]) 16 | youtube_id = StringField('Youtube video id', [Length(max=255)]) 17 | text = TextAreaField('Content', [DataRequired()]) 18 | -------------------------------------------------------------------------------- /Chapter-12/webapp/blog/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm as Form 2 | from wtforms import StringField, TextAreaField 3 | from wtforms.validators import DataRequired, Length 4 | 5 | 6 | class CommentForm(Form): 7 | name = StringField( 8 | 'Name', 9 | validators=[DataRequired(), Length(max=255)] 10 | ) 11 | text = TextAreaField(u'Comment', validators=[DataRequired()]) 12 | 13 | 14 | class PostForm(Form): 15 | title = StringField('Title', [DataRequired(),Length(max=255)]) 16 | youtube_id = StringField('Youtube video id', [Length(max=255)]) 17 | text = TextAreaField('Content', [DataRequired()]) 18 | -------------------------------------------------------------------------------- /Chapter-13/webapp/blog/forms.py: -------------------------------------------------------------------------------- 1 | from flask_wtf import FlaskForm as Form 2 | from wtforms import StringField, TextAreaField 3 | from wtforms.validators import DataRequired, Length 4 | 5 | 6 | class CommentForm(Form): 7 | name = StringField( 8 | 'Name', 9 | validators=[DataRequired(), Length(max=255)] 10 | ) 11 | text = TextAreaField(u'Comment', validators=[DataRequired()]) 12 | 13 | 14 | class PostForm(Form): 15 | title = StringField('Title', [DataRequired(), Length(max=255)]) 16 | youtube_id = StringField('Youtube video id', [Length(max=255)]) 17 | text = TextAreaField('Content', [DataRequired()]) 18 | -------------------------------------------------------------------------------- /Chapter-7/config.py: -------------------------------------------------------------------------------- 1 | class Config(object): 2 | SECRET_KEY = '736670cb10a600b695a55839ca3a5aa54a7d7356cdef815d2ad6e19a2031182b' 3 | RECAPTCHA_PUBLIC_KEY = "6LdKkQQTAAAAAEH0GFj7NLg5tGicaoOus7G9Q5Uw" 4 | RECAPTCHA_PRIVATE_KEY = '6LdKkQQTAAAAAMYroksPTJ7pWhobYb88fTAcxcYn' 5 | POSTS_PER_PAGE = 10 6 | 7 | TWITTER_API_KEY = "XXXX" 8 | TWITTER_API_SECRET = "XXXX" 9 | FACEBOOK_CLIENT_ID = "XXX" 10 | FACEBOOK_CLIENT_SECRET = "XXXX" 11 | 12 | 13 | class DevConfig(Config): 14 | DEBUG = True 15 | MONGODB_SETTINGS = { 16 | 'db': 'local', 17 | 'host': 'localhost', 18 | 'port': 27017 19 | } 20 | -------------------------------------------------------------------------------- /Chapter-13/deploy/docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | db: 4 | image: mysql:5.7 5 | env_file: 6 | - prod.env 7 | rmq: 8 | image: rabbitmq:3-management 9 | env_file: 10 | - prod.env 11 | ports: 12 | - 15672:15672 13 | redis: 14 | container_name: redis 15 | image: redis 16 | worker: 17 | image: myblog_worker:latest 18 | depends_on: 19 | - db 20 | - rmq 21 | env_file: 22 | - prod.env 23 | frontend: 24 | image: myblog 25 | depends_on: 26 | - db 27 | - rmq 28 | env_file: 29 | - prod.env 30 | restart: always 31 | ports: 32 | - 80:80 33 | -------------------------------------------------------------------------------- /Chapter-3/templates/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Recent Posts
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
Popular Tags
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-13/webapp/admin/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_admin import Admin 2 | from .. import db 3 | from .controllers import CustomModelView, CustomView, CustomFileAdmin 4 | from webapp.blog.models import Post, Comment, Reminder, Tag 5 | from webapp.auth.models import User, Role 6 | 7 | admin = Admin() 8 | 9 | 10 | def create_module(app, **kwargs): 11 | admin.init_app(app) 12 | admin.add_view(CustomView(name='Custom')) 13 | 14 | models = [User, Role, Post, Comment, Reminder, Tag] 15 | 16 | for model in models: 17 | admin.add_view(CustomModelView(model, db.session, category='Models')) 18 | 19 | admin.add_view(CustomFileAdmin(app.static_folder, 20 | '/static/', name='Static Files')) 21 | -------------------------------------------------------------------------------- /Chapter-4/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Recent Posts
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
Popular Tags
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-5/webapp/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Recent Posts
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
Popular Tags
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-6/webapp/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Recent Posts
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
Popular Tags
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-7/webapp/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Recent Posts
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
Popular Tags
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-8/webapp/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Recent Posts
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
Popular Tags
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-9/webapp/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
Recent Posts
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
Popular Tags
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /NOTES.txt: -------------------------------------------------------------------------------- 1 | blog/controllers.py 2 | 3 | def home(page=1): 4 | posts = Post.query.order_by(Post.publish_date.desc()).paginate(page, 5 | current_app.config.get('POSTS_PER_PAGE', 10), 6 | False) 7 | 8 | def new_post(): 9 | ... 10 | remove datetime.datetime.now 11 | 12 | 13 | def edit_post(): 14 | .. 15 | # replace add by merge 16 | db.session.merge(post) 17 | 18 | Check requirements.txt 19 | 20 | Change test_data.py (generate_users) 21 | 22 | Update manage.py 23 | 24 | - Update api 25 | 26 | - Update config.py with CELERY_RESULT_BACKEND 27 | 28 | - Update celery_runner.py 29 | 30 | - Update all admin module 31 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{_('Recent Posts')}}
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
{{_('Popular Tags')}}
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{_('Recent Posts')}}
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
{{_('Popular Tags')}}
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{_('Recent Posts')}}
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
{{_('Popular Tags')}}
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/blog/rightbody.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
{{_('Recent Posts')}}
4 |
5 |
6 |
    7 | {% for post in recent %} 8 |
  • 9 | {{ post.title }} 10 |
  • 11 | {% endfor %} 12 |
13 |
14 |
15 |
{{_('Popular Tags')}}
16 |
17 |
18 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Chapter-10/webapp/admin/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_admin import Admin 2 | from .. import db 3 | from .controllers import CustomModelView, CustomView, CustomFileAdmin, PostView 4 | from webapp.blog.models import Post, Comment, Reminder, Tag 5 | from webapp.auth.models import User, Role 6 | 7 | admin = Admin() 8 | 9 | 10 | def create_module(app, **kwargs): 11 | admin.init_app(app) 12 | admin.add_view(CustomView(name='Custom')) 13 | 14 | models = [User, Role, Comment, Reminder, Tag] 15 | 16 | for model in models: 17 | admin.add_view(CustomModelView(model, db.session, category='Models')) 18 | 19 | admin.add_view(PostView(Post, db.session, category='Models')) 20 | admin.add_view(CustomFileAdmin(app.static_folder, '/static/', name='Static Files')) 21 | -------------------------------------------------------------------------------- /Chapter-11/webapp/admin/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_admin import Admin 2 | from .. import db 3 | from .controllers import CustomModelView, CustomView, CustomFileAdmin, PostView 4 | from webapp.blog.models import Post, Comment, Reminder, Tag 5 | from webapp.auth.models import User, Role 6 | 7 | admin = Admin() 8 | 9 | 10 | def create_module(app, **kwargs): 11 | admin.init_app(app) 12 | admin.add_view(CustomView(name='Custom')) 13 | 14 | models = [User, Role, Comment, Reminder, Tag] 15 | 16 | for model in models: 17 | admin.add_view(CustomModelView(model, db.session, category='Models')) 18 | 19 | admin.add_view(PostView(Post, db.session, category='Models')) 20 | admin.add_view(CustomFileAdmin(app.static_folder, '/static/', name='Static Files')) 21 | -------------------------------------------------------------------------------- /Chapter-12/webapp/admin/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_admin import Admin 2 | from .. import db 3 | from .controllers import CustomModelView, CustomView, CustomFileAdmin, PostView 4 | from webapp.blog.models import Post, Comment, Reminder, Tag 5 | from webapp.auth.models import User, Role 6 | 7 | admin = Admin() 8 | 9 | 10 | def create_module(app, **kwargs): 11 | admin.init_app(app) 12 | admin.add_view(CustomView(name='Custom')) 13 | 14 | models = [User, Role, Comment, Reminder, Tag] 15 | 16 | for model in models: 17 | admin.add_view(CustomModelView(model, db.session, category='Models')) 18 | 19 | admin.add_view(PostView(Post, db.session, category='Models')) 20 | admin.add_view(CustomFileAdmin(app.static_folder, '/static/', name='Static Files')) 21 | -------------------------------------------------------------------------------- /Chapter-8/webapp/api/blog/fields.py: -------------------------------------------------------------------------------- 1 | try: 2 | # Try python3 3 | from html.parser import HTMLParser 4 | except Exception as e: 5 | # Nop python2 6 | from HTMLParser import HTMLParser 7 | 8 | from flask_restful import fields 9 | 10 | 11 | class HTMLStripper(HTMLParser): 12 | fed = list() 13 | 14 | def __init__(self): 15 | self.reset() 16 | self.fed = [] 17 | 18 | def handle_data(self, d): 19 | self.fed.append(d) 20 | 21 | def get_data(self): 22 | return ''.join(self.fed) 23 | 24 | 25 | def strip_tags(html): 26 | s = HTMLStripper() 27 | s.feed(html) 28 | 29 | return s.get_data() 30 | 31 | 32 | class HTMLField(fields.Raw): 33 | def format(self, value): 34 | return strip_tags(str(value)) 35 | -------------------------------------------------------------------------------- /Chapter-9/webapp/api/blog/fields.py: -------------------------------------------------------------------------------- 1 | try: 2 | # Try python3 3 | from html.parser import HTMLParser 4 | except Exception as e: 5 | # Nop python2 6 | from HTMLParser import HTMLParser 7 | 8 | from flask_restful import fields 9 | 10 | 11 | class HTMLStripper(HTMLParser): 12 | fed = list() 13 | 14 | def __init__(self): 15 | self.reset() 16 | self.fed = [] 17 | 18 | def handle_data(self, d): 19 | self.fed.append(d) 20 | 21 | def get_data(self): 22 | return ''.join(self.fed) 23 | 24 | 25 | def strip_tags(html): 26 | s = HTMLStripper() 27 | s.feed(html) 28 | 29 | return s.get_data() 30 | 31 | 32 | class HTMLField(fields.Raw): 33 | def format(self, value): 34 | return strip_tags(str(value)) 35 | -------------------------------------------------------------------------------- /Chapter-10/webapp/api/blog/fields.py: -------------------------------------------------------------------------------- 1 | try: 2 | # Try python3 3 | from html.parser import HTMLParser 4 | except Exception as e: 5 | # Nop python2 6 | from HTMLParser import HTMLParser 7 | 8 | from flask_restful import fields 9 | 10 | 11 | class HTMLStripper(HTMLParser): 12 | fed = list() 13 | 14 | def __init__(self): 15 | self.reset() 16 | self.fed = [] 17 | 18 | def handle_data(self, d): 19 | self.fed.append(d) 20 | 21 | def get_data(self): 22 | return ''.join(self.fed) 23 | 24 | 25 | def strip_tags(html): 26 | s = HTMLStripper() 27 | s.feed(html) 28 | 29 | return s.get_data() 30 | 31 | 32 | class HTMLField(fields.Raw): 33 | def format(self, value): 34 | return strip_tags(str(value)) 35 | -------------------------------------------------------------------------------- /Chapter-11/webapp/api/blog/fields.py: -------------------------------------------------------------------------------- 1 | try: 2 | # Try python3 3 | from html.parser import HTMLParser 4 | except Exception as e: 5 | # Nop python2 6 | from HTMLParser import HTMLParser 7 | 8 | from flask_restful import fields 9 | 10 | 11 | class HTMLStripper(HTMLParser): 12 | fed = list() 13 | 14 | def __init__(self): 15 | self.reset() 16 | self.fed = [] 17 | 18 | def handle_data(self, d): 19 | self.fed.append(d) 20 | 21 | def get_data(self): 22 | return ''.join(self.fed) 23 | 24 | 25 | def strip_tags(html): 26 | s = HTMLStripper() 27 | s.feed(html) 28 | 29 | return s.get_data() 30 | 31 | 32 | class HTMLField(fields.Raw): 33 | def format(self, value): 34 | return strip_tags(str(value)) 35 | -------------------------------------------------------------------------------- /Chapter-12/webapp/api/blog/fields.py: -------------------------------------------------------------------------------- 1 | try: 2 | # Try python3 3 | from html.parser import HTMLParser 4 | except Exception as e: 5 | # Nop python2 6 | from HTMLParser import HTMLParser 7 | 8 | from flask_restful import fields 9 | 10 | 11 | class HTMLStripper(HTMLParser): 12 | fed = list() 13 | 14 | def __init__(self): 15 | self.reset() 16 | self.fed = [] 17 | 18 | def handle_data(self, d): 19 | self.fed.append(d) 20 | 21 | def get_data(self): 22 | return ''.join(self.fed) 23 | 24 | 25 | def strip_tags(html): 26 | s = HTMLStripper() 27 | s.feed(html) 28 | 29 | return s.get_data() 30 | 31 | 32 | class HTMLField(fields.Raw): 33 | def format(self, value): 34 | return strip_tags(str(value)) 35 | -------------------------------------------------------------------------------- /Chapter-13/webapp/api/blog/fields.py: -------------------------------------------------------------------------------- 1 | try: 2 | # Try python3 3 | from html.parser import HTMLParser 4 | except Exception as e: 5 | # Nop python2 6 | from HTMLParser import HTMLParser 7 | 8 | from flask_restful import fields 9 | 10 | 11 | class HTMLStripper(HTMLParser): 12 | fed = list() 13 | 14 | def __init__(self): 15 | self.reset() 16 | self.fed = [] 17 | 18 | def handle_data(self, d): 19 | self.fed.append(d) 20 | 21 | def get_data(self): 22 | return ''.join(self.fed) 23 | 24 | 25 | def strip_tags(html): 26 | s = HTMLStripper() 27 | s.feed(html) 28 | 29 | return s.get_data() 30 | 31 | 32 | class HTMLField(fields.Raw): 33 | def format(self, value): 34 | return strip_tags(str(value)) 35 | -------------------------------------------------------------------------------- /Chapter-10/celery_runner.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from celery import Celery 4 | 5 | 6 | def make_celery(app): 7 | celery = Celery( 8 | app.import_name, 9 | broker=app.config['CELERY_BROKER_URL'], 10 | backend=app.config['CELERY_RESULT_BACKEND'] 11 | ) 12 | celery.conf.update(app.config) 13 | TaskBase = celery.Task 14 | 15 | class ContextTask(TaskBase): 16 | abstract = True 17 | 18 | def __call__(self, *args, **kwargs): 19 | with app.app_context(): 20 | return TaskBase.__call__(self, *args, **kwargs) 21 | 22 | celery.Task = ContextTask 23 | 24 | return celery 25 | 26 | env = os.environ.get('WEBAPP_ENV', 'dev') 27 | flask_app = create_app('config.%sConfig' % env.capitalize()) 28 | 29 | celery = make_celery(flask_app) 30 | -------------------------------------------------------------------------------- /Chapter-11/celery_runner.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from celery import Celery 4 | 5 | 6 | def make_celery(app): 7 | celery = Celery( 8 | app.import_name, 9 | broker=app.config['CELERY_BROKER_URL'], 10 | backend=app.config['CELERY_RESULT_BACKEND'] 11 | ) 12 | celery.conf.update(app.config) 13 | TaskBase = celery.Task 14 | 15 | class ContextTask(TaskBase): 16 | abstract = True 17 | 18 | def __call__(self, *args, **kwargs): 19 | with app.app_context(): 20 | return TaskBase.__call__(self, *args, **kwargs) 21 | 22 | celery.Task = ContextTask 23 | 24 | return celery 25 | 26 | env = os.environ.get('WEBAPP_ENV', 'dev') 27 | flask_app = create_app('config.%sConfig' % env.capitalize()) 28 | 29 | celery = make_celery(flask_app) 30 | -------------------------------------------------------------------------------- /Chapter-12/celery_runner.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from celery import Celery 4 | 5 | 6 | def make_celery(app): 7 | celery = Celery( 8 | app.import_name, 9 | broker=app.config['CELERY_BROKER_URL'], 10 | backend=app.config['CELERY_RESULT_BACKEND'] 11 | ) 12 | celery.conf.update(app.config) 13 | TaskBase = celery.Task 14 | 15 | class ContextTask(TaskBase): 16 | abstract = True 17 | 18 | def __call__(self, *args, **kwargs): 19 | with app.app_context(): 20 | return TaskBase.__call__(self, *args, **kwargs) 21 | 22 | celery.Task = ContextTask 23 | 24 | return celery 25 | 26 | env = os.environ.get('WEBAPP_ENV', 'dev') 27 | flask_app = create_app('config.%sConfig' % env.capitalize()) 28 | 29 | celery = make_celery(flask_app) 30 | -------------------------------------------------------------------------------- /Chapter-9/celery_runner.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from celery import Celery 4 | 5 | 6 | def make_celery(app): 7 | celery = Celery( 8 | app.import_name, 9 | broker=app.config['CELERY_BROKER_URL'], 10 | backend=app.config['CELERY_RESULT_BACKEND'] 11 | ) 12 | celery.conf.update(app.config) 13 | TaskBase = celery.Task 14 | 15 | class ContextTask(TaskBase): 16 | abstract = True 17 | 18 | def __call__(self, *args, **kwargs): 19 | with app.app_context(): 20 | return TaskBase.__call__(self, *args, **kwargs) 21 | 22 | celery.Task = ContextTask 23 | 24 | return celery 25 | 26 | env = os.environ.get('WEBAPP_ENV', 'dev') 27 | flask_app = create_app('config.%sConfig' % env.capitalize()) 28 | 29 | celery = make_celery(flask_app) 30 | -------------------------------------------------------------------------------- /Chapter-7/webapp/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | from flask_mongoengine import MongoEngine 4 | 5 | mongo = MongoEngine() 6 | 7 | 8 | def create_app(object_name): 9 | """ 10 | An flask application factory, as explained here: 11 | http://flask.pocoo.org/docs/patterns/appfactories/ 12 | 13 | Arguments: 14 | object_name: the python path of the config object, 15 | e.g. project.config.ProdConfig 16 | """ 17 | app = Flask(__name__) 18 | app.config.from_object(object_name) 19 | 20 | mongo.init_app(app) 21 | 22 | from .auth import create_module as auth_create_module 23 | from .blog import create_module as blog_create_module 24 | from .main import create_module as main_create_module 25 | auth_create_module(app) 26 | blog_create_module(app) 27 | main_create_module(app) 28 | 29 | return app 30 | 31 | -------------------------------------------------------------------------------- /Chapter-13/celery_runner.py: -------------------------------------------------------------------------------- 1 | import os 2 | from webapp import create_app 3 | from celery import Celery 4 | 5 | 6 | def make_celery(app): 7 | print("!!! CONFIG: %s" % app.config['CELERY_BROKER_URL']) 8 | celery = Celery( 9 | app.import_name, 10 | broker=app.config['CELERY_BROKER_URL'], 11 | backend=app.config['CELERY_RESULT_BACKEND'] 12 | ) 13 | celery.conf.update(app.config) 14 | TaskBase = celery.Task 15 | 16 | class ContextTask(TaskBase): 17 | abstract = True 18 | 19 | def __call__(self, *args, **kwargs): 20 | with app.app_context(): 21 | return TaskBase.__call__(self, *args, **kwargs) 22 | 23 | celery.Task = ContextTask 24 | 25 | return celery 26 | 27 | env = os.environ.get('WEBAPP_ENV', 'dev') 28 | flask_app = create_app('config.%sConfig' % env.capitalize()) 29 | 30 | celery = make_celery(flask_app) 31 | -------------------------------------------------------------------------------- /Chapter-6/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | basedir = os.path.abspath(os.path.dirname(__file__)) 4 | 5 | 6 | class Config(object): 7 | SECRET_KEY = '736670cb10a600b695a55839ca3a5aa54a7d7356cdef815d2ad6e19a2031182b' 8 | RECAPTCHA_PUBLIC_KEY = "6LdKkQQTAAAAAEH0GFj7NLg5tGicaoOus7G9Q5Uw" 9 | RECAPTCHA_PRIVATE_KEY = '6LdKkQQTAAAAAMYroksPTJ7pWhobYb88fTAcxcYn' 10 | POSTS_PER_PAGE = 10 11 | 12 | TWITTER_API_KEY = "XXXX" 13 | TWITTER_API_SECRET = "XXXX" 14 | FACEBOOK_CLIENT_ID = "XXX" 15 | FACEBOOK_CLIENT_SECRET = "XXXX" 16 | 17 | 18 | class ProdConfig(Config): 19 | SQLALCHEMY_TRACK_MODIFICATIONS = False 20 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 21 | 22 | 23 | class DevConfig(Config): 24 | DEBUG = True 25 | SQLALCHEMY_TRACK_MODIFICATIONS = False 26 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 27 | -------------------------------------------------------------------------------- /Chapter-8/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | basedir = os.path.abspath(os.path.dirname(__file__)) 4 | 5 | 6 | class Config(object): 7 | SECRET_KEY = '736670cb10a600b695a55839ca3a5aa54a7d7356cdef815d2ad6e19a2031182b' 8 | RECAPTCHA_PUBLIC_KEY = "6LdKkQQTAAAAAEH0GFj7NLg5tGicaoOus7G9Q5Uw" 9 | RECAPTCHA_PRIVATE_KEY = '6LdKkQQTAAAAAMYroksPTJ7pWhobYb88fTAcxcYn' 10 | POSTS_PER_PAGE = 10 11 | 12 | TWITTER_API_KEY = "XXXX" 13 | TWITTER_API_SECRET = "XXXX" 14 | FACEBOOK_CLIENT_ID = "XXX" 15 | FACEBOOK_CLIENT_SECRET = "XXXX" 16 | 17 | 18 | class ProdConfig(Config): 19 | SQLALCHEMY_TRACK_MODIFICATIONS = False 20 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 21 | 22 | 23 | class DevConfig(Config): 24 | DEBUG = True 25 | SQLALCHEMY_TRACK_MODIFICATIONS = False 26 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 27 | -------------------------------------------------------------------------------- /Chapter-7/webapp/blog/models.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from ..auth.models import User 3 | from .. import mongo 4 | 5 | 6 | class Comment(mongo.EmbeddedDocument): 7 | name = mongo.StringField(required=True) 8 | text = mongo.StringField(required=True) 9 | date = mongo.DateTimeField(default=datetime.datetime.now()) 10 | 11 | def __repr__(self): 12 | return "".format(self.text[:15]) 13 | 14 | 15 | class Post(mongo.Document): 16 | meta = {'ordering': ['-publish_date']} 17 | title = mongo.StringField(required=True) 18 | text = mongo.StringField() 19 | publish_date = mongo.DateTimeField(default=datetime.datetime.now()) 20 | user = mongo.ReferenceField(User) 21 | comments = mongo.ListField(mongo.EmbeddedDocumentField(Comment)) 22 | tags = mongo.ListField(mongo.StringField()) 23 | 24 | def __repr__(self): 25 | return "".format(self.title) 26 | -------------------------------------------------------------------------------- /Chapter-3/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | 11 | export FLASK_APP=main.py 12 | if [ ! -d "migrations" ]; then 13 | echo -------------------- 14 | echo INIT THE migrations folder 15 | echo -------------------- 16 | export FLASK_APP=main.py; flask db init 17 | fi 18 | echo -------------------- 19 | echo Generate migration DDL code 20 | echo -------------------- 21 | flask db migrate 22 | echo -------------------- 23 | echo Run the DDL code and migrate 24 | echo -------------------- 25 | echo -------------------- 26 | echo This is the DDL code that will be run 27 | echo -------------------- 28 | flask db upgrade 29 | echo -------------------- 30 | echo Generating test data 31 | echo -------------------- 32 | python test_data.py 33 | 34 | -------------------------------------------------------------------------------- /Chapter-4/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | 11 | export FLASK_APP=main.py 12 | if [ ! -d "migrations" ]; then 13 | echo -------------------- 14 | echo INIT THE migrations folder 15 | echo -------------------- 16 | export FLASK_APP=main.py; flask db init 17 | fi 18 | echo -------------------- 19 | echo Generate migration DDL code 20 | echo -------------------- 21 | flask db migrate 22 | echo -------------------- 23 | echo Run the DDL code and migrate 24 | echo -------------------- 25 | echo -------------------- 26 | echo This is the DDL code that will be run 27 | echo -------------------- 28 | flask db upgrade 29 | echo -------------------- 30 | echo Generating test data 31 | echo -------------------- 32 | python test_data.py 33 | 34 | -------------------------------------------------------------------------------- /Chapter-5/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | 11 | export FLASP_APP=main.py 12 | if [ ! -d "migrations" ]; then 13 | echo -------------------- 14 | echo INIT THE migrations folder 15 | echo -------------------- 16 | export FLASK_APP=main.py; flask db init 17 | fi 18 | echo -------------------- 19 | echo Generate migration DDL code 20 | echo -------------------- 21 | flask db migrate 22 | echo -------------------- 23 | echo Run the DDL code and migrate 24 | echo -------------------- 25 | echo -------------------- 26 | echo This is the DDL code that will be run 27 | echo -------------------- 28 | flask db upgrade 29 | echo -------------------- 30 | echo Generating test data 31 | echo -------------------- 32 | python test_data.py 33 | 34 | -------------------------------------------------------------------------------- /Chapter-10/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | 11 | export FLASK_APP=main.py 12 | if [ ! -d "migrations" ]; then 13 | echo -------------------- 14 | echo INIT THE migrations folder 15 | echo -------------------- 16 | export FLASK_APP=main.py; flask db init 17 | fi 18 | echo -------------------- 19 | echo Generate migration DDL code 20 | echo -------------------- 21 | flask db migrate 22 | echo -------------------- 23 | echo Run the DDL code and migrate 24 | echo -------------------- 25 | echo -------------------- 26 | echo This is the DDL code that will be run 27 | echo -------------------- 28 | flask db upgrade 29 | echo -------------------- 30 | echo Generating test data 31 | echo -------------------- 32 | flask test-data 33 | 34 | 35 | -------------------------------------------------------------------------------- /Chapter-11/Flask-YouTube/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='Flask-YouTube', 5 | version='0.4', 6 | license='MIT', 7 | description='Flask extension to allow easy embedding of YouTube videos', 8 | author='Jack Stouffer', 9 | author_email='example@gmail.com', 10 | platforms='any', 11 | install_requires=['Flask'], 12 | packages=find_packages(), 13 | include_package_data=True, 14 | package_data = { 15 | 'templates': ['*'] 16 | }, 17 | zip_safe=False, 18 | classifiers=[ 19 | 'Development Status :: 5 - Production/Stable', 20 | 'Environment :: Web Environment', 21 | 'Intended Audience :: Developers', 22 | 'License :: OSI Approved :: BSD License', 23 | 'Operating System :: OS Independent', 24 | 'Programming Language :: Python', 25 | 'Topic :: Software Development :: Libraries :: Python Modules' 26 | ] 27 | ) 28 | 29 | -------------------------------------------------------------------------------- /Chapter-12/Flask-YouTube/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='Flask-YouTube', 5 | version='0.4', 6 | license='MIT', 7 | description='Flask extension to allow easy embedding of YouTube videos', 8 | author='Jack Stouffer', 9 | author_email='example@gmail.com', 10 | platforms='any', 11 | install_requires=['Flask'], 12 | packages=find_packages(), 13 | include_package_data=True, 14 | package_data = { 15 | 'templates': ['*'] 16 | }, 17 | zip_safe=False, 18 | classifiers=[ 19 | 'Development Status :: 5 - Production/Stable', 20 | 'Environment :: Web Environment', 21 | 'Intended Audience :: Developers', 22 | 'License :: OSI Approved :: BSD License', 23 | 'Operating System :: OS Independent', 24 | 'Programming Language :: Python', 25 | 'Topic :: Software Development :: Libraries :: Python Modules' 26 | ] 27 | ) 28 | 29 | -------------------------------------------------------------------------------- /Chapter-13/Flask-YouTube/setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='Flask-YouTube', 5 | version='0.4', 6 | license='MIT', 7 | description='Flask extension to allow easy embedding of YouTube videos', 8 | author='Jack Stouffer', 9 | author_email='example@gmail.com', 10 | platforms='any', 11 | install_requires=['Flask'], 12 | packages=find_packages(), 13 | include_package_data=True, 14 | package_data = { 15 | 'templates': ['*'] 16 | }, 17 | zip_safe=False, 18 | classifiers=[ 19 | 'Development Status :: 5 - Production/Stable', 20 | 'Environment :: Web Environment', 21 | 'Intended Audience :: Developers', 22 | 'License :: OSI Approved :: BSD License', 23 | 'Operating System :: OS Independent', 24 | 'Programming Language :: Python', 25 | 'Topic :: Software Development :: Libraries :: Python Modules' 26 | ] 27 | ) 28 | 29 | -------------------------------------------------------------------------------- /Chapter-6/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | 11 | export FLASK_APP=main.py 12 | if [ ! -d "migrations" ]; then 13 | echo -------------------- 14 | echo INIT THE migrations folder 15 | echo -------------------- 16 | export FLASK_APP=main.py; flask db init 17 | fi 18 | echo -------------------- 19 | echo Generate migration DDL code 20 | echo -------------------- 21 | flask db migrate 22 | echo -------------------- 23 | echo Run the DDL code and migrate 24 | echo -------------------- 25 | echo -------------------- 26 | echo This is the DDL code that will be run 27 | echo -------------------- 28 | flask db upgrade 29 | echo -------------------- 30 | echo Generating test data 31 | echo -------------------- 32 | source venv/bin/activate; python test_data.py 33 | 34 | -------------------------------------------------------------------------------- /Chapter-8/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | 11 | export FLASK_APP=main.py 12 | if [ ! -d "migrations" ]; then 13 | echo -------------------- 14 | echo INIT THE migrations folder 15 | echo -------------------- 16 | export FLASK_APP=main.py; flask db init 17 | fi 18 | echo -------------------- 19 | echo Generate migration DDL code 20 | echo -------------------- 21 | flask db migrate 22 | echo -------------------- 23 | echo Run the DDL code and migrate 24 | echo -------------------- 25 | echo -------------------- 26 | echo This is the DDL code that will be run 27 | echo -------------------- 28 | flask db upgrade 29 | echo -------------------- 30 | echo Generating test data 31 | echo -------------------- 32 | source venv/bin/activate; python test_data.py 33 | 34 | -------------------------------------------------------------------------------- /Chapter-9/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | 11 | export FLASK_APP=main.py 12 | if [ ! -d "migrations" ]; then 13 | echo -------------------- 14 | echo INIT THE migrations folder 15 | echo -------------------- 16 | export FLASK_APP=main.py; flask db init 17 | fi 18 | echo -------------------- 19 | echo Generate migration DDL code 20 | echo -------------------- 21 | flask db migrate 22 | echo -------------------- 23 | echo Run the DDL code and migrate 24 | echo -------------------- 25 | echo -------------------- 26 | echo This is the DDL code that will be run 27 | echo -------------------- 28 | flask db upgrade 29 | echo -------------------- 30 | echo Generating test data 31 | echo -------------------- 32 | source venv/bin/activate; python test_data.py 33 | 34 | -------------------------------------------------------------------------------- /Chapter-2/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | export FLASP_APP=main.py 11 | if [ ! -d "migrations" ]; then 12 | echo -------------------- 13 | echo INIT THE migrations folder 14 | echo -------------------- 15 | export FLASK_APP=main.py; flask db init 16 | fi 17 | echo -------------------- 18 | echo Generate migration DDL code 19 | echo -------------------- 20 | flask db migrate 21 | echo -------------------- 22 | echo Run the DDL code and migrate 23 | echo -------------------- 24 | echo -------------------- 25 | echo This is the DDL code that will be run 26 | echo -------------------- 27 | flask db upgrade --sql 28 | flask db upgrade 29 | echo -------------------- 30 | echo Show database tables 31 | echo -------------------- 32 | sqlite3 database.db .tables 33 | 34 | -------------------------------------------------------------------------------- /Chapter-6/webapp/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | from flask_sqlalchemy import SQLAlchemy 4 | from flask_migrate import Migrate 5 | 6 | db = SQLAlchemy() 7 | migrate = Migrate() 8 | 9 | 10 | def create_app(object_name): 11 | """ 12 | An flask application factory, as explained here: 13 | http://flask.pocoo.org/docs/patterns/appfactories/ 14 | 15 | Arguments: 16 | object_name: the python path of the config object, 17 | e.g. project.config.ProdConfig 18 | """ 19 | app = Flask(__name__) 20 | app.config.from_object(object_name) 21 | 22 | db.init_app(app) 23 | migrate.init_app(app, db) 24 | 25 | from .auth import create_module as auth_create_module 26 | from .blog import create_module as blog_create_module 27 | from .main import create_module as main_create_module 28 | auth_create_module(app) 29 | blog_create_module(app) 30 | main_create_module(app) 31 | 32 | return app 33 | 34 | -------------------------------------------------------------------------------- /Chapter-11/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | pushd Flask-Youtube 11 | python setup.py build 12 | python setup.py install 13 | popd 14 | 15 | export FLASK_APP=main.py 16 | if [ ! -d "migrations" ]; then 17 | echo -------------------- 18 | echo INIT THE migrations folder 19 | echo -------------------- 20 | export FLASK_APP=main.py; flask db init 21 | fi 22 | echo -------------------- 23 | echo Generate migration DDL code 24 | echo -------------------- 25 | flask db migrate 26 | echo -------------------- 27 | echo Run the DDL code and migrate 28 | echo -------------------- 29 | echo -------------------- 30 | echo This is the DDL code that will be run 31 | echo -------------------- 32 | flask db upgrade 33 | echo -------------------- 34 | echo Generating test data 35 | echo -------------------- 36 | flask test-data 37 | -------------------------------------------------------------------------------- /Chapter-12/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | pushd Flask-Youtube 11 | python setup.py build 12 | python setup.py install 13 | popd 14 | 15 | export FLASK_APP=main.py 16 | if [ ! -d "migrations" ]; then 17 | echo -------------------- 18 | echo INIT THE migrations folder 19 | echo -------------------- 20 | export FLASK_APP=main.py; flask db init 21 | fi 22 | echo -------------------- 23 | echo Generate migration DDL code 24 | echo -------------------- 25 | flask db migrate 26 | echo -------------------- 27 | echo Run the DDL code and migrate 28 | echo -------------------- 29 | echo -------------------- 30 | echo This is the DDL code that will be run 31 | echo -------------------- 32 | flask db upgrade 33 | echo -------------------- 34 | echo Generating test data 35 | echo -------------------- 36 | flask test-data 37 | -------------------------------------------------------------------------------- /Chapter-13/init.sh: -------------------------------------------------------------------------------- 1 | if [ ! -d "venv" ]; then 2 | echo -------------------- 3 | echo Creating virtualenv 4 | echo -------------------- 5 | virtualenv venv 6 | fi 7 | source venv/bin/activate 8 | 9 | pip install -r requirements.txt 10 | pushd Flask-Youtube 11 | python setup.py build 12 | python setup.py install 13 | popd 14 | 15 | export FLASK_APP=main.py 16 | if [ ! -d "migrations" ]; then 17 | echo -------------------- 18 | echo INIT THE migrations folder 19 | echo -------------------- 20 | export FLASK_APP=main.py; flask db init 21 | fi 22 | echo -------------------- 23 | echo Generate migration DDL code 24 | echo -------------------- 25 | flask db migrate 26 | echo -------------------- 27 | echo Run the DDL code and migrate 28 | echo -------------------- 29 | echo -------------------- 30 | echo This is the DDL code that will be run 31 | echo -------------------- 32 | flask db upgrade 33 | echo -------------------- 34 | echo Generating test data 35 | echo -------------------- 36 | flask test-data 37 | 38 | -------------------------------------------------------------------------------- /Chapter-5/webapp/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template 2 | from flask_sqlalchemy import SQLAlchemy 3 | from flask_migrate import Migrate 4 | 5 | db = SQLAlchemy() 6 | migrate = Migrate() 7 | 8 | 9 | def page_not_found(error): 10 | return render_template('404.html'), 404 11 | 12 | 13 | def create_app(object_name): 14 | """ 15 | An flask application factory, as explained here: 16 | http://flask.pocoo.org/docs/patterns/appfactories/ 17 | 18 | Arguments: 19 | object_name: the python path of the config object, 20 | e.g. project.config.ProdConfig 21 | """ 22 | from .blog.controllers import blog_blueprint 23 | from .main.controllers import main_blueprint 24 | 25 | app = Flask(__name__) 26 | app.config.from_object(object_name) 27 | 28 | db.init_app(app) 29 | migrate.init_app(app, db) 30 | app.register_blueprint(main_blueprint) 31 | app.register_blueprint(blog_blueprint) 32 | app.register_error_handler(404, page_not_found) 33 | return app 34 | -------------------------------------------------------------------------------- /Chapter-11/Flask-YouTube/flask_youtube/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, Blueprint, Markup 2 | 3 | 4 | class Video(object): 5 | def __init__(self, video_id, cls="youtube"): 6 | self.video_id = video_id 7 | self.cls = cls 8 | 9 | @property 10 | def html(self): 11 | return Markup(render_template('youtube/video.html', video=self)) 12 | 13 | 14 | def youtube(*args, **kwargs): 15 | video = Video(*args, **kwargs) 16 | return video.html 17 | 18 | 19 | class Youtube(object): 20 | def __init__(self, app=None, **kwargs): 21 | if app: 22 | self.init_app(app) 23 | 24 | def init_app(self, app): 25 | self.register_blueprint(app) 26 | app.add_template_global(youtube) 27 | 28 | def register_blueprint(self, app): 29 | module = Blueprint( 30 | "youtube", 31 | __name__, 32 | url_prefix='youtube', 33 | template_folder="templates" 34 | ) 35 | app.register_blueprint(module) 36 | return module 37 | -------------------------------------------------------------------------------- /Chapter-12/Flask-YouTube/flask_youtube/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, Blueprint, Markup 2 | 3 | 4 | class Video(object): 5 | def __init__(self, video_id, cls="youtube"): 6 | self.video_id = video_id 7 | self.cls = cls 8 | 9 | @property 10 | def html(self): 11 | return Markup(render_template('youtube/video.html', video=self)) 12 | 13 | 14 | def youtube(*args, **kwargs): 15 | video = Video(*args, **kwargs) 16 | return video.html 17 | 18 | 19 | class Youtube(object): 20 | def __init__(self, app=None, **kwargs): 21 | if app: 22 | self.init_app(app) 23 | 24 | def init_app(self, app): 25 | self.register_blueprint(app) 26 | app.add_template_global(youtube) 27 | 28 | def register_blueprint(self, app): 29 | module = Blueprint( 30 | "youtube", 31 | __name__, 32 | url_prefix='youtube', 33 | template_folder="templates" 34 | ) 35 | app.register_blueprint(module) 36 | return module 37 | -------------------------------------------------------------------------------- /Chapter-13/Flask-YouTube/flask_youtube/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import render_template, Blueprint, Markup 2 | 3 | 4 | class Video(object): 5 | def __init__(self, video_id, cls="youtube"): 6 | self.video_id = video_id 7 | self.cls = cls 8 | 9 | @property 10 | def html(self): 11 | return Markup(render_template('youtube/video.html', video=self)) 12 | 13 | 14 | def youtube(*args, **kwargs): 15 | video = Video(*args, **kwargs) 16 | return video.html 17 | 18 | 19 | class Youtube(object): 20 | def __init__(self, app=None, **kwargs): 21 | if app: 22 | self.init_app(app) 23 | 24 | def init_app(self, app): 25 | self.register_blueprint(app) 26 | app.add_template_global(youtube) 27 | 28 | def register_blueprint(self, app): 29 | module = Blueprint( 30 | "youtube", 31 | __name__, 32 | url_prefix='youtube', 33 | template_folder="templates" 34 | ) 35 | app.register_blueprint(module) 36 | return module 37 | -------------------------------------------------------------------------------- /Chapter-8/webapp/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | from flask_sqlalchemy import SQLAlchemy 4 | from flask_migrate import Migrate 5 | 6 | db = SQLAlchemy() 7 | migrate = Migrate() 8 | 9 | 10 | def create_app(object_name): 11 | """ 12 | An flask application factory, as explained here: 13 | http://flask.pocoo.org/docs/patterns/appfactories/ 14 | 15 | Arguments: 16 | object_name: the python path of the config object, 17 | e.g. project.config.ProdConfig 18 | """ 19 | app = Flask(__name__) 20 | app.config.from_object(object_name) 21 | 22 | db.init_app(app) 23 | migrate.init_app(app, db) 24 | 25 | from .auth import create_module as auth_create_module 26 | from .blog import create_module as blog_create_module 27 | from .main import create_module as main_create_module 28 | from .api import create_module as api_create_module 29 | auth_create_module(app) 30 | blog_create_module(app) 31 | main_create_module(app) 32 | api_create_module(app) 33 | 34 | return app 35 | -------------------------------------------------------------------------------- /Chapter-9/webapp/__init__.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask_sqlalchemy import SQLAlchemy 3 | from flask_migrate import Migrate 4 | from flask_celery import Celery 5 | 6 | db = SQLAlchemy() 7 | migrate = Migrate() 8 | celery = Celery() 9 | 10 | 11 | def create_app(object_name): 12 | """ 13 | An flask application factory, as explained here: 14 | http://flask.pocoo.org/docs/patterns/appfactories/ 15 | 16 | Arguments: 17 | object_name: the python path of the config object, 18 | e.g. project.config.ProdConfig 19 | """ 20 | app = Flask(__name__) 21 | app.config.from_object(object_name) 22 | 23 | db.init_app(app) 24 | migrate.init_app(app, db) 25 | 26 | celery.init_app(app) 27 | 28 | from .auth import create_module as auth_create_module 29 | from .blog import create_module as blog_create_module 30 | from .main import create_module as main_create_module 31 | from .api import create_module as api_create_module 32 | auth_create_module(app) 33 | blog_create_module(app) 34 | main_create_module(app) 35 | api_create_module(app) 36 | 37 | return app 38 | -------------------------------------------------------------------------------- /Chapter-11/Flask-GZip/flask_gzip/__init__.py: -------------------------------------------------------------------------------- 1 | from gzip import GzipFile 2 | from io import BytesIO 3 | 4 | from flask import request 5 | 6 | 7 | class GZip(object): 8 | def __init__(self, app=None): 9 | self.app = app 10 | if app is not None: 11 | self.init_app(app) 12 | 13 | def init_app(self, app): 14 | app.after_request(self.after_request) 15 | 16 | def after_request(self, response): 17 | encoding = request.headers.get('Accept-Encoding') 18 | 19 | if 'gzip' not in encoding or \ 20 | not response.status_code == 200 or \ 21 | 'Content-Encoding' in response.headers: 22 | return response 23 | 24 | response.direct_passthrough = False 25 | 26 | gzip_buffer = BytesIO() 27 | with GzipFile(mode='wb', compresslevel=5, fileobj=gzip_buffer) as gzip_file: 28 | gzip_file.write(response.get_data()) 29 | 30 | response.set_data(bytes(gzip_buffer.getvalue())) 31 | 32 | response.headers['Content-Encoding'] = 'gzip' 33 | response.headers['Content-Length'] = response.content_length 34 | 35 | return response 36 | -------------------------------------------------------------------------------- /Chapter-3/templates/navbar.html: -------------------------------------------------------------------------------- 1 | 2 | 29 | -------------------------------------------------------------------------------- /Chapter-4/templates/blog/navbar.html: -------------------------------------------------------------------------------- 1 | 2 | 29 | -------------------------------------------------------------------------------- /Chapter-5/webapp/templates/navbar.html: -------------------------------------------------------------------------------- 1 | 2 | 29 | -------------------------------------------------------------------------------- /Chapter-10/webapp/admin/controllers.py: -------------------------------------------------------------------------------- 1 | from flask_admin import BaseView, expose 2 | from flask_admin.contrib.sqla import ModelView 3 | from flask_admin.contrib.fileadmin import FileAdmin 4 | from flask_login import login_required, current_user 5 | 6 | from webapp.auth import has_role 7 | from .forms import CKTextAreaField 8 | 9 | 10 | class CustomView(BaseView): 11 | @expose('/') 12 | @login_required 13 | @has_role('admin') 14 | def index(self): 15 | return self.render('admin/custom.html') 16 | 17 | @expose('/second_page') 18 | @login_required 19 | @has_role('admin') 20 | def second_page(self): 21 | return self.render('admin/second_page.html') 22 | 23 | 24 | class CustomModelView(ModelView): 25 | def is_accessible(self): 26 | return current_user.is_authenticated and current_user.has_role('admin') 27 | 28 | 29 | class PostView(CustomModelView): 30 | form_overrides = dict(text=CKTextAreaField) 31 | column_searchable_list = ('text', 'title') 32 | column_filters = ('publish_date',) 33 | 34 | create_template = 'admin/post_edit.html' 35 | edit_template = 'admin/post_edit.html' 36 | 37 | 38 | class CustomFileAdmin(FileAdmin): 39 | def is_accessible(self): 40 | return current_user.is_authenticated and current_user.has_role('admin') 41 | -------------------------------------------------------------------------------- /Chapter-11/webapp/admin/controllers.py: -------------------------------------------------------------------------------- 1 | from flask_admin import BaseView, expose 2 | from flask_admin.contrib.sqla import ModelView 3 | from flask_admin.contrib.fileadmin import FileAdmin 4 | from flask_login import login_required, current_user 5 | 6 | from webapp.auth import has_role 7 | from .forms import CKTextAreaField 8 | 9 | 10 | class CustomView(BaseView): 11 | @expose('/') 12 | @login_required 13 | @has_role('admin') 14 | def index(self): 15 | return self.render('admin/custom.html') 16 | 17 | @expose('/second_page') 18 | @login_required 19 | @has_role('admin') 20 | def second_page(self): 21 | return self.render('admin/second_page.html') 22 | 23 | 24 | class CustomModelView(ModelView): 25 | def is_accessible(self): 26 | return current_user.is_authenticated and current_user.has_role('admin') 27 | 28 | 29 | class PostView(CustomModelView): 30 | form_overrides = dict(text=CKTextAreaField) 31 | column_searchable_list = ('text', 'title') 32 | column_filters = ('publish_date',) 33 | 34 | create_template = 'admin/post_edit.html' 35 | edit_template = 'admin/post_edit.html' 36 | 37 | 38 | class CustomFileAdmin(FileAdmin): 39 | def is_accessible(self): 40 | return current_user.is_authenticated and current_user.has_role('admin') 41 | -------------------------------------------------------------------------------- /Chapter-12/webapp/admin/controllers.py: -------------------------------------------------------------------------------- 1 | from flask_admin import BaseView, expose 2 | from flask_admin.contrib.sqla import ModelView 3 | from flask_admin.contrib.fileadmin import FileAdmin 4 | from flask_login import login_required, current_user 5 | 6 | from webapp.auth import has_role 7 | from .forms import CKTextAreaField 8 | 9 | 10 | class CustomView(BaseView): 11 | @expose('/') 12 | @login_required 13 | @has_role('admin') 14 | def index(self): 15 | return self.render('admin/custom.html') 16 | 17 | @expose('/second_page') 18 | @login_required 19 | @has_role('admin') 20 | def second_page(self): 21 | return self.render('admin/second_page.html') 22 | 23 | 24 | class CustomModelView(ModelView): 25 | def is_accessible(self): 26 | return current_user.is_authenticated and current_user.has_role('admin') 27 | 28 | 29 | class PostView(CustomModelView): 30 | form_overrides = dict(text=CKTextAreaField) 31 | column_searchable_list = ('text', 'title') 32 | column_filters = ('publish_date',) 33 | 34 | create_template = 'admin/post_edit.html' 35 | edit_template = 'admin/post_edit.html' 36 | 37 | 38 | class CustomFileAdmin(FileAdmin): 39 | def is_accessible(self): 40 | return current_user.is_authenticated and current_user.has_role('admin') 41 | -------------------------------------------------------------------------------- /Chapter-13/webapp/admin/controllers.py: -------------------------------------------------------------------------------- 1 | from flask_admin import BaseView, expose 2 | from flask_admin.contrib.sqla import ModelView 3 | from flask_admin.contrib.fileadmin import FileAdmin 4 | from flask_login import login_required, current_user 5 | 6 | from webapp.auth import has_role 7 | from .forms import CKTextAreaField 8 | 9 | 10 | class CustomView(BaseView): 11 | @expose('/') 12 | @login_required 13 | @has_role('admin') 14 | def index(self): 15 | return self.render('admin/custom.html') 16 | 17 | @expose('/second_page') 18 | @login_required 19 | @has_role('admin') 20 | def second_page(self): 21 | return self.render('admin/second_page.html') 22 | 23 | 24 | class CustomModelView(ModelView): 25 | def is_accessible(self): 26 | return current_user.is_authenticated and current_user.has_role('admin') 27 | 28 | 29 | class PostView(CustomModelView): 30 | form_overrides = dict(text=CKTextAreaField) 31 | column_searchable_list = ('text', 'title') 32 | column_filters = ('publish_date',) 33 | 34 | create_template = 'admin/post_edit.html' 35 | edit_template = 'admin/post_edit.html' 36 | 37 | 38 | class CustomFileAdmin(FileAdmin): 39 | def is_accessible(self): 40 | return current_user.is_authenticated and current_user.has_role('admin') 41 | -------------------------------------------------------------------------------- /Chapter-10/babel/messages.pot: -------------------------------------------------------------------------------- 1 | # Translations template for PROJECT. 2 | # Copyright (C) 2018 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2018. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PROJECT VERSION\n" 10 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 11 | "POT-Creation-Date: 2018-08-19 15:54+0100\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=utf-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Generated-By: Babel 2.4.0\n" 19 | 20 | #: webapp/templates/head.html:5 21 | msgid "Welcome to this Blog" 22 | msgstr "" 23 | 24 | #: webapp/templates/macros.html:57 25 | msgid "Read More" 26 | msgstr "" 27 | 28 | #: webapp/templates/navbar.html:11 29 | msgid "New Post" 30 | msgstr "" 31 | 32 | #: webapp/templates/navbar.html:40 33 | msgid "Logout" 34 | msgstr "" 35 | 36 | #: webapp/templates/navbar.html:45 37 | msgid "Login" 38 | msgstr "" 39 | 40 | #: webapp/templates/navbar.html:49 41 | msgid "Register" 42 | msgstr "" 43 | 44 | #: webapp/templates/blog/rightbody.html:3 45 | msgid "Recent Posts" 46 | msgstr "" 47 | 48 | #: webapp/templates/blog/rightbody.html:15 49 | msgid "Popular Tags" 50 | msgstr "" 51 | 52 | -------------------------------------------------------------------------------- /Chapter-11/babel/messages.pot: -------------------------------------------------------------------------------- 1 | # Translations template for PROJECT. 2 | # Copyright (C) 2018 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2018. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PROJECT VERSION\n" 10 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 11 | "POT-Creation-Date: 2018-08-19 15:54+0100\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=utf-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Generated-By: Babel 2.4.0\n" 19 | 20 | #: webapp/templates/head.html:5 21 | msgid "Welcome to this Blog" 22 | msgstr "" 23 | 24 | #: webapp/templates/macros.html:57 25 | msgid "Read More" 26 | msgstr "" 27 | 28 | #: webapp/templates/navbar.html:11 29 | msgid "New Post" 30 | msgstr "" 31 | 32 | #: webapp/templates/navbar.html:40 33 | msgid "Logout" 34 | msgstr "" 35 | 36 | #: webapp/templates/navbar.html:45 37 | msgid "Login" 38 | msgstr "" 39 | 40 | #: webapp/templates/navbar.html:49 41 | msgid "Register" 42 | msgstr "" 43 | 44 | #: webapp/templates/blog/rightbody.html:3 45 | msgid "Recent Posts" 46 | msgstr "" 47 | 48 | #: webapp/templates/blog/rightbody.html:15 49 | msgid "Popular Tags" 50 | msgstr "" 51 | 52 | -------------------------------------------------------------------------------- /Chapter-12/babel/messages.pot: -------------------------------------------------------------------------------- 1 | # Translations template for PROJECT. 2 | # Copyright (C) 2018 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2018. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PROJECT VERSION\n" 10 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 11 | "POT-Creation-Date: 2018-08-19 15:54+0100\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=utf-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Generated-By: Babel 2.4.0\n" 19 | 20 | #: webapp/templates/head.html:5 21 | msgid "Welcome to this Blog" 22 | msgstr "" 23 | 24 | #: webapp/templates/macros.html:57 25 | msgid "Read More" 26 | msgstr "" 27 | 28 | #: webapp/templates/navbar.html:11 29 | msgid "New Post" 30 | msgstr "" 31 | 32 | #: webapp/templates/navbar.html:40 33 | msgid "Logout" 34 | msgstr "" 35 | 36 | #: webapp/templates/navbar.html:45 37 | msgid "Login" 38 | msgstr "" 39 | 40 | #: webapp/templates/navbar.html:49 41 | msgid "Register" 42 | msgstr "" 43 | 44 | #: webapp/templates/blog/rightbody.html:3 45 | msgid "Recent Posts" 46 | msgstr "" 47 | 48 | #: webapp/templates/blog/rightbody.html:15 49 | msgid "Popular Tags" 50 | msgstr "" 51 | 52 | -------------------------------------------------------------------------------- /Chapter-13/babel/messages.pot: -------------------------------------------------------------------------------- 1 | # Translations template for PROJECT. 2 | # Copyright (C) 2018 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2018. 5 | # 6 | #, fuzzy 7 | msgid "" 8 | msgstr "" 9 | "Project-Id-Version: PROJECT VERSION\n" 10 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 11 | "POT-Creation-Date: 2018-08-19 15:54+0100\n" 12 | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "MIME-Version: 1.0\n" 16 | "Content-Type: text/plain; charset=utf-8\n" 17 | "Content-Transfer-Encoding: 8bit\n" 18 | "Generated-By: Babel 2.4.0\n" 19 | 20 | #: webapp/templates/head.html:5 21 | msgid "Welcome to this Blog" 22 | msgstr "" 23 | 24 | #: webapp/templates/macros.html:57 25 | msgid "Read More" 26 | msgstr "" 27 | 28 | #: webapp/templates/navbar.html:11 29 | msgid "New Post" 30 | msgstr "" 31 | 32 | #: webapp/templates/navbar.html:40 33 | msgid "Logout" 34 | msgstr "" 35 | 36 | #: webapp/templates/navbar.html:45 37 | msgid "Login" 38 | msgstr "" 39 | 40 | #: webapp/templates/navbar.html:49 41 | msgid "Register" 42 | msgstr "" 43 | 44 | #: webapp/templates/blog/rightbody.html:3 45 | msgid "Recent Posts" 46 | msgstr "" 47 | 48 | #: webapp/templates/blog/rightbody.html:15 49 | msgid "Popular Tags" 50 | msgstr "" 51 | 52 | -------------------------------------------------------------------------------- /Chapter-13/deploy/docker/worker_entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo -------------------- 4 | echo Going to wait for Mysql 5 | echo -------------------- 6 | while ! mysqladmin ping -h"${DB_HOST}" -u "${MYSQL_USER}" -p"${MYSQL_PASSWORD}" --silent; do 7 | echo "MySQL not available waiting" 8 | sleep 1 9 | done 10 | echo -------------------- 11 | echo Going to Create database myblog 12 | echo -------------------- 13 | mysql -h "${DB_HOST}" -u "${MYSQL_USER}" -p"${MYSQL_PASSWORD}" -e "create database myblog"; 14 | export LC_ALL=C.UTF-8 15 | export LANG=C.UTF-8 16 | export FLASK_APP=main.py 17 | if [ ! -d "migrations" ]; then 18 | echo -------------------- 19 | echo INIT THE migrations folder 20 | echo -------------------- 21 | export FLASK_APP=main.py; flask db init 22 | fi 23 | echo -------------------- 24 | echo Generate migration DDL code 25 | echo -------------------- 26 | flask db migrate 27 | echo -------------------- 28 | echo Run the DDL code and migrate 29 | echo -------------------- 30 | echo -------------------- 31 | echo This is the DDL code that will be run 32 | echo -------------------- 33 | flask db upgrade 34 | echo -------------------- 35 | echo Generating test data 36 | echo -------------------- 37 | flask test-data 38 | echo -------------------- 39 | echo Starting Celery 40 | echo -------------------- 41 | /usr/bin/supervisord --nodaemon 42 | -------------------------------------------------------------------------------- /Chapter-8/webapp/api/blog/parsers.py: -------------------------------------------------------------------------------- 1 | from flask_restful import reqparse 2 | 3 | user_post_parser = reqparse.RequestParser() 4 | user_post_parser.add_argument('username', type=str, required=True) 5 | user_post_parser.add_argument('password', type=str, required=True) 6 | 7 | post_get_parser = reqparse.RequestParser() 8 | post_get_parser.add_argument('page', type=int, location=['args', 'headers']) 9 | post_get_parser.add_argument('user', type=str, location=['args', 'headers']) 10 | 11 | post_post_parser = reqparse.RequestParser() 12 | post_post_parser.add_argument( 13 | 'title', 14 | type=str, 15 | required=True, 16 | help="Title is required", 17 | location=('json', 'values') 18 | ) 19 | post_post_parser.add_argument( 20 | 'text', 21 | type=str, 22 | required=True, 23 | help="Body text is required", 24 | location=('json', 'values') 25 | ) 26 | post_post_parser.add_argument( 27 | 'tags', 28 | type=str, 29 | action='append', 30 | location=('json', 'values') 31 | ) 32 | 33 | post_put_parser = reqparse.RequestParser() 34 | post_put_parser.add_argument( 35 | 'title', 36 | type=str, 37 | location=('json', 'values') 38 | ) 39 | post_put_parser.add_argument( 40 | 'text', 41 | type=str, 42 | location=('json', 'values') 43 | ) 44 | post_put_parser.add_argument( 45 | 'tags', 46 | type=str, 47 | action='append', 48 | location=('json', 'values') 49 | ) 50 | -------------------------------------------------------------------------------- /Chapter-9/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from celery.schedules import crontab 3 | 4 | basedir = os.path.abspath(os.path.dirname(__file__)) 5 | 6 | 7 | class Config(object): 8 | SECRET_KEY = '736670cb10a600b695a55839ca3a5aa54a7d7356cdef815d2ad6e19a2031182b' 9 | RECAPTCHA_PUBLIC_KEY = "6LdKkQQTAAAAAEH0GFj7NLg5tGicaoOus7G9Q5Uw" 10 | RECAPTCHA_PRIVATE_KEY = '6LdKkQQTAAAAAMYroksPTJ7pWhobYb88fTAcxcYn' 11 | POSTS_PER_PAGE = 10 12 | 13 | TWITTER_API_KEY = "XXXX" 14 | TWITTER_API_SECRET = "XXXX" 15 | FACEBOOK_CLIENT_ID = "XXX" 16 | FACEBOOK_CLIENT_SECRET = "XXXX" 17 | 18 | 19 | class ProdConfig(Config): 20 | SQLALCHEMY_TRACK_MODIFICATIONS = False 21 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 22 | 23 | 24 | class DevConfig(Config): 25 | DEBUG = True 26 | SQLALCHEMY_TRACK_MODIFICATIONS = False 27 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 28 | 29 | CELERY_BROKER_URL = "amqp://rabbitmq:rabbitmq@localhost//" 30 | CELERY_RESULT_BACKEND = "amqp://rabbitmq:rabbitmq@localhost//" 31 | 32 | SMTP_SERVER = "smtp.gmail.com" 33 | SMTP_USER = "someemail@gmail.com" 34 | SMTP_PASSWORD = "password" 35 | SMTP_FROM = "from@flask.com" 36 | 37 | CELERYBEAT_SCHEDULE = { 38 | 'weekly-digest': { 39 | 'task': 'blog.tasks.digest', 40 | 'schedule': crontab(day_of_week=6, hour='10') 41 | }, 42 | } 43 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/blog/new.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Create a New Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-6/webapp/templates/blog/new.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Create a New Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-7/webapp/templates/blog/new.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Create a New Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-8/webapp/templates/blog/new.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Create a New Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-9/webapp/templates/blog/new.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Create a New Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-10/webapp/templates/blog/edit.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Edit Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-6/webapp/templates/blog/edit.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Edit Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-7/webapp/templates/blog/edit.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Edit Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-8/webapp/templates/blog/edit.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Edit Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-9/webapp/templates/blog/edit.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Edit Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.text.label }} 25 | {% if form.text.errors %} 26 | {% for e in form.text.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.text(id="editor", class_='form-control') }} 31 |
32 | 33 |
34 |
35 |
36 | {% endblock %} 37 | 38 | {% block js %} 39 | 41 | 44 | {% endblock %} 45 | -------------------------------------------------------------------------------- /Chapter-10/webapp/translations/pt/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Portuguese translations for PROJECT. 2 | # Copyright (C) 2018 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2018. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2018-08-19 15:54+0100\n" 11 | "PO-Revision-Date: 2018-08-19 13:29+0100\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: pt\n" 14 | "Language-Team: pt \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.4.0\n" 20 | 21 | #: webapp/templates/head.html:5 22 | msgid "Welcome to this Blog" 23 | msgstr "Bem-vindo a este Blog" 24 | 25 | #: webapp/templates/macros.html:57 26 | msgid "Read More" 27 | msgstr "Ler Mais" 28 | 29 | #: webapp/templates/navbar.html:11 30 | msgid "New Post" 31 | msgstr "Novo Artigo" 32 | 33 | #: webapp/templates/navbar.html:40 34 | msgid "Logout" 35 | msgstr "Sair" 36 | 37 | #: webapp/templates/navbar.html:45 38 | msgid "Login" 39 | msgstr "Entrar" 40 | 41 | #: webapp/templates/navbar.html:49 42 | msgid "Register" 43 | msgstr "Registo" 44 | 45 | #: webapp/templates/blog/rightbody.html:3 46 | msgid "Recent Posts" 47 | msgstr "Artigos recentes" 48 | 49 | #: webapp/templates/blog/rightbody.html:15 50 | msgid "Popular Tags" 51 | msgstr "Tags Populares" 52 | 53 | -------------------------------------------------------------------------------- /Chapter-11/webapp/translations/pt/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Portuguese translations for PROJECT. 2 | # Copyright (C) 2018 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2018. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2018-08-19 15:54+0100\n" 11 | "PO-Revision-Date: 2018-08-19 13:29+0100\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: pt\n" 14 | "Language-Team: pt \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.4.0\n" 20 | 21 | #: webapp/templates/head.html:5 22 | msgid "Welcome to this Blog" 23 | msgstr "Bem-vindo a este Blog" 24 | 25 | #: webapp/templates/macros.html:57 26 | msgid "Read More" 27 | msgstr "Ler Mais" 28 | 29 | #: webapp/templates/navbar.html:11 30 | msgid "New Post" 31 | msgstr "Novo Artigo" 32 | 33 | #: webapp/templates/navbar.html:40 34 | msgid "Logout" 35 | msgstr "Sair" 36 | 37 | #: webapp/templates/navbar.html:45 38 | msgid "Login" 39 | msgstr "Entrar" 40 | 41 | #: webapp/templates/navbar.html:49 42 | msgid "Register" 43 | msgstr "Registo" 44 | 45 | #: webapp/templates/blog/rightbody.html:3 46 | msgid "Recent Posts" 47 | msgstr "Artigos recentes" 48 | 49 | #: webapp/templates/blog/rightbody.html:15 50 | msgid "Popular Tags" 51 | msgstr "Tags Populares" 52 | 53 | -------------------------------------------------------------------------------- /Chapter-12/webapp/translations/pt/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Portuguese translations for PROJECT. 2 | # Copyright (C) 2018 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2018. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2018-08-19 15:54+0100\n" 11 | "PO-Revision-Date: 2018-08-19 13:29+0100\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: pt\n" 14 | "Language-Team: pt \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.4.0\n" 20 | 21 | #: webapp/templates/head.html:5 22 | msgid "Welcome to this Blog" 23 | msgstr "Bem-vindo a este Blog" 24 | 25 | #: webapp/templates/macros.html:57 26 | msgid "Read More" 27 | msgstr "Ler Mais" 28 | 29 | #: webapp/templates/navbar.html:11 30 | msgid "New Post" 31 | msgstr "Novo Artigo" 32 | 33 | #: webapp/templates/navbar.html:40 34 | msgid "Logout" 35 | msgstr "Sair" 36 | 37 | #: webapp/templates/navbar.html:45 38 | msgid "Login" 39 | msgstr "Entrar" 40 | 41 | #: webapp/templates/navbar.html:49 42 | msgid "Register" 43 | msgstr "Registo" 44 | 45 | #: webapp/templates/blog/rightbody.html:3 46 | msgid "Recent Posts" 47 | msgstr "Artigos recentes" 48 | 49 | #: webapp/templates/blog/rightbody.html:15 50 | msgid "Popular Tags" 51 | msgstr "Tags Populares" 52 | 53 | -------------------------------------------------------------------------------- /Chapter-13/webapp/translations/pt/LC_MESSAGES/messages.po: -------------------------------------------------------------------------------- 1 | # Portuguese translations for PROJECT. 2 | # Copyright (C) 2018 ORGANIZATION 3 | # This file is distributed under the same license as the PROJECT project. 4 | # FIRST AUTHOR , 2018. 5 | # 6 | msgid "" 7 | msgstr "" 8 | "Project-Id-Version: PROJECT VERSION\n" 9 | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" 10 | "POT-Creation-Date: 2018-08-19 15:54+0100\n" 11 | "PO-Revision-Date: 2018-08-19 13:29+0100\n" 12 | "Last-Translator: FULL NAME \n" 13 | "Language: pt\n" 14 | "Language-Team: pt \n" 15 | "Plural-Forms: nplurals=2; plural=(n != 1)\n" 16 | "MIME-Version: 1.0\n" 17 | "Content-Type: text/plain; charset=utf-8\n" 18 | "Content-Transfer-Encoding: 8bit\n" 19 | "Generated-By: Babel 2.4.0\n" 20 | 21 | #: webapp/templates/head.html:5 22 | msgid "Welcome to this Blog" 23 | msgstr "Bem-vindo a este Blog" 24 | 25 | #: webapp/templates/macros.html:57 26 | msgid "Read More" 27 | msgstr "Ler Mais" 28 | 29 | #: webapp/templates/navbar.html:11 30 | msgid "New Post" 31 | msgstr "Novo Artigo" 32 | 33 | #: webapp/templates/navbar.html:40 34 | msgid "Logout" 35 | msgstr "Sair" 36 | 37 | #: webapp/templates/navbar.html:45 38 | msgid "Login" 39 | msgstr "Entrar" 40 | 41 | #: webapp/templates/navbar.html:49 42 | msgid "Register" 43 | msgstr "Registo" 44 | 45 | #: webapp/templates/blog/rightbody.html:3 46 | msgid "Recent Posts" 47 | msgstr "Artigos recentes" 48 | 49 | #: webapp/templates/blog/rightbody.html:15 50 | msgid "Popular Tags" 51 | msgstr "Tags Populares" 52 | 53 | -------------------------------------------------------------------------------- /Chapter-7/webapp/auth/models.py: -------------------------------------------------------------------------------- 1 | from . import bcrypt, AnonymousUserMixin 2 | from .. import mongo 3 | 4 | 5 | class Role(mongo.Document): 6 | name = mongo.StringField(max_length=64, required=True, unique=True) 7 | description = mongo.StringField() 8 | 9 | def __unicode__(self): 10 | return self.name 11 | 12 | def __repr__(self): 13 | return self.name 14 | 15 | 16 | class User(mongo.Document): 17 | username = mongo.StringField(required=True) 18 | password = mongo.StringField() 19 | 20 | roles = mongo.ListField(mongo.ReferenceField(Role)) 21 | 22 | def __unicode__(self): 23 | return ''.format(self.username) 24 | 25 | def __repr__(self): 26 | return ''.format(self.username) 27 | 28 | def has_role(self, name): 29 | for role in self.roles: 30 | if role.name == name: 31 | return True 32 | return False 33 | 34 | def set_password(self, password): 35 | self.password = bcrypt.generate_password_hash(password) 36 | 37 | def check_password(self, password): 38 | return bcrypt.check_password_hash(self.password, password) 39 | 40 | @property 41 | def is_authenticated(self): 42 | if isinstance(self, AnonymousUserMixin): 43 | return False 44 | else: 45 | return True 46 | 47 | @property 48 | def is_active(self): 49 | return True 50 | 51 | @property 52 | def is_anonymous(self): 53 | if isinstance(self, AnonymousUserMixin): 54 | return True 55 | else: 56 | return False 57 | 58 | def get_id(self): 59 | return str(self.id) 60 | -------------------------------------------------------------------------------- /Chapter-13/.ebextensions/10_post_deploy.config: -------------------------------------------------------------------------------- 1 | files: 2 | "/opt/elasticbeanstalk/hooks/appdeploy/post/98_install_flask_youtube.sh": 3 | mode: "000755" 4 | owner: root 5 | group: root 6 | content: | 7 | #!/usr/bin/env bash 8 | 9 | cd /opt/python/current/app 10 | . /opt/python/current/env 11 | source /opt/python/run/venv/bin/activate 12 | sh install_flask_youtube.sh 13 | 14 | "/opt/elasticbeanstalk/hooks/appdeploy/post/99_migrate_database.sh": 15 | mode: "000755" 16 | owner: root 17 | group: root 18 | content: | 19 | #!/usr/bin/env bash 20 | 21 | cd /opt/python/current/app 22 | . /opt/python/current/env 23 | source /opt/python/run/venv/bin/activate 24 | export FLASK_APP=main.py 25 | if [ $WEBAPP_ENV = "Dev" ]; then 26 | rm -Rf migrations 27 | flask db init 28 | fi 29 | echo -------------------- 30 | echo Generate migration DDL code 31 | echo -------------------- 32 | flask db migrate 33 | echo -------------------- 34 | echo Run the DDL code and migrate 35 | echo -------------------- 36 | echo -------------------- 37 | echo This is the DDL code that will be run 38 | echo -------------------- 39 | flask db upgrade 40 | echo -------------------- 41 | echo Generating test data 42 | echo -------------------- 43 | flask test-data 44 | service httpd restart 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Chapter-11/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from celery.schedules import crontab 3 | 4 | basedir = os.path.abspath(os.path.dirname(__file__)) 5 | 6 | 7 | class Config(object): 8 | SECRET_KEY = '736670cb10a600b695a55839ca3a5aa54a7d7356cdef815d2ad6e19a2031182b' 9 | RECAPTCHA_PUBLIC_KEY = "6LdKkQQTAAAAAEH0GFj7NLg5tGicaoOus7G9Q5Uw" 10 | RECAPTCHA_PRIVATE_KEY = '6LdKkQQTAAAAAMYroksPTJ7pWhobYb88fTAcxcYn' 11 | POSTS_PER_PAGE = 10 12 | 13 | TWITTER_API_KEY = "XXXX" 14 | TWITTER_API_SECRET = "XXXX" 15 | FACEBOOK_CLIENT_ID = "XXX" 16 | FACEBOOK_CLIENT_SECRET = "XXXX" 17 | 18 | CELERY_BROKER_URL = "amqp://rabbitmq:rabbitmq@localhost//" 19 | CELERY_BACKEND_URL = "amqp://rabbitmq:rabbitmq@localhost//" 20 | 21 | MAIL_SERVER = "smtp.gmail.com" 22 | MAIL_PORT = 465 23 | MAIL_USE_SSL = True 24 | MAIL_USER = "@gmail.com" 25 | MAIL_PASSWORD = "password" 26 | MAIL_DEFAULT_SENDER = "from@flask.com" 27 | 28 | CELERYBEAT_SCHEDULE = { 29 | 'weekly-digest': { 30 | 'task': 'blog.tasks.digest', 31 | 'schedule': crontab(day_of_week=6, hour='10') 32 | }, 33 | } 34 | 35 | 36 | class ProdConfig(Config): 37 | SQLALCHEMY_TRACK_MODIFICATIONS = False 38 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 39 | 40 | CACHE_TYPE = 'redis' 41 | CACHE_REDIS_HOST = 'localhost' 42 | CACHE_REDIS_PORT = '6379' 43 | CACHE_REDIS_PASSWORD = '' 44 | CACHE_REDIS_DB = '0' 45 | 46 | 47 | class DevConfig(Config): 48 | DEBUG = True 49 | DEBUG_TB_INTERCEPT_REDIRECTS = False 50 | SQLALCHEMY_TRACK_MODIFICATIONS = False 51 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 52 | 53 | CACHE_TYPE = 'simple' 54 | -------------------------------------------------------------------------------- /Chapter-3/alembic.ini: -------------------------------------------------------------------------------- 1 | # A generic, single database configuration. 2 | 3 | [alembic] 4 | # path to migration scripts 5 | script_location = alembic 6 | 7 | # template used to generate migration files 8 | # file_template = %%(rev)s_%%(slug)s 9 | 10 | # max length of characters to apply to the 11 | # "slug" field 12 | #truncate_slug_length = 40 13 | 14 | # set to 'true' to run the environment during 15 | # the 'revision' command, regardless of autogenerate 16 | # revision_environment = false 17 | 18 | # set to 'true' to allow .pyc and .pyo files without 19 | # a source .py file to be detected as revisions in the 20 | # versions/ directory 21 | # sourceless = false 22 | 23 | # version location specification; this defaults 24 | # to alembic/versions. When using multiple version 25 | # directories, initial revisions must be specified with --version-path 26 | # version_locations = %(here)s/bar %(here)s/bat alembic/versions 27 | 28 | # the output encoding used when revision files 29 | # are written from script.py.mako 30 | # output_encoding = utf-8 31 | 32 | sqlalchemy.url = driver://user:pass@localhost/dbname 33 | 34 | 35 | # Logging configuration 36 | [loggers] 37 | keys = root,sqlalchemy,alembic 38 | 39 | [handlers] 40 | keys = console 41 | 42 | [formatters] 43 | keys = generic 44 | 45 | [logger_root] 46 | level = WARN 47 | handlers = console 48 | qualname = 49 | 50 | [logger_sqlalchemy] 51 | level = WARN 52 | handlers = 53 | qualname = sqlalchemy.engine 54 | 55 | [logger_alembic] 56 | level = INFO 57 | handlers = 58 | qualname = alembic 59 | 60 | [handler_console] 61 | class = StreamHandler 62 | args = (sys.stderr,) 63 | level = NOTSET 64 | formatter = generic 65 | 66 | [formatter_generic] 67 | format = %(levelname)-5.5s [%(name)s] %(message)s 68 | datefmt = %H:%M:%S 69 | -------------------------------------------------------------------------------- /Chapter-6/webapp/blog/models.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from .. import db 3 | 4 | tags = db.Table( 5 | 'post_tags', 6 | db.Column('post_id', db.Integer, db.ForeignKey('post.id')), 7 | db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')) 8 | ) 9 | 10 | 11 | class Post(db.Model): 12 | id = db.Column(db.Integer(), primary_key=True) 13 | title = db.Column(db.String(255), nullable=False) 14 | text = db.Column(db.Text(), nullable=False) 15 | publish_date = db.Column(db.DateTime(), default=datetime.datetime.now) 16 | user_id = db.Column(db.Integer(), db.ForeignKey('user.id')) 17 | comments = db.relationship( 18 | 'Comment', 19 | backref='post', 20 | lazy='dynamic' 21 | ) 22 | tags = db.relationship( 23 | 'Tag', 24 | secondary=tags, 25 | backref=db.backref('posts', lazy='dynamic') 26 | ) 27 | 28 | def __init__(self, title=""): 29 | self.title = title 30 | 31 | def __repr__(self): 32 | return "".format(self.title) 33 | 34 | 35 | class Comment(db.Model): 36 | id = db.Column(db.Integer(), primary_key=True) 37 | name = db.Column(db.String(255), nullable=False) 38 | text = db.Column(db.Text(), nullable=False) 39 | date = db.Column(db.DateTime(), default=datetime.datetime.now) 40 | post_id = db.Column(db.Integer(), db.ForeignKey('post.id')) 41 | 42 | def __repr__(self): 43 | return "".format(self.text[:15]) 44 | 45 | 46 | class Tag(db.Model): 47 | id = db.Column(db.Integer(), primary_key=True) 48 | title = db.Column(db.String(255), nullable=False, unique=True) 49 | 50 | def __init__(self, title=""): 51 | self.title = title 52 | 53 | def __repr__(self): 54 | return "".format(self.title) 55 | -------------------------------------------------------------------------------- /Chapter-8/webapp/blog/models.py: -------------------------------------------------------------------------------- 1 | import datetime 2 | from .. import db 3 | 4 | tags = db.Table( 5 | 'post_tags', 6 | db.Column('post_id', db.Integer, db.ForeignKey('post.id')), 7 | db.Column('tag_id', db.Integer, db.ForeignKey('tag.id')) 8 | ) 9 | 10 | 11 | class Post(db.Model): 12 | id = db.Column(db.Integer(), primary_key=True) 13 | title = db.Column(db.String(255), nullable=False) 14 | text = db.Column(db.Text(), nullable=False) 15 | publish_date = db.Column(db.DateTime(), default=datetime.datetime.now) 16 | user_id = db.Column(db.Integer(), db.ForeignKey('user.id')) 17 | comments = db.relationship( 18 | 'Comment', 19 | backref='post', 20 | lazy='dynamic' 21 | ) 22 | tags = db.relationship( 23 | 'Tag', 24 | secondary=tags, 25 | backref=db.backref('posts', lazy='dynamic') 26 | ) 27 | 28 | def __init__(self, title=""): 29 | self.title = title 30 | 31 | def __repr__(self): 32 | return "".format(self.title) 33 | 34 | 35 | class Comment(db.Model): 36 | id = db.Column(db.Integer(), primary_key=True) 37 | name = db.Column(db.String(255), nullable=False) 38 | text = db.Column(db.Text(), nullable=False) 39 | date = db.Column(db.DateTime(), default=datetime.datetime.now) 40 | post_id = db.Column(db.Integer(), db.ForeignKey('post.id')) 41 | 42 | def __repr__(self): 43 | return "".format(self.text[:15]) 44 | 45 | 46 | class Tag(db.Model): 47 | id = db.Column(db.Integer(), primary_key=True) 48 | title = db.Column(db.String(255), nullable=False, unique=True) 49 | 50 | def __init__(self, title=""): 51 | self.title = title 52 | 53 | def __repr__(self): 54 | return "".format(self.title) 55 | -------------------------------------------------------------------------------- /Chapter-10/config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from celery.schedules import crontab 3 | 4 | basedir = os.path.abspath(os.path.dirname(__file__)) 5 | 6 | 7 | class Config(object): 8 | SECRET_KEY = '736670cb10a600b695a55839ca3a5aa54a7d7356cdef815d2ad6e19a2031182b' 9 | RECAPTCHA_PUBLIC_KEY = "6LdKkQQTAAAAAEH0GFj7NLg5tGicaoOus7G9Q5Uw" 10 | RECAPTCHA_PRIVATE_KEY = '6LdKkQQTAAAAAMYroksPTJ7pWhobYb88fTAcxcYn' 11 | POSTS_PER_PAGE = 10 12 | 13 | TWITTER_API_KEY = "XXXX" 14 | TWITTER_API_SECRET = "XXXX" 15 | FACEBOOK_CLIENT_ID = "XXX" 16 | FACEBOOK_CLIENT_SECRET = "XXXX" 17 | 18 | CELERY_BROKER_URL = "amqp://rabbitmq:rabbitmq@localhost//" 19 | CELERY_RESULT_BACKEND = "amqp://rabbitmq:rabbitmq@localhost//" 20 | 21 | MAIL_SERVER = "smtp.gmail.com" 22 | MAIL_PORT = 465 23 | MAIL_USE_SSL=True 24 | SMTP_SERVER = "smtp.gmail.com" 25 | SMTP_USER = "someemail@gmail.com" 26 | SMTP_PASSWORD = "password" 27 | SMTP_FROM = "from@flask.com" 28 | 29 | CELERYBEAT_SCHEDULE = { 30 | 'weekly-digest': { 31 | 'task': 'blog.tasks.digest', 32 | 'schedule': crontab(day_of_week=6, hour='10') 33 | }, 34 | } 35 | 36 | 37 | class ProdConfig(Config): 38 | SQLALCHEMY_TRACK_MODIFICATIONS = False 39 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 40 | 41 | CACHE_TYPE = 'redis' 42 | CACHE_REDIS_HOST = 'localhost' 43 | CACHE_REDIS_PORT = '6379' 44 | CACHE_REDIS_PASSWORD = '' 45 | CACHE_REDIS_DB = '0' 46 | 47 | 48 | class DevConfig(Config): 49 | DEBUG = True 50 | DEBUG_TB_INTERCEPT_REDIRECTS = False 51 | SQLALCHEMY_TRACK_MODIFICATIONS = False 52 | SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'database.db') 53 | 54 | CACHE_TYPE = 'simple' 55 | -------------------------------------------------------------------------------- /Chapter-11/webapp/templates/blog/new.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Create a New Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.youtube_id.label }} 25 | {% if form.youtube_id.errors %} 26 | {% for e in form.youtube_id.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.youtube_id(class_='form-control') }} 31 |
32 |
33 | {{ form.text.label }} 34 | {% if form.text.errors %} 35 | {% for e in form.text.errors %} 36 |

{{ e }}

37 | {% endfor %} 38 | {% endif %} 39 | {{ form.text(id="editor", class_='form-control') }} 40 |
41 | 42 |
43 |
44 |
45 | {% endblock %} 46 | 47 | {% block js %} 48 | 50 | 53 | {% endblock %} 54 | -------------------------------------------------------------------------------- /Chapter-12/webapp/templates/blog/new.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Create a New Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.youtube_id.label }} 25 | {% if form.youtube_id.errors %} 26 | {% for e in form.youtube_id.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.youtube_id(class_='form-control') }} 31 |
32 |
33 | {{ form.text.label }} 34 | {% if form.text.errors %} 35 | {% for e in form.text.errors %} 36 |

{{ e }}

37 | {% endfor %} 38 | {% endif %} 39 | {{ form.text(id="editor", class_='form-control') }} 40 |
41 | 42 |
43 |
44 |
45 | {% endblock %} 46 | 47 | {% block js %} 48 | 50 | 53 | {% endblock %} 54 | -------------------------------------------------------------------------------- /Chapter-13/webapp/templates/blog/new.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Post Creation{% endblock %} 3 | {% block body %} 4 |
5 |
6 |
7 |

Create a New Post

8 |
9 |
10 | 11 |
12 |
13 | {{ form.hidden_tag() }} 14 |
15 | {{ form.title.label }} 16 | {% if form.title.errors %} 17 | {% for e in form.title.errors %} 18 |

{{ e }}

19 | {% endfor %} 20 | {% endif %} 21 | {{ form.title(class_='form-control') }} 22 |
23 |
24 | {{ form.youtube_id.label }} 25 | {% if form.youtube_id.errors %} 26 | {% for e in form.youtube_id.errors %} 27 |

{{ e }}

28 | {% endfor %} 29 | {% endif %} 30 | {{ form.youtube_id(class_='form-control') }} 31 |
32 |
33 | {{ form.text.label }} 34 | {% if form.text.errors %} 35 | {% for e in form.text.errors %} 36 |

{{ e }}

37 | {% endfor %} 38 | {% endif %} 39 | {{ form.text(id="editor", class_='form-control') }} 40 |
41 | 42 |
43 |
44 |
45 | {% endblock %} 46 | 47 | {% block js %} 48 | 50 | 53 | {% endblock %} 54 | -------------------------------------------------------------------------------- /Chapter-10/webapp/api/blog/parsers.py: -------------------------------------------------------------------------------- 1 | from flask_restful import reqparse 2 | 3 | user_post_parser = reqparse.RequestParser() 4 | user_post_parser.add_argument('username', type=str, required=True) 5 | user_post_parser.add_argument('password', type=str, required=True) 6 | 7 | post_get_parser = reqparse.RequestParser() 8 | post_get_parser.add_argument('page', type=int, location=['args', 'headers']) 9 | post_get_parser.add_argument('user', type=str, location=['args', 'headers']) 10 | 11 | post_post_parser = reqparse.RequestParser() 12 | post_post_parser.add_argument( 13 | 'title', 14 | type=str, 15 | required=True, 16 | help="Title is required", 17 | location=('json', 'values') 18 | ) 19 | post_post_parser.add_argument( 20 | 'text', 21 | type=str, 22 | required=True, 23 | help="Body text is required", 24 | location=('json', 'values') 25 | ) 26 | post_post_parser.add_argument( 27 | 'tags', 28 | type=str, 29 | action='append', 30 | location=('json', 'values') 31 | ) 32 | 33 | post_put_parser = reqparse.RequestParser() 34 | post_put_parser.add_argument( 35 | 'title', 36 | type=str, 37 | location=('json', 'values') 38 | ) 39 | post_put_parser.add_argument( 40 | 'text', 41 | type=str, 42 | location=('json', 'values') 43 | ) 44 | post_put_parser.add_argument( 45 | 'tags', 46 | type=str, 47 | action='append', 48 | location=('json', 'values') 49 | ) 50 | 51 | reminder_post_parser = reqparse.RequestParser() 52 | reminder_post_parser.add_argument( 53 | 'email', 54 | type=str, 55 | required=True, 56 | help="Email is required", 57 | location=('json', 'values') 58 | ) 59 | reminder_post_parser.add_argument( 60 | 'text', 61 | type=str, 62 | required=True, 63 | help="Text is required", 64 | location=('json', 'values') 65 | ) 66 | --------------------------------------------------------------------------------