Skip to content

Commit c613e5a

Browse files
committed
Add DynamicHTML options and endpoints for Cyberstorm
1 parent 4c9d27c commit c613e5a

File tree

6 files changed

+211
-0
lines changed

6 files changed

+211
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import pytest
2+
from rest_framework.test import APIClient
3+
4+
from thunderstore.frontend.models import DynamicHTML, DynamicPlacement
5+
6+
7+
@pytest.mark.django_db
8+
def test_get_dynamic_html__returns_not_found__when_no_active(
9+
api_client: APIClient,
10+
) -> None:
11+
DynamicHTML.objects.create(
12+
name="dynamic_placement_1",
13+
placement=DynamicPlacement.cyberstorm_header,
14+
content="<title>DYNAMIC HTML TITLE</title>",
15+
ordering=0,
16+
is_active=False,
17+
)
18+
DynamicHTML.objects.create(
19+
name="dynamic_placement_2",
20+
placement=DynamicPlacement.cyberstorm_header,
21+
content='<script>console.log("DYNAMIC HTML SCRIPT")</script>',
22+
ordering=1,
23+
is_active=False,
24+
)
25+
26+
response = api_client.get(
27+
f"/api/cyberstorm/dynamichtml/{DynamicPlacement.cyberstorm_header}/",
28+
)
29+
actual = response.json()
30+
31+
print(actual)
32+
assert actual["detail"] == "Not found."
33+
34+
35+
@pytest.mark.django_db
36+
def test_get_dynamic_html__returns_not_found__when_bad_placement_arg(
37+
api_client: APIClient,
38+
) -> None:
39+
DynamicHTML.objects.create(
40+
name="dynamic_placement_1",
41+
placement=DynamicPlacement.cyberstorm_header,
42+
content="<title>DYNAMIC HTML TITLE</title>",
43+
ordering=0,
44+
)
45+
46+
response = api_client.get(
47+
f"/api/cyberstorm/dynamichtml/{DynamicPlacement.cyberstorm_header + 'bad'}/",
48+
)
49+
actual = response.json()
50+
51+
assert actual["detail"] == "Not found."
52+
53+
54+
@pytest.mark.django_db
55+
def test_get_dynamic_html__returns_not_found__when_placement_arg_doesnt_start_with_cyberstorm(
56+
api_client: APIClient,
57+
) -> None:
58+
DynamicHTML.objects.create(
59+
name="dynamic_placement_1",
60+
placement=DynamicPlacement.cyberstorm_header,
61+
content="<title>DYNAMIC HTML TITLE</title>",
62+
ordering=0,
63+
)
64+
65+
response = api_client.get(
66+
f"/api/cyberstorm/dynamichtml/{DynamicPlacement.cyberstorm_header[len('cyberstorm_'):]}/",
67+
)
68+
actual = response.json()
69+
70+
assert actual["detail"] == "Not found."
71+
72+
73+
@pytest.mark.django_db
74+
def test_get_dynamic_html__returns_correct_object__when_multiple(
75+
api_client: APIClient,
76+
) -> None:
77+
DynamicHTML.objects.create(
78+
name="dynamic_placement_1",
79+
placement=DynamicPlacement.cyberstorm_header,
80+
content="<title>DYNAMIC HTML TITLE</title>",
81+
ordering=0,
82+
is_active=False,
83+
)
84+
DynamicHTML.objects.create(
85+
name="dynamic_placement_2",
86+
placement=DynamicPlacement.cyberstorm_header,
87+
content='<script>console.log("DYNAMIC HTML SCRIPT")</script>',
88+
ordering=1,
89+
)
90+
91+
response = api_client.get(
92+
f"/api/cyberstorm/dynamichtml/{DynamicPlacement.cyberstorm_header}/",
93+
)
94+
actual = response.json()
95+
96+
assert (
97+
actual["dynamic_htmls"][0]
98+
== "\\u003Cscript\\u003Econsole.log(\\u0022DYNAMIC HTML SCRIPT\\u0022)\\u003C/script\\u003E"
99+
)
100+
101+
102+
@pytest.mark.django_db
103+
def test_get_dynamic_html__returns_multiple(api_client: APIClient) -> None:
104+
DynamicHTML.objects.create(
105+
name="dynamic_placement_1",
106+
placement=DynamicPlacement.cyberstorm_header,
107+
content="<title>DYNAMIC HTML TITLE</title>",
108+
ordering=1,
109+
)
110+
DynamicHTML.objects.create(
111+
name="dynamic_placement_2",
112+
placement=DynamicPlacement.cyberstorm_header,
113+
content='<script>console.log("DYNAMIC HTML SCRIPT")</script>',
114+
ordering=0,
115+
)
116+
117+
response = api_client.get(
118+
f"/api/cyberstorm/dynamichtml/{DynamicPlacement.cyberstorm_header}/",
119+
)
120+
actual = response.json()
121+
122+
assert (
123+
actual["dynamic_htmls"][0]
124+
== "\\u003Cscript\\u003Econsole.log(\\u0022DYNAMIC HTML SCRIPT\\u0022)\\u003C/script\\u003E"
125+
)
126+
assert (
127+
actual["dynamic_htmls"][1]
128+
== "\\u003Ctitle\\u003EDYNAMIC HTML TITLE\\u003C/title\\u003E"
129+
)

