Skip to content

Commit

Permalink
Add chapter 7
Browse files Browse the repository at this point in the history
  • Loading branch information
lubianat committed May 4, 2023
1 parent 13720b2 commit 1db65be
Show file tree
Hide file tree
Showing 10 changed files with 155 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ Thumbs.db
*venv*

.flaskenv
mail_config.sh
39 changes: 38 additions & 1 deletion app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_login import LoginManager
import logging
from logging.handlers import SMTPHandler
from logging.handlers import RotatingFileHandler
import os

app = Flask(__name__)
login = LoginManager(app)
Expand All @@ -11,5 +15,38 @@
db = SQLAlchemy(app)
migrate = Migrate(app, db) # Migrate is a wrapper around Alembic

if not app.debug:
if app.config["MAIL_SERVER"]:
auth = None
secure = None

from app import routes, models
if app.config["MAIL_USERNAME"] or app.config["MAIL_PASSWORD"]:
auth = (app.config["MAIL_USERNAME"], app.config["MAIL_PASSWORD"])
if app.config["MAIL_USE_TLS"]:
secure = ()
mail_handler = SMTPHandler(
mailhost=(app.config["MAIL_SERVER"], app.config["MAIL_PORT"]),
fromaddr="no-reply@" + app.config["MAIL_SERVER"],
toaddrs=app.config["ADMINS"],
subject="Microblog Failure",
credentials=auth,
secure=secure,
)
mail_handler.setLevel(logging.ERROR)
app.logger.addHandler(mail_handler)
if not os.path.exists("logs"):
os.mkdir("logs")
file_handler = RotatingFileHandler(
"logs/microblog.log", maxBytes=10240, backupCount=10
)
file_handler.setFormatter(
logging.Formatter(
"%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]"
)
)
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info("Microblog startup")

from app import routes, models, errors
Binary file modified app/app.db
Binary file not shown.
6 changes: 6 additions & 0 deletions app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,9 @@ class Config(object):
"DATABASE_URL"
) or "sqlite:///" + os.path.join(basedir, "app.db")
SQLALCHEMY_TRACK_MODIFICATIONS = False
MAIL_SERVER = os.environ.get("MAIL_SERVER")
MAIL_PORT = int(os.environ.get("MAIL_PORT") or 25)
MAIL_USE_TLS = os.environ.get("MAIL_USE_TLS") is not None
MAIL_USERNAME = os.environ.get("MAIL_USERNAME")
MAIL_PASSWORD = os.environ.get("MAIL_PASSWORD")
ADMINS = ["tiago.lubiana.alves@usp.br"]
13 changes: 13 additions & 0 deletions app/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from flask import render_template
from app import app, db


@app.errorhandler(404)
def not_found_error(error):
return render_template("404.html"), 404


@app.errorhandler(500)
def internal_error(error):
db.session.rollback()
return render_template("500.html"), 500
10 changes: 10 additions & 0 deletions app/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ class EditProfileForm(FlaskForm):
about_me = TextAreaField("About me", validators=[Length(min=0, max=140)])
submit = SubmitField("Submit")

def __init__(self, original_username, *args, **kwargs):
super(EditProfileForm, self).__init__(*args, **kwargs)
self.original_username = original_username

def validate_username(self, username):
if username.data != self.original_username:
user = User.query.filter_by(username=self.username.data).first()
if user is not None:
raise ValidationError("Please use a different username.")


class RegistrationForm(FlaskForm):
username = StringField("Username", validators=[DataRequired()])
Expand Down
2 changes: 1 addition & 1 deletion app/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def before_request():
@app.route("/edit_profile", methods=["GET", "POST"])
@login_required
def edit_profile():
form = EditProfileForm()
form = EditProfileForm(current_user.username)
if form.validate_on_submit():
current_user.username = form.username.data
current_user.about_me = form.about_me.data
Expand Down
5 changes: 5 additions & 0 deletions app/templates/404.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{% extends "base.html" %}
{% block content %}
<h1>File Not Found</h1>
<p><a href="{{ url_for('index') }}">Back</a></p>
{% endblock %}
6 changes: 6 additions & 0 deletions app/templates/500.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{% extends "base.html" %}
{% block content %}
<h1>An unexpected error has occurred</h1>
<p>The administrator has been notified. Sorry for the inconvenience!</p>
<p><a href="{{ url_for('index') }}">Back</a></p>
{% endblock %}
75 changes: 75 additions & 0 deletions logs/microblog.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
2023-05-03 14:42:48,422 INFO: Microblog startup [in /home/lubianat/Documents/random/flask_tutorial/app/__init__.py:50]
2023-05-03 14:43:04,661 ERROR: Exception on /edit_profile [POST] [in /home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/flask/app.py:1744]
Traceback (most recent call last):
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1964, in _exec_single_context
self.dialect.do_execute(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/engine/default.py", line 748, in do_execute
cursor.execute(statement, parameters)
sqlite3.IntegrityError: UNIQUE constraint failed: user.username

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/flask/app.py", line 2528, in wsgi_app
response = self.full_dispatch_request()
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/flask/app.py", line 1825, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/flask/app.py", line 1823, in full_dispatch_request
rv = self.dispatch_request()
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/flask/app.py", line 1799, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/flask_login/utils.py", line 290, in decorated_view
return current_app.ensure_sync(func)(*args, **kwargs)
File "/home/lubianat/Documents/random/flask_tutorial/app/routes.py", line 27, in edit_profile
db.session.commit()
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/scoping.py", line 553, in commit
return self._proxied.commit()
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1903, in commit
trans.commit(_to_root=True)
File "<string>", line 2, in commit
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go
ret_value = fn(self, *arg, **kw)
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1218, in commit
self._prepare_impl()
File "<string>", line 2, in _prepare_impl
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/state_changes.py", line 137, in _go
ret_value = fn(self, *arg, **kw)
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 1193, in _prepare_impl
self.session.flush()
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 4155, in flush
self._flush(objects)
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 4292, in _flush
transaction.rollback(_capture_exception=True)
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/util/langhelpers.py", line 147, in __exit__
raise exc_value.with_traceback(exc_tb)
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/session.py", line 4252, in _flush
flush_context.execute()
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/unitofwork.py", line 467, in execute
rec.execute(self)
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/unitofwork.py", line 644, in execute
util.preloaded.orm_persistence.save_obj(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/persistence.py", line 85, in save_obj
_emit_update_statements(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/orm/persistence.py", line 890, in _emit_update_statements
c = connection.execute(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1414, in execute
return meth(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/sql/elements.py", line 486, in _execute_on_connection
return connection._execute_clauseelement(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1638, in _execute_clauseelement
ret = self._execute_context(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1842, in _execute_context
return self._exec_single_context(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1983, in _exec_single_context
self._handle_dbapi_exception(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 2326, in _handle_dbapi_exception
raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/engine/base.py", line 1964, in _exec_single_context
self.dialect.do_execute(
File "/home/lubianat/Documents/random/flask_tutorial/venv/lib/python3.8/site-packages/sqlalchemy/engine/default.py", line 748, in do_execute
cursor.execute(statement, parameters)
sqlalchemy.exc.IntegrityError: (sqlite3.IntegrityError) UNIQUE constraint failed: user.username
[SQL: UPDATE user SET username=?, about_me=? WHERE user.id = ?]
[parameters: ('susan', 'a', 2)]
(Background on this error at: https://sqlalche.me/e/20/gkpj)
2023-05-03 14:45:41,536 INFO: Microblog startup [in /home/lubianat/Documents/random/flask_tutorial/app/__init__.py:50]

0 comments on commit 1db65be

Please sign in to comment.