Exemple #1
0
class ActivityLogDayCountViewset(viewsets.ModelViewSet):
    serializer_class = serializers.ActivityLogDayCountSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["event_type__name", "actor_user", "effected_user"]

    permission_classes = [
        core_permissions.ActionIs("list")
        & (core_permissions.IsCurrentUserInSpecificFilter("actor_user")
           | core_permissions.IsCurrentUserInSpecificFilter("effected_user")
           | core_permissions.HasObjectPermission(
               permissions=Team.PERMISSION_VIEW,
               get_objects=core_permissions.get_teams_from_user_filter(
                   "actor_user"),
           )
           | core_permissions.HasObjectPermission(
               permissions=Team.PERMISSION_VIEW,
               get_objects=core_permissions.get_teams_from_user_filter(
                   "effected_user"),
           ))
    ]

    def get_queryset(self):
        query = models.LogEntry.objects.annotate(
            date=Cast("timestamp", output_field=DateField()))
        query = query.values("date").annotate(total=Count("date"))
        query = query.order_by("-date")

        filters = "&".join(
            [f"{key}={value}" for key, value in self.request.GET.items()])

        query = query.annotate(
            filters=Value(filters, output_field=CharField()))

        return query
Exemple #2
0
    def get_permissions(self):

        # if self.action == 'retrieve':
        # else:
        permission_classes = [
            permissions.IsAdminUser
            | core_permissions.IsStaffUser
            | core_permissions.IsCurrentUserInSpecificFilter("recruit_users")
            | core_permissions.IsCurrentUserInSpecificFilter("reviewer_users")
            | curriculum_permissions.IsCurrentUserInRecruitsForFilteredProject
            | curriculum_permissions.IsCurrentUserInReviewersForFilteredProject
        ]
        return [permission() for permission in permission_classes]
Exemple #3
0
class WorkshopAttendanceViewset(viewsets.ModelViewSet):

    serializer_class = serializers.WorkshopAttendanceSerializer
    queryset = models.WorkshopAttendance.objects.order_by("pk")
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["attendee_user"]

    permission_classes = [
        ActionIs("retrieve")
        & (
            curriculum_permissions.IsWorkshopAttendee
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=_get_teams_from_workshop_attendance,
            )
        )
        | ActionIs("list")
        & (
            core_permissions.IsCurrentUserInSpecificFilter("attendee_user")
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=core_permissions.get_teams_from_user_filter(
                    "attendee_user"
                ),
            )
        )
    ]
Exemple #4
0
    def get_permissions(self):
        # breakpoint()

        # o = core_permissions.HasObjectPermission(
        #     Team.PERMISSION_VIEW,
        #     core_permissions.get_teams_from_user_filter("recruit_users"),
        # )()
        # o.has_permission(view=self, request=self.request)

        # wooo
        permission_classes = [IsReadOnly]
        if self.action == "retrieve":
            permission_classes = [
                permissions.IsAdminUser
                | curriculum_permissions.IsProjectAssignee
                | curriculum_permissions.IsProjectReviewer
                | core_permissions.HasObjectPermission(
                    permissions=Team.PERMISSION_VIEW,
                    get_objects=_get_teams_from_recruit_project,
                )
            ]
        elif self.action == "list":
            permission_classes = [
                permissions.IsAdminUser
                | core_permissions.IsCurrentUserInSpecificFilter("recruit_users")
                | core_permissions.HasObjectPermission(
                    permissions=Team.PERMISSION_VIEW,
                    get_objects=core_permissions.get_teams_from_user_filter(
                        "recruit_users"
                    ),
                )
            ]
        return [permission() for permission in permission_classes]
