## Copyright © 2026 Olaf Kolkman ## SPDX-License-Identifier: GPL-3.0-or-later import math from fastapi import APIRouter, Depends, Query from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer from backend.app.core.config import settings from backend.app.services.link_service import list_public_links, list_public_users from backend.app.services.token_service import validate_token from backend.app.services.theme_service import THEMES, get_enabled_themes router = APIRouter() optional_bearer = HTTPBearer(auto_error=False) @router.get('/users') def public_users(): return list_public_users() @router.get('/themes') def public_themes(): enabled = get_enabled_themes() return [{'id': theme, **THEMES[theme]} for theme in enabled] @router.get('/config') def public_config(): return {'feed_page_sizes': settings.feed_page_sizes, 'default_page_size': settings.feed_page_sizes[0]} @router.get('/feed') @router.get('/feed/{username}') def public_feed( username: str | None = None, tag: str | None = None, search: str | None = None, sort: str = 'newest', page: int = Query(1, ge=1), page_size: int | None = Query(None, ge=1), credentials: HTTPAuthorizationCredentials | None = Depends(optional_bearer), ): current_user_id = None if credentials: token_data = validate_token(credentials.credentials) if token_data: current_user_id = token_data['user_id'] allowed_sizes = settings.feed_page_sizes effective_page_size = page_size if page_size in allowed_sizes else allowed_sizes[0] result = list_public_links(username, tag=tag, search=search, sort=sort, page=page, page_size=effective_page_size) items = [ { 'id': item['id'], 'title': item['title'], 'url': item['url'], 'comment': item['comment'], 'tags': item['tags'], 'user': { 'username': item['username'], 'avatar_url': item['avatar_url'], 'bio': item['bio'], }, 'is_owner': item['user_id'] == current_user_id, 'can_edit': item['user_id'] == current_user_id, 'created_at': item['created_at'], 'mastodon_posted': bool(item['mastodon_posted']), } for item in result['items'] ] total = result['total'] total_pages = max(1, math.ceil(total / effective_page_size)) return { 'items': items, 'total': total, 'page': page, 'page_size': effective_page_size, 'total_pages': total_pages, }