')
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 |
5 |
6 | {{ message }}
7 |
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 |
5 |
6 | {{ message }}
7 |
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 | |
10 | {{col}} {{ obj[col] }}
11 | |
12 | {% endfor %}
13 |
14 | {% endfor %}
15 |
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 |
5 |
6 | {{ message }}
7 |
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 |
5 |
6 | {{ message }}
7 |
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 |
5 |
6 | {{ message }}
7 |
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 |
5 |
6 | {{ message }}
7 |
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 |
5 |
6 | {{ message }}
7 |
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 |
5 |
6 | {{ message }}
7 |
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 |
5 |
6 | {{ message }}
7 |
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 |
5 |
6 | {{ message }}
7 |
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 |
5 |
6 | {{ message }}
7 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
--------------------------------------------------------------------------------