django/thunderstore/api/cyberstorm/views/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from .community import CommunityAPIView
22
from .community_filters import CommunityFiltersAPIView
33
from .community_list import CommunityListAPIView
4+
from .dynamic_html import DynamicHTMLAPIView
45
from .markdown import PackageVersionChangelogAPIView, PackageVersionReadmeAPIView
56
from .package_listing import PackageListingAPIView
67
from .package_listing_list import (
@@ -31,4 +32,5 @@
3132
"TeamMemberAddAPIView",
3233
"TeamMemberListAPIView",
3334
"TeamServiceAccountListAPIView",
35+
"DynamicHTMLAPIView",
3436
]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
from django.http import Http404
2+
from django.utils.html import escapejs
3+
from rest_framework import serializers
4+
from rest_framework.generics import RetrieveAPIView
5+
6+
from thunderstore.api.utils import CyberstormAutoSchemaMixin
7+
from thunderstore.frontend.models import DynamicHTML, DynamicPlacement
8+
9+
10+
class CyberstormDynamicHTMLResponseSerializer(serializers.Serializer):
11+
dynamic_htmls = serializers.ListField(child=serializers.CharField())
12+
13+
14+
class DynamicHTMLAPIView(CyberstormAutoSchemaMixin, RetrieveAPIView):
15+
"""
16+
Return Cyberstorm dynamic html placement contents as prerendered HTML.
17+
"""
18+
19+
serializer_class = CyberstormDynamicHTMLResponseSerializer
20+
21+
def get_object(self):
22+
if (
23+
self.kwargs["placement"].startswith("cyberstorm_")
24+
and self.kwargs["placement"] in DynamicPlacement.options()
25+
):
26+
dynamic_htmls = DynamicHTML.objects.filter(
27+
placement=self.kwargs["placement"],
28+
is_active=True,
29+
).order_by("ordering")
30+
if len(dynamic_htmls) != 0:
31+
return {"dynamic_htmls": [escapejs(dh.content) for dh in dynamic_htmls]}
32+
raise Http404

django/thunderstore/api/urls.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
CommunityAPIView,
55
CommunityFiltersAPIView,
66
CommunityListAPIView,
7+
DynamicHTMLAPIView,
78
PackageListingAPIView,
89
PackageListingByCommunityListAPIView,
910
PackageListingByDependencyListAPIView,
@@ -18,6 +19,11 @@
1819
)
1920

2021
cyberstorm_urls = [
22+
path(
23+
"dynamichtml/<str:placement>/",
24+
DynamicHTMLAPIView.as_view(),
25+
name="cyberstorm.dynamichtml",
26+
),
2127
path(
2228
"community/",
2329
CommunityListAPIView.as_view(),
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Generated by Django 3.1.7 on 2024-05-23 17:11
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
("frontend", "0012_add_footer_links"),
10+
]
11+
12+
operations = [
13+
migrations.AlterField(
14+
model_name="dynamichtml",
15+
name="placement",
16+
field=models.CharField(
17+
choices=[
18+
("ads_txt", "ads_txt"),
19+
("robots_txt", "robots_txt"),
20+
("html_head", "html_head"),
21+
("html_body_beginning", "html_body_beginning"),
22+
("content_beginning", "content_beginning"),
23+
("footer_top", "footer_top"),
24+
("footer_bottom", "footer_bottom"),
25+
("content_end", "content_end"),
26+
("package_page_actions", "package_page_actions"),
27+
("main_content_left", "main_content_left"),
28+
("main_content_right", "main_content_right"),
29+
("cyberstorm_header", "cyberstorm_header"),
30+
("cyberstorm_body_beginning", "cyberstorm_body_beginning"),
31+
("cyberstorm_content_left", "cyberstorm_content_left"),
32+
("cyberstorm_content_right", "cyberstorm_content_right"),
33+
],
34+
db_index=True,
35+
max_length=256,
36+
),
37+
),
38+
]

django/thunderstore/frontend/models.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ class DynamicPlacement(ChoiceEnum):
2222
package_page_actions = "package_page_actions"
2323
main_content_left = "main_content_left"
2424
main_content_right = "main_content_right"
25+
cyberstorm_header = "cyberstorm_header"
26+
cyberstorm_body_beginning = "cyberstorm_body_beginning"
27+
cyberstorm_content_left = "cyberstorm_content_left"
28+
cyberstorm_content_right = "cyberstorm_content_right"
2529

2630

2731
class DynamicHTML(models.Model):

0 commit comments

Comments
 (0)