Skip to content

Commit 11bcc07

Browse files
committed
Add CS Package Listing Edit Categories form and view
1 parent 896d7f5 commit 11bcc07

File tree

8 files changed

+682
-4
lines changed

8 files changed

+682
-4
lines changed

django/conftest.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from copy import copy, deepcopy
55
from http.server import BaseHTTPRequestHandler
66
from http.server import HTTPServer as SuperHTTPServer
7-
from typing import Any
7+
from typing import Any, List
88
from zipfile import ZIP_DEFLATED, ZipFile
99

1010
import pytest
@@ -276,6 +276,18 @@ def package_category(community):
276276
)
277277

278278

279+
@pytest.fixture()
280+
def package_categories(community) -> List[PackageCategory]:
281+
return [
282+
PackageCategory.objects.create(community=community, slug=slug, name=name)
283+
for slug, name in [
284+
("cat-1", "Category One"),
285+
("cat-2", "Category Two"),
286+
("cat-3", "Category Three"),
287+
]
288+
]
289+
290+
279291
@pytest.fixture()
280292
def package_listing_section(community):
281293
return PackageListingSection.objects.create(

django/thunderstore/api/cyberstorm/tests/test_package_listing.py

+271-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
import json
12
from datetime import datetime
2-
from typing import Optional
3+
from typing import List, Optional
34

45
import pytest
56
from rest_framework.test import APIClient
@@ -13,11 +14,14 @@
1314
PackageCategoryFactory,
1415
PackageListingFactory,
1516
)
17+
from thunderstore.community.models.package_category import PackageCategory
18+
from thunderstore.community.models.package_listing import PackageListing
1619
from thunderstore.repository.factories import (
1720
PackageRatingFactory,
1821
PackageVersionFactory,
1922
TeamMemberFactory,
2023
)
24+
from thunderstore.repository.models.team import TeamMember
2125

2226

2327
@pytest.mark.django_db
@@ -332,5 +336,271 @@ def test_dependency_serializer__when_dependency_is_not_active__censors_icon_and_
332336
assert actual["icon_url"] is None
333337

334338

