CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-django-notifications-hq

GitHub notifications alike app for Django providing comprehensive activity tracking and notification features.

Pending
Overview
Eval results
Files

utilities.mddocs/

Utilities

Helper functions for formatting notifications, converting IDs to URL-safe slugs, and retrieving notification data for API responses with configurable limits and pagination.

Capabilities

Notification Helper Functions

Functions for processing and formatting notification data for API responses and template display.

def get_notification_list(request, method_name='all'):
    """
    Get formatted notification list for API responses.
    
    Args:
        request: Django HTTP request object
        method_name (str): QuerySet method name ('all', 'unread', 'read', etc.)
        
    Query Parameters (from request.GET):
        max (int): Maximum notifications to return (1-100)
        mark_as_read (str): Mark notifications as read if parameter exists
        
    Returns:
        list: List of notification dictionaries with formatted data
        
    Dictionary structure:
        {
            'id': int,
            'slug': int,
            'actor': str,
            'verb': str, 
            'target': str or None,
            'action_object': str or None,
            'description': str,
            'timestamp': datetime,
            'unread': bool,
            'level': str,
            'public': bool,
            'deleted': bool,
            'emailed': bool,
            'data': dict
        }
    """

def get_num_to_fetch(request):
    """
    Extract and validate number of notifications to fetch from request.
    
    Args:
        request: Django HTTP request object
        
    Query Parameters (from request.GET):
        max (int, optional): Number of notifications requested
        
    Returns:
        int: Validated number between 1-100, defaults to NUM_TO_FETCH setting
        
    Validation:
        - Must be integer
        - Must be between 1 and 100 inclusive
        - Falls back to default if invalid
    """

ID and Slug Conversion

Utility functions for converting between notification IDs and URL-safe slugs for secure URL patterns.

def slug2id(slug):
    """
    Convert notification slug back to database ID.
    
    Args:
        slug (int or str): URL slug representing notification
        
    Returns:
        int: Database ID for notification lookup
        
    Formula: ID = slug - 110909
    """

def id2slug(notification_id):
    """
    Convert notification database ID to URL-safe slug.
    
    Args:
        notification_id (int): Database ID of notification
        
    Returns:
        int: URL-safe slug for use in URLs and templates
        
    Formula: slug = ID + 110909
    """

Usage Examples

API Response Formatting

from notifications.helpers import get_notification_list, get_num_to_fetch
from django.http import JsonResponse

def custom_notification_api(request):
    """Custom API endpoint using helper functions."""
    
    # Get validated number to fetch
    num_to_fetch = get_num_to_fetch(request)
    print(f"Fetching {num_to_fetch} notifications")
    
    # Get formatted notification list
    unread_notifications = get_notification_list(request, 'unread')
    all_notifications = get_notification_list(request, 'all')
    
    return JsonResponse({
        'unread': unread_notifications,
        'all': all_notifications,
        'meta': {
            'requested_count': num_to_fetch,
            'unread_count': len(unread_notifications),
            'all_count': len(all_notifications)
        }
    })

# Example request: /api/notifications/?max=25&mark_as_read=true
# Returns formatted notification data with auto-read functionality

Custom View with Helpers

from django.shortcuts import render
from django.contrib.auth.decorators import login_required
from notifications.helpers import get_notification_list

@login_required
def dashboard_notifications(request):
    """Dashboard view showing formatted notifications."""
    
    # Get recent notifications for display
    recent_notifications = get_notification_list(request, 'all')[:5]
    unread_notifications = get_notification_list(request, 'unread')
    
    # Process notifications for template
    processed_notifications = []
    for notification in recent_notifications:
        processed_notifications.append({
            'id': notification['id'],
            'display_text': f"{notification['actor']} {notification['verb']}",
            'target_text': notification.get('target', ''),
            'time_ago': notification['timestamp'],
            'is_unread': notification['unread'],
            'edit_url': f"/admin/notifications/notification/{notification['id']}/change/",
            'mark_read_url': f"/notifications/mark-as-read/{notification['slug']}/"
        })
    
    return render(request, 'dashboard/notifications.html', {
        'notifications': processed_notifications,
        'unread_count': len(unread_notifications)
    })

Slug Conversion Examples

from notifications.utils import id2slug, slug2id
from notifications.models import Notification

# Convert ID to slug for URL
notification = Notification.objects.get(id=123)
url_slug = id2slug(notification.id)
print(f"URL slug: {url_slug}")  # Output: 111032

# Use in URL pattern
notification_url = f"/notifications/mark-as-read/{url_slug}/"

# Convert slug back to ID for database lookup
def mark_notification_read(request, slug):
    notification_id = slug2id(slug)
    notification = Notification.objects.get(
        id=notification_id, 
        recipient=request.user
    )
    notification.mark_as_read()
    return redirect('notifications:all')

# Bulk slug operations
notification_ids = [100, 101, 102, 103]
slugs = [id2slug(nid) for nid in notification_ids]
print(f"Slugs: {slugs}")  # [111009, 111010, 111011, 111012]

# Convert back
original_ids = [slug2id(slug) for slug in slugs]
print(f"Original IDs: {original_ids}")  # [100, 101, 102, 103]

Request Parameter Processing

from notifications.helpers import get_num_to_fetch

