diff --git a/kerckhoff/packages/models.py b/kerckhoff/packages/models.py index fc7d78e..3b1cdbf 100644 --- a/kerckhoff/packages/models.py +++ b/kerckhoff/packages/models.py @@ -194,7 +194,6 @@ def create_version( updated_package_item_titles: List[str], ): """Creates new PackageVersion object - Arguments: user {User} -- User object, required argument package_version {PackageVersion} -- the package version to be added @@ -300,4 +299,4 @@ def create_from_google_drive_item( mime_type=google_drive_file.mimeType, ) pi.save() - return pi + return pi \ No newline at end of file diff --git a/kerckhoff/packages/serializers.py b/kerckhoff/packages/serializers.py index b1c9d1b..9f9ac7a 100644 --- a/kerckhoff/packages/serializers.py +++ b/kerckhoff/packages/serializers.py @@ -1,3 +1,5 @@ +import os +from dataclasses import field from rest_framework import serializers from rest_framework.validators import UniqueTogetherValidator @@ -172,3 +174,67 @@ def get_version_data(self, obj: Package): class Meta(PackageSerializer.Meta): fields = PackageSerializer.Meta.fields + ("version_data",) read_only_fields = PackageSerializer.Meta.read_only_fields + ("version_data",) + +class PublicPackageSerializer(serializers.ModelSerializer): + package_set = serializers.StringRelatedField() + latest_version = serializers.StringRelatedField() + description = serializers.SerializerMethodField() + + data = serializers.SerializerMethodField() + cached_article_preview = serializers.SerializerMethodField() + + def get_description(self, obj: Package): + + obj.fetch_cache() + if not obj.latest_version: + return "Has Not Created A Version Yet" + versionSerializer = PackageVersionSerializer(obj.get_version(obj.latest_version.id_num)) + return versionSerializer.data["version_description"] + + def get_data(self, obj: Package): + obj.fetch_cache() + if not obj.latest_version: + return "Has Not Created A Version Yet" + package_items = obj.get_version(obj.latest_version.id_num).packageitem_set.all() + for file in package_items: + file_ext = os.path.splitext(file.file_name)[-1] + if(file.file_name == "article.aml"): + aml_data = file.data["content_rich"]["data"] + return {"article": aml_data} + + def get_cached_article_preview(self, obj: Package): + obj.fetch_cache() + cached = obj.cached + for item in cached: + if(item["title"] == "article.aml"): + cached_article_preview = item["content_plain"]["raw"] + return cached_article_preview + + + class Meta: + model = Package + fields = ( + "slug", + "description", + "metadata", + "data", + "cached_article_preview", + "last_fetched_date", + "package_set", + "latest_version", + + ) + read_only_fields = ( + "description", + "metadata", + "data", + "cached_article_preview", + "last_fetched_date", + "package_set", + "latest_version", + ) + validators = [ + UniqueTogetherValidator( + queryset=Package.objects.all(), fields=("slug", "package_set") + ) + ] \ No newline at end of file diff --git a/kerckhoff/packages/views.py b/kerckhoff/packages/views.py index 20869a0..479d8c4 100644 --- a/kerckhoff/packages/views.py +++ b/kerckhoff/packages/views.py @@ -1,5 +1,11 @@ +from multiprocessing import log_to_stderr +import os +from typing import List +import os +import json +from importlib_metadata import packages_distributions from rest_framework import mixins, viewsets, filters -from rest_framework.permissions import IsAuthenticated +from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly from rest_framework.decorators import action from rest_framework.serializers import Serializer from rest_framework.response import Response @@ -7,7 +13,7 @@ from kerckhoff.integrations.serializers import IntegrationSerializer from .tasks import sync_gdrive_task -from .models import PackageSet, Package +from .models import PackageSet, Package, PackageVersion, PackageItem from .serializers import ( PackageSetSerializer, PackageSerializer, @@ -15,6 +21,8 @@ PackageVersionSerializer, CreatePackageVersionSerializer, PackageSetDetailedSerializer, + PackageItemSerializer, + PackageInfoSerializer ) @@ -80,7 +88,7 @@ class PackageViewSet( ): """ Updates and retrieves packages - """ + """ def get_queryset(self): return Package.objects.filter(package_set__slug=self.kwargs["package_set_slug"]) @@ -128,6 +136,22 @@ def retrieve(self, request, **kwargs): ) response = serializer.data return Response(response) + + @action(methods=["get"], detail=True, serializer_class=Serializer, + url_path='version/(?P[^/.]+)') + def version(self, request, **kwargs): + package_items = self.get_object().get_version(kwargs['ver']).packageitem_set.all() + img_urls = {} + supported_image_types = [".jpg", ".jpeg", ".png"] + for file in package_items: + file_ext = os.path.splitext(file.file_name)[-1] + if(file.file_name == "article.aml"): + aml_data = file.data["content_rich"]["data"] + if(file_ext in supported_image_types): + # Don't worry about images for now + img_urls[file.file_name] = file.data["src_large"] + return Response({"data": aml_data, "images": img_urls} ) + class PackageCreateAndListViewSet( @@ -150,3 +174,33 @@ def perform_create(self, serializer): lookup_value_regex = slug_with_dots filter_backends = (filters.OrderingFilter,) ordering_fields = ("slug", "last_fetched_date", "created_at", "updated_at") + + + +# Public Package View set for External site Kerckhoff API + +# mixins.ListModelMixin list out all packages in package set +# mixins.RetrieveModelMixin retrieves specific/individual package within the package set +class PublicPackageViewSet(viewsets.GenericViewSet, mixins.ListModelMixin, mixins.RetrieveModelMixin): + """ + List and retrieve packages for external site + """ + + # Retrieve only the packages from the package set that has the same name/ slug as the defined package set name/slug in the url + def get_queryset(self): + # return package_set + return Package.objects.filter(package_set__slug=self.kwargs["package_set_slug"]) + + + serializer_class = PackageInfoSerializer + permission_classes = (IsAuthenticatedOrReadOnly,) + # set slug as the lookup field so that we look up for packages in the package set with the same slug + lookup_field = "slug" + # verifies if the url slug is a valid slug and matches our valid slug format defined at the top of this file + lookup_value_regex = slug_with_dots + + + + + + diff --git a/kerckhoff/urls.py b/kerckhoff/urls.py index d1aa887..b93cf2a 100755 --- a/kerckhoff/urls.py +++ b/kerckhoff/urls.py @@ -18,6 +18,7 @@ PackageSetCreateAndListViewSet, PackageViewSet, PackageCreateAndListViewSet, + PublicPackageViewSet ) from .comments.views import CommentViewSet from .integrations.views import IntegrationOAuthView @@ -28,16 +29,47 @@ router.register(r"package-sets", PackageSetViewSet) router.register(r"package-sets", PackageSetCreateAndListViewSet) -package_set_router = NestedSimpleRouter(router, r"package-sets", lookup="package_set") +# API Router for Public External Site +public_package_set_router = NestedSimpleRouter( + router, + r"package-sets", + lookup="package_set") + +public_package_set_router.register( + r"packages", + PublicPackageViewSet, + base_name="public-package" +) + + + +# To Internal Kerckhoff Frontend Site +package_set_router = NestedSimpleRouter( + router, + r"package-sets", + lookup="package_set") + package_set_router.register( - r"packages", PackageViewSet, base_name="package-sets_packages" + r"packages", + PackageViewSet, + base_name="package-generate_packages" ) + package_set_router.register( - r"packages", PackageCreateAndListViewSet, base_name="package-sets_packages" + r"packages", + PackageCreateAndListViewSet, + base_name="package-sets_packages" ) -package_router = NestedSimpleRouter(package_set_router, r"packages", lookup="package") -package_router.register(r"comments", CommentViewSet, base_name="comments") +package_router = NestedSimpleRouter( + package_set_router, + r"packages", + lookup="package") + +package_router.register( + r"comments", + CommentViewSet, + base_name="comments") schema_view = get_schema_view( openapi.Info( @@ -73,6 +105,9 @@ path("api/v1/", include(router.urls)), path("api/v1/", include(package_set_router.urls)), path("api/v1/", include(package_router.urls)), + # path for external site api + path("api/v1/public/",include(public_package_set_router.urls)), + path("api/v1/integrations/", IntegrationOAuthView.as_view()), path("api-oauth/", include(auth_urlpatterns)), path("api-token-auth/", views.obtain_auth_token),