Exemple #5
0
class CardSummaryViewset(viewsets.ModelViewSet):

    permission_classes = [
        permissions.IsAdminUser
        | core_permissions.ActionIs("retrieve")
        & (
            curriculum_permissions.IsCardAssignee
            | curriculum_permissions.IsCardReviewer
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW, get_objects=_get_teams_from_card
            )
        )
        | core_permissions.IsReadOnly
        | core_permissions.IsStaffUser
        | core_permissions.IsCurrentUserInSpecificFilter("assignees")
        | core_permissions.HasObjectPermission(
            permissions=Team.PERMISSION_VIEW,
            get_objects=core_permissions.get_teams_from_user_filter("assignees"),
        ),
    ]
    serializer_class = serializers.CardSummarySerializer
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    filterset_fields = ["assignees", "content_item__content_type", "status"]

    ordering_fields = ["recruit_project__complete_time"]

    queryset = (
        models.AgileCard.objects.order_by("order")
        .filter(
            Q(content_item__content_type=models.ContentItem.PROJECT)
            | Q(content_item__topic_needs_review=True)
        )
        .prefetch_related("content_item")
        .prefetch_related("recruit_project")
    )
Exemple #6
0
class RecruitProjectReviewViewset(viewsets.ModelViewSet):
    serializer_class = serializers.RecruitProjectReviewSerializer
    queryset = models.RecruitProjectReview.objects.order_by("-timestamp")
    filter_backends = [DjangoFilterBackend]
    filterset_fields = [
        "status",
        "reviewer_user",
        "recruit_project",
        "recruit_project__recruit_users",
    ]

    permission_classes = [
        ActionIs("list")
        & (
            curriculum_permissions.IsCurrentUserInRecruitsForFilteredProject
            | curriculum_permissions.IsCurrentUserInReviewersForFilteredProject
            | core_permissions.IsCurrentUserInSpecificFilter("reviewer_user")
            | core_permissions.IsCurrentUserInSpecificFilter(
                "recruit_project__recruit_users"
            )
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=core_permissions.get_teams_from_user_filter(
                    "recruit_project__recruit_users"
                ),
            )
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=core_permissions.get_teams_from_user_filter(
                    "reviewer_user"
                ),
            )
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=_get_teams_from_recruit_project_filter,
            )
        )
        | ActionIs("retrieve")
        & (
            # curriculum_permissions.IsCurrentUserInRecruitsForFilteredProject
            # | curriculum_permissions.IsCurrentUserInReviewersForFilteredProject
            core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=_get_teams_from_recruit_project_review,
            )
        )
    ]
Exemple #7
0
class TopicReviewViewset(viewsets.ModelViewSet):
    serializer_class = serializers.TopicReviewSerializer
    queryset = models.TopicReview.objects.order_by("pk")
    filter_backends = [DjangoFilterBackend]
    filterset_fields = [
        "status",
        "reviewer_user",
        "topic_progress",
        "topic_progress__user",
    ]

    permission_classes = [
        ActionIs("list")
        & (
            curriculum_permissions.IsCurrentUserInUsersForFilteredTopicProgress
            | curriculum_permissions.IsCurrentUserInReviewersForFilteredTopicProgress
            | core_permissions.IsCurrentUserInSpecificFilter("reviewer_user")
            | core_permissions.IsCurrentUserInSpecificFilter("topic_progress__user")
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=core_permissions.get_teams_from_user_filter(
                    "topic_progress__user"
                ),
            )
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=core_permissions.get_teams_from_user_filter(
                    "reviewer_user"
                ),
            )
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=_get_teams_from_topic_progress_filter,
            )
        )
        | ActionIs("retrieve")
        & (
            curriculum_permissions.IsCurrentUserInUsersForFilteredTopicProgress
            | core_permissions.HasObjectPermission(
                permissions=Team.PERMISSION_VIEW,
                get_objects=_get_teams_from_topic_review,
            )
        )
    ]
Exemple #8
0
 def get_permissions(self):
     permission_classes = [
         permissions.IsAdminUser
         | core_permissions.IsStaffUser
         | core_permissions.IsCurrentUserInSpecificFilter("reviewer_user")
         |
         curriculum_permissions.IsCurrentUserInUsersForFilteredTopicProgress
         # | curriculum_permissions.IsCurrentUserInReviewersForFilteredTopicProgress
     ]
     return [permission() for permission in permission_classes]
