fastapi-fastio 0.1.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. fastapi_fastio-0.1.2.dist-info/METADATA +159 -0
  2. fastapi_fastio-0.1.2.dist-info/RECORD +91 -0
  3. fastapi_fastio-0.1.2.dist-info/WHEEL +4 -0
  4. fastapi_fastio-0.1.2.dist-info/entry_points.txt +2 -0
  5. fastapi_fastio-0.1.2.dist-info/licenses/LICENSE +21 -0
  6. fastio/__init__.py +2 -0
  7. fastio/cli/__init__.py +0 -0
  8. fastio/cli/app.py +151 -0
  9. fastio/generators/__init__.py +0 -0
  10. fastio/generators/base.py +33 -0
  11. fastio/generators/monolith.py +31 -0
  12. fastio/generators/monorepo.py +42 -0
  13. fastio/generators/service.py +92 -0
  14. fastio/main.py +5 -0
  15. fastio/models/__init__.py +0 -0
  16. fastio/models/options.py +65 -0
  17. fastio/renderers/__init__.py +0 -0
  18. fastio/renderers/jinja.py +20 -0
  19. fastio/renderers/writer.py +8 -0
  20. fastio/templates/common/Dockerfile.j2 +9 -0
  21. fastio/templates/common/compose.yml.j2 +58 -0
  22. fastio/templates/common/empty.py.j2 +0 -0
  23. fastio/templates/common/env.example.j2 +20 -0
  24. fastio/templates/common/gitignore.j2 +15 -0
  25. fastio/templates/common/publish.yml.j2 +33 -0
  26. fastio/templates/common/test_smoke.py.j2 +2 -0
  27. fastio/templates/monolith/README.md.j2 +11 -0
  28. fastio/templates/monolith/alembic.ini.j2 +7 -0
  29. fastio/templates/monolith/app/core/config.py.j2 +22 -0
  30. fastio/templates/monolith/app/main.py.j2 +11 -0
  31. fastio/templates/monolith/app/modules/users/api.py.j2 +8 -0
  32. fastio/templates/monolith/app/modules/users/models.py.j2 +2 -0
  33. fastio/templates/monolith/app/modules/users/schemas.py.j2 +6 -0
  34. fastio/templates/monolith/app/modules/users/service.py.j2 +3 -0
  35. fastio/templates/monolith/app/tasks/celery_app.py.j2 +18 -0
  36. fastio/templates/monolith/pyproject.toml.j2 +43 -0
  37. fastio/templates/monorepo/README.md.j2 +9 -0
  38. fastio/templates/monorepo/packages/shared-auth/README.md.j2 +3 -0
  39. fastio/templates/monorepo/packages/shared-clients/README.md.j2 +3 -0
  40. fastio/templates/monorepo/packages/shared-events/README.md.j2 +3 -0
  41. fastio/templates/monorepo/packages/shared-schemas/README.md.j2 +3 -0
  42. fastio/templates/monorepo/pyproject.toml.j2 +11 -0
  43. fastio/templates/service/README.md.j2 +47 -0
  44. fastio/templates/service/alembic.ini.j2 +7 -0
  45. fastio/templates/service/app/admin.py.j2 +137 -0
  46. fastio/templates/service/app/api/deps.py.j2 +13 -0
  47. fastio/templates/service/app/api/v1/airdrop.py.j2 +35 -0
  48. fastio/templates/service/app/api/v1/api.py.j2 +33 -0
  49. fastio/templates/service/app/api/v1/items.py.j2 +18 -0
  50. fastio/templates/service/app/api/v1/members.py.j2 +46 -0
  51. fastio/templates/service/app/api/v1/moderation.py.j2 +28 -0
  52. fastio/templates/service/app/api/v1/orders.py.j2 +28 -0
  53. fastio/templates/service/app/api/v1/products.py.j2 +35 -0
  54. fastio/templates/service/app/api/v1/profile.py.j2 +8 -0
  55. fastio/templates/service/app/bot/bot.py.j2 +7 -0
  56. fastio/templates/service/app/bot/handlers/airdrop.py.j2 +90 -0
  57. fastio/templates/service/app/bot/handlers/ecommerce.py.j2 +81 -0
  58. fastio/templates/service/app/bot/handlers/membership.py.j2 +57 -0
  59. fastio/templates/service/app/bot/handlers/police_group.py.j2 +111 -0
  60. fastio/templates/service/app/bot/handlers.py.j2 +17 -0
  61. fastio/templates/service/app/core/config.py.j2 +29 -0
  62. fastio/templates/service/app/core/security.py.j2 +2 -0
  63. fastio/templates/service/app/db/base.py.j2 +14 -0
  64. fastio/templates/service/app/db/models/item.py.j2 +12 -0
  65. fastio/templates/service/app/db/models/member.py.j2 +15 -0
  66. fastio/templates/service/app/db/models/order.py.j2 +18 -0
  67. fastio/templates/service/app/db/models/participant.py.j2 +18 -0
  68. fastio/templates/service/app/db/models/product.py.j2 +15 -0
  69. fastio/templates/service/app/db/models/report.py.j2 +26 -0
  70. fastio/templates/service/app/db/session.py.j2 +7 -0
  71. fastio/templates/service/app/main.py.j2 +23 -0
  72. fastio/templates/service/app/main_telegram.py.j2 +37 -0
  73. fastio/templates/service/app/schemas/item.py.j2 +13 -0
  74. fastio/templates/service/app/schemas/member.py.j2 +16 -0
  75. fastio/templates/service/app/schemas/order.py.j2 +18 -0
  76. fastio/templates/service/app/schemas/participant.py.j2 +20 -0
  77. fastio/templates/service/app/schemas/product.py.j2 +27 -0
  78. fastio/templates/service/app/schemas/report.py.j2 +27 -0
  79. fastio/templates/service/app/schemas/user.py.j2 +6 -0
  80. fastio/templates/service/app/services/airdrop_service.py.j2 +81 -0
  81. fastio/templates/service/app/services/item_service.py.j2 +21 -0
  82. fastio/templates/service/app/services/member_service.py.j2 +46 -0
  83. fastio/templates/service/app/services/moderation_service.py.j2 +70 -0
  84. fastio/templates/service/app/services/shop_service.py.j2 +96 -0
  85. fastio/templates/service/app/tasks/celery_app.py.j2 +18 -0
  86. fastio/templates/service/app/tasks/item_tasks.py.j2 +6 -0
  87. fastio/templates/service/app/tasks/user_tasks.py.j2 +21 -0
  88. fastio/templates/service/app/users/auth.py.j2 +1 -0
  89. fastio/templates/service/app/users/manager.py.j2 +1 -0
  90. fastio/templates/service/app/users/oauth.py.j2 +1 -0
  91. fastio/templates/service/pyproject.toml.j2 +46 -0