339+
@pytest.mark.django_db
340+
def test_package_listing_edit_categories_view__returns_error_for_non_existent_package_listing(
341+
api_client: APIClient,
342+
team_member: TeamMember,
343+
active_package_listing: PackageListing,
344+
package_categories: List[PackageCategory],
345+
) -> None:
346+
active_package_listing.categories.set(package_categories)
347+
active_package_listing.save()
348+
apl_categories = active_package_listing.categories.all()
349+
assert len(apl_categories) == 3
350+
351+
api_client.force_authenticate(team_member.user)
352+
response = api_client.post(
353+
f"/api/cyberstorm/listing/BAD/{active_package_listing.package.namespace.name}/{active_package_listing.package.name}/edit/categories/",
354+
json.dumps(
355+
{
356+
"current_categories": [x.slug for x in apl_categories],
357+
"new_categories": [
358+
x.slug for x in [apl_categories[0], apl_categories[1]]
359+
],
360+
}
361+
),
362+
content_type="application/json",
363+
)
364+
actual = response.json()
365+
366+
assert actual["detail"] == "Not found."
367+
assert (
368+
len(
369+
set(apl_categories).symmetric_difference(
370+
PackageListing.objects.get(
371+
pk=active_package_listing.pk
372+
).categories.all()
373+
)
374+
)
375+
== 0
376+
)
377+
378+
response = api_client.post(
379+
f"/api/cyberstorm/listing/{active_package_listing.community.identifier}/BAD/{active_package_listing.package.name}/edit/categories/",
380+
json.dumps(
381+
{
382+
"current_categories": [x.slug for x in apl_categories],
383+
"new_categories": [
384+
x.slug for x in [apl_categories[0], apl_categories[1]]
385+
],
386+
}
387+
),
388+
content_type="application/json",
389+
)
390+
actual = response.json()
391+
392+
assert actual["detail"] == "Not found."
393+
assert (
394+
len(
395+
set(apl_categories).symmetric_difference(
396+
PackageListing.objects.get(
397+
pk=active_package_listing.pk
398+
).categories.all()
399+
)
400+
)
401+
== 0
402+
)
403+
404+
response = api_client.post(
405+
f"/api/cyberstorm/listing/{active_package_listing.community.identifier}/{active_package_listing.package.namespace.name}/BAD/edit/categories/",
406+
json.dumps(
407+
{
408+
"current_categories": [x.slug for x in apl_categories],
409+
"new_categories": [
410+
x.slug for x in [apl_categories[0], apl_categories[1]]
411+
],
412+
}
413+
),
414+
content_type="application/json",
415+
)
416+
actual = response.json()
417+
418+
assert actual["detail"] == "Not found."
419+
assert (
420+
len(
421+
set(apl_categories).symmetric_difference(
422+
PackageListing.objects.get(
423+
pk=active_package_listing.pk
424+
).categories.all()
425+
)
426+
)
427+
== 0
428+
)
429+
430+
431+
@pytest.mark.django_db
432+
def test_package_listing_edit_categories_view__correct_values__remove_one_category__succeeds(
433+
api_client: APIClient,
434+
team_member: TeamMember,
435+
active_package_listing: PackageListing,
436+
package_categories: List[PackageCategory],
437+
) -> None:
438+
active_package_listing.categories.set(package_categories)
439+
active_package_listing.save()
440+
apl_categories = active_package_listing.categories.all()
441+
assert len(apl_categories) == 3
442+
443+
api_client.force_authenticate(team_member.user)
444+
response = api_client.post(
445+
f"/api/cyberstorm/listing/{active_package_listing.community.identifier}/{active_package_listing.package.namespace.name}/{active_package_listing.package.name}/edit/categories/",
446+
json.dumps(
447+
{
448+
"current_categories": [x.slug for x in apl_categories],
449+
"new_categories": [
450+
x.slug for x in [apl_categories[0], apl_categories[1]]
451+
],
452+
}
453+
),
454+
content_type="application/json",
455+
)
456+
actual = response.json()
457+
458+
assert actual["categories"] == [
459+
{"id": str(x.id), "name": x.name, "slug": x.slug}
460+
for x in [apl_categories[0], apl_categories[1]]
461+
]
462+
463+
464+
@pytest.mark.django_db
465+
def test_package_listing_edit_categories_view__correct_values__no_user__fails(
466+
api_client: APIClient,
467+
active_package_listing: PackageListing,
468+
package_categories: List[PackageCategory],
469+
) -> None:
470+
active_package_listing.categories.set(package_categories)
471+
active_package_listing.save()
472+
apl_categories = active_package_listing.categories.all()
473+
assert len(apl_categories) == 3
474+
475+
response = api_client.post(
476+
f"/api/cyberstorm/listing/{active_package_listing.community.identifier}/{active_package_listing.package.namespace.name}/{active_package_listing.package.name}/edit/categories/",
477+
json.dumps(
478+
{
479+
"current_categories": [x.slug for x in apl_categories],
480+
"new_categories": [
481+
x.slug for x in [apl_categories[0], apl_categories[1]]
482+
],
483+
}
484+
),
485+
content_type="application/json",
486+
)
487+
actual = response.json()
488+
489+
assert actual["detail"] == "Authentication credentials were not provided."
490+
491+
492+
@pytest.mark.django_db
493+
def test_package_listing_edit_categories_view__wrong_current_categories__fails(
494+
api_client: APIClient,
495+
team_member: TeamMember,
496+
active_package_listing: PackageListing,
497+
package_categories: List[PackageCategory],
498+
) -> None:
499+
active_package_listing.categories.set(package_categories)
500+
active_package_listing.save()
501+
apl_categories = active_package_listing.categories.all()
502+
assert len(apl_categories) == 3
503+
504+
api_client.force_authenticate(team_member.user)
505+
response = api_client.post(
506+
f"/api/cyberstorm/listing/{active_package_listing.community.identifier}/{active_package_listing.package.namespace.name}/{active_package_listing.package.name}/edit/categories/",
507+
json.dumps(
508+
{"current_categories": [apl_categories[0].slug], "new_categories": []}
509+
),
510+
content_type="application/json",
511+
)
512+
actual = response.json()
513+
514+
assert actual["__all__"] == [
515+
"Listings current categories do not match provided ones"
516+
]
517+
assert (
518+
len(
519+
set(apl_categories).symmetric_difference(
520+
PackageListing.objects.get(
521+
pk=active_package_listing.pk
522+
).categories.all()
523+
)
524+
)
525+
== 0
526+
)
527+
528+
529+
@pytest.mark.django_db
530+
def test_package_listing_edit_categories_view__correct_values__remove_all_categories__succeeds(
531+
api_client: APIClient,
532+
team_member: TeamMember,
533+
active_package_listing: PackageListing,
534+
package_categories: List[PackageCategory],
535+
) -> None:
536+
active_package_listing.categories.set(package_categories)
537+
active_package_listing.save()
538+
apl_categories = active_package_listing.categories.all()
539+
assert len(apl_categories) == 3
540+
541+
api_client.force_authenticate(team_member.user)
542+
response = api_client.post(
543+
f"/api/cyberstorm/listing/{active_package_listing.community.identifier}/{active_package_listing.package.namespace.name}/{active_package_listing.package.name}/edit/categories/",
544+
json.dumps(
545+
{
546+
"current_categories": [x.slug for x in apl_categories],
547+
"new_categories": [],
548+
}
549+
),
550+
content_type="application/json",
551+
)
552+
actual = response.json()
553+
554+
assert len(actual["categories"]) == 0
555+
556+
557+
@pytest.mark.django_db
558+
def test_package_listing_edit_categories_view__bad_values__fails(
559+
api_client: APIClient,
560+
team_member: TeamMember,
561+
active_package_listing: PackageListing,
562+
package_categories: List[PackageCategory],
563+
) -> None:
564+
active_package_listing.categories.set(package_categories)
565+
active_package_listing.save()
566+
apl_categories = active_package_listing.categories.all()
567+
assert len(apl_categories) == 3
568+
569+
api_client.force_authenticate(team_member.user)
570+
response = api_client.post(
571+
f"/api/cyberstorm/listing/{active_package_listing.community.identifier}/{active_package_listing.package.namespace.name}/{active_package_listing.package.name}/edit/categories/",
572+
json.dumps(
573+
{
574+
"current_categories": [x.slug for x in apl_categories],
575+
"new_categories": "bad",
576+
}
577+
),
578+
content_type="application/json",
579+
)
580+
actual = response.json()
581+
582+
assert 'Expected a list of items but got type "str".' in str(
583+
actual["new_categories"]
584+
)
585+
586+
response = api_client.post(
587+
f"/api/cyberstorm/listing/{active_package_listing.community.identifier}/{active_package_listing.package.namespace.name}/{active_package_listing.package.name}/edit/categories/",
588+
json.dumps(
589+
{
590+
"current_categories": "bad",
591+
"new_categories": [
592+
x.slug for x in [apl_categories[0], apl_categories[1]]
593+
],
594+
}
595+
),
596+
content_type="application/json",
597+
)
598+
actual = response.json()
599+
600+
assert 'Expected a list of items but got type "str".' in str(
601+
actual["current_categories"]
602+
)
603+
604+
335605
def _date_to_z(value: datetime) -> str:
336606
return value.strftime("%Y-%m-%dT%H:%M:%S.%fZ")

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

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from .community_list import CommunityListAPIView
44
from .markdown import PackageVersionChangelogAPIView, PackageVersionReadmeAPIView
55
from .package import PackageDeprecateAPIView
6-
from .package_listing import PackageListingAPIView
6+
from .package_listing import PackageListingAPIView, PackageListingEditCategoriesAPIView
77
from .package_listing_list import (
88
PackageListingByCommunityListAPIView,
99
PackageListingByDependencyListAPIView,
@@ -35,4 +35,5 @@
3535
"TeamServiceAccountListAPIView",
3636
"PackageRatingRateAPIView",
3737
"PackageDeprecateAPIView",
38+
"PackageListingEditCategoriesAPIView",
3839
]

0 commit comments

Comments
 (0)