This is one of my hobby projects, to learn a new framework that is different to what I usually use at work. It is a blogging platform, where users can register, post their thoughts, and interact with each other by following each other, commenting and voting on others' posts.
Main programming languages used:
- Python
- JavaScript
- CSS3
- HTML5
- SQL
Libraries and Frameworks used:
- Flask (for back-end)
- Bootstrap 5 (to easily style the whole blog)
- SQLAlchemy (ORM to conduct CRUD operations with the database)
- jQuery (To help ease client-side data processing)
- Alembic (Database migration tool, to help update the database with schema changes (e.g. addition or deletion of a column for a particular table))
- Jinja2 (Templating language for Flask to help display backend data to frontend)
- Unittest (To test the application automatically)
CI/CD and deployment:
- DigitalOcean as the Linux server where the live blog is currently deployed
- Docker (To ease deployment of the app)
- GitHub Action (To automate testing and deployment of the blog to the live server)
- Git (Version control)
- Gunicorn (A Python WSGI HTTP server used to serve the application in the live server)
The database schema is as shown below, generated using drawsql.app. SQLite is used as the development and testing database, and MYSQL is used in the live blog (i.e. production).
Some notes on the database schema:
-
To ensure unique users, the
users
table requires uniqueemail
andusername
column values. -
Only password hashes are being stored in the database. Any password input for login are hashed using a particular hash algorithm and the generated value compared against the one stored.
-
roles
table allow us to group users into different types; currently they are generic users, moderators and administrators, each with different permissions. These are assigned to each user and processed inmodels.py
. -
posts
andcomments
tables havetitle_html
andbody_html
columns. These are filtered inputs of posts and comments to the blog, and the raw input is stored intitle
andbody
columns respectively.The
_html
versions are the ones used in rendering the posts and comments to the blog. The filter is needed to avoid any risks of being attacked withHTML
orJavaScript
injection, for example inputs such as<script>alert('xss')</script>
, which if used could render dangerous outputs to the blog, such as login forms or buttons that lead to malicious websites. TheJinja2
renderer used, actually already implement their own filters to any values to be rendered. However, since the posts and comments allow markdown input, I have my own filters for extra security. -
The
follows
andvotes
tables are association tables.follows
table cover the many-to-many relationship betweenusers
andusers
table.votes
table cover the one-to-many relationship betweenusers
andvotes
, and many-to-one betweenvotes
andposts
. These represent the fact that one user can follow and be followed by multiple users, and that a user can vote for multiple posts and that a post can have multiple votes.The
follower_id
andfollowing_id
are foreign keys of thefollows
association table, andvoter_id
andpost_id
are foreign keys for thevotes
association table. -
Validation of input (e.g. email has to be of format [email protected]) is done at the server-side, using Python packages such as
flask-form
. -
No index column is made on any of the tables, I'll add this in the future to speed up queries.
To deploy the project in your own system:
- Download
Python 3.9.5
or higher to your system, andsqlite3
for the database - Fork this repository, open up a terminal session, and navigate to the forked repository
- Create a virtual environment (recommended) using
python -m venv venvYourName
- Install all Python requirements using
python -m pip install -r requirements/common.txt
- Create an environment variable in the terminal
FLASK_APP
with valueblogging.py
, andSECRET_KEY
with a hard to guess string as its value; you can create one here https://randomkeygen.com/ - Run the command
flask run
in the terminal, and navigate tolocalhost:5000
in your browser. A databasedata-dev.sqlite
will automatically be created and used by your system.
Alternatively, you can use Docker to deploy:
- Download and install docker in your system
- Create a new folder in your file system, and copy the file
docker-compose.yml
andDockerfile
from this repository to that folder, and then dodocker-compose build .
. Alternatively instead of local build, download the docker image for this blog by runningdocker pull aldosebastian/blogging
(login to your Dockerhub account first). - Create a new file in the folder you created called
.env-blogging
with the following data:
FLASK_APP=blogging.py
FLASK_CONFIG=docker
SECRET_KEY=a hard to guess string as its value; you can create one from https://randomkeygen.com/
DATABASE_URL=mysql+pymysql://yourName:yourPassword@mysql-server/blogging
and a new file .env-mysql
with the data:
MYSQL_RANDOM_ROOT_PASSWORD=yes
MYSQL_DATABASE=blogging
MYSQL_USER=yourName
MYSQL_PASSWORD=yourPassword
Replace yourName
and yourPassword
in the above commands with your own chosen name and password, this is used to access the database.
- Create a new folder named
persisted_data
in the folder you previously made. Opendocker-compose.yml
file, go tovolumes
section undermysql
, and change/home/aldo/bloggingDB/data
with./persisted_data
. All the data of the app will be inside here. - Finally, run
docker-compose up -d
to start the blog server in the background, open up your browser and go tolocalhost:8000
- To stop the blog from running, type
docker-compose down
The folder tests
contains unit tests for the application. To run all the tests, simply run flask test