This commit implements a comprehensive system for managing social media
links dynamically without hardcoding any URLs in the frontend code.
Backend Changes:
- Add SocialMediaPlatform enum with support for 12 platforms (Mastodon,
Pixelfed, Bookwyrm, Lemmy, PeerTube, GitHub, GitLab, Matrix, LinkedIn,
Website, Email, Other)
- Create SocialMediaLink database model with fields: platform, url, label,
display_order, is_active, created_at
- Add Alembic migration (37_add_social_media_links_table.py)
- Create comprehensive API endpoints:
* GET /api/v1/social-media-links/public (no auth, returns active links)
* GET /api/v1/social-media-links (admin only, returns all links)
* POST /api/v1/social-media-links (admin only, create link)
* PATCH /api/v1/social-media-links/{id} (admin only, update link)
* DELETE /api/v1/social-media-links/{id} (admin only, delete link)
- Add Pydantic schemas for validation and serialization
- Register routes in main router
Frontend Changes:
- Update footer component to fetch links from public API endpoint
- Implement icon mapping for all supported platforms
- Add proper loading states and error handling
- Remove all hardcoded social media URLs
- Icons only display when URLs are configured via admin panel
- Proper accessibility (aria-labels, target="_blank", rel="noopener noreferrer")
Authentication Cleanup:
- Remove GoogleLoginButton.tsx component (no longer used)
- Delete Google OAuth documentation images
- Login and register pages already use email/password only
Documentation:
- Add comprehensive SOCIAL_MEDIA_LINKS_ADMIN.md with:
* API endpoint documentation
* cURL examples for all operations
* Platform support matrix
* Icon mapping reference
* Security notes
* Troubleshooting guide
Features:
✅ No hardcoded social media URLs
✅ Admin can add/edit/remove links via API
✅ Links automatically show/hide based on is_active flag
✅ Customizable display order
✅ Platform-specific icons automatically selected
✅ Public endpoint for frontend (no auth required)
✅ Admin endpoints protected (superuser only)
✅ Proper validation and error handling
✅ Email/password authentication only (OAuth removed)
Migration Required:
Run `alembic upgrade head` to create the social_media_links table.
Co-authored-by: Ojārs Kapteiņš <ojars@kapteinis.lv>
Co-authored-by: Claude AI Assistant <odede@anthropic.com>
6.2 KiB
Social Media Links Management
This document explains how to manage dynamic social media links for the SurfSense homepage footer.
Overview
Social media links are now managed dynamically through the backend API. No hardcoded links exist in the frontend code. Administrators can add, edit, or remove links, and they will automatically appear or disappear from the homepage footer.
API Endpoints
All admin endpoints require authentication and superuser privileges.
Base URL
{BACKEND_URL}/api/v1/social-media-links
1. Get All Links (Admin)
GET /api/v1/social-media-links
Authorization: Bearer {your_jwt_token}
Response:
[
{
"id": 1,
"platform": "MASTODON",
"url": "https://mastodon.social/@username",
"label": "Follow us on Mastodon",
"display_order": 0,
"is_active": true,
"created_at": "2025-11-17T00:00:00Z"
}
]
2. Get Public Links (No Auth Required)
GET /api/v1/social-media-links/public
This endpoint returns only active links, ordered by display_order. Used by the homepage footer.
3. Create a Link (Admin)
POST /api/v1/social-media-links
Authorization: Bearer {your_jwt_token}
Content-Type: application/json
{
"platform": "MASTODON",
"url": "https://mastodon.social/@username",
"label": "Mastodon",
"display_order": 0,
"is_active": true
}
Supported Platforms:
MASTODONPIXELFEDBOOKWYRMLEMMYPEERTUBEGITHUBGITLABMATRIXLINKEDINWEBSITEEMAILOTHER
4. Update a Link (Admin)
PATCH /api/v1/social-media-links/{link_id}
Authorization: Bearer {your_jwt_token}
Content-Type: application/json
{
"url": "https://new-url.example.com",
"is_active": false
}
You can update any field(s). Omit fields you don't want to change.
5. Delete a Link (Admin)
DELETE /api/v1/social-media-links/{link_id}
Authorization: Bearer {your_jwt_token}
Example: Using cURL
Add a Mastodon Link
# First, login to get JWT token
TOKEN=$(curl -X POST "http://localhost:8000/auth/jwt/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "username=admin@example.com&password=yourpassword" \
| jq -r '.access_token')
# Create the link
curl -X POST "http://localhost:8000/api/v1/social-media-links" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"platform": "MASTODON",
"url": "https://mastodon.social/@surfsense",
"label": "Mastodon",
"display_order": 1,
"is_active": true
}'
Add Multiple Links
# Pixelfed
curl -X POST "http://localhost:8000/api/v1/social-media-links" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"platform": "PIXELFED",
"url": "https://pixelfed.social/username",
"label": "Pixelfed",
"display_order": 2,
"is_active": true
}'
# Bookwyrm
curl -X POST "http://localhost:8000/api/v1/social-media-links" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"platform": "BOOKWYRM",
"url": "https://bookwyrm.social/user/username",
"label": "Bookwyrm",
"display_order": 3,
"is_active": true
}'
Update a Link
# Hide a link without deleting it
curl -X PATCH "http://localhost:8000/api/v1/social-media-links/1" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"is_active": false}'
List All Links
curl "http://localhost:8000/api/v1/social-media-links" \
-H "Authorization: Bearer $TOKEN"
Delete a Link
curl -X DELETE "http://localhost:8000/api/v1/social-media-links/1" \
-H "Authorization: Bearer $TOKEN"
Icon Mapping
The frontend automatically maps platform names to appropriate icons:
| Platform | Icon |
|---|---|
| MASTODON | Mastodon logo |
| PIXELFED | Photo icon |
| BOOKWYRM | Book icon |
| GITHUB | GitHub logo |
| GITLAB | GitLab logo |
| LinkedIn logo | |
| WEBSITE | World/globe icon |
| Mail icon | |
| MATRIX | Matrix logo |
| PEERTUBE | TV/video icon |
| LEMMY | World icon |
| OTHER | World icon |
How It Works
- Backend: Social media links are stored in the
social_media_linksdatabase table - Public API: The
/api/v1/social-media-links/publicendpoint returns only active links - Frontend: The footer component (
components/homepage/footer.tsx) fetches links on page load - Display: Only links with
is_active=trueare shown, ordered bydisplay_order - Icons: Platform-specific icons are automatically selected based on the
platformfield
Database Migration
To apply the database schema:
cd surfsense_backend
alembic upgrade head
This will create the social_media_links table and the socialmediaplatform enum type.
Security Notes
- Admin endpoints require superuser privileges - regular users cannot manage links
- Public endpoint is unauthenticated - anyone can view active links (as intended for homepage display)
- No hardcoded URLs - all social media links come from the database
- Validation - URLs are validated (max 500 chars), labels max 100 chars
Future Enhancements
Future improvements could include:
- Web UI: A graphical admin panel in the dashboard for managing links
- Drag-and-drop reordering: UI to easily reorder links by changing
display_order - Link analytics: Track clicks on social media links
- Per-user links: Allow different users to have different social links (currently global)
- Link preview: Show how the footer will look before saving changes
Troubleshooting
Links not appearing on homepage:
- Check that
is_active=truefor the link - Verify the backend API is reachable from frontend
- Check browser console for fetch errors
- Confirm
NEXT_PUBLIC_FASTAPI_BACKEND_URLenvironment variable is set correctly
Cannot create links:
- Ensure you're logged in as a superuser
- Check JWT token is valid and not expired
- Verify request payload matches the schema
Icons not displaying:
- Check that the platform name exactly matches one of the supported platforms (case-sensitive)
- Unsupported platforms will default to the world/globe icon