A Telegram bot that encourages sharing quality LinkedIn content in group chats through a karma-based reward system. Users earn karma points when their shared LinkedIn posts receive reactions from other members.
- LinkedIn URL Detection: Automatically detects and validates LinkedIn post, feed, and Pulse article URLs
- Karma System: Users earn karma points when others react to their shared posts
- User Status Tracking:
- Newcomers: Users who haven't made their first post yet
- Veterans: Users who have accumulated significant karma (configurable threshold)
- Reaction Management: Track and manage reactions to posts with automatic karma updates
- Group Settings: Customizable settings per Telegram group:
- Language preferences (Russian/English)
- Karma calculation period (default: 7 days)
- Veteran threshold (default: 30 karma points)
- Post cost in karma (optional barrier to posting)
- Statistics: View top users, karma leaderboards, and group statistics
- Database Support: Works with both SQLite (development) and PostgreSQL (production)
- Python 3.11+
- aiogram 3.13: Modern async Telegram bot framework
- SQLAlchemy 2.0: Async ORM for database operations
- Alembic: Database migrations
- Pydantic: Settings and configuration management
- pytest: Testing framework with async support
linkedin-karma-bot/
├── bot/
│ ├── __init__.py
│ ├── config.py # Configuration management
│ ├── database/
│ │ ├── __init__.py
│ │ ├── connection.py # Database connection setup
│ │ └── repositories.py # Data access layer
│ ├── handlers/ # Telegram message handlers
│ │ └── __init__.py
│ ├── i18n/ # Internationalization
│ │ └── __init__.py
│ ├── models/ # SQLAlchemy models
│ │ ├── __init__.py
│ │ ├── base.py
│ │ ├── user.py
│ │ ├── post.py
│ │ ├── reaction.py
│ │ └── settings.py
│ └── services/ # Business logic
│ ├── __init__.py
│ ├── linkedin.py # LinkedIn URL parsing
│ ├── karma.py # Karma calculations
│ └── stats.py # Statistics
├── migrations/ # Alembic database migrations
├── scripts/
│ └── simulator.py # CLI simulator for testing
├── tests/
│ ├── __init__.py
│ ├── conftest.py # Pytest fixtures
│ ├── test_linkedin.py # LinkedIn parser tests
│ ├── test_karma.py # Karma service tests
│ └── test_repositories.py # Repository tests
├── .env.example # Example environment variables
├── Dockerfile # Docker image definition
├── docker-compose.yml # Docker services configuration
├── pytest.ini # Pytest configuration
├── requirements.txt # Python dependencies
└── README.md # This file
-
Clone the repository:
git clone <repository-url> cd linkedin-karma-bot
-
Create a virtual environment:
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies:
pip install -r requirements.txt
-
Configure environment variables:
cp .env.example .env # Edit .env and add your Telegram bot token -
Initialize the database:
alembic upgrade head
-
Run the bot:
python -m bot.main
-
Configure environment variables:
cp .env.example .env # Edit .env with your settings -
Start the services:
docker-compose up -d
-
View logs:
docker-compose logs -f bot
-
Stop the services:
docker-compose down
Configuration is managed through environment variables. See .env.example for all available options:
| Variable | Description | Default |
|---|---|---|
TELEGRAM_BOT_TOKEN |
Telegram Bot API token (from @BotFather) | Required |
DATABASE_URL |
Database connection URL | sqlite+aiosqlite:///./karma_bot.db |
DEFAULT_LANGUAGE |
Default language (ru/en) | ru |
DEFAULT_KARMA_PERIOD |
Default karma period in days | 7 |
DEFAULT_VETERAN_THRESHOLD |
Karma points needed for veteran status | 30 |
DEFAULT_POST_COST |
Karma cost to post (0 = free) | 0 |
- SQLite (development):
sqlite+aiosqlite:///./karma_bot.db - PostgreSQL (production):
postgresql+asyncpg://user:password@localhost:5432/karma_bot
/start- Start the bot and see welcome message/help- Show help and available commands/karma- View your current karma and statistics/top- View top users by karma in this group/stats- View group statistics
/settings- View current group settings/set_language <ru|en>- Set group language/set_period <days>- Set karma calculation period/set_threshold <points>- Set veteran threshold/set_cost <points>- Set karma cost to post/reset_karma @username- Reset user's karma to zero/export- Export group statistics as CSV file
- Add the bot to a Telegram group
- Grant admin permissions (required for admin commands)
- Share LinkedIn posts in the group:
- Post any LinkedIn URL (posts, articles, feed updates)
- Other members can react to your post
- Earn +1 karma for each reaction
- View your karma: Use
/karmato see your current karma and status - Compete on the leaderboard: Use
/topto see who has the most karma
Run the full test suite:
pytestRun with coverage:
pytest --cov=bot --cov-report=html --cov-report=term-missingRun specific test file:
pytest tests/test_linkedin.pyRun specific test:
pytest tests/test_karma.py::TestKarmaService::test_karma_to_stars_zeroTest bot functionality without Telegram using the CLI simulator:
Create a post:
python scripts/simulator.py post 123456 johndoe "https://linkedin.com/posts/johndoe_test"React to a post:
python scripts/simulator.py react 789012 janedoe 1Remove a reaction:
python scripts/simulator.py unreact 789012 1View user karma:
python scripts/simulator.py karma 123456View top users:
python scripts/simulator.py top 10View statistics:
python scripts/simulator.py statsCreate a new migration:
alembic revision --autogenerate -m "description of changes"Apply migrations:
alembic upgrade headRollback migration:
alembic downgrade -1View migration history:
alembic historyfrom bot.services.linkedin import extract_linkedin_urls, is_linkedin_post
# Extract all LinkedIn URLs from text
urls = extract_linkedin_urls(text)
# Check if a URL is a valid LinkedIn post
is_valid = is_linkedin_post(url)from bot.services.karma import KarmaService
service = KarmaService(session)
# Convert karma to stars
stars = KarmaService.karma_to_stars(karma_points)
# Check if user is a newcomer
is_new = await service.is_newcomer(user_id)
# Check if user is a veteran
is_vet = await service.is_veteran(user_id, threshold=30)
# Get user's total karma
karma = await service.get_total_karma(user_id)
# Get weekly post count
posts = await service.get_weekly_posts_count(user_id, chat_id, period_days=7)from bot.database.repositories import UserRepository, PostRepository, ReactionRepository
# User operations
user_repo = UserRepository(session)
user, created = await user_repo.get_or_create(telegram_id, username, display_name)
await user_repo.update_karma_total(telegram_id, karma_delta)
# Post operations
post_repo = PostRepository(session)
post = await post_repo.create(message_id, chat_id, author_id, linkedin_url)
posts = await post_repo.get_user_posts_in_period(user_id, days=7)
# Reaction operations
reaction_repo = ReactionRepository(session)
reaction = await reaction_repo.add_reaction(post_id, user_id)
removed = await reaction_repo.remove_reaction(post_id, user_id)- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Make your changes
- Run tests:
pytest - Commit your changes:
git commit -am 'Add feature' - Push to the branch:
git push origin feature-name - Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Built with aiogram - Modern Telegram Bot framework
- Database management with SQLAlchemy
- Testing with pytest