Exemple #9
0
    def get_permissions(self):
        if self.action == "retrieve":
            permission_classes = [
                curriculum_permissions.IsTopicProgressUser
                | permissions.IsAdminUser
                | core_permissions.IsStaffUser
            ]
        else:
            permission_classes = [
                permissions.IsAdminUser
                | core_permissions.IsStaffUser
                | core_permissions.IsCurrentUserInSpecificFilter("user")
            ]

        return [permission() for permission in permission_classes]
Exemple #10
0
 def get_permissions(self):
     if self.action == "retrieve":
         permission_classes = [
             curriculum_permissions.IsProjectAssignee
             | curriculum_permissions.IsProjectReviewer
             | permissions.IsAdminUser
             | core_permissions.IsStaffUser
         ]
     else:
         permission_classes = [
             permissions.IsAdminUser
             | core_permissions.IsStaffUser
             |
             core_permissions.IsCurrentUserInSpecificFilter("recruit_users")
         ]
     return [permission() for permission in permission_classes]
Exemple #11
0
class ReviewTrustsViewSet(viewsets.ModelViewSet):

    permission_classes = [
        permissions.IsAdminUser
        | ActionIs("list")
        & (core_permissions.IsCurrentUserInSpecificFilter("user")
           | core_permissions.HasObjectPermission(
               permissions=Team.PERMISSION_VIEW,
               get_objects=core_permissions.get_teams_from_user_filter("user"),
           ))
    ]

    queryset = models.ReviewTrust.objects.order_by("user").all()
    serializer_class = serializers.ReviewTrustSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["user"]
Exemple #12
0
class ProjectCardSummaryViewset(AuthMixin, viewsets.ModelViewSet):
    # TODO: make this view only
    permission_classes = [
        permissions.IsAdminUser
        | core_permissions.IsStaffUser
        | core_permissions.IsCurrentUserInSpecificFilter("assignees")
    ]

    serializer_class = serializers.ProjectCardSummarySerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["assignees"]

    queryset = (
        models.AgileCard.objects.order_by("order").filter(
            content_item__content_type=models.ContentItem.PROJECT)
        # .filter(Q(is_hard_milestone=True) | Q(is_soft_milestone=True))
        .prefetch_related("content_item").prefetch_related("recruit_project"))
Exemple #13
0
    def get_permissions(self):
        permission_classes = [IsReadOnly]
        if self.action == "retrieve":
            permission_classes = [
                curriculum_permissions.IsTopicProgressUser
                | core_permissions.HasObjectPermission(
                    permissions=Team.PERMISSION_VIEW,
                    get_objects=_get_teams_from_topic_progress,
                )
            ]
        elif self.action == "list":
            permission_classes = [
                core_permissions.IsCurrentUserInSpecificFilter("user")
                | core_permissions.HasObjectPermission(
                    permissions=Team.PERMISSION_VIEW,
                    get_objects=core_permissions.get_teams_from_user_filter("user"),
                )
            ]

        return [permission() for permission in permission_classes]
