Metadata-Version: 2.4
Name: toptl-aiogram
Version: 0.1.0
Summary: aiogram plugin for TOP.TL — autopost bot stats, gate handlers behind votes, handle vote webhooks.
Project-URL: Homepage, https://top.tl
Project-URL: Documentation, https://top.tl/developers
Project-URL: Repository, https://github.com/top-tl/aiogram
Project-URL: Issues, https://github.com/top-tl/aiogram/issues
Author-email: "TOP.TL" <hello@top.tl>
License: MIT
License-File: LICENSE
Keywords: aiogram,bot,plugin,stats,telegram,top.tl,toptl,votes
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Communications :: Chat
Classifier: Typing :: Typed
Requires-Python: >=3.9
Requires-Dist: aiogram>=3.0
Requires-Dist: toptl>=0.1.1
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: mypy>=1.8; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Description-Content-Type: text/markdown

# toptl-aiogram

[![PyPI version](https://img.shields.io/pypi/v/toptl-aiogram.svg?label=pypi&color=3775a9)](https://pypi.org/project/toptl-aiogram/)
[![Python versions](https://img.shields.io/pypi/pyversions/toptl-aiogram.svg?color=3776ab)](https://pypi.org/project/toptl-aiogram/)
[![Downloads](https://img.shields.io/pypi/dm/toptl-aiogram.svg?color=blue)](https://pypi.org/project/toptl-aiogram/)
[![License](https://img.shields.io/pypi/l/toptl-aiogram.svg?color=green)](https://github.com/top-tl/aiogram/blob/main/LICENSE)
[![aiogram](https://img.shields.io/badge/aiogram-3%2B-26a5e4)](https://github.com/aiogram/aiogram)
[![TOP.TL](https://img.shields.io/badge/top.tl-developers-2ec4b6)](https://top.tl/developers)

Official [TOP.TL](https://top.tl) plugin for **aiogram 3**. One call wires up autoposted bot stats, vote-gated handlers, and webhook helpers — all on top of the [`toptl`](https://pypi.org/project/toptl/) SDK.

## Install

```bash
pip install toptl-aiogram
```

Python 3.9+. Pulls in `toptl>=0.1.1` and `aiogram>=3.0`.

## Quick start

```python
import asyncio
from aiogram import Bot, Dispatcher
from aiogram.filters import Command
from aiogram.types import Message
from toptl import AsyncTopTL
from toptl_aiogram import setup_toptl, vote_required

async def main():
    bot = Bot("BOT_TOKEN")
    dp = Dispatcher()
    client = AsyncTopTL("toptl_xxx")

    # One call installs the middleware + autoposter, tied to dp's
    # startup/shutdown hooks — no background task bookkeeping for you.
    plugin = setup_toptl(dp, client, "mybot")

    @dp.message(Command("premium"))
    @vote_required(plugin, vote_url="https://top.tl/mybot")
    async def premium(message: Message):
        await message.answer("Thanks for voting!")

    await dp.start_polling(bot)

asyncio.run(main())
```

`setup_toptl` does three things:

1. Registers a middleware on `dp.update.middleware` that records unique user / group / channel IDs from every update (messages, callbacks, chat_member, …).
2. Hooks an `AsyncAutoposter` into the dispatcher's startup/shutdown events — it flushes stats every 30 min, only when counts changed.
3. Returns a `TopTLPlugin` handle you use for vote checks and manual flushes.

## Vote gating

```python
@dp.message(Command("premium"))
@vote_required(plugin, message="Vote first: https://top.tl/mybot")
async def premium(message: Message):
    ...
```

Works on message and callback-query handlers. Network or auth failures fall through as "not voted" and log at ERROR level — vote gates never brick your bot.

For checks inside existing logic:

```python
@dp.message(Command("check"))
async def check(message: Message):
    if await plugin.has_voted(message.from_user.id):
        await message.answer("You voted, thanks!")
    else:
        await message.answer("Please vote at https://top.tl/mybot")
```

The plugin handle is also injected into handler data under `data["toptl"]`:

```python
async def handler(message: Message, toptl):  # aiogram reads the param name
    if await toptl.has_voted(message.from_user.id):
        ...
```

## Tuning the autoposter

```python
plugin = setup_toptl(
    dp, client, "mybot",
    interval_seconds=15 * 60,  # flush every 15 min instead of 30
)
```

Manual flush (e.g. before shutdown):

```python
await plugin.post_now()
```

## Requirements

- `aiogram>=3.0`
- Python 3.9+

## License

MIT.

---

Part of the [TOP.TL developer ecosystem](https://top.tl/developers). Issues and contributions: [`top-tl/aiogram`](https://github.com/top-tl/aiogram).
