Untitled

mail@pastecode.io avatar
unknown
python
2 years ago
5.2 kB
2
Indexable
Never
class UserRetailerAnnouncementViewSet(BaseViewSet):
    @authorized_user_required
    def list(self, request, user_pk, retailer_pk=None):
        """
        List retailer announcements.
        ---
        parameters:
          - name: user_pk
            paramType: path
            defaultValue: me
            required: true
            type: integer
        response_serializer: serializers.AnnouncementListSerializer
        """
        # This ViewSet is used in both 'user-announcement' and
        # 'user-retailer-announcement' routes.

        country = context.country

        if not country:
            raise ServiceException('HTTP_YOYO_COUNTRY header is missing', status=400)

        retailer_ids_for_mobile_filtering = self.get_retailer_ids_for_mobile_filtering(
            user_id=request.user.pk, path_retailer_id=retailer_pk
        )

        if (
            context.api_client_name == APPLICATION_DEFAULT
            and not self.request_retailer_id
            and not retailer_pk
        ):
            # Unfiltered request from Yoyo Wallet. Return retailer space enabled
            # retailer ids that are visible to app.
            retailer_ids = list(
                set(
                    retailer_tasks_sync.get_retailer_ids_for_enabled_retailer_spaces(
                        user_id=user_pk
                    )
                )
                & set(
                    get_retailer_ids_by_api_client_name(
                        api_client_name=context.api_client_name
                    )
                )
            )
        else:
            retailer_ids = self.resolve_retailer_ids(path_retailer_id=retailer_pk)

        announcements_to_m2m_ids = defaultdict(list)
        announcements_to_retailer_ids = defaultdict(list)

        retailer_read_replica_db = read_replica_router.db_for_read(
            retailer_models.AnnouncementExcludedApiKey
        )

        if retailer_ids:
            eligible_rule_ids = list(
                loyalty_rules_tasks_sync.get_eligible_rule_ids(
                    user_id=user_pk,
                    retailer_ids=retailer_ids,
                    country_code=context.country,
                )
            )

            api_key_excluded_announcements_pks = (
                retailer_models.AnnouncementExcludedApiKey.objects.filter(
                    api_key_id=context.api_key_id
                ).values_list('announcement_id', flat=True)
            )  # yapf: disable

            announcements_qs = (
                retailer_models.Announcement.objects.not_dismissed_for_user(
                    user_id=user_pk
                )
                .active(country_code=context.country)
                .prefetch_related_userannouncement_for_user(user_id=user_pk)
                .filter(retailers__in=retailer_ids)
                .filter(Q(rule_id__in=eligible_rule_ids) | Q(rule_id__isnull=True))
                .exclude(pk__in=api_key_excluded_announcements_pks)
                .order_by('priority_visibility', 'pk')
            )  # yapf: disable
            announcement_retailer_values = (
                retailer_models.Announcement.retailers.through.objects.filter(
                    announcement_id__in=announcements_qs.values_list('pk', flat=True),
                    retailer_id__in=retailer_ids,
                )
                .values_list('announcement_id', 'pk', 'retailer_id')
                .using(retailer_read_replica_db)
            )

            for (announcement_id, m2m_id, retailer_id) in announcement_retailer_values:
                announcements_to_retailer_ids[announcement_id].append(retailer_id)
                announcements_to_m2m_ids[announcement_id].append(m2m_id)

        else:
            announcements_qs = retailer_models.Announcement.objects.none()

        announcements_qs = announcements_qs.prefetch_related(
            'brand_announcement_content__assets'
        )

        # add read replica at this point to avoid issues using read replica in
        # a SQL IN statement
        announcements_qs = announcements_qs.using(retailer_read_replica_db)
        # Create auto dismiss entries. Materialises queryset.
        announcements_qs.ensure_auto_dismiss_for_user(user_id=user_pk)

        loyalty_read_replica_db = read_replica_router.db_for_read(
            loyalty_rules_models.Rule
        )
        announcements_rules = loyalty_rules_models.Rule.objects.using(
            loyalty_read_replica_db
        ).filter(
            pk__in=list(
                announcement.rule_id
                for announcement in announcements_qs
                if announcement.rule_id
            )
        )  # yapf: disable

        data = serializers.AnnouncementListSerializer(
            {
                'announcements': announcements_qs,
                'retailer_ids': retailer_ids_for_mobile_filtering,
            },
            context={
                'rule_ids_to_rules': {rule.id: rule for rule in announcements_rules},
                'announcements_to_retailer_ids': announcements_to_retailer_ids,
                'announcements_to_m2m_ids': announcements_to_m2m_ids,
            },
        ).data

        return render_success_response(data)