Exemple #14
0
class AgileCardViewset(viewsets.ModelViewSet):

    serializer_class = serializers.AgileCardSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["assignees", "reviewers", "status"]

    queryset = (
        models.AgileCard.objects.order_by("order")
        .prefetch_related("recruit_project")
        .prefetch_related("recruit_project__repository__pull_requests")
    )

    permission_classes = [
        (
            core_permissions.ActionIs("retrieve")
            & (
                curriculum_permissions.CardBelongsToRequestingUser
                | core_permissions.HasObjectPermission(
                    permissions=Team.PERMISSION_VIEW,
                    get_objects=_get_teams_from_card,
                )
            )
        )
        | (
            core_permissions.ActionIs("list")
            & (
                core_permissions.IsCurrentUserInSpecificFilter("assignees")
                | core_permissions.IsCurrentUserInSpecificFilter("reviewers")
                | core_permissions.HasObjectPermission(
                    permissions=Team.PERMISSION_VIEW,
                    get_objects=core_permissions.get_teams_from_user_filter(
                        "assignees"
                    ),
                )
                | core_permissions.HasObjectPermission(
                    permissions=Team.PERMISSION_VIEW,
                    get_objects=core_permissions.get_teams_from_user_filter(
                        "reviewers"
                    ),
                )
            )
        )
    ]

    def get_card_or_error(self, status_or_404, type_or_404):
        card = self.get_object()
        if status_or_404 and card.status != status_or_404:
            raise Http404()
        if card.content_type != type_or_404:
            raise Http404()

        return card

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.SetDueTimeSerializer,
        permission_classes=[
            (
                curriculum_permissions.IsCardAssignee
                & curriculum_permissions.CardDueTimeIsNotSet
            )
            | IsStaffUser
            | HasObjectPermission(
                permissions=Team.PERMISSION_MANAGE_CARDS,
                get_objects=_get_teams_from_card,
            )
        ],
    )
    def set_card_due_time(self, request, pk=None):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            card = self.get_object()
            card.set_due_time(serializer.data["due_time"])

            return Response(serializers.AgileCardSerializer(card).data)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    # @action(
    #     detail=True,
    #     methods=["post"],
    #     serializer_class=serializers.AddReviewerUserSerializer,
    #     permission_classes=[permissions.IsAdminUser | core_permissions.IsStaffUser],
    # )
    # def add_reviewer(self, request, pk=None):
    #     serializer = self.get_serializer(data=request.data)
    #     if serializer.is_valid():
    #         TODO
    #         return Response(serializers.AgileCardSerializer(card).data)
    #     else:
    #         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NewReviewSerializer,
        permission_classes=[
            curriculum_permissions.IsCardReviewer
            | HasObjectPermission(
                permissions=Team.PERMISSION_REVIEW_CARDS,
                get_objects=_get_teams_from_card,
            )
            | HasObjectPermission(
                permissions=Team.PERMISSION_TRUSTED_REVIEWER,
                get_objects=_get_teams_from_card,
            )
        ],
    )
    def add_review(self, request, pk=None):
        card = self.get_object()

        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            if card.content_item.content_type == models.ContentItem.PROJECT:
                if card.recruit_project == None:
                    raise Http404

                review = models.RecruitProjectReview.objects.create(
                    status=serializer.data["status"],
                    timestamp=timezone.now(),
                    comments=serializer.data["comments"],
                    recruit_project=card.recruit_project,
                    reviewer_user=request.user,
                )
                log_creators.log_project_competence_review_done(review)

            elif card.content_item.content_type == models.ContentItem.TOPIC:
                if card.topic_progress == None:
                    raise Http404

                review = models.TopicReview.objects.create(
                    status=serializer.data["status"],
                    timestamp=timezone.now(),
                    comments=serializer.data["comments"],
                    topic_progress=card.topic_progress,
                    reviewer_user=request.user,
                )

                log_creators.log_topic_competence_review_done(review)

            card.refresh_from_db()

            return Response(serializers.AgileCardSerializer(card).data)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | HasObjectPermission(
                permissions=Team.PERMISSION_MANAGE_CARDS,
                get_objects=_get_teams_from_card,
            )
        ],
    )
    def request_review(self, request, pk=None):
        card: models.AgileCard = self.get_object()
        if card.recruit_project:
            card.recruit_project.request_review(force_timestamp=timezone.now())
        elif card.topic_progress:
            card.finish_topic()
        else:
            raise Http404
        card.refresh_from_db()
        assert (
            card.status == models.AgileCard.IN_REVIEW
        ), f"Expected to be in review, but got {card.status}"
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | HasObjectPermission(
                permissions=Team.PERMISSION_MANAGE_CARDS,
                get_objects=_get_teams_from_card,
            )
        ],
    )
    def cancel_review_request(self, request, pk=None):
        card = self.get_object()
        if card.status != models.AgileCard.IN_REVIEW:
            raise Http404()
        if card.recruit_project:
            card.recruit_project.cancel_request_review()
        elif card.topic_progress:
            card.topic_progress.cancel_request_review()

        # card.status = models.AgileCard.IN_PROGRESS
        # card.save()
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            (
                curriculum_permissions.IsCardAssignee
                & curriculum_permissions.CardCanStart
            )
            | (
                HasObjectPermission(
                    permissions=Team.PERMISSION_MANAGE_CARDS,
                    get_objects=_get_teams_from_card,
                )
                & curriculum_permissions.CardCanForceStart
            ),
        ],
    )
    def start_project(self, request, pk=None):
        card: models.AgileCard = self.get_card_or_error(
            status_or_404=None,
            type_or_404=models.ContentItem.PROJECT,
        )
        card.start_project()

        log_creators.log_card_started(card=card, actor_user=request.user)

        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.ProjectSubmitLink,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | HasObjectPermission(
                permissions=Team.PERMISSION_MANAGE_CARDS,
                get_objects=_get_teams_from_card,
            )
        ],
    )
    def set_project_link(self, request, pk=None):
        card = self.get_card_or_error(
            status_or_404=None,
            type_or_404=models.ContentItem.PROJECT,
        )
        content_item = card.content_item
        assert (
            content_item.project_submission_type == content_item.LINK
        ), "Cannot submit a link for project with submision type: {content_item.project_submission_type}\n\tcard={card}"

        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            card.recruit_project.link_submission = serializer.data["link_submission"]
            card.recruit_project.save()
            card.refresh_from_db()
            return Response(serializers.AgileCardSerializer(card).data)

        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            (
                curriculum_permissions.IsCardAssignee
                & curriculum_permissions.CardCanStart
            )
            | (
                HasObjectPermission(
                    permissions=Team.PERMISSION_MANAGE_CARDS,
                    get_objects=_get_teams_from_card,
                )
                & curriculum_permissions.CardCanForceStart
            ),
        ],
    )
    def start_topic(self, request, pk=None):
        card = self.get_card_or_error(
            status_or_404=models.AgileCard.READY, type_or_404=models.ContentItem.TOPIC
        )
        if not card.can_start():
            raise HttpResponseForbidden()
        card.start_topic()
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | HasObjectPermission(
                permissions=Team.PERMISSION_MANAGE_CARDS,
                get_objects=_get_teams_from_card,
            )
        ],
    )
    def stop_topic(self, request, pk=None):
        card = self.get_card_or_error(
            status_or_404=models.AgileCard.IN_PROGRESS,
            type_or_404=models.ContentItem.TOPIC,
        )
        card.stop_topic()
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | HasObjectPermission(
                permissions=Team.PERMISSION_MANAGE_CARDS,
                get_objects=_get_teams_from_card,
            )
        ],
    )
    def finish_topic(self, request, pk=None):
        card = self.get_card_or_error(
            status_or_404=models.AgileCard.IN_PROGRESS,
            type_or_404=models.ContentItem.TOPIC,
        )

        card.finish_topic()
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            HasObjectPermission(
                permissions=Team.PERMISSION_MANAGE_CARDS,
                get_objects=_get_teams_from_card,
            )
        ],
    )
    def mark_workshop_attendance(self, request, pk=None):

        card = self.get_card_or_error(
            status_or_404=None, type_or_404=models.ContentItem.WORKSHOP
        )
        card.attended_workshop(timestamp=timezone.now())
        return Response(serializers.AgileCardSerializer(card).data)
        # serializer = self.get_serializer(data=request.data)

        # if serializer.is_valid():
        #     card.attended_workshop(timestamp = serializer.data['timestamp'])
        #     return Response(serializers.AgileCardSerializer(card).data)
        # else:
        #     return Response(serializer.errors,
        #                     status=status.HTTP_400_BAD_REQUEST)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            HasObjectPermission(
                permissions=Team.PERMISSION_MANAGE_CARDS,
                get_objects=_get_teams_from_card,
            )
        ],
    )
    def cancel_workshop_attendance(self, request, pk=None):
        card = self.get_card_or_error(
            status_or_404=models.AgileCard.COMPLETE,
            type_or_404=models.ContentItem.WORKSHOP,
        )
        card.delete_workshop_attendance()
        return Response(serializers.AgileCardSerializer(card).data)
