Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions backend/apps/sitemap/views/chapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ class ChapterSitemap(BaseSitemap):
change_frequency = "weekly"
prefix = "/chapters"

def items(self):
"""Return list of chapters for sitemap generation."""
def items(self) -> list[Chapter]:
"""Return chapters for sitemap generation.

Returns:
list: List of indexable Chapter objects ordered by update/creation date.

"""
return [
c
for c in Chapter.active_chapters.order_by(
Expand Down
9 changes: 7 additions & 2 deletions backend/apps/sitemap/views/committee.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ class CommitteeSitemap(BaseSitemap):
change_frequency = "monthly"
prefix = "/committees"

def items(self):
"""Return list of committees for sitemap generation."""
def items(self) -> list[Committee]:
"""Return committees for sitemap generation.

Returns:
list: List of indexable Committee objects ordered by update/creation date.

"""
return [
c
for c in Committee.active_committees.order_by(
Expand Down
20 changes: 17 additions & 3 deletions backend/apps/sitemap/views/member.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ class MemberSitemap(BaseSitemap):
change_frequency = "daily"
prefix = "/members"

def items(self):
"""Return list of members for sitemap generation."""
return [u for u in User.objects.filter(is_bot=False) if u.is_indexable]
def items(self) -> list[User]:
"""Return members for sitemap generation.

Returns:
list: List of indexable User objects ordered by update/creation date

"""
return [
u
for u in User.objects.filter(
is_bot=False,
).order_by(
"-updated_at",
"-created_at",
)
if u.is_indexable
]
14 changes: 9 additions & 5 deletions backend/apps/sitemap/views/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ class OrganizationSitemap(BaseSitemap):
change_frequency = "monthly"
prefix = "/organizations"

def items(self):
"""Return a queryset of indexable Organization objects."""
def items(self) -> list[Organization]:
"""Return organizations for sitemap generation.

Returns:
list: List of indexable OWASP-related Organization objects
ordered by update/creation date.

"""
return [
o
for o in Organization.objects.filter(
is_owasp_related_organization=True,
).order_by(
for o in Organization.related_organizations.order_by(
"-updated_at",
"-created_at",
)
Expand Down
9 changes: 7 additions & 2 deletions backend/apps/sitemap/views/project.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,13 @@ class ProjectSitemap(BaseSitemap):
change_frequency = "weekly"
prefix = "/projects"

def items(self):
"""Return list of projects for sitemap generation."""
def items(self) -> list[Project]:
"""Return projects for sitemap generation.

Returns:
list: List of indexable Project objects ordered by update/creation date.

"""
return [
p
for p in Project.active_projects.order_by(
Expand Down
29 changes: 16 additions & 13 deletions backend/apps/sitemap/views/repository.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Repository sitemap."""

from django.db.models import QuerySet

from apps.github.models.repository import Repository
from apps.sitemap.views.base import BaseSitemap

Expand All @@ -12,17 +10,22 @@ class RepositorySitemap(BaseSitemap):
change_frequency = "weekly"
prefix = "/repositories"

def items(self) -> QuerySet[Repository]:
"""Return list of repositories for sitemap generation."""
return Repository.objects.filter(
is_archived=False,
is_empty=False,
is_template=False,
organization__isnull=False,
).order_by(
"-updated_at",
"-created_at",
)
def items(self) -> list[Repository]:
"""Return repositories for sitemap generation.

Returns:
list[Repository]: List of indexable Repository objects ordered by
update/creation date.

"""
return [
r
for r in Repository.objects.order_by(
"-updated_at",
"-created_at",
)
if r.organization and r.is_indexable
]

def location(self, obj: Repository) -> str:
"""Return the URL path for a repository.
Expand Down
21 changes: 18 additions & 3 deletions backend/apps/sitemap/views/snapshot.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Snapshot sitemap."""

from django.db.models import QuerySet

from apps.owasp.models.snapshot import Snapshot
from apps.sitemap.views.base import BaseSitemap

Expand All @@ -10,8 +12,13 @@ class SnapshotSitemap(BaseSitemap):
change_frequency = "monthly"
prefix = "/snapshots"

def items(self):
"""Return queryset of snapshots for sitemap generation."""
def items(self) -> QuerySet[Snapshot]:
"""Return snapshots for sitemap generation.

Returns:
QuerySet: Queryset of completed Snapshot objects ordered by update/creation date.

"""
return Snapshot.objects.filter(
status=Snapshot.Status.COMPLETED,
).order_by(
Expand All @@ -20,5 +27,13 @@ def items(self):
)

def location(self, obj):
"""Return the URL path for an object."""
"""Return the URL path for a snapshot.

Args:
obj: Snapshot instance to generate URL for.

Returns:
str: The URL path for the snapshot.

"""
return f"{self.prefix}/{obj.key}"
60 changes: 49 additions & 11 deletions backend/apps/sitemap/views/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,50 @@
class StaticSitemap(BaseSitemap):
"""A sitemap for static routes that includes all other dynamic sitemaps."""

def changefreq(self, item):
"""Return the change frequency for a static route item."""
def changefreq(self, item) -> str:
"""Return the change frequency for a static route item.

Args:
item: Dictionary containing static route information.

Returns:
str: Change frequency value for the sitemap entry.

"""
return item["changefreq"]

def location(self, item):
"""Return the URL path for a static route item."""
def location(self, item) -> str:
"""Return the URL path for a static route item.

Args:
item: Dictionary containing static route information.

Returns:
str: The URL path for the static route.

"""
return item["path"]

def items(self):
"""Return list of static routes for sitemap generation."""
def items(self) -> tuple[dict, ...]:
"""Return static routes for sitemap generation.

Returns:
tuple: Tuple of dictionaries containing static route configurations.

"""
return BaseSitemap.STATIC_ROUTES

def lastmod(self, item):
"""Return the last modification date for a static route item."""
def lastmod(self, item: dict) -> datetime:
"""Return the last modification date for a static route item.

Args:
item: Dictionary containing static route information.

Returns:
datetime: Last modification timestamp based on the most recently updated
object of the corresponding model, or current time if no model mapping exists.

"""
path_to_model = {
"/chapters": Chapter,
"/committees": Committee,
Expand All @@ -41,11 +71,19 @@ def lastmod(self, item):
}

return (
model.objects.aggregate(latest=Max("updated_at"))["latest"]
model.objects.aggregate(latest=Max("updated_at"))["latest"] # type: ignore[attr-defined]
if (model := path_to_model.get(item["path"]))
else datetime.now(UTC)
)

def priority(self, item):
"""Return the priority score for a static route item."""
def priority(self, item: dict) -> float:
"""Return the priority score for a static route item.

Args:
item: Dictionary containing static route information.

Returns:
float: Priority value for the sitemap entry (0.0 to 1.0).

"""
return item["priority"]
2 changes: 1 addition & 1 deletion backend/tests/apps/sitemap/views/member_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def test_inherits_from_base(self):
@patch("apps.sitemap.views.member.User")
def test_items(self, mock_user):
mock_obj = MagicMock(is_indexable=True)
mock_user.objects.filter.return_value = [mock_obj]
mock_user.objects.filter.return_value.order_by.return_value = [mock_obj]
sitemap = MemberSitemap()

assert list(sitemap.items()) == [mock_obj]
Expand Down
6 changes: 3 additions & 3 deletions backend/tests/apps/sitemap/views/organization_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ def test_inherits_from_base(self):
@patch("apps.sitemap.views.organization.Organization")
def test_items(self, mock_organization):
mock_obj = MagicMock(is_indexable=True)
mock_qs = MagicMock()
mock_qs.order_by.return_value = [mock_obj]
mock_organization.objects.filter.return_value = mock_qs
mock_queryset = MagicMock()
mock_queryset.__iter__ = lambda _: iter([mock_obj])
mock_organization.related_organizations.order_by.return_value = mock_queryset
sitemap = OrganizationSitemap()

assert list(sitemap.items()) == [mock_obj]
Expand Down
7 changes: 2 additions & 5 deletions backend/tests/apps/sitemap/views/repository_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,10 @@ def test_inherits_from_base(self):

@patch("apps.sitemap.views.repository.Repository")
def test_items(self, mock_repository):
mock_queryset = MagicMock()
mock_queryset.order_by.return_value = mock_queryset

mock_obj = MagicMock(is_indexable=True)
mock_queryset = MagicMock()
mock_queryset.__iter__ = lambda _: iter([mock_obj])

mock_repository.objects.filter.return_value = mock_queryset
mock_repository.objects.order_by.return_value = mock_queryset

sitemap = RepositorySitemap()

Expand Down