Skip to content

Commit

Permalink
Merge branch 'release/1.0.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
bunya017 committed Apr 4, 2021
2 parents 1aa5d8c + 2ec8464 commit 600afb9
Show file tree
Hide file tree
Showing 38 changed files with 2,043 additions and 3 deletions.
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ __pycache__
*.pyc

# Environments
.env
venv/

# Editors and IDE
Expand All @@ -12,4 +11,4 @@ venv/

# Mac-Stuff
.DS_Store
cloud_storage_key.json

21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) [2021] [Bunyamin Sani]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
83 changes: 83 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# FastAPI Project Template

Generate a FastAPI application backend with Role Based Access Control(RBAC) using Python, including interactive API documentation.

## Features

* **Production ready** Python web server using Uvicorn and Gunicorn.
* Everything that comes with [FastAPI](https://fastapi.tiangolo.com/features/)
* **Fast:** Very high performance, on par with NodeJS and Go (thanks to Starlette and Pydantic).
* **Intuitive:** Great editor support. Completion everywhere. Less time debugging.
* **Easy:** Designed to be easy to use and learn. Less time reading docs.
* **Short:** Minimize code duplication. Multiple features from each parameter declaration.
* **Robust:** Get production-ready code. With automatic interactive documentation.
* **Standards-based:** Based on (and fully compatible with) the open standards for APIs: OpenAPI and JSON Schema.
* Many other features including automatic validation, serialization, interactive documentation, authentication with OAuth2 JWT tokens, etc.
* **RBAC:** Role Based Access Control
* **Secure password** hashing by default.
* **JWT** token authentication.
* **SQLAlchemy** models.
* **Alembic** migrations.
* **CORS** (Cross Origin Resource Sharing).
* Browse API docs offline
* Basic starting models for users (modify and remove as you need).
* Dependencies to check permission
* Initial data for admin User, permissions , roles, and group
* Dummy email for development

## How to use it

Go to the directory where you want to create your project and run:

```bash
pip install cookiecutter
cookiecutter https://github.com/Bexils/fastapi-project-template
```

### Generate passwords

You will be asked to provide secret key whic will be used for password hashing. Open another terminal and run:

```bash
openssl rand -hex 32
# Outputs something like: f5e601cffde98e116dab4e31c50764006c765295732d40a57dbebc02e273eeb1
```

If you're on Windows, run the command above on a WSL terminal or git bash.
Copy the contents and use that as password / secret key. And run that again to generate another secure key.


### Input variables

The generator (cookiecutter) will ask you for some data, you might want to have at hand before generating the project.

The input variables, with their default values (some auto generated) are:

* `project_name`: The name of the project
* `project_slug`: The development friendly name of the project. By default, based on the project name
* `secret_key`: Backend server secret key. Use the method above to generate it.
* `superuser_email`: The first superuser generated, with it you will be able to create more users, etc. By default, based on the domain.
* `superuser_password`: First superuser password. Use the method above to generate it or set a frendlier one.
* `db_host`: Database server url
* `db_port`: Database server port
* `db_name`: Name of database to use on the database server
* `db_engine`: Database server type, e.g postgres(default), mysql, e.t.c
* `db_user`: Database server user's username
* `db_password`: Database server user's password, use the method above to generate it or set a frendlier one.

## More details

After using this generator, your new project (the directory created) will contain an extensive `README.md` with instructions for development, deployment, etc. You can pre-read [the project `README.md` template here too](./{{cookiecutter.project_slug}}/README.md).

## Won't Do

This project does not intend to support any other ORM apart from SQLAlchemy unless it works as smoothly with pydantic as SQLAlchemy does.

## License

This project is licensed under the terms of the MIT license.

## Screenshots

![Screenshot 1](./assets/01.png)
![Screenshot 2](./assets/02.png)
Binary file added assets/01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"project_name": "Base Project",
"project_slug": "{{ cookiecutter.project_name|lower|replace(' ', '-') }}",
"secret_key": "change_this",
"superuser_email": "admin@example.com",
"superuser_password": "superadminpassword",
"db_host": "localhost",
"db_port": 5432,
"db_name": "test_db",
"db_engine": "postgres",
"db_user": "user",
"db_password": "password",
"_copy_without_render": [
"*.js",
"*.ini"
]
}
18 changes: 18 additions & 0 deletions {{cookiecutter.project_slug}}/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Python compile stuff
__pycache__
*.pyc

# Environments
.env
venv/

# Editors and IDE
.idea
.vscode/

# Mac-Stuff
.DS_Store
cloud_storage_key.json

# Own directories
emails/
39 changes: 39 additions & 0 deletions {{cookiecutter.project_slug}}/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# {{cookiecutter.project_name}}

This is a backend server application power with Python and [FastAPI](https://fastapi.tiangolo.com).

## Local Development

### Install the dependencies

Create a virtual environment:
```bash
python -m venv venv
```

Activate the virtual environment:
```bash
venv/Scripts/activate
```
Change directory to `app/` folder
```bash
cd app/
```
Install dependencies
```bash
pip install -r requirements.txt
```
Ensure that your database config in `.env` is correct, then run [alembic](https://alembic.sqlalchemy.org) migrations
```bash
alembic upgrade head
```
Initialise database with User & RBAC tables and initial entries
```bash
python initial_data.py
```

### Start the development server
Run without `--reload` flag if you want to disable hot module reloading (HMR)
```bash
uvicorn main:app --reload
```
49 changes: 49 additions & 0 deletions {{cookiecutter.project_slug}}/app/access_control/cruds.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
from sqlalchemy.orm import Session

from access_control import models, schemas



def create_permission(db: Session, perm_data: schemas.PermissionCreate):
permission = models.Permission(**perm_data.dict(exclude_unset=True))
permission.name = permission.name.lower()
db.add(permission)
db.commit()
db.refresh(permission)
return permission


def get_perm_by_name(db: Session, name: str):
return db.query(models.Permission). \
filter(models.Permission.name == name.lower()). \
first()


def create_role(db: Session, role_data: schemas.RoleCreate):
role = models.Role(**role_data.dict(exclude_unset=True))
role.name = role.name.lower()
db.add(role)
db.commit()
db.refresh(role)
return role


def get_role_by_name(db: Session, name: str):
return db.query(models.Role). \
filter(models.Role.name == name.lower()). \
first()


def create_group(db: Session, group_data: schemas.GroupCreate):
group = models.Group(**group_data.dict(exclude_unset=True))
group.name = group.name.lower()
db.add(group)
db.commit()
db.refresh(group)
return group


def get_group_by_name(db: Session, name: str):
return db.query(models.Group). \
filter(models.Group.name == name.lower()). \
first()
29 changes: 29 additions & 0 deletions {{cookiecutter.project_slug}}/app/access_control/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from sqlalchemy import Column, ForeignKey, Integer, Table
from sqlalchemy.orm import relationship

from config.db import Base
from mixins.columns import BaseMixin, BaseUACMixin



# Many to Many associations
permission_role = Table('permission_role', Base.metadata,
Column('permission_id', Integer, ForeignKey('permissions.id')),
Column('role_id', Integer, ForeignKey('roles.id'))
)
role_group = Table('role_group', Base.metadata,
Column('role_id', Integer, ForeignKey('roles.id')),
Column('group_id', Integer, ForeignKey('groups.id'))
)


class Permission(BaseUACMixin, Base):
pass


class Role(BaseUACMixin, Base):
permissions = relationship("Permission", secondary=permission_role)


class Group(BaseUACMixin, Base):
roles = relationship("Role", secondary=role_group)
Loading

0 comments on commit 600afb9

Please sign in to comment.