Phase 2: T-201 至 T-206 前台 MVP 全部实现(11 templates + CSS + 31 tests)
This commit is contained in:
+18
-1
@@ -2,6 +2,23 @@ from django.db import models
|
||||
|
||||
from wagtail.models import Page
|
||||
|
||||
from core.models import ScenarioPage, SkeletonProjectPage, ArticlePage
|
||||
|
||||
|
||||
class HomePage(Page):
|
||||
pass
|
||||
parent_page_types = ["wagtailcore.Page"]
|
||||
max_count = 1
|
||||
|
||||
def get_context(self, request, *args, **kwargs):
|
||||
context = super().get_context(request, *args, **kwargs)
|
||||
context["scenarios"] = ScenarioPage.objects.live()
|
||||
context["featured_projects"] = (
|
||||
SkeletonProjectPage.objects.live().filter(is_featured=True)
|
||||
.prefetch_related("scenarios", "languages")
|
||||
.order_by("-first_published_at")[:6]
|
||||
)
|
||||
context["latest_articles"] = (
|
||||
ArticlePage.objects.live()
|
||||
.order_by("-first_published_at")[:4]
|
||||
)
|
||||
return context
|
||||
|
||||
@@ -1,21 +1,64 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
|
||||
{% block body_class %}template-homepage{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
|
||||
{% comment %}
|
||||
Delete the line below if you're just getting started and want to remove the welcome screen!
|
||||
{% endcomment %}
|
||||
<link rel="stylesheet" href="{% static 'css/welcome_page.css' %}">
|
||||
{% endblock extra_css %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% comment %}
|
||||
Delete the line below if you're just getting started and want to remove the welcome screen!
|
||||
{% endcomment %}
|
||||
{% include 'home/welcome_page.html' %}
|
||||
<h1>Find the Right Project Skeleton</h1>
|
||||
<p>Browse open-source project skeletons by scenario, language, framework, and AI-coding friendliness score.</p>
|
||||
|
||||
{% if scenarios %}
|
||||
<section>
|
||||
<h2>Scenarios</h2>
|
||||
<div class="card-grid">
|
||||
{% for scenario in scenarios %}
|
||||
<a class="card" href="{% url 'wagtail_serve' '' %}scenarios/{{ scenario.slug }}/">
|
||||
<h3>{{ scenario.title }}</h3>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% if featured_projects %}
|
||||
<section>
|
||||
<h2>Featured Projects</h2>
|
||||
<div class="card-grid">
|
||||
{% for project in featured_projects %}
|
||||
<a class="card" href="{% url 'wagtail_serve' '' %}projects/{{ project.slug }}/">
|
||||
<h3>
|
||||
{{ project.title }}
|
||||
{% if project.is_sponsored %}
|
||||
<span class="badge badge-sponsored">Sponsored</span>
|
||||
{% endif %}
|
||||
</h3>
|
||||
<p>{{ project.summary|truncatewords:20 }}</p>
|
||||
<div class="score-bar">
|
||||
<span class="score-total">{{ project.total_score }}/30</span>
|
||||
<span class="score-detail">AI-Friendly Score</span>
|
||||
</div>
|
||||
<div class="tag-list">
|
||||
{% for lang in project.languages.all|slice:":3" %}
|
||||
<span class="tag">{{ lang.name }}</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% if latest_articles %}
|
||||
<section>
|
||||
<h2>Latest Articles</h2>
|
||||
<div class="card-grid">
|
||||
{% for article in latest_articles %}
|
||||
<a class="card" href="{% url 'wagtail_serve' '' %}articles/{{ article.slug }}/">
|
||||
<h3>{{ article.title }}</h3>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
+53
-15
@@ -5,6 +5,14 @@ from home.models import HomePage
|
||||
from wagtail.models import Page, Site
|
||||
from wagtail.test.utils import WagtailPageTestCase
|
||||
|
||||
from core.models import (
|
||||
Language,
|
||||
ScenarioPage,
|
||||
SkeletonProjectPage,
|
||||
ScenarioIndexPage,
|
||||
ProjectIndexPage,
|
||||
)
|
||||
|
||||
|
||||
class Smoketest(TestCase):
|
||||
def test_homepage_returns_200(self):
|
||||
@@ -12,33 +20,63 @@ class Smoketest(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class HomeSetUpTests(WagtailPageTestCase):
|
||||
"""
|
||||
Tests for basic page structure setup and HomePage creation.
|
||||
"""
|
||||
class HomepageContextTests(TestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
root = Page.get_first_root_node()
|
||||
cls.home = HomePage.objects.get(slug="home")
|
||||
|
||||
scenario_index = ScenarioIndexPage(title="Scenarios", slug="scenarios")
|
||||
cls.home.add_child(instance=scenario_index)
|
||||
|
||||
cls.scenario = ScenarioPage(title="Test Scenario", slug="test-scenario")
|
||||
scenario_index.add_child(instance=cls.scenario)
|
||||
|
||||
project_index = ProjectIndexPage(title="Projects", slug="projects")
|
||||
cls.home.add_child(instance=project_index)
|
||||
|
||||
lang = Language.objects.create(name="Python", slug="python")
|
||||
|
||||
project = SkeletonProjectPage(
|
||||
title="Featured Project",
|
||||
slug="featured-project",
|
||||
summary="A featured test project",
|
||||
github_url="https://github.com/test/featured",
|
||||
maturity="stable",
|
||||
recommended_for="Testing",
|
||||
structure_score=4, docs_score=4, tests_score=3,
|
||||
example_score=3, dependency_score=3, incremental_score=3,
|
||||
is_featured=True,
|
||||
)
|
||||
project_index.add_child(instance=project)
|
||||
project.languages.add(lang)
|
||||
project.scenarios.add(cls.scenario)
|
||||
project.save()
|
||||
|
||||
def test_homepage_contains_featured_project(self):
|
||||
response = self.client.get("/")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "Featured Project")
|
||||
|
||||
|
||||
class HomeSetUpTests(WagtailPageTestCase):
|
||||
def test_root_create(self):
|
||||
root_page = Page.objects.get(pk=1)
|
||||
self.assertIsNotNone(root_page)
|
||||
|
||||
def test_homepage_create(self):
|
||||
root_page = Page.objects.get(pk=1)
|
||||
homepage = HomePage(title="Home")
|
||||
homepage = HomePage(title="Home Test")
|
||||
root_page.add_child(instance=homepage)
|
||||
self.assertTrue(HomePage.objects.filter(title="Home").exists())
|
||||
self.assertTrue(HomePage.objects.filter(title="Home Test").exists())
|
||||
|
||||
|
||||
class HomeTests(WagtailPageTestCase):
|
||||
"""
|
||||
Tests for homepage functionality and rendering.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""
|
||||
Create a homepage instance for testing.
|
||||
"""
|
||||
root_page = Page.get_first_root_node()
|
||||
Site.objects.create(hostname="testsite", root_page=root_page, is_default_site=True)
|
||||
Site.objects.create(
|
||||
hostname="testsite", root_page=root_page, is_default_site=True
|
||||
)
|
||||
self.homepage = HomePage(title="Home")
|
||||
root_page.add_child(instance=self.homepage)
|
||||
|
||||
@@ -47,4 +85,4 @@ class HomeTests(WagtailPageTestCase):
|
||||
|
||||
def test_homepage_template_used(self):
|
||||
response = self.client.get(self.homepage.url)
|
||||
self.assertTemplateUsed(response, "home/home_page.html")
|
||||
self.assertTemplateUsed(response, "home/home_page.html")
|
||||
Reference in New Issue
Block a user