fastio/main.py ADDED
@@ -0,0 +1,5 @@
1
+ from fastio.cli.app import app
2
+
3
+
4
+ def run() -> None:
5
+ app()
File without changes
@@ -0,0 +1,65 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Literal, Optional
5
+
6
+ from pydantic import BaseModel, Field, field_validator
7
+
8
+
9
+ Mode = Literal["service", "monolith", "monorepo"]
10
+ Blueprint = Literal["base", "crud-service", "user-service", "telegram-bot"]
11
+ Database = Literal["sqlite", "postgres"]
12
+ AlchemyMode = Literal["sync", "async"]
13
+ TelegramTemplate = Literal["membership", "police-group", "airdrop", "ecommerce"]
14
+
15
+
16
+ class ProjectOptions(BaseModel):
17
+ name: str = Field(min_length=2)
18
+ output_dir: Path
19
+ mode: Mode = "service"
20
+ blueprint: Blueprint = "base"
21
+ database: Database = "sqlite"
22
+ sqlalchemy_mode: AlchemyMode = "sync"
23
+ use_sqladmin: bool = True
24
+ use_celery: bool = True
25
+ use_docker: bool = True
26
+ use_tests: bool = True
27
+ use_ci: bool = True
28
+ use_fastapi_users: bool = False
29
+ use_google_oauth: bool = False
30
+ use_telegram_bot: bool = False
31
+ telegram_template: Optional[TelegramTemplate] = None
32
+
33
+ @field_validator("name")
34
+ @classmethod
35
+ def validate_name(cls, value: str) -> str:
36
+ clean = value.strip()
37
+ if not clean:
38
+ raise ValueError("Project name cannot be empty.")
39
+ return clean
40
+
41
+ @property
42
+ def project_dir(self) -> Path:
43
+ return self.output_dir / self.name
44
+
45
+ @property
46
+ def package_name(self) -> str:
47
+ return self.name.replace("-", "_")
48
+
49
+ @property
50
+ def app_import_path(self) -> str:
51
+ return "app.main:app"
52
+
53
+ @property
54
+ def uses_async(self) -> bool:
55
+ return self.sqlalchemy_mode == "async"
56
+
57
+ def normalized(self) -> "ProjectOptions":
58
+ data = self.model_dump()
59
+ if self.blueprint == "user-service":
60
+ data["use_fastapi_users"] = True
61
+ data["use_google_oauth"] = True
62
+ data["sqlalchemy_mode"] = "async"
63
+ elif self.blueprint == "telegram-bot":
64
+ data["use_telegram_bot"] = True
65
+ return ProjectOptions(**data)
File without changes
@@ -0,0 +1,20 @@
1
+ from __future__ import annotations
2
+
3
+ from functools import lru_cache
4
+ from pathlib import Path
5
+
6
+ from jinja2 import Environment, FileSystemLoader, StrictUndefined, select_autoescape
7
+
8
+ _TEMPLATES_DIR = Path(__file__).parent.parent / "templates"
9
+
10
+
11
+ @lru_cache(maxsize=1)
12
+ def get_environment() -> Environment:
13
+ return Environment(
14
+ loader=FileSystemLoader(str(_TEMPLATES_DIR)),
15
+ autoescape=select_autoescape(enabled_extensions=("html", "xml")),
16
+ keep_trailing_newline=True,
17
+ lstrip_blocks=True,
18
+ trim_blocks=True,
19
+ undefined=StrictUndefined,
20
+ )
@@ -0,0 +1,8 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ def write_text(path: Path, content: str) -> None:
7
+ path.parent.mkdir(parents=True, exist_ok=True)
8
+ path.write_text(content, encoding="utf-8", newline="\n")
@@ -0,0 +1,9 @@
1
+ FROM python:3.12-slim
2
+
3
+ WORKDIR /app
4
+ COPY . /app
5
+
6
+ RUN pip install uv && uv sync --frozen || uv sync
7
+
8
+ EXPOSE 8000
9
+ CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
@@ -0,0 +1,58 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ app:
5
+ build: .
6
+ ports:
7
+ - "8000:8000"
8
+ environment:
9
+ - DATABASE_URL=postgresql://{{ project_name }}:password@db:5432/{{ project_name }}
10
+ - REDIS_URL=redis://redis:6379/0
11
+ depends_on:
12
+ - db
13
+ - redis
14
+ volumes:
15
+ - .:/app
16
+ command: uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload
17
+
18
+ {% if project.database == "postgres" %}
19
+ db:
20
+ image: postgres:16-alpine
21
+ environment:
22
+ - POSTGRES_USER={{ project_name }}
23
+ - POSTGRES_PASSWORD=password
24
+ - POSTGRES_DB={{ project_name }}
25
+ ports:
26
+ - "5432:5432"
27
+ volumes:
28
+ - postgres_data:/var/lib/postgresql/data
29
+ {% endif %}
30
+
31
+ {% if project.use_celery %}
32
+ redis:
33
+ image: redis:7-alpine
34
+ ports:
35
+ - "6379:6379"
36
+ volumes:
37
+ - redis_data:/data
38
+
39
+ celery:
40
+ build: .
41
+ command: uv run celery -A app.tasks.celery_app worker --loglevel=info
42
+ environment:
43
+ - DATABASE_URL=postgresql://{{ project_name }}:password@db:5432/{{ project_name }}
44
+ - REDIS_URL=redis://redis:6379/0
45
+ depends_on:
46
+ - db
47
+ - redis
48
+ volumes:
49
+ - .:/app
50
+ {% endif %}
51
+
52
+ volumes:
53
+ {% if project.database == "postgres" %}
54
+ postgres_data:
55
+ {% endif %}
56
+ {% if project.use_celery %}
57
+ redis_data:
58
+ {% endif %}
File without changes
@@ -0,0 +1,20 @@
1
+ APP_NAME={{ project_name }}
2
+ ENVIRONMENT=local
3
+ DEBUG=true
4
+ {% if project.database == "postgres" %}
5
+ DATABASE_URL=postgresql://{{ project_name }}:password@localhost:5432/{{ project_name }}
6
+ {% else %}
7
+ DATABASE_URL=sqlite:///./{{ package_name }}.db
8
+ {% endif %}
9
+ SECRET_KEY=change-me
10
+ {% if project.use_celery %}
11
+ CELERY_BROKER_URL=redis://localhost:6379/0
12
+ CELERY_RESULT_BACKEND=redis://localhost:6379/1
13
+ {% endif %}
14
+ {% if project.use_google_oauth %}
15
+ GOOGLE_CLIENT_ID=
16
+ GOOGLE_CLIENT_SECRET=
17
+ {% endif %}
18
+ {% if project.use_telegram_bot %}
19
+ TELEGRAM_BOT_TOKEN=
20
+ {% endif %}
@@ -0,0 +1,15 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.pyo
4
+ *.egg-info/
5
+ dist/
6
+ build/
7
+ .venv/
8
+ .env
9
+ *.db
10
+ *.sqlite3
11
+ .pytest_cache/
12
+ .mypy_cache/
13
+ .ruff_cache/
14
+ htmlcov/
15
+ .coverage
@@ -0,0 +1,33 @@
1
+ name: publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ jobs:
9
+ build-and-publish:
10
+ runs-on: ubuntu-latest
11
+ permissions:
12
+ id-token: write
13
+ contents: read
14
+
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@v4
18
+
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: "3.12"
23
+
24
+ - name: Install uv
25
+ uses: astral-sh/setup-uv@v3
26
+
27
+ - name: Build
28
+ run: |
29
+ uv sync --group dev
30
+ uv run python -m build
31
+
32
+ - name: Publish to PyPI
33
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,2 @@
1
+ def test_smoke() -> None:
2
+ assert True
@@ -0,0 +1,11 @@
1
+ # {{ project_name }}
2
+
3
+ Generated modular monolith by `fastio`.
4
+
5
+ ## Run locally
6
+
7
+ ```bash
8
+ uv sync
9
+ uv run alembic upgrade head
10
+ uv run fastapi dev app.main:app
11
+ ```
@@ -0,0 +1,7 @@
1
+ [alembic]
2
+ script_location = alembic
3
+ {% if project.database == "postgres" %}
4
+ sqlalchemy.url = postgresql://{{ project_name }}:password@localhost:5432/{{ project_name }}
5
+ {% else %}
6
+ sqlalchemy.url = sqlite:///./{{ package_name }}.db
7
+ {% endif %}
@@ -0,0 +1,22 @@
1
+ from pydantic_settings import BaseSettings, SettingsConfigDict
2
+
3
+
4
+ class Settings(BaseSettings):
5
+ app_name: str = "{{ project_name }}"
6
+ environment: str = "local"
7
+ debug: bool = True
8
+ {% if project.database == "postgres" %}
9
+ database_url: str = "postgresql://{{ project_name }}:password@localhost:5432/{{ project_name }}"
10
+ {% else %}
11
+ database_url: str = "sqlite:///./{{ package_name }}.db"
12
+ {% endif %}
13
+ secret_key: str = "change-me"
14
+ {% if project.use_celery %}
15
+ celery_broker_url: str = "redis://localhost:6379/0"
16
+ celery_result_backend: str = "redis://localhost:6379/1"
17
+ {% endif %}
18
+
19
+ model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8")
20
+
21
+
22
+ settings = Settings()
@@ -0,0 +1,11 @@
1
+ from fastapi import FastAPI
2
+
3
+ from app.modules.users.api import router as users_router
4
+
5
+ app = FastAPI(title="{{ project_name }}", docs_url="/docs")
6
+ app.include_router(users_router, prefix="/api/v1/users", tags=["users"])
7
+
8
+
9
+ @app.get("/health/live")
10
+ def live() -> dict[str, str]:
11
+ return {"status": "ok"}
@@ -0,0 +1,8 @@
1
+ from fastapi import APIRouter
2
+
3
+ router = APIRouter()
4
+
5
+
6
+ @router.get("/")
7
+ def list_users() -> list[dict[str, str]]:
8
+ return [{"id": "1", "email": "admin@example.com"}]
@@ -0,0 +1,2 @@
1
+ class User:
2
+ pass
@@ -0,0 +1,6 @@
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class UserRead(BaseModel):
5
+ id: str
6
+ email: str
@@ -0,0 +1,3 @@
1
+ class UserService:
2
+ def list_users(self) -> list[dict[str, str]]:
3
+ return [{"id": "1", "email": "admin@example.com"}]
@@ -0,0 +1,18 @@
1
+ from celery import Celery
2
+
3
+ from app.core.config import settings
4
+
5
+ celery_app = Celery(
6
+ "{{ project_name }}",
7
+ broker=settings.celery_broker_url,
8
+ backend=settings.celery_result_backend,
9
+ )
10
+
11
+ celery_app.conf.update(
12
+ task_serializer="json",
13
+ accept_content=["json"],
14
+ result_serializer="json",
15
+ timezone="UTC",
16
+ enable_utc=True,
17
+ task_track_started=True,
18
+ )
@@ -0,0 +1,43 @@
1
+ [project]
2
+ name = "{{ project_name }}"
3
+ version = "0.1.0"
4
+ description = "{{ project_name }} generated by fastio"
5
+ readme = "README.md"
6
+ requires-python = ">=3.11"
7
+ dependencies = [
8
+ "fastapi[standard]>=0.115.0",
9
+ "sqlalchemy>=2.0.35",
10
+ "alembic>=1.13.2",
11
+ "pydantic>=2.8.2",
12
+ "pydantic-settings>=2.4.0",
13
+ {% if project.use_sqladmin %}
14
+ "sqladmin>=0.18.0",
15
+ {% endif %}
16
+ {% if project.use_celery %}
17
+ "celery[redis]>=5.4.0",
18
+ {% endif %}
19
+ {% if project.uses_async and project.database == "postgres" %}
20
+ "asyncpg>=0.29.0",
21
+ {% elif project.uses_async %}
22
+ "aiosqlite>=0.20.0",
23
+ {% elif project.database == "postgres" %}
24
+ "psycopg2-binary>=2.9.9",
25
+ {% endif %}
26
+ {% if project.use_fastapi_users %}
27
+ "fastapi-users[sqlalchemy,oauth]>=13.0.0",
28
+ {% endif %}
29
+ ]
30
+
31
+ [build-system]
32
+ requires = ["hatchling>=1.25.0"]
33
+ build-backend = "hatchling.build"
34
+
35
+ [tool.uv]
36
+ package = false
37
+
38
+ [dependency-groups]
39
+ dev = [
40
+ "pytest>=8.3.2",
41
+ "httpx>=0.27.2",
42
+ "ruff>=0.6.5",
43
+ ]
@@ -0,0 +1,9 @@
1
+ # {{ project_name }}
2
+
3
+ Generated monorepo by `fastio`.
4
+
5
+ ## Layout
6
+
7
+ - `services/` independent services
8
+ - `packages/` shared internal packages
9
+ - each service owns its DB and migrations
@@ -0,0 +1,3 @@
1
+ # shared-auth
2
+
3
+ JWT verification helpers, service tokens, and role constants.
@@ -0,0 +1,3 @@
1
+ # shared-clients
2
+
3
+ Internal HTTP clients, retry helpers, and auth header helpers.
@@ -0,0 +1,3 @@
1
+ # shared-events
2
+
3
+ Event names, task payload schemas, and event contracts.
@@ -0,0 +1,3 @@
1
+ # shared-schemas
2
+
3
+ Common DTOs, pagination schemas, and API response envelopes.
@@ -0,0 +1,11 @@
1
+ [project]
2
+ name = "{{ project_name }}"
3
+ version = "0.1.1"
4
+ requires-python = ">=3.11"
5
+
6
+ [build-system]
7
+ requires = ["hatchling>=1.25.0"]
8
+ build-backend = "hatchling.build"
9
+
10
+ [tool.uv.workspace]
11
+ members = ["services/*", "packages/*"]
@@ -0,0 +1,47 @@
1
+ # {{ project_name }}
2
+
3
+ Generated by `fastio`.
4
+
5
+ ## Run locally
6
+
7
+ ```bash
8
+ uv sync
9
+ uv run alembic upgrade head
10
+ uv run fastapi dev app.main:app
11
+ ```
12
+
13
+ ## Structure
14
+
15
+ - `app/api/v1` for versioned routes
16
+ - `app/services` for business logic
17
+ {% if project.use_celery %}
18
+ - `app/tasks` for Celery jobs
19
+ {% endif %}
20
+ - `app/db` for SQLAlchemy setup
21
+ {% if project.use_sqladmin %}
22
+ - `app/admin.py` for SQLAdmin at `/admin`
23
+ {% endif %}
24
+ {% if project.use_celery %}
25
+
26
+ ## Celery
27
+
28
+ Start a worker:
29
+
30
+ ```bash
31
+ uv run celery -A app.tasks.celery_app worker --loglevel=info
32
+ ```
33
+
34
+ > **Windows:** Celery's default prefork pool is not supported on Windows.
35
+ > Use `--pool=solo` for local development:
36
+ > ```bash
37
+ > uv run celery -A app.tasks.celery_app worker --loglevel=info --pool=solo
38
+ > ```
39
+ {% endif %}
40
+ {% if project.use_docker %}
41
+
42
+ ## Docker
43
+
44
+ ```bash
45
+ docker compose up --build
46
+ ```
47
+ {% endif %}
@@ -0,0 +1,7 @@
1
+ [alembic]
2
+ script_location = alembic
3
+ {% if project.database == "postgres" %}
4
+ sqlalchemy.url = postgresql://{{ project_name }}:password@localhost:5432/{{ project_name }}
5
+ {% else %}
6
+ sqlalchemy.url = sqlite:///./{{ package_name }}.db
7
+ {% endif %}
@@ -0,0 +1,137 @@
1
+ from fastapi import FastAPI
2
+ from sqladmin import Admin, ModelView
3
+
4
+ from app.db.session import engine
5
+
6
+ {% if project.blueprint == "crud-service" %}
7
+ from app.db.models.item import Item
8
+
9
+
10
+ class ItemAdmin(ModelView, model=Item):
11
+ name = "Item"
12
+ name_plural = "Items"
13
+ icon = "fa-solid fa-box"
14
+ column_list = [Item.id, Item.name, Item.slug]
15
+ column_searchable_list = [Item.name, Item.slug]
16
+ column_sortable_list = [Item.id, Item.name]
17
+
18
+ {% elif project.blueprint == "user-service" %}
19
+ class UserAdmin:
20
+ pass
21
+
22
+ {% elif project.blueprint == "telegram-bot" and project.telegram_template == "membership" %}
23
+ from app.db.models.member import Member
24
+
25
+
26
+ class MemberAdmin(ModelView, model=Member):
27
+ name = "Member"
28
+ name_plural = "Members"
29
+ icon = "fa-solid fa-users"
30
+ column_list = [Member.id, Member.telegram_id, Member.first_name, Member.username, Member.phone, Member.is_active, Member.created_at]
31
+ column_searchable_list = [Member.first_name, Member.username, Member.phone]
32
+ column_sortable_list = [Member.id, Member.first_name, Member.created_at]
33
+ column_filters = [Member.is_active]
34
+ can_create = True
35
+ can_edit = True
36
+ can_delete = True
37
+ can_view_details = True
38
+ form_columns = [Member.first_name, Member.username, Member.phone, Member.is_active]
39
+
40
+ {% elif project.blueprint == "telegram-bot" and project.telegram_template == "police-group" %}
41
+ from app.db.models.report import Report, Warning
42
+
43
+
44
+ class ReportAdmin(ModelView, model=Report):
45
+ name = "Report"
46
+ name_plural = "Reports"
47
+ icon = "fa-solid fa-flag"
48
+ column_list = [Report.id, Report.group_id, Report.reporter_id, Report.reported_id, Report.reported_username, Report.reason, Report.created_at]
49
+ column_searchable_list = [Report.reported_username, Report.reason]
50
+ column_sortable_list = [Report.id, Report.created_at]
51
+ can_create = False
52
+ can_edit = False
53
+ can_delete = True
54
+ can_view_details = True
55
+
56
+
57
+ class WarningAdmin(ModelView, model=Warning):
58
+ name = "Warning"
59
+ name_plural = "Warnings"
60
+ icon = "fa-solid fa-triangle-exclamation"
61
+ column_list = [Warning.id, Warning.group_id, Warning.user_id, Warning.username, Warning.reason, Warning.issued_by, Warning.created_at]
62
+ column_searchable_list = [Warning.username, Warning.reason]
63
+ column_sortable_list = [Warning.id, Warning.user_id, Warning.created_at]
64
+ can_create = False
65
+ can_edit = False
66
+ can_delete = True
67
+ can_view_details = True
68
+
69
+ {% elif project.blueprint == "telegram-bot" and project.telegram_template == "airdrop" %}
70
+ from app.db.models.participant import Participant
71
+
72
+
73
+ class ParticipantAdmin(ModelView, model=Participant):
74
+ name = "Participant"
75
+ name_plural = "Participants"
76
+ icon = "fa-solid fa-parachute-box"
77
+ column_list = [Participant.id, Participant.telegram_id, Participant.first_name, Participant.username, Participant.wallet_address, Participant.referral_code, Participant.points, Participant.is_verified, Participant.created_at]
78
+ column_searchable_list = [Participant.first_name, Participant.username, Participant.wallet_address, Participant.referral_code]
79
+ column_sortable_list = [Participant.id, Participant.points, Participant.created_at]
80
+ column_filters = [Participant.is_verified]
81
+ can_create = False
82
+ can_edit = True
83
+ can_delete = True
84
+ can_view_details = True
85
+ form_columns = [Participant.wallet_address, Participant.points, Participant.is_verified]
86
+
87
+ {% elif project.blueprint == "telegram-bot" and project.telegram_template == "ecommerce" %}
88
+ from app.db.models.order import Order
89
+ from app.db.models.product import Product
90
+
91
+
92
+ class ProductAdmin(ModelView, model=Product):
93
+ name = "Product"
94
+ name_plural = "Products"
95
+ icon = "fa-solid fa-tag"
96
+ column_list = [Product.id, Product.name, Product.price, Product.stock, Product.is_active, Product.created_at]
97
+ column_searchable_list = [Product.name]
98
+ column_sortable_list = [Product.id, Product.name, Product.price, Product.stock]
99
+ column_filters = [Product.is_active]
100
+ can_create = True
101
+ can_edit = True
102
+ can_delete = True
103
+ can_view_details = True
104
+ form_columns = [Product.name, Product.description, Product.price, Product.stock, Product.is_active]
105
+
106
+
107
+ class OrderAdmin(ModelView, model=Order):
108
+ name = "Order"
109
+ name_plural = "Orders"
110
+ icon = "fa-solid fa-cart-shopping"
111
+ column_list = [Order.id, Order.telegram_id, Order.username, Order.product_id, Order.quantity, Order.total_price, Order.status, Order.created_at]
112
+ column_searchable_list = [Order.username, Order.status]
113
+ column_sortable_list = [Order.id, Order.total_price, Order.status, Order.created_at]
114
+ column_filters = [Order.status]
115
+ can_create = False
116
+ can_edit = True
117
+ can_delete = True
118
+ can_view_details = True
119
+ form_columns = [Order.status]
120
+
121
+ {% endif %}
122
+
123
+ def setup_admin(app: FastAPI) -> None:
124
+ admin = Admin(app, engine, base_url="/admin")
125
+ {% if project.blueprint == "crud-service" %}
126
+ admin.add_view(ItemAdmin)
127
+ {% elif project.blueprint == "telegram-bot" and project.telegram_template == "membership" %}
128
+ admin.add_view(MemberAdmin)
129
+ {% elif project.blueprint == "telegram-bot" and project.telegram_template == "police-group" %}
130
+ admin.add_view(ReportAdmin)
131
+ admin.add_view(WarningAdmin)
132
+ {% elif project.blueprint == "telegram-bot" and project.telegram_template == "airdrop" %}
133
+ admin.add_view(ParticipantAdmin)
134
+ {% elif project.blueprint == "telegram-bot" and project.telegram_template == "ecommerce" %}
135
+ admin.add_view(ProductAdmin)
136
+ admin.add_view(OrderAdmin)
137
+ {% endif %}
@@ -0,0 +1,13 @@
1
+ from collections.abc import Generator
2
+
3
+ from sqlalchemy.orm import Session
4
+
5
+ from app.db.session import SessionLocal
6
+
7
+
8
+ def get_db() -> Generator[Session, None, None]:
9
+ db = SessionLocal()
10
+ try:
11
+ yield db
12
+ finally:
13
+ db.close()