import hashlib from django.contrib import messages from django.db.models import Q from django.shortcuts import get_object_or_404, redirect, render from django.utils import timezone from .forms import ArticleFilterForm, OriginalArticleForm from .models import Article, NewsSource, Topic from .rss import sync_active_sources def _published_articles(): return Article.objects.filter(is_published=True).select_related('topic', 'source') def _build_filter_form(data=None): return ArticleFilterForm(data or None) def home(request): sync_active_sources(limit=6) filter_form = _build_filter_form(request.GET or None) stories = _published_articles() if filter_form.is_valid(): query = filter_form.cleaned_data.get('q') topic_slug = filter_form.cleaned_data.get('topic') if query: stories = stories.filter( Q(title__icontains=query) | Q(excerpt__icontains=query) | Q(content__icontains=query) | Q(author_name__icontains=query) ) if topic_slug: stories = stories.filter(topic__slug=topic_slug) featured_story = stories.filter(is_featured=True).first() or stories.first() spotlight_stories = stories.exclude(pk=getattr(featured_story, 'pk', None))[:6] original_story = _published_articles().filter(article_kind=Article.ArticleKind.ORIGINAL).first() context = { 'page_title': 'Signal / Startup & Tech Newsroom', 'meta_description': 'A polished startup and tech news magazine with RSS aggregation, editorial curation, and a fast CMS workflow.', 'filter_form': filter_form, 'featured_story': featured_story, 'spotlight_stories': spotlight_stories, 'topics': Topic.objects.order_by('name'), 'sources': NewsSource.objects.filter(is_active=True).order_by('name')[:6], 'story_count': stories.count(), 'original_story': original_story, 'last_updated': _published_articles().first(), } return render(request, 'core/index.html', context) def article_list(request): sync_active_sources(limit=4) filter_form = _build_filter_form(request.GET or None) stories = _published_articles() selected_topic = None if filter_form.is_valid(): query = filter_form.cleaned_data.get('q') topic_slug = filter_form.cleaned_data.get('topic') if query: stories = stories.filter( Q(title__icontains=query) | Q(excerpt__icontains=query) | Q(content__icontains=query) | Q(author_name__icontains=query) ) if topic_slug: stories = stories.filter(topic__slug=topic_slug) selected_topic = Topic.objects.filter(slug=topic_slug).first() context = { 'page_title': 'All Stories / Signal', 'meta_description': 'Browse curated startup and tech stories by topic, recency, and editorial origin.', 'filter_form': filter_form, 'stories': stories[:24], 'selected_topic': selected_topic, 'topics': Topic.objects.order_by('name'), } return render(request, 'core/article_list.html', context) def article_detail(request, slug): article = get_object_or_404(_published_articles(), slug=slug) related_articles = _published_articles().filter(topic=article.topic).exclude(pk=article.pk)[:3] context = { 'page_title': f'{article.title} / Signal', 'meta_description': article.excerpt or 'Read the latest curated startup and tech story on Signal.', 'article': article, 'related_articles': related_articles, } return render(request, 'core/article_detail.html', context) def article_submit(request): if request.method == 'POST': form = OriginalArticleForm(request.POST) if form.is_valid(): article = form.save(commit=False) article.article_kind = Article.ArticleKind.ORIGINAL article.is_published = True article.published_at = timezone.now() article.dedupe_key = hashlib.sha256(f"original|{timezone.now().isoformat()}|{article.title}".encode('utf-8')).hexdigest() article.save() messages.success(request, 'Your editorial story is live in the newsroom.') return redirect('article_submit_success', slug=article.slug) else: form = OriginalArticleForm() context = { 'page_title': 'Publish a Story / Signal CMS', 'meta_description': 'Draft an original startup or tech story and publish it into the Signal magazine flow.', 'form': form, } return render(request, 'core/article_form.html', context) def article_submit_success(request, slug): article = get_object_or_404(Article, slug=slug, article_kind=Article.ArticleKind.ORIGINAL) context = { 'page_title': 'Story Published / Signal CMS', 'meta_description': 'Your original story has been published and added to the curated tech newsroom.', 'article': article, } return render(request, 'core/article_submit_success.html', context)