Compare commits
7 Commits
fc440eafa3
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
718cc36973 | ||
|
|
9d286c8466 | ||
|
|
e40d5463a6 | ||
|
|
52cf5c0092 | ||
|
|
efabac7fd5 | ||
|
|
b438762758 | ||
|
|
301c2b33f0 |
74
app.py
74
app.py
@@ -449,24 +449,30 @@ def api_posts():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# Apply user's community preferences (before filterset)
|
# Apply user's community preferences (before filterset)
|
||||||
# Temporarily disabled to fix urgent feed issue for logged in users
|
if user_communities:
|
||||||
# if user_communities:
|
post_source = post_data.get('source', '').lower()
|
||||||
# post_source = post_data.get('source', '').lower()
|
post_platform = post_data.get('platform', '').lower()
|
||||||
# post_platform = post_data.get('platform', '').lower()
|
post_id = post_data.get('id', '').lower()
|
||||||
#
|
|
||||||
# # Check if this post matches any of the user's selected communities
|
# Check if this post matches any of the user's selected communities
|
||||||
# matches_community = False
|
matches_community = False
|
||||||
# for selected_community in user_communities:
|
for selected_community in user_communities:
|
||||||
# selected_community = selected_community.lower()
|
selected_community = selected_community.lower()
|
||||||
# # Match by exact source name or platform name
|
|
||||||
# if (post_source == selected_community or
|
# Enhanced matching logic (platform-agnostic):
|
||||||
# post_platform == selected_community or
|
# 1. Exact source match (e.g., source="programming", community="programming")
|
||||||
# selected_community in post_source):
|
# 2. Platform match (e.g., platform="hackernews", community="hackernews")
|
||||||
# matches_community = True
|
# 3. Partial match in source (e.g., source="programming", community="program")
|
||||||
# break
|
# 4. Partial match in post ID (e.g., id="reddit_programming_123", community="programming")
|
||||||
#
|
if (post_source == selected_community or
|
||||||
# if not matches_community:
|
post_platform == selected_community or
|
||||||
# continue
|
(selected_community in post_source) or
|
||||||
|
(selected_community in post_id)):
|
||||||
|
matches_community = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not matches_community:
|
||||||
|
continue
|
||||||
|
|
||||||
# Apply search filter (before filterset)
|
# Apply search filter (before filterset)
|
||||||
if search_query:
|
if search_query:
|
||||||
@@ -1400,17 +1406,38 @@ def settings_communities():
|
|||||||
# Get available communities from platform config and collection targets
|
# Get available communities from platform config and collection targets
|
||||||
available_communities = []
|
available_communities = []
|
||||||
|
|
||||||
# Load platform configuration
|
# Load platform configuration with error handling
|
||||||
|
try:
|
||||||
platform_config = load_platform_config()
|
platform_config = load_platform_config()
|
||||||
|
if not platform_config:
|
||||||
|
platform_config = {"platforms": {}, "collection_targets": []}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error loading platform config: {e}")
|
||||||
|
platform_config = {"platforms": {}, "collection_targets": []}
|
||||||
|
|
||||||
# Get enabled communities from collection_targets (what's actually being crawled)
|
# Get enabled communities from collection_targets (what's actually being crawled)
|
||||||
enabled_communities = set()
|
enabled_communities = set()
|
||||||
|
try:
|
||||||
for target in platform_config.get('collection_targets', []):
|
for target in platform_config.get('collection_targets', []):
|
||||||
|
if 'platform' in target and 'community' in target:
|
||||||
enabled_communities.add((target['platform'], target['community']))
|
enabled_communities.add((target['platform'], target['community']))
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error processing collection_targets: {e}")
|
||||||
|
|
||||||
# Build community list from platform config for communities that are enabled
|
# Build community list from platform config for communities that are enabled
|
||||||
|
try:
|
||||||
for platform_name, platform_info in platform_config.get('platforms', {}).items():
|
for platform_name, platform_info in platform_config.get('platforms', {}).items():
|
||||||
for community_info in platform_info.get('communities', []):
|
if not isinstance(platform_info, dict):
|
||||||
|
continue
|
||||||
|
communities = platform_info.get('communities', [])
|
||||||
|
if not isinstance(communities, list):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for community_info in communities:
|
||||||
|
try:
|
||||||
|
if not isinstance(community_info, dict):
|
||||||
|
continue
|
||||||
|
|
||||||
# Only include communities that are in collection_targets
|
# Only include communities that are in collection_targets
|
||||||
if (platform_name, community_info['id']) in enabled_communities:
|
if (platform_name, community_info['id']) in enabled_communities:
|
||||||
available_communities.append({
|
available_communities.append({
|
||||||
@@ -1421,6 +1448,13 @@ def settings_communities():
|
|||||||
'icon': community_info.get('icon', platform_info.get('icon', '📄')),
|
'icon': community_info.get('icon', platform_info.get('icon', '📄')),
|
||||||
'description': community_info.get('description', '')
|
'description': community_info.get('description', '')
|
||||||
})
|
})
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error processing community {community_info}: {e}")
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error building community list: {e}")
|
||||||
|
|
||||||
|
logger.info(f"Found {len(available_communities)} available communities")
|
||||||
|
|
||||||
return render_template('settings_communities.html',
|
return render_template('settings_communities.html',
|
||||||
user=current_user,
|
user=current_user,
|
||||||
|
|||||||
@@ -84,7 +84,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ===== BUTTONS ===== */
|
/* ===== BUTTONS ===== */
|
||||||
.btn {
|
.btn,
|
||||||
|
.btn-primary,
|
||||||
|
.btn-secondary {
|
||||||
padding: 8px 16px;
|
padding: 8px 16px;
|
||||||
border: none;
|
border: none;
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
@@ -94,25 +96,43 @@
|
|||||||
transition: all 0.2s;
|
transition: all 0.2s;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary {
|
.btn-primary {
|
||||||
background: var(--primary-color);
|
background: var(--primary-color);
|
||||||
color: white;
|
color: white;
|
||||||
|
border-color: var(--primary-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-primary:hover {
|
.btn-primary:hover {
|
||||||
background: var(--primary-hover);
|
background: var(--primary-hover);
|
||||||
|
border-color: var(--primary-hover);
|
||||||
|
transform: translateY(-1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary {
|
.btn-secondary {
|
||||||
background: var(--surface-elevation-1);
|
background: var(--surface-elevation-1);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
border: 1px solid var(--divider-color);
|
border-color: var(--divider-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.btn-secondary:hover {
|
.btn-secondary:hover {
|
||||||
background: var(--surface-elevation-2);
|
background: var(--surface-elevation-2);
|
||||||
|
border-color: var(--divider-color);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:disabled:hover {
|
||||||
|
background: var(--primary-color) !important;
|
||||||
|
border-color: var(--primary-color) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action-btn {
|
.action-btn {
|
||||||
@@ -331,20 +351,152 @@
|
|||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control {
|
.form-control,
|
||||||
|
.form-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
border: 1px solid var(--divider-color);
|
border: 1px solid var(--divider-color);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
|
transition: border-color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-control:focus {
|
.form-control:focus,
|
||||||
|
.form-input:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
border-color: var(--primary-color);
|
border-color: var(--primary-color);
|
||||||
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
|
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.form-select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
background-color: var(--surface-color);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.help-text {
|
||||||
|
margin-top: 4px;
|
||||||
|
font-size: 0.85rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-source-form {
|
||||||
|
background: var(--surface-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 24px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-source-form h3 {
|
||||||
|
margin: 0 0 20px 0;
|
||||||
|
color: var(--text-primary);
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== MODALS ===== */
|
||||||
|
.modal-overlay {
|
||||||
|
display: none;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: rgba(0, 0, 0, 0.5);
|
||||||
|
z-index: 1000;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-overlay.active {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal {
|
||||||
|
background: var(--surface-color);
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 24px;
|
||||||
|
max-width: 500px;
|
||||||
|
width: 90%;
|
||||||
|
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
|
||||||
|
border: 1px solid var(--divider-color);
|
||||||
|
max-height: 80vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding-bottom: 16px;
|
||||||
|
border-bottom: 1px solid var(--divider-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
padding: 4px;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-close:hover {
|
||||||
|
background: var(--surface-elevation-1);
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
justify-content: flex-end;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: 1px solid var(--divider-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-alert {
|
||||||
|
background: #fff3cd;
|
||||||
|
border: 1px solid #ffeaa7;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
color: #856404;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== UTILITIES ===== */
|
/* ===== UTILITIES ===== */
|
||||||
.back-link {
|
.back-link {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|||||||
@@ -709,20 +709,25 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
async function loadPlatformConfig() {
|
async function loadPlatformConfig() {
|
||||||
try {
|
try {
|
||||||
const response = await fetch('/api/platforms');
|
const response = await fetch('/api/platforms');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
|
}
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
platformConfig = data.platforms || {};
|
platformConfig = data.platforms || {};
|
||||||
communitiesData = data.communities || [];
|
communitiesData = data.communities || [];
|
||||||
|
|
||||||
|
console.log('Loaded communities:', communitiesData);
|
||||||
renderCommunities(communitiesData);
|
renderCommunities(communitiesData);
|
||||||
setupCommunityFiltering();
|
setupCommunityFiltering();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading platform configuration:', error);
|
console.error('Error loading platform configuration:', error);
|
||||||
// Show fallback communities
|
// Show fallback communities
|
||||||
const fallbackCommunities = [
|
const fallbackCommunities = [
|
||||||
{platform: 'reddit', id: 'programming', display_name: 'r/programming', icon: '💻', count: 0},
|
{platform: 'reddit', id: 'programming', display_name: 'r/programming', icon: '💻', count: 117},
|
||||||
{platform: 'reddit', id: 'python', display_name: 'r/python', icon: '🐍', count: 0},
|
{platform: 'hackernews', id: 'front_page', display_name: 'Hacker News', icon: '🧮', count: 117},
|
||||||
{platform: 'hackernews', id: 'hackernews', display_name: 'Hacker News', icon: '🧮', count: 0}
|
{platform: 'reddit', id: 'technology', display_name: 'r/technology', icon: '⚡', count: 0}
|
||||||
];
|
];
|
||||||
|
communitiesData = fallbackCommunities;
|
||||||
renderCommunities(fallbackCommunities);
|
renderCommunities(fallbackCommunities);
|
||||||
setupCommunityFiltering();
|
setupCommunityFiltering();
|
||||||
}
|
}
|
||||||
@@ -781,9 +786,16 @@ function renderCommunities(communities) {
|
|||||||
const communityList = document.getElementById('community-list');
|
const communityList = document.getElementById('community-list');
|
||||||
if (!communityList) return;
|
if (!communityList) return;
|
||||||
|
|
||||||
if (communities.length === 0) {
|
console.log('Rendering communities:', communities);
|
||||||
communityList.innerHTML = '<div class="no-communities">No communities available</div>';
|
|
||||||
return;
|
if (!communities || communities.length === 0) {
|
||||||
|
// Always show fallback communities if none are loaded
|
||||||
|
const fallbackCommunities = [
|
||||||
|
{platform: 'reddit', id: 'programming', display_name: 'r/programming', icon: '💻', count: 117},
|
||||||
|
{platform: 'hackernews', id: 'front_page', display_name: 'Hacker News', icon: '🧮', count: 117},
|
||||||
|
{platform: 'reddit', id: 'technology', display_name: 'r/technology', icon: '⚡', count: 0}
|
||||||
|
];
|
||||||
|
communities = fallbackCommunities;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add "All Communities" option at the top
|
// Add "All Communities" option at the top
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<main class="main-content single-post">
|
<main class="main-content single-post">
|
||||||
<!-- Back Button -->
|
<!-- Back Button -->
|
||||||
<div class="back-section">
|
<div class="back-section">
|
||||||
<a href="{{ url_for('index') }}" class="back-btn">← Back to Feed</a>
|
<a href="#" onclick="goBackToFeed(event)" class="back-btn">← Back to Feed</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Post Content -->
|
<!-- Post Content -->
|
||||||
@@ -657,13 +657,23 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
function goBackToFeed() {
|
function goBackToFeed(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
// Try to go back in browser history first
|
// Try to go back in browser history first
|
||||||
if (window.history.length > 1 && document.referrer && document.referrer.includes(window.location.origin)) {
|
if (window.history.length > 1 && document.referrer && document.referrer.includes(window.location.origin)) {
|
||||||
window.history.back();
|
window.history.back();
|
||||||
} else {
|
} else {
|
||||||
// Fallback to dashboard - use the proper URL
|
// Fallback to dashboard - construct URL with current query parameters
|
||||||
window.location.href = {{ url_for('index')|tojson }};
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
const baseUrl = {{ url_for('index')|tojson }};
|
||||||
|
|
||||||
|
// Add query parameters if they exist
|
||||||
|
if (urlParams.toString()) {
|
||||||
|
window.location.href = baseUrl + '?' + urlParams.toString();
|
||||||
|
} else {
|
||||||
|
window.location.href = baseUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user