Exemple #15
0
class AgileCardViewset(AuthMixin, viewsets.ModelViewSet):
    permission_classes = [
        permissions.IsAdminUser
        | core_permissions.IsStaffUser
        | core_permissions.IsCurrentUserInSpecificFilter("assignees")
        | core_permissions.IsCurrentUserInSpecificFilter("reviewers")
        # curriculum_permissions.ProjectOrReviewIsMine
        | curriculum_permissions.CardBelongsToRequestingUser
    ]

    serializer_class = serializers.AgileCardSerializer
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ["assignees", "reviewers", "status"]

    def get_queryset(self):
        return models.AgileCard.objects.order_by("order").prefetch_related(
            "recruit_project")

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.SetDueTimeSerializer,
        permission_classes=[
            permissions.IsAdminUser
            | core_permissions.IsStaffUser
            | (curriculum_permissions.IsCardAssignee
               & curriculum_permissions.CardDueTimeIsNotSet)
        ],
    )
    def set_card_due_time(self, request, pk=None):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            card = self.get_object()
            card.set_due_time(serializer.data["due_time"])

            return Response(serializers.AgileCardSerializer(card).data)
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

    # @action(
    #     detail=True,
    #     methods=["post"],
    #     serializer_class=serializers.AddReviewerUserSerializer,
    #     permission_classes=[permissions.IsAdminUser | core_permissions.IsStaffUser],
    # )
    # def add_reviewer(self, request, pk=None):
    #     serializer = self.get_serializer(data=request.data)
    #     if serializer.is_valid():
    #         TODO
    #         return Response(serializers.AgileCardSerializer(card).data)
    #     else:
    #         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NewReviewSerializer,
        permission_classes=[
            curriculum_permissions.IsCardReviewer
            | permissions.IsAdminUser
            | core_permissions.IsStaffUser
        ],
    )
    def add_review(self, request, pk=None):
        card = self.get_object()

        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            if card.content_item.content_type == models.ContentItem.PROJECT:
                if card.recruit_project == None:
                    raise Http404
                review = models.RecruitProjectReview.objects.create(
                    status=serializer.data["status"],
                    timestamp=timezone.datetime.now(),
                    comments=serializer.data["comments"],
                    recruit_project=card.recruit_project,
                    reviewer_user=request.user,
                )
            elif card.content_item.content_type == models.ContentItem.TOPIC:
                if card.topic_progress == None:
                    raise Http404

                review = models.TopicReview.objects.create(
                    status=serializer.data["status"],
                    timestamp=timezone.datetime.now(),
                    comments=serializer.data["comments"],
                    topic_progress=card.topic_progress,
                    reviewer_user=request.user,
                )

            review.save()
            card.refresh_from_db()
            return Response(serializers.AgileCardSerializer(card).data)
        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | permissions.IsAdminUser
            | core_permissions.IsStaffUser
        ],
    )
    def request_review(self, request, pk=None):
        card: models.AgileCard = self.get_object()
        if card.recruit_project == None:
            raise Http404
        card.recruit_project.request_review(force_timestamp=timezone.now())
        card.refresh_from_db()
        assert (card.status == models.AgileCard.IN_REVIEW
                ), f"Expected to be in review, but got {card.status}"
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | permissions.IsAdminUser
            | core_permissions.IsStaffUser
        ],
    )
    def cancel_review_request(self, request, pk=None):
        card = self.get_object()
        if card.status != models.AgileCard.IN_REVIEW:
            raise Http404()
        card.recruit_project.cancel_request_review()
        card.status = models.AgileCard.IN_PROGRESS
        card.save()
        return Response(serializers.AgileCardSerializer(card).data)

    def get_card_or_error(self, status_or_404, type_or_404):
        card = self.get_object()
        if status_or_404 and card.status != status_or_404:
            raise Http404()
        if card.content_type != dict(
                models.ContentItem.CONTENT_TYPES)[type_or_404]:
            raise Http404()

        return card

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | permissions.IsAdminUser
            | core_permissions.IsStaffUser
        ],
    )
    def start_project(self, request, pk=None):
        card = self.get_card_or_error(
            # status_or_404=models.AgileCard.READY,
            status_or_404=None,
            type_or_404=models.ContentItem.PROJECT,
        )
        user = request.user
        if user.is_staff or user.is_superuser:
            if card.status not in [
                    models.AgileCard.READY, models.AgileCard.BLOCKED
            ]:
                raise Http404()
        else:
            assert user in card.assignees.all()
            if not card.can_start():
                return Response(serializers.AgileCardSerializer(card).data)

        card.start_project()
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.ProjectSubmitLink,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | permissions.IsAdminUser
            | core_permissions.IsStaffUser
        ],
    )
    def set_project_link(self, request, pk=None):
        card = self.get_card_or_error(
            status_or_404=None,
            type_or_404=models.ContentItem.PROJECT,
        )
        content_item = card.content_item
        assert (
            content_item.project_submission_type == content_item.LINK
        ), "Cannot submit a link for project with submision type: {content_item.project_submission_type}\n\tcard={card}"

        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            card.recruit_project.link_submission = serializer.data[
                "link_submission"]
            card.recruit_project.save()
            card.refresh_from_db()
            return Response(serializers.AgileCardSerializer(card).data)

        else:
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | permissions.IsAdminUser
            | core_permissions.IsStaffUser
        ],
    )
    def start_topic(self, request, pk=None):
        card = self.get_card_or_error(status_or_404=models.AgileCard.READY,
                                      type_or_404=models.ContentItem.TOPIC)
        if not card.can_start():
            raise HttpResponseForbidden()
        card.start_topic()
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | permissions.IsAdminUser
            | core_permissions.IsStaffUser
        ],
    )
    def stop_topic(self, request, pk=None):
        card = self.get_card_or_error(
            status_or_404=models.AgileCard.IN_PROGRESS,
            type_or_404=models.ContentItem.TOPIC,
        )
        card.stop_topic()
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            curriculum_permissions.IsCardAssignee
            | permissions.IsAdminUser
            | core_permissions.IsStaffUser
        ],
    )
    def finish_topic(self, request, pk=None):
        card = self.get_card_or_error(
            status_or_404=models.AgileCard.IN_PROGRESS,
            type_or_404=models.ContentItem.TOPIC,
        )

        card.finish_topic()
        return Response(serializers.AgileCardSerializer(card).data)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            permissions.IsAdminUser | core_permissions.IsStaffUser
        ],
    )
    def mark_workshop_attendance(self, request, pk=None):

        card = self.get_card_or_error(status_or_404=None,
                                      type_or_404=models.ContentItem.WORKSHOP)
        card.attended_workshop(timestamp=timezone.datetime.now())
        return Response(serializers.AgileCardSerializer(card).data)
        # serializer = self.get_serializer(data=request.data)

        # if serializer.is_valid():
        #     card.attended_workshop(timestamp = serializer.data['timestamp'])
        #     return Response(serializers.AgileCardSerializer(card).data)
        # else:
        #     return Response(serializer.errors,
        #                     status=status.HTTP_400_BAD_REQUEST)

    @action(
        detail=True,
        methods=["post"],
        serializer_class=serializers.NoArgs,
        permission_classes=[
            # curriculum_permissions.IsCardAssignee |
            permissions.IsAdminUser
            | core_permissions.IsStaffUser
        ],
    )
    def cancel_workshop_attendance(self, request, pk=None):
        card = self.get_card_or_error(
            status_or_404=models.AgileCard.COMPLETE,
            type_or_404=models.ContentItem.WORKSHOP,
        )
        card.delete_workshop_attendance()
        return Response(serializers.AgileCardSerializer(card).data)