diff --git a/scipost_django/api/urls.py b/scipost_django/api/urls.py index 81669f12db98ac7a553d99bcda9f2babf4bd5355..83fbc8ae39e4c5378970d948762be1b62718a111 100644 --- a/scipost_django/api/urls.py +++ b/scipost_django/api/urls.py @@ -8,12 +8,16 @@ from rest_framework import routers # journals from journals.api.viewsets import ( + PublicationPublicAPIViewSet, PublicationPublicSearchAPIViewSet, PubFractionPublicAPIViewSet, ) # submissions -from submissions.api.viewsets import SubmissionPublicSearchAPIViewSet +from submissions.api.viewsets import ( + SubmissionPublicAPIViewSet, + SubmissionPublicSearchAPIViewSet, +) # organizations from organizations.api.viewsets import ( @@ -39,14 +43,20 @@ app_name = "api" router = routers.SimpleRouter() -# search (Vue) routes +# search (Vue-based) routes router.register("search/publications", PublicationPublicSearchAPIViewSet) router.register("search/submissions", SubmissionPublicSearchAPIViewSet) +############################# +# publicly-accessible routes +############################# + # journals +router.register("publications", PublicationPublicAPIViewSet) router.register("pubfractions", PubFractionPublicAPIViewSet) # submissions +router.register("submissions", SubmissionPublicAPIViewSet) # organizations router.register("organizations", OrganizationPublicAPIViewSet) diff --git a/scipost_django/comments/api/serializers/__init__.py b/scipost_django/comments/api/serializers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..5958284822c67d728958fc5a35a44b5577a7350c --- /dev/null +++ b/scipost_django/comments/api/serializers/__init__.py @@ -0,0 +1,5 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from .comment import CommentPublicSerializer diff --git a/scipost_django/comments/api/serializers/comment.py b/scipost_django/comments/api/serializers/comment.py new file mode 100644 index 0000000000000000000000000000000000000000..79433a8bae97c1cfb3a7b904fae52d892fafc3c7 --- /dev/null +++ b/scipost_django/comments/api/serializers/comment.py @@ -0,0 +1,35 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from rest_framework import serializers + +from ...models import Comment + + +class CommentPublicSerializer(serializers.ModelSerializer): + status = serializers.CharField(source="get_status_display") + author = serializers.SerializerMethodField() + nested_comments = serializers.SerializerMethodField() + url = serializers.URLField(source="get_absolute_url") + + class Meta: + model = Comment + fields = [ + "status", + "author", + "is_author_reply", + "file_attachment", + "date_submitted", + "doi_string", + "citation", + "url", + "nested_comments", + ] + + def get_author(self, obj): + return obj.get_author_str() + + def get_nested_comments(self, obj): + comments = obj.comments.vetted() + return CommentPublicSerializer(comments, many=True, read_only=True).data diff --git a/scipost_django/journals/api/filtersets/__init__.py b/scipost_django/journals/api/filtersets/__init__.py index 2fd7ba0e69d3ca10186b58577888415306d82095..4076babe7d0e0c4e953c14f8e5a74d8ad163f6c4 100644 --- a/scipost_django/journals/api/filtersets/__init__.py +++ b/scipost_django/journals/api/filtersets/__init__.py @@ -2,6 +2,9 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" -from .publication import PublicationPublicSearchAPIFilterSet +from .publication import ( + PublicationPublicAPIFilterSet, + PublicationPublicSearchAPIFilterSet, +) from .pubfraction import PubFractionPublicAPIFilterSet diff --git a/scipost_django/journals/api/filtersets/publication.py b/scipost_django/journals/api/filtersets/publication.py index bf209fb71ead7d76c43102395770c3f0e48d3c17..4fe8d3f38caa8a6056c7a0f53e34073bf66989d4 100644 --- a/scipost_django/journals/api/filtersets/publication.py +++ b/scipost_django/journals/api/filtersets/publication.py @@ -7,6 +7,39 @@ from django_filters import rest_framework as df_filters from ...models import Publication +class PublicationPublicAPIFilterSet(df_filters.FilterSet): + class Meta: + model = Publication + fields = { + "title": ["icontains", "contains", "istartswith", "iregex", "regex"], + "author_list": ["icontains", "contains", "iregex", "regex"], + "abstract": ["icontains", "contains", "iregex", "regex"], + "publication_date": [ + "year", + "month", + "exact", + "year__gte", + "year__lte", + "year__range", + "gte", + "lte", + "range", + ], + "doi_label": [ + "icontains", + ], + "acad_field__name": [ + "icontains", + ], + "specialties__name": [ + "icontains", + ], + "topics__name": [ + "icontains", + ], + } + + class PublicationPublicSearchAPIFilterSet(df_filters.FilterSet): class Meta: model = Publication diff --git a/scipost_django/journals/api/serializers/__init__.py b/scipost_django/journals/api/serializers/__init__.py index 7991aad30aefeb50dffebfecbe44b519ff9def27..b564fb91b86cf50b362554f59538bc07bd2c77d6 100644 --- a/scipost_django/journals/api/serializers/__init__.py +++ b/scipost_django/journals/api/serializers/__init__.py @@ -2,6 +2,9 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" -from .publication import PublicationPublicSearchSerializer +from .publication import ( + PublicationPublicSerializer, + PublicationPublicSearchSerializer, +) from .pubfraction import PubFractionPublicSerializer diff --git a/scipost_django/journals/api/serializers/publication.py b/scipost_django/journals/api/serializers/publication.py index 238c8af021b5f756e3a700883e24485b9e068afd..c202fc5a634af02e8725d012288e3747d1f85884 100644 --- a/scipost_django/journals/api/serializers/publication.py +++ b/scipost_django/journals/api/serializers/publication.py @@ -8,6 +8,26 @@ from api.serializers import DynamicFieldsModelSerializer from ...models import Publication +class PublicationPublicSerializer(DynamicFieldsModelSerializer): + url = serializers.URLField(source="get_absolute_url") + accepted_submission = serializers.SerializerMethodField() + + class Meta: + model = Publication + fields = [ + "url", + "title", + "author_list", + "abstract", + "doi_label", + "publication_date", + "accepted_submission", + ] + + def get_accepted_submission(self, obj): + return obj.accepted_submission.get_absolute_url() + + class PublicationPublicSearchSerializer(DynamicFieldsModelSerializer): url = serializers.URLField(source="get_absolute_url") diff --git a/scipost_django/journals/api/viewsets/__init__.py b/scipost_django/journals/api/viewsets/__init__.py index 80af7492dc4a8b84fc19fd0d145000f5def60bf7..e7344e94a68969446a27740e883702d8f4d48aad 100644 --- a/scipost_django/journals/api/viewsets/__init__.py +++ b/scipost_django/journals/api/viewsets/__init__.py @@ -2,6 +2,9 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" -from .publication import PublicationPublicSearchAPIViewSet +from .publication import ( + PublicationPublicAPIViewSet, + PublicationPublicSearchAPIViewSet, +) from .pubfraction import PubFractionPublicAPIViewSet diff --git a/scipost_django/journals/api/viewsets/publication.py b/scipost_django/journals/api/viewsets/publication.py index f7df91e8ece8f6b72906bc4dde7b121df33b7816..11f53b68bac2da909c31273af8d993a5e55f3cf9 100644 --- a/scipost_django/journals/api/viewsets/publication.py +++ b/scipost_django/journals/api/viewsets/publication.py @@ -11,10 +11,50 @@ from api.viewsets.mixins import FilteringOptionsActionMixin from journals.models import Publication from journals.regexes import PUBLICATION_DOI_LABEL_REGEX -from journals.api.filtersets import PublicationPublicSearchAPIFilterSet -from journals.api.serializers import PublicationPublicSearchSerializer +from journals.api.filtersets import ( + PublicationPublicAPIFilterSet, + PublicationPublicSearchAPIFilterSet, +) +from journals.api.serializers import ( + PublicationPublicSerializer, + PublicationPublicSearchSerializer, +) +class PublicationPublicAPIViewSet( + FilteringOptionsActionMixin, ExtraFilteredReadOnlyModelViewSet +): + queryset = Publication.objects.published() + permission_classes = [ + AllowAny, + ] + serializer_class = PublicationPublicSerializer + lookup_field = "doi_label" + lookup_value_regex = PUBLICATION_DOI_LABEL_REGEX + search_fields = ["title", "author_list", "abstract", "doi_label"] + ordering_fields = [ + "publication_date", + ] + filterset_class = PublicationPublicAPIFilterSet + extra_filters = { + "journal__name": { + "fields": [ + "in_journal__name", + "in_issue__in_journal__name", + "in_issue__in_volume__in_journal__name", + ], + "lookups": ["icontains", "istartswith", "iexact", "exact"], + } + } + default_filtering_fields = [ + "title__icontains", + "author_list__icontains", + "abstract__icontains", + "doi_label__icontains", + ] + + +# For Vue-based search class PublicationPublicSearchAPIViewSet( FilteringOptionsActionMixin, ExtraFilteredReadOnlyModelViewSet ): diff --git a/scipost_django/preprints/api/serializers/__init__.py b/scipost_django/preprints/api/serializers/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..7256c0db45cb9f7ce90cac103db837ce43c029ea --- /dev/null +++ b/scipost_django/preprints/api/serializers/__init__.py @@ -0,0 +1,5 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from .preprint import PreprintPublicSerializer diff --git a/scipost_django/preprints/api/serializers/preprint.py b/scipost_django/preprints/api/serializers/preprint.py new file mode 100644 index 0000000000000000000000000000000000000000..106b817b1198824b0ff336cb39d14f7e4521d58e --- /dev/null +++ b/scipost_django/preprints/api/serializers/preprint.py @@ -0,0 +1,18 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from rest_framework import serializers + +from ...models import Preprint + + +class PreprintPublicSerializer(serializers.ModelSerializer): + url = serializers.URLField(source="get_absolute_url") + + class Meta: + model = Preprint + fields = [ + "identifier_w_vn_nr", + "url", + ] diff --git a/scipost_django/submissions/api/filtersets/__init__.py b/scipost_django/submissions/api/filtersets/__init__.py index b0b80ee43a449337091951f2f33f68612d798851..7103ca96a194eef218712335eb231e6428737c8a 100644 --- a/scipost_django/submissions/api/filtersets/__init__.py +++ b/scipost_django/submissions/api/filtersets/__init__.py @@ -2,4 +2,7 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" -from .submission import SubmissionPublicSearchAPIFilterSet +from .submission import ( + SubmissionPublicAPIFilterSet, + SubmissionPublicSearchAPIFilterSet, +) diff --git a/scipost_django/submissions/api/filtersets/submission.py b/scipost_django/submissions/api/filtersets/submission.py index 12209bd5f92ce910c66f155700a40a945fe44f43..e3410595c9996afe75af79b7bb798ab8331611dd 100644 --- a/scipost_django/submissions/api/filtersets/submission.py +++ b/scipost_django/submissions/api/filtersets/submission.py @@ -7,6 +7,36 @@ from django_filters import rest_framework as df_filters from submissions.models import Submission +class SubmissionPublicAPIFilterSet(df_filters.FilterSet): + class Meta: + model = Submission + fields = { + "title": ["icontains", "contains", "istartswith", "iregex", "regex"], + "author_list": ["icontains", "contains", "iregex", "regex"], + "abstract": ["icontains", "contains", "iregex", "regex"], + "submission_date": [ + "date__year", + "date__month", + "date__exact", + "date__year__gte", + "date__year__lte", + "date__year__range", + "date__gte", + "date__lte", + "date__range", + ], + "acad_field__name": [ + "icontains", + ], + "specialties__name": [ + "icontains", + ], + "topics__name": [ + "icontains", + ], + } + + class SubmissionPublicSearchAPIFilterSet(df_filters.FilterSet): class Meta: model = Submission diff --git a/scipost_django/submissions/api/serializers/__init__.py b/scipost_django/submissions/api/serializers/__init__.py index 12c9478b87e117853dd2393c9db33beb02483753..19f7ff1056ee994fe3556b901e49f80578241418 100644 --- a/scipost_django/submissions/api/serializers/__init__.py +++ b/scipost_django/submissions/api/serializers/__init__.py @@ -2,4 +2,11 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" -from .submission import SubmissionPublicSearchSerializer +from .report import ReportPublicSerializer + +from .submission_event import SubmissionEventPublicSerializer + +from .submission import ( + SubmissionPublicSerializer, + SubmissionPublicSearchSerializer, +) diff --git a/scipost_django/submissions/api/serializers/report.py b/scipost_django/submissions/api/serializers/report.py new file mode 100644 index 0000000000000000000000000000000000000000..11e1c5ee12e1eea6f9c81171792815d03d41aa96 --- /dev/null +++ b/scipost_django/submissions/api/serializers/report.py @@ -0,0 +1,38 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from rest_framework import serializers + +from ...models import Report + +from comments.api.serializers import CommentPublicSerializer + + +class ReportPublicSerializer(serializers.ModelSerializer): + author = serializers.SerializerMethodField() + url = serializers.URLField(source="get_absolute_url") + comments = serializers.SerializerMethodField() + + class Meta: + model = Report + fields = [ + "status", + "report_type", + "report_nr", + "invited", + "author", + "doi_string", + "date_submitted", + "url", + "comments", + ] + + def get_author(self, obj): + if not obj.anonymous: + return str(obj.author) + return "Anonymous" + + def get_comments(self, obj): + comments = obj.comments.vetted() + return CommentPublicSerializer(comments, many=True, read_only=True).data diff --git a/scipost_django/submissions/api/serializers/submission.py b/scipost_django/submissions/api/serializers/submission.py index 41ea65172e6388cacb927a34fff7fafa27000d1b..2413a95ddda8441c497db269b62f62058c003244 100644 --- a/scipost_django/submissions/api/serializers/submission.py +++ b/scipost_django/submissions/api/serializers/submission.py @@ -4,7 +4,81 @@ __license__ = "AGPL v3" from rest_framework import serializers -from submissions.models import Submission +from submissions.models import Submission, Report +from submissions.api.serializers import ( + ReportPublicSerializer, + SubmissionEventPublicSerializer, +) + +from comments.models import Comment +from comments.api.serializers import CommentPublicSerializer +from preprints.api.serializers import PreprintPublicSerializer + + +class SubmissionPublicSerializer(serializers.ModelSerializer): + identifier = serializers.CharField(source="preprint.identifier_w_vn_nr") + url = serializers.URLField(source="get_absolute_url") + publication = serializers.SerializerMethodField() + acad_field = serializers.StringRelatedField() + specialties = serializers.StringRelatedField(many=True) + topics = serializers.StringRelatedField(many=True) + approaches = serializers.StringRelatedField() + submission_date = serializers.CharField(source="submission_date_ymd") + is_resubmission_of = serializers.SerializerMethodField() + submitted_to = serializers.StringRelatedField() + thread_sequence_order = serializers.IntegerField() + preprint = PreprintPublicSerializer() + reports = serializers.SerializerMethodField() + comments = serializers.SerializerMethodField() + events = SubmissionEventPublicSerializer(many=True, read_only=True) + + class Meta: + model = Submission + fields = [ + "title", + "author_list", + "abstract", + "identifier", + "url", + "publication", + "acad_field", + "specialties", + "topics", + "approaches", + "status", + "is_current", + "submission_date", + "original_submission_date", + "submitted_to", + "proceedings", + "is_resubmission_of", + "thread_hash", + "thread_sequence_order", + "code_repository_url", + "data_repository_url", + "preprint", + "reports", + "comments", + "events", + ] + + def get_publication(self, obj): + if hasattr(obj, "publication") and obj.publication.is_published: + return obj.publication.get_absolute_url() + return None + + def get_is_resubmission_of(self, obj): + if obj.is_resubmission_of: + return obj.is_resubmission_of.get_absolute_url() + return None + + def get_reports(self, obj): + reports = obj.reports.accepted() + return ReportPublicSerializer(reports, many=True, read_only=True).data + + def get_comments(self, obj): + comments = obj.comments.vetted() + return CommentPublicSerializer(comments, many=True, read_only=True).data class SubmissionPublicSearchSerializer(serializers.ModelSerializer): diff --git a/scipost_django/submissions/api/serializers/submission_event.py b/scipost_django/submissions/api/serializers/submission_event.py new file mode 100644 index 0000000000000000000000000000000000000000..d6523582b720f3c1ce95f32a2b0e76d6d75c6296 --- /dev/null +++ b/scipost_django/submissions/api/serializers/submission_event.py @@ -0,0 +1,19 @@ +__copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" +__license__ = "AGPL v3" + + +from rest_framework import serializers + +from ...models import SubmissionEvent + + +class SubmissionEventPublicSerializer(serializers.ModelSerializer): + event = serializers.CharField(source="get_event_display") + + class Meta: + model = SubmissionEvent + fields = [ + "created", + "event", + "submission", + ] diff --git a/scipost_django/submissions/api/viewsets/__init__.py b/scipost_django/submissions/api/viewsets/__init__.py index 220db5cda37db34303930072003f96a89f843332..fa2550d10bd43dd1972787c52f7be81709aecbb6 100644 --- a/scipost_django/submissions/api/viewsets/__init__.py +++ b/scipost_django/submissions/api/viewsets/__init__.py @@ -2,4 +2,7 @@ __copyright__ = "Copyright © Stichting SciPost (SciPost Foundation)" __license__ = "AGPL v3" -from .submission import SubmissionPublicSearchAPIViewSet +from .submission import ( + SubmissionPublicAPIViewSet, + SubmissionPublicSearchAPIViewSet, +) diff --git a/scipost_django/submissions/api/viewsets/submission.py b/scipost_django/submissions/api/viewsets/submission.py index 52cb196fce3b19d90bdf3d9a4281dfbc12297c0c..915a8c5e805e9a13e3cd40860dffc7bf67ed5f75 100644 --- a/scipost_django/submissions/api/viewsets/submission.py +++ b/scipost_django/submissions/api/viewsets/submission.py @@ -8,8 +8,34 @@ from rest_framework.permissions import AllowAny from api.viewsets.mixins import FilteringOptionsActionMixin from submissions.models import Submission -from submissions.api.filtersets import SubmissionPublicSearchAPIFilterSet -from submissions.api.serializers import SubmissionPublicSearchSerializer +from submissions.api.filtersets import ( + SubmissionPublicAPIFilterSet, + SubmissionPublicSearchAPIFilterSet, +) +from submissions.api.serializers import ( + SubmissionPublicSerializer, + SubmissionPublicSearchSerializer, +) + + +class SubmissionPublicAPIViewSet( + FilteringOptionsActionMixin, viewsets.ReadOnlyModelViewSet +): + queryset = Submission.objects.public() + permission_classes = [ + AllowAny, + ] + serializer_class = SubmissionPublicSerializer + search_fields = ["title", "author_list", "abstract"] + ordering_fields = [ + "submission_date", + ] + filterset_class = SubmissionPublicAPIFilterSet + default_filtering_fields = [ + "title__icontains", + "author_list__icontains", + "abstract__icontains", + ] class SubmissionPublicSearchAPIViewSet(