A real-time web application for monitoring blog posts with intelligent notifications, Azure AD authentication, and web push support.
This Flask-based application automatically monitors blog content and delivers personalized notifications to users. It features Microsoft Azure AD single sign-on authentication, customizable notification filters, and web push notifications for real-time updates.
- Real-time Blog Monitoring: Automatically polls blog APIs and parses new posts
- Azure AD Authentication: Secure single sign-on with Microsoft accounts
- Intelligent Filtering: Location-based and keyword-based notification filters
- Web Push Notifications: Cross-platform push notifications with VAPID support
- User Dashboard: Comprehensive interface for managing settings and viewing notifications
- Multi-language Support: English, Hungarian, and Swedish language options
- Responsive Design: Mobile-friendly web interface
- Export Functionality: Export posts and notifications to JSON format
- Session Management: Secure session handling with token validation
- Python 3.10 or higher
- Azure AD application registration
- VAPID keys for web push notifications
-
Clone the repository
git clone https://github.com/vakesz/notification_app.git cd notification_app -
Create a virtual environment
python -m venv venv source venv/bin/activate # On Windows: venv\Scripts\activate
-
Install dependencies
pip install -e . -
Environment Configuration
Create a
.envfile in the project root:# Flask Configuration SECRET_KEY=your-secret-key-here FLASK_ENV=development # Azure AD Configuration AAD_CLIENT_ID=your-azure-ad-client-id AAD_CLIENT_SECRET=your-azure-ad-client-secret AAD_TENANT_ID=your-azure-ad-tenant-id AAD_REDIRECT_URI=http://localhost:5000/auth/callback # Blog API Configuration BLOG_API_URL=https://your-blog-api-url.com BLOG_API_AUTH_METHOD=none # Optional Blog API Authentication (choose one if needed) # For OAuth2: # BLOG_API_OAUTH2_CLIENT_ID=your-oauth2-client-id # BLOG_API_OAUTH2_CLIENT_SECRET=your-oauth2-client-secret # BLOG_API_OAUTH2_TOKEN_URL=https://your-oauth2-token-url.com # For MSAL: # BLOG_API_MSAL_CLIENT_ID=your-msal-client-id # BLOG_API_MSAL_CLIENT_SECRET=your-msal-client-secret # BLOG_API_MSAL_TENANT_ID=your-msal-tenant-id # BLOG_API_MSAL_SCOPE=your-msal-scope # For NTLM: # BLOG_API_NTLM_USER=your-ntlm-user # BLOG_API_NTLM_PASSWORD=your-ntlm-password # BLOG_API_NTLM_DOMAIN=your-ntlm-domain # For Cookie (session cookie on target blog domain): # BLOG_API_AUTH_METHOD=cookie # Option A: Multiple cookies (recommended when the site sets more than one) # BLOG_API_COOKIES=name1=value1; name2=value2 # Option B: Single cookie (fallback) # BLOG_API_COOKIE_NAME=your-cookie-name # BLOG_API_COOKIE_VALUE=your-cookie-value # BLOG_API_COOKIE_DOMAIN=your-blog-domain.com # optional, defaults to BLOG_API_URL host # BLOG_API_COOKIE_PATH=/ # optional, defaults to '/' # Web Push Configuration PUSH_VAPID_PUBLIC_KEY=your-vapid-public-key PUSH_VAPID_PRIVATE_KEY=your-vapid-private-key PUSH_CONTACT_EMAIL=[email protected] # Token Encryption (required) # Generate with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" TOKEN_ENCRYPTION_KEY=base64-urlsafe-32-byte-fernet-key # Application Settings APP_NAME=Blog Notifications Parser APP_DATABASE_PATH=db/posts.db POLLING_INTERVAL_MINUTES=15 HTTP_TIMEOUT=30 # Optional Advanced Settings # HTTP_MAX_RETRIES=3 # HTTP_RETRY_BACKOFF=1 # POLLING_BACKOFF_FACTOR=1.5 # POLLING_MAX_BACKOFF=3600 # AUTH_TOKEN_TTL_DAYS=30 # PUSH_TTL=86400
-
Database Setup
mkdir -p db # Database will be automatically initialized on first run
# Pull the latest image
docker pull ghcr.io/vakesz/notification_app:latest
# Run with environment variables
docker run -d \
--name notification-app \
-p 5000:5000 \
-e SECRET_KEY=your-secret-key \
-e AAD_CLIENT_ID=your-azure-ad-client-id \
-e AAD_CLIENT_SECRET=your-azure-ad-client-secret \
-e AAD_TENANT_ID=your-azure-ad-tenant-id \
-e BLOG_API_URL=https://your-blog-api-url.com \
-e PUSH_VAPID_PUBLIC_KEY=your-vapid-public-key \
-e PUSH_VAPID_PRIVATE_KEY=your-vapid-private-key \
-e [email protected] \
-e TOKEN_ENCRYPTION_KEY=your-fernet-key \
-v notification-db:/app/db \
ghcr.io/vakesz/notification_app:latestversion: "3.8"
services:
app:
image: ghcr.io/vakesz/notification_app:latest
ports:
- "5000:5000"
environment:
- SECRET_KEY=your-secret-key
- AAD_CLIENT_ID=your-client-id
- AAD_CLIENT_SECRET=your-azure-ad-client-secret
- AAD_TENANT_ID=your-tenant-id
- AAD_REDIRECT_URI=http://localhost:5000/auth/callback
- BLOG_API_URL=https://your-blog-api-url.com
- PUSH_VAPID_PUBLIC_KEY=your-vapid-public-key
- PUSH_VAPID_PRIVATE_KEY=your-vapid-private-key
- [email protected]
- TOKEN_ENCRYPTION_KEY=your-fernet-key
volumes:
- notification-db:/app/db
volumes:
notification-db:Note: The Docker image uses multi-architecture support (amd64/arm64) and runs with gunicorn -w 4 -b 0.0.0.0:5000 "app.web.main:create_app()" to properly initialize the Flask application factory.
Development Mode:
export FLASK_APP=app.web.main
export FLASK_ENV=development
flask runProduction Mode:
gunicorn -w 4 -b 0.0.0.0:5000 "app.web.main:create_app()"- Navigate to
http://localhost:5000 - Click "Login with Microsoft" to authenticate
- Configure your notification preferences in the dashboard
- Enable push notifications when prompted by your browser
The application provides several API endpoints:
POST /api/subscriptions- Subscribe to push notificationsDELETE /api/subscriptions- Unsubscribe from push notificationsGET /api/notifications/status- Get notification summaryPOST /api/notifications/mark-read- Mark notifications as readPOST /api/notifications/settings- Update notification settingsGET /api/session/validate- Validate current session
Notification Settings:
Users can customize their notification preferences through the dashboard:
- Language: Choose from English, Hungarian, or Swedish
- Location Filter: Filter notifications by specific locations (only receive notifications for selected locations)
- Keyword Filter: Filter notifications by custom keywords (only receive notifications containing specified keywords)
- Push Notifications: Enable/disable web push notifications (respects user opt-out preferences)
Intelligent Notification Filtering:
The application implements intelligent filtering to ensure users only receive relevant notifications:
- Location-based Filtering: Users can select specific locations and will only receive notifications for posts from those locations
- Keyword-based Filtering: Users can define custom keywords and will only receive notifications for posts containing those keywords
- Push Opt-out: Users can disable push notifications while keeping other notification types active
- Targeted Delivery: Push notifications are only sent to users whose filters match the post content, respecting individual preferences
- Per-User Read State: Each user has their own read/unread status for notifications, allowing independent tracking
Blog API Authentication:
The application supports multiple authentication methods:
- OAuth2 client credentials
- Microsoft MSAL authentication
- NTLM authentication
- Cookie (session cookie supplied via environment)
- No authentication (public APIs)
├── app/
│ ├── api/routes/ # Flask blueprints and routes
│ ├── core/ # Core configuration and security
│ ├── db/ # Database models and management
│ ├── services/ # Business logic services
│ ├── utils/ # Utility functions
│ └── web/ # Web application entry point
├── static/ # Frontend assets
├── templates/ # Jinja2 templates
└── db/ # SQLite database files
- AuthService: Handles Azure AD authentication and token management
- PollingService: Monitors blog APIs for new content
- NotificationService: Manages user notifications and web push with intelligent filtering
- DatabaseManager: Handles all database operations including user-targeted push subscriptions
- ContentParser: Parses HTML content from blog APIs
The application implements a sophisticated notification filtering system that ensures users only receive relevant content:
-
Two-Stage Filtering:
- Location-based filtering: Users can specify which locations they're interested in
- Keyword-based filtering: Users can define keywords that must be present in posts
-
Targeted Push Delivery:
- Push notifications are only sent to users whose filters match the post content
- The system queries for push subscriptions of matched users only, not all users
- Individual push notification preferences are respected (users can opt-out of push while keeping other notifications)
The project includes development tools configured in pyproject.toml:
- pytest: Testing framework with coverage reporting
- ruff: Linting, import sorting, and code formatting
All development dependencies are automatically installed with:
pip install -e .[dev]# Install development dependencies
pip install -e .[dev]
# Run tests
pytest
# Run with coverage
pytest --cov=app --maxfail=1 --disable-warnings -qThe project uses automated code quality tools that are also run in CI:
# Format code (Black-compatible)
ruff format app/
# Check formatting only
ruff format --check .
# Lint and sort imports (includes isort via rule I)
ruff check .
# Autofix lint and import issues
ruff check --fix .
# Only sort imports (if needed)
ruff check --select I --fix .This project uses GitHub Actions for automated testing and code quality checks. The CI pipeline:
- Multi-Python Testing: Tests against Python 3.10, 3.11, and 3.12
- Code Formatting: Validates code formatting with Ruff
- Import Sorting: Ensures consistent import organization with Ruff (isort rules)
- Linting: Code quality checks with Ruff
- Test Coverage: Automated test execution with coverage reporting
The CI workflow runs on every push to main and on pull requests, ensuring code quality and compatibility across Python versions.
Contributions are welcome. Open an issue or create a pull request.
- Fork the repository
- Create a feature branch:
git checkout -b feature/your-feature-name - Make your changes following the coding standards below
- Write tests for new functionality
- Submit a pull request with a clear description
- Python Code: Follow PEP 8 style guidelines
- Type Hints: Use type annotations for all functions
- Documentation: Include docstrings for all classes and functions
- Logging: Use the logging module instead of print statements
- Error Handling: Implement comprehensive error handling
- Use the GitHub issue tracker
- Include detailed reproduction steps
- Provide environment information (Python version, OS, etc.)
- Include relevant log files when possible
This project is licensed under the MIT License.
This project uses several open-source libraries:
- Flask (BSD-3-Clause)
- MSAL (MIT)
- pywebpush (MIT)
- APScheduler (MIT)
- Beautiful Soup (MIT)
See pyproject.toml for a complete list of dependencies.
- Question: Use Discussions
- Bug Reports: GitHub Issues
- Security Issues (Confidential): Use the Security Policy
Built with ❤️ for efficient company communication.