diff --git a/app/core/admin.py b/app/core/admin.py index 8a06d8b9..4f46d1a1 100644 --- a/app/core/admin.py +++ b/app/core/admin.py @@ -18,8 +18,8 @@ from .models import Project from .models import Sdg from .models import Skill +from .models import StackElement from .models import StackElementType -from .models import Technology from .models import User @@ -194,8 +194,8 @@ class SkillAdmin(admin.ModelAdmin): list_filter = ("name",) -@admin.register(Technology) -class TechnologyAdmin(admin.ModelAdmin): +@admin.register(StackElement) +class StackElementAdmin(admin.ModelAdmin): list_display = ( "name", "description", diff --git a/app/core/api/serializers.py b/app/core/api/serializers.py index 480a9679..35376bd3 100644 --- a/app/core/api/serializers.py +++ b/app/core/api/serializers.py @@ -14,8 +14,8 @@ from core.models import Project from core.models import Sdg from core.models import Skill +from core.models import StackElement from core.models import StackElementType -from core.models import Technology from core.models import User @@ -228,11 +228,11 @@ class Meta: ) -class TechnologySerializer(serializers.ModelSerializer): - """Used to retrieve technology info""" +class StackElementSerializer(serializers.ModelSerializer): + """Used to retrieve stack element info""" class Meta: - model = Technology + model = StackElement fields = ( "uuid", "name", @@ -240,6 +240,7 @@ class Meta: "url", "logo", "active", + "element_type", ) read_only_fields = ( "uuid", diff --git a/app/core/api/urls.py b/app/core/api/urls.py index 664d397f..6a60e495 100644 --- a/app/core/api/urls.py +++ b/app/core/api/urls.py @@ -15,7 +15,7 @@ from .views import SdgViewSet from .views import SkillViewSet from .views import StackElementTypeViewSet -from .views import TechnologyViewSet +from .views import StackElementViewSet from .views import UserProfileAPIView from .views import UserViewSet @@ -30,7 +30,7 @@ router.register(r"locations", LocationViewSet, basename="location") router.register(r"program-areas", ProgramAreaViewSet, basename="program-area") router.register(r"skills", SkillViewSet, basename="skill") -router.register(r"technologies", TechnologyViewSet, basename="technology") +router.register(r"stack-elements", StackElementViewSet, basename="stack-element") router.register(r"permission-types", PermissionTypeViewSet, basename="permission-type") router.register( r"stack-element-types", StackElementTypeViewSet, basename="stack-element-type" diff --git a/app/core/api/views.py b/app/core/api/views.py index f932a051..573877a0 100644 --- a/app/core/api/views.py +++ b/app/core/api/views.py @@ -24,8 +24,8 @@ from ..models import Project from ..models import Sdg from ..models import Skill +from ..models import StackElement from ..models import StackElementType -from ..models import Technology from .serializers import AffiliateSerializer from .serializers import AffiliationSerializer from .serializers import CheckTypeSerializer @@ -39,8 +39,8 @@ from .serializers import ProjectSerializer from .serializers import SdgSerializer from .serializers import SkillSerializer +from .serializers import StackElementSerializer from .serializers import StackElementTypeSerializer -from .serializers import TechnologySerializer from .serializers import UserSerializer @@ -265,17 +265,17 @@ class SkillViewSet(viewsets.ModelViewSet): @extend_schema_view( - list=extend_schema(description="Return a list of all the technologies"), - create=extend_schema(description="Create a new technology"), - retrieve=extend_schema(description="Return the details of a technology"), - destroy=extend_schema(description="Delete a technology"), - update=extend_schema(description="Update a technology"), - partial_update=extend_schema(description="Patch a technology"), + list=extend_schema(description="Return a list of all the stack elements"), + create=extend_schema(description="Create a new stack element"), + retrieve=extend_schema(description="Return the details of a stack element"), + destroy=extend_schema(description="Delete a stack element"), + update=extend_schema(description="Update a stack element"), + partial_update=extend_schema(description="Patch a stack element"), ) -class TechnologyViewSet(viewsets.ModelViewSet): +class StackElementViewSet(viewsets.ModelViewSet): permission_classes = [IsAuthenticated] - queryset = Technology.objects.all() - serializer_class = TechnologySerializer + queryset = StackElement.objects.all() + serializer_class = StackElementSerializer @extend_schema_view( diff --git a/app/core/migrations/0025_stackelement_delete_technology.py b/app/core/migrations/0025_stackelement_delete_technology.py new file mode 100644 index 00000000..f6388d93 --- /dev/null +++ b/app/core/migrations/0025_stackelement_delete_technology.py @@ -0,0 +1,56 @@ +# Generated by Django 4.2.11 on 2024-09-06 21:30 + +from django.db import migrations, models +import django.db.models.deletion +import uuid + + +class Migration(migrations.Migration): + + dependencies = [ + ("core", "0024_checktype"), + ] + + operations = [ + migrations.CreateModel( + name="StackElement", + fields=[ + ( + "uuid", + models.UUIDField( + default=uuid.uuid4, + editable=False, + primary_key=True, + serialize=False, + unique=True, + ), + ), + ( + "created_at", + models.DateTimeField(auto_now_add=True, verbose_name="Created at"), + ), + ( + "updated_at", + models.DateTimeField(auto_now=True, verbose_name="Updated at"), + ), + ("name", models.CharField(max_length=255)), + ("description", models.TextField(blank=True)), + ("url", models.URLField(blank=True)), + ("logo", models.URLField(blank=True)), + ("active", models.BooleanField(null=True)), + ( + "element_type", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="core.stackelementtype", + ), + ), + ], + options={ + "verbose_name_plural": "Stack Elements", + }, + ), + migrations.DeleteModel( + name="Technology", + ), + ] diff --git a/app/core/migrations/max_migration.txt b/app/core/migrations/max_migration.txt index 0e1e2cb3..1ab13a42 100644 --- a/app/core/migrations/max_migration.txt +++ b/app/core/migrations/max_migration.txt @@ -1 +1 @@ -0024_checktype +0025_stackelement_delete_technology diff --git a/app/core/models.py b/app/core/models.py index 77f8c00c..3ef5962a 100644 --- a/app/core/models.py +++ b/app/core/models.py @@ -276,26 +276,6 @@ def __str__(self): return f"{self.name}" -class Technology(AbstractBaseModel): - """ - Dictionary of technologies used in projects - """ - - name = models.CharField(max_length=255) - description = models.TextField(blank=True) - url = models.URLField(blank=True) - logo = models.URLField(blank=True) - active = models.BooleanField(null=True) - - # PK of this model is the ForeignKey for project_partner_xref - - class Meta: - verbose_name_plural = "Technologies" - - def __str__(self): - return f"{self.name}" - - class PermissionType(AbstractBaseModel): """ Permission Type @@ -325,6 +305,28 @@ def __str__(self): return f"{self.name}" +class StackElement(AbstractBaseModel): + """ + Dictionary of stack elements used in projects + """ + + name = models.CharField(max_length=255) + description = models.TextField(blank=True) + url = models.URLField(blank=True) + logo = models.URLField(blank=True) + active = models.BooleanField(null=True) + element_type = models.ForeignKey(StackElementType, on_delete=models.CASCADE) + + # PK of this model is the ForeignKey for project_stack_element_xref + # we might be able to use the builtin django many-to-many relation that manages the xref table automatically + + class Meta: + verbose_name_plural = "Stack Elements" + + def __str__(self): + return f"{self.name}" + + class Sdg(AbstractBaseModel): """ Dictionary of SDGs diff --git a/app/core/tests/conftest.py b/app/core/tests/conftest.py index ef942c8a..4ceb4b03 100644 --- a/app/core/tests/conftest.py +++ b/app/core/tests/conftest.py @@ -14,8 +14,8 @@ from ..models import Project from ..models import Sdg from ..models import Skill +from ..models import StackElement from ..models import StackElementType -from ..models import Technology @pytest.fixture @@ -145,8 +145,10 @@ def skill(): @pytest.fixture -def technology(): - return Technology.objects.create(name="Test Technology") +def stack_element(stack_element_type): + return StackElement.objects.create( + name="Test Stack Element", element_type=stack_element_type + ) @pytest.fixture diff --git a/app/core/tests/test_api.py b/app/core/tests/test_api.py index d5f02700..b3f729bf 100644 --- a/app/core/tests/test_api.py +++ b/app/core/tests/test_api.py @@ -18,7 +18,7 @@ LOCATION_URL = reverse("location-list") PROGRAM_AREA_URL = reverse("program-area-list") SKILL_URL = reverse("skill-list") -TECHNOLOGY_URL = reverse("technology-list") +STACK_ELEMENT_URL = reverse("stack-element-list") PERMISSION_TYPE = reverse("permission-type-list") STACK_ELEMENT_TYPE_URL = reverse("stack-element-type-list") SDG_URL = reverse("sdg-list") @@ -291,15 +291,16 @@ def test_create_skill(auth_client): assert res.data["name"] == payload["name"] -def test_create_technology(auth_client): +def test_create_stack_element(auth_client, stack_element_type): payload = { - "name": "Test Technology", - "description": "Technology description", + "name": "Test StackElement", + "description": "StackElement description", "url": "http://www.testurl.org", "logo": "http://www.logourl.com", "active": True, + "element_type": stack_element_type.pk, } - res = auth_client.post(TECHNOLOGY_URL, payload) + res = auth_client.post(STACK_ELEMENT_URL, payload) assert res.status_code == status.HTTP_201_CREATED assert res.data["name"] == payload["name"] diff --git a/app/core/tests/test_models.py b/app/core/tests/test_models.py index 0d8e780e..c0ffaab7 100644 --- a/app/core/tests/test_models.py +++ b/app/core/tests/test_models.py @@ -58,8 +58,8 @@ def test_skill(skill): assert str(skill) == "Test Skill" -def test_technology(technology): - assert str(technology) == "Test Technology" +def test_stack_element(stack_element): + assert str(stack_element) == "Test Stack Element" def test_permission_type1(permission_type1):