def process_notification_request(request):
    """Demonstrate request parameter processing."""
    
    # Various request scenarios
    test_requests = [
        {'GET': {}},                           # Default: 10
        {'GET': {'max': '25'}},               # Valid: 25
        {'GET': {'max': '150'}},              # Too large: 10 (default)
        {'GET': {'max': '0'}},                # Too small: 10 (default)
        {'GET': {'max': 'invalid'}},          # Invalid: 10 (default)
        {'GET': {'max': '50'}},               # Valid: 50
    ]
    
    results = []
    for req_data in test_requests:
        # Mock request object
        class MockRequest:
            def __init__(self, get_data):
                self.GET = get_data
        
        mock_request = MockRequest(req_data['GET'])
        num_to_fetch = get_num_to_fetch(mock_request)
        results.append({
            'input': req_data['GET'].get('max', 'not provided'),
            'output': num_to_fetch
        })
    
    return results

# Example output:
# [
#     {'input': 'not provided', 'output': 10},
#     {'input': '25', 'output': 25},
#     {'input': '150', 'output': 10},
#     {'input': '0', 'output': 10},
#     {'input': 'invalid', 'output': 10},
#     {'input': '50', 'output': 50}
# ]

Custom Notification Formatter

from notifications.helpers import get_notification_list
from django.contrib.humanize.templatetags.humanize import naturaltime

def format_notifications_for_email(user, max_notifications=20):
    """Format notifications for email digest."""
    
    # Create mock request for helper function
    class MockRequest:
        def __init__(self, user, max_count):
            self.user = user
            self.GET = {'max': str(max_count)}
    
    mock_request = MockRequest(user, max_notifications)
    notifications = get_notification_list(mock_request, 'unread')
    
    formatted_notifications = []
    for notification in notifications:
        formatted_notifications.append({
            'subject': f"New notification: {notification['verb']}",
            'message': notification.get('description', 
                f"{notification['actor']} {notification['verb']}"),
            'time': naturaltime(notification['timestamp']),
            'actor': notification['actor'],
            'action': notification['verb'],
            'target': notification.get('target'),
            'url': f"https://example.com/notifications/mark-as-read/{notification['slug']}/"
        })
    
    return formatted_notifications

# Usage
user_notifications = format_notifications_for_email(user, 10)
for notif in user_notifications:
    print(f"Email: {notif['subject']}")
    print(f"Content: {notif['message']}")
    print(f"Time: {notif['time']}")
    print("---")

Pagination Helper

from notifications.helpers import get_num_to_fetch
from django.core.paginator import Paginator

def paginated_notifications(request, method_name='all'):
    """Get paginated notifications using helper functions."""
    
    # Get number to fetch per page
    per_page = get_num_to_fetch(request)
    
    # Get user's notifications
    if method_name == 'unread':
        notifications = request.user.notifications.unread()
    elif method_name == 'read':
        notifications = request.user.notifications.read()
    else:
        notifications = request.user.notifications.all()
    
    # Create paginator
    paginator = Paginator(notifications, per_page)
    page_number = request.GET.get('page', 1)
    page_obj = paginator.get_page(page_number)
    
    # Format notifications for response
    formatted_notifications = []
    for notification in page_obj:
        formatted_notifications.append({
            'id': notification.id,
            'slug': notification.slug,
            'actor': str(notification.actor),
            'verb': notification.verb,
            'target': str(notification.target) if notification.target else None,
            'description': notification.description,
            'timestamp': notification.timestamp,
            'unread': notification.unread,
            'level': notification.level
        })
    
    return {
        'notifications': formatted_notifications,
        'pagination': {
            'has_previous': page_obj.has_previous(),
            'has_next': page_obj.has_next(),
            'previous_page_number': page_obj.previous_page_number() if page_obj.has_previous() else None,
            'next_page_number': page_obj.next_page_number() if page_obj.has_next() else None,
            'current_page': page_obj.number,
            'total_pages': page_obj.paginator.num_pages,
            'total_count': page_obj.paginator.count,
            'per_page': per_page
        }
    }

# Usage in view
def notification_list_api(request):
    result = paginated_notifications(request, 'unread')
    return JsonResponse(result)

Bulk Operations with Utilities

from notifications.utils import slug2id
from notifications.models import Notification

def bulk_mark_notifications_read(request):
    """Mark multiple notifications as read using slugs."""
    
    # Get slugs from request (e.g., form data or JSON)
    slugs = request.POST.getlist('notification_slugs')
    # or from JSON: slugs = json.loads(request.body).get('slugs', [])
    
    # Convert slugs to IDs
    notification_ids = [slug2id(slug) for slug in slugs]
    
    # Bulk update notifications
    updated_count = Notification.objects.filter(
        id__in=notification_ids,
        recipient=request.user,
        unread=True
    ).update(unread=False)
    
    return JsonResponse({
        'success': True,
        'updated_count': updated_count,
        'processed_ids': notification_ids
    })

def generate_notification_urls(notifications):
    """Generate URLs for a list of notifications."""
    
    urls = {}
    for notification in notifications:
        slug = notification.slug  # Uses property from model
        urls[notification.id] = {
            'mark_read': f"/notifications/mark-as-read/{slug}/",
            'mark_unread': f"/notifications/mark-as-unread/{slug}/",
            'delete': f"/notifications/delete/{slug}/",
            'detail': f"/notifications/{slug}/"
        }
    
    return urls

# Example usage
user_notifications = user.notifications.unread()[:10]
notification_urls = generate_notification_urls(user_notifications)

for notification in user_notifications:
    urls = notification_urls[notification.id]
    print(f"Notification {notification.id}:")
    print(f"  Mark Read: {urls['mark_read']}")
    print(f"  Delete: {urls['delete']}")

Install with Tessl CLI

npx tessl i tessl/pypi-django-notifications-hq

docs

admin-integration.md

api-endpoints.md

configuration.md

core-system.md

index.md

signals.md

template-integration.md

utilities.md

web-interface.md

tile.json