Metadata-Version: 2.4
Name: roleflow
Version: 0.1.4
Summary: A lightweight, hassle-free and production-ready RBAC (Role-Based Access Control) library.
Project-URL: Homepage, https://github.com/developer/easy-rbac
Author-email: sougata <sougatachongder8@gmail.com>
License: MIT
Requires-Python: >=3.8
Requires-Dist: pydantic>=2.0.0
Provides-Extra: fastapi
Requires-Dist: fastapi>=0.100.0; extra == 'fastapi'
Provides-Extra: test
Requires-Dist: fastapi; extra == 'test'
Requires-Dist: httpx; extra == 'test'
Requires-Dist: pytest; extra == 'test'
Requires-Dist: pytest-asyncio; extra == 'test'
Description-Content-Type: text/markdown

# RoleFlow

A lightweight, production-ready Role-Based Access Control (RBAC) package for Python, designed to be simple, fast, and framework-agnostic, while featuring seamless integration out-of-the-box for FastAPI.

## Features
- **Generic RBAC Engine**: Easily verify permissions using wildcards (`*`, `table.*`) or exact matches.
- **Pydantic Validation**: Strong typing and validation for your Role and Permission schemas.
- **FastAPI Integration**: Native `RBACGuard` dependency injection for secure and hassle-free route protection.

## Installation

```bash
pip install roleflow
```

To install with FastAPI dependencies:   
```bash
pip install roleflow[fastapi]
```

## Quick Start

### 1. Define your Roles
```python
from roleflow import Role, RBACEngine

roles = [
    Role(id=1, name="ROLE_ADMIN", permissions=["*"]),
    Role(id=2, name="ROLE_STUDENT", permissions=["profile.read", "profile.edit", "course.read"]),
    Role(id=3, name="ROLE_HOD", permissions=["course.*", "leave.approve"])
]

engine = RBACEngine(roles=roles)
```

### 2. Fetch Roles from a Database (Dynamic Loading)
You don't have to provide all roles upfront. You can hook into your Database ORM by passing a `role_loader` callback function to the engine:

```python
from roleflow import Role, RBACEngine

# Simulated database fetch function (e.g. using SQLAlchemy)
def db_role_loader(role_name: str) -> Role:
    # 1. Query your database here using SQLAlchemy
    # db_record = session.query(DbRole).filter(DbRole.name == role_name).first()
    # 2. Convert database result into the generic easy_rbac.Role schema
    # return Role(id=db_record.id, name=db_record.name, permissions=db_record.permissions)
    pass

# Initialize engine without static roles
engine = RBACEngine(role_loader=db_role_loader)

# The engine will automatically call db_role_loader("ROLE_ADMIN") and cache it!
engine.is_granted("ROLE_ADMIN", "table1.read")
```

### 3. Check Permissions
```python
# Returns True
engine.is_granted("ROLE_ADMIN", "anything.you.want") 
engine.is_granted("ROLE_STUDENT", "profile.read")
engine.is_granted("ROLE_HOD", "course.create")

# Returns False
engine.is_granted("ROLE_STUDENT", "course.create")
```

### 4. FastAPI Integration
```python
from fastapi import FastAPI, Depends
from roleflow.fastapi import RBACGuard

app = FastAPI()

# A mock function to get the current user's role
def get_current_user_role() -> str:
    return "ROLE_STUDENT"

guard = RBACGuard(engine=engine, role_provider=get_current_user_role)

@app.get("/courses", dependencies=[Depends(guard("course.read"))])
def list_courses():
    return {"message": "You can read courses!"}
```
