예제 #1
0
    async def video_post(self, task_message: VideoPostTaskMessage):
        post = Post.objects.get(pk=task_message.post_id)

        user = User.objects.get(pk=task_message.user_id)
        campaign = AdvertisingCampaign.objects.get(pk=task_message.campaign_id)
        group = Group.objects.get(pk=task_message.target_group_id)

        custom_campaign = CustomCampaign.objects.filter(user=user,
                                                        campaign=campaign)
        text = campaign.text if not custom_campaign else custom_campaign.first(
        ).text

        social_uid, access_token = self._get_vk_credentials(user=user)
        video_owner, video_vid = campaign.link.split('video-')[1].split('_')

        method = WallPostMethod(access_token=access_token,
                                owner_id=format_group_id(group.group_id),
                                attachments=[{
                                    'type':
                                    VK_MESSAGE_KEY.ATTACHMENT_TYPE,
                                    'owner_id':
                                    format_group_id(video_owner),
                                    'id':
                                    video_vid
                                }],
                                priority=task_message.priority,
                                message=text)

        response_dict = await method.execute()

        if not self.check_response(post,
                                   response_dict,
                                   fail_status=Post.FAILED,
                                   delete_status=Post.IS_DELETED):
            return False

        response = response_dict.get(VK_MESSAGE_KEY.RESPONSE)
        post.status = Post.IS_ACTIVE
        post.post_id = response.get(VK_MESSAGE_KEY.POST_ID)
        post.save()

        post_screen_exists = GroupPostImgs.objects.filter(
            group__group_id=post.group.group_id,
            campaign__pk=post.campaign.pk).first()

        if not post_screen_exists and ENABLED_POSTING_SCREENSHOT:
            SocialService.post_vk_screenshot(post_id=post.post_id,
                                             group_id=post.group.group_id,
                                             campaign_pk=post.campaign.pk)

        return True
예제 #2
0
    async def delete_post(self, task_message: DeletePostTaskMessage) -> bool:
        post = get_object_or_none(Post, pk=task_message.post_id)

        if not post:
            logger.error('Post Not Found Post id {}'.format(
                task_message.post_id))
            return False

        social_uid, access_token = self._get_vk_credentials(post.user)

        method = WallDeleteMethod(priority=task_message.priority,
                                  access_token=access_token,
                                  owner_id=format_group_id(
                                      post.group.group_id),
                                  post_id=post.post_id)

        response_dict = await method.execute()

        status = self.check_response(post,
                                     response_dict,
                                     fail_status=Post.FAILED_DELETE,
                                     delete_status=Post.IS_DELETED)

        if not status:
            return False

        post.status = Post.IS_DELETED if task_message.delete_status == Post.IS_DELETED else task_message.delete_status
        post.save()
        return True
예제 #3
0
    async def _wall_post(self, access_token, group, video, priority,
                         description, post, campaign_pk):
        method = WallPostMethod(access_token=access_token,
                                owner_id=format_group_id(group.group_id),
                                attachments=[{
                                    'type': VK_MESSAGE_KEY.ATTACHMENT_TYPE,
                                    'owner_id': video.owner,
                                    'id': video.vid
                                }],
                                priority=priority,
                                message=description)

        response_dict = await method.execute()

        if not self.check_response(post,
                                   response_dict,
                                   fail_status=Post.FAILED,
                                   delete_status=Post.IS_DELETED):
            return False

        response = response_dict.get(VK_MESSAGE_KEY.RESPONSE)
        post.status = Post.IS_ACTIVE
        post.post_id = response.get(VK_MESSAGE_KEY.POST_ID)
        post.save()

        post_screen_exists = GroupPostImgs.objects.filter(
            group__group_id=post.group.group_id,
            campaign__pk=campaign_pk).first()
        if not post_screen_exists and ENABLED_POSTING_SCREENSHOT:
            SocialService.post_vk_screenshot(post_id=post.post_id,
                                             group_id=post.group.group_id,
                                             campaign_pk=campaign_pk)

        payment, create_ = Payment.objects.get_or_create(
            campaign_id=campaign_pk, user=post.user)

        if payment.is_Payment:
            payment.is_Payment = False
            payment.save()

        return True
예제 #4
0
    async def bulk_delete_post(self, task_message: BulkDeletePostTaskMessage) -> bool:
        user = get_object_or_none(User, pk=task_message.user_id)
        if not user:
            logger.error('User not found {}'.format(task_message.user_id))
            return False

        social_uid, access_token = self._get_vk_credentials(user)
        posts_queryset = Post.objects.filter(pk__in=task_message.post_ids)
        posts_list = list(posts_queryset)
        call_method_list = []

        post_splits = split_list(posts_list, 25)

        for post_split in post_splits:
            for post in post_split:
                args = {
                    VK_MESSAGE_KEY.OWNER_ID: format_group_id(post.group.group_id),
                    VK_MESSAGE_KEY.POST_ID: post.post_id
                }
                call = ExecuteMethod.construct(
                    ExecuteMethod.WALL_ENTITY,
                    ExecuteMethod.DELETE_METHOD,
                    json.dumps(args)
                )
                call_method_list.append(call)

            method = ExecuteMethod(
                priority=task_message.priority,
                access_token=access_token,
                code=ExecuteMethod.construct_code(call_method_list)
            )

            response_dict = await method.execute()

            if not response_dict:
                error = DefaultError(
                    error_key=ErrorCode.RESPONSE_IS_EMPTY_KEY,
                    text=ErrorCode.RESPONSE_IS_EMPTY_TEXT
                )
                for post in posts_list:
                    post.vk_response = error.to_json()
                    post.status = Post.FAILED_DELETE
                    post.save()
                return False

            if VK_MESSAGE_KEY.ERROR in response_dict:
                # берем ошибку по коду ответа (только в execute)
                error_dict = response_dict.get(VK_MESSAGE_KEY.ERROR)
                error = DefaultError.get_error_from_response(
                    error_dict=error_dict,
                    error_key=VK_MESSAGE_KEY.ERROR_CODE
                )

                sentry_error = {
                    'error': response_dict,
                    'error_msg': error,
                    'user_id': user.pk,
                    'username': user.get_full_name()
                }
                sentry_logger.error(msg=sentry_error)

                for post in posts_list:
                    post.vk_response = error
                    post.status = Post.FAILED_DELETE
                    post.save()

                return False

            response_list = response_dict.get(VK_MESSAGE_KEY.RESPONSE)

            if VK_MESSAGE_KEY.EXECUTE_ERRORS in response_dict:
                error_list = response_dict.get(VK_MESSAGE_KEY.EXECUTE_ERRORS)

                sentry_logger.warning(msg="Execute errors while post deleting", extra={
                    'error': response_dict,
                    'user_id': user.pk,
                    'username': user.get_full_name()
                })

                false_response_posts = []

                # порядок постов в сплите совпадает с порядко постов в ответе
                for index, post in enumerate(post_split):
                    if not response_list[index]:
                        false_response_posts.append(post)

                if false_response_posts:
                    for index, post in enumerate(false_response_posts):
                        concrete_error = error_list[index]
                        concrete_error_msg = DefaultError.get_error_from_response(
                            error_dict=concrete_error,
                            error_key=VK_MESSAGE_KEY.ERROR_MSG
                        )

                        # error code 7, Access denied распознаем, как удаленные
                        error_message = concrete_error.get(VK_MESSAGE_KEY.ERROR_MSG)
                        if error_message == ErrorCode.WALL_DELETE_ACCESS_DENIED_KEY:
                            post.status = Post.IS_DELETED
                        else:
                            post.status = Post.FAILED_DELETE

                        post.vk_response = concrete_error_msg

                        post.save()
                        self.log_to_sentry(post, concrete_error_msg, level='warning')
            else:
                for index, post in enumerate(post_split):
                    if response_list[index]:
                        post.status = Post.IS_DELETED
                        post.save()
            call_method_list[:] = []

        posts_queryset.update(status=Post.IS_DELETED)
        return True
예제 #5
0
    async def get_stats_post(self, task_message: GetStatsPostMessage):
        posts_queryset = Post.objects.filter(pk__in=task_message.post_ids, group__members__gt=5000)
        prefetch = Prefetch(
            'posts',
            queryset=posts_queryset,
            to_attr='custom_prefetch_posts'
        )
        user_id_list = posts_queryset.values_list('user_id', flat=True).distinct()
        users = User.objects.filter(pk__in=user_id_list).prefetch_related(prefetch)

        try:
            if not posts_queryset:
                logger.error('Posts are empty {}'.format(task_message.post_ids))
                return False

            posts_queryset.update(is_stat_fetching=True)

            for user in users:
                posts = user.custom_prefetch_posts
                social_uid, access_token = self._get_vk_credentials(user)
                api_calls = [
                    ExecuteMethod.construct(
                        ExecuteMethod.STATS_ENTITY,
                        ExecuteMethod.POST_REACH,
                        json.dumps({
                            VK_MESSAGE_KEY.OWNER_ID: format_group_id(post.group.group_id),
                            VK_MESSAGE_KEY.POST_ID: post.post_id
                        })
                    ) for post in posts
                ]

                execute_parts = split_list(api_calls, 25)
                posts_parts = split_list(posts, 25)

                for index_part, execute_part in enumerate(execute_parts):
                    post_part = posts_parts[index_part]
                    method = ExecuteMethod(
                        priority=task_message.priority,
                        access_token=access_token,
                        code=ExecuteMethod.construct_code(execute_part)
                    )

                    response_dict = await method.execute()
                    if not response_dict:
                        traceback_log = traceback.format_exc()
                        sentry_logger.error(msg="False response on get stat Post", extra={
                            'trace': traceback_log,
                            'locals': locals()
                        })
                        continue
                    response_list = response_dict.get(VK_MESSAGE_KEY.RESPONSE)
                    if VK_MESSAGE_KEY.ERROR in response_dict:
                        sentry_error = {
                            'error': response_dict
                        }
                        sentry_logger.warning(msg=sentry_error)
                        continue

                    if VK_MESSAGE_KEY.EXECUTE_ERRORS in response_dict:
                        false_response_list = []

                        for index, post_api_call in enumerate(execute_part):
                            if not response_list[index]:
                                post = post_part[index]
                                false_response_list.append(post)

                        errors = response_dict.get(VK_MESSAGE_KEY.EXECUTE_ERRORS)

                        if errors and false_response_list:
                            for index, post in enumerate(false_response_list):
                                error = errors[index]
                                post_stats, is_created = PostStats.objects.get_or_create(post=post)
                                post_stats.vk_response = error
                                post_stats.save()
                                sentry_logger.warning(
                                    msg='False response get_stat for post pk {}'.format(post.pk),
                                    extra={
                                        'post_id_in_vk': post.post_id,
                                        'group': post.group.name,
                                        'user_pk': post.user_id,
                                        'username': post.user.get_full_name(),
                                        'error': error,
                                        'link': 'https://vk.com/wall-{}_{}'.format(
                                            post.group.group_id,
                                            post.post_id
                                        )
                                    }
                                )
                                SocialService.vk_check_post(SocialType.VK, post_id=post.pk)

                    for index, post_api_call in enumerate(execute_part):
                        if response_list[index]:
                            posts_array = response_list[index]
                            post = post_part[index]
                            post_stats, is_created = PostStats.objects.get_or_create(post=post)

                            u_stat, _ = UnitedPostsStat.objects.get_or_create(
                                user=post.user,
                                group=post.group,
                                campaign=post.campaign
                            )

                            if 'reach_subscribers' in posts_array[0] and 'reach_total' in posts_array[0]:
                                if post.campaign.campaign_type in [AdvertisingCampaign.VK_VIDEO_POST,
                                                                   AdvertisingCampaign.VK_REPOST]:
                                    last_views = int(
                                        post_stats.reach.split('/')[1].replace('-', '0')) if post_stats.reach else 0
                                    diff = posts_array[0]['reach_total'] - last_views
                                    today = timezone.make_aware(
                                        datetime.now(),
                                        timezone.get_default_timezone()
                                    ).date()

                                    views_stat, _ = ViewsStat.objects.get_or_create(
                                        group=post.group,
                                        campaign=post.campaign,
                                        date__contains=today,
                                        user=post.user
                                    )
                                    if diff:
                                        views_stat.views += diff
                                        views_stat.save()

                                post_stats.reach = '{}/{}'.format(
                                    str(posts_array[0]['reach_subscribers']),
                                    str(posts_array[0]['reach_total'])
                                )
                                post_stats.save()
                            try:
                                if len(SuspiciousUser.objects.filter(user=post.user, campaign=post.campaign)) > 0:
                                    reach_tags = {
                                        'type': 'reach',
                                        'campaign_pk': post.campaign.pk,
                                        'user_pk': post.user.pk,
                                        'user': translit(str(post.user), 'ru', reversed=True),
                                        'group_pk': post.group.pk,
                                        'group_name': translit(post.group.name, 'ru', reversed=True)
                                    }
                                    StatsClient.event('video-seed__suspicious_users',
                                                      value=posts_array[0]['reach_total'],
                                                      tags=reach_tags)
                            except Exception as e:
                                sentry_logger.error(msg=e)

                for post in posts:
                    post.is_stat_fetching = False
                    post.last_stat_fetch_date = timezone.make_aware(datetime.now(), timezone.get_default_timezone())
                    post.save()

        except Exception as e:
            traceback_log = traceback.format_exc()
            sentry_logger.error(msg=e, extra={
                'trace': traceback_log,
                'locals': locals()
            })

        posts_queryset.update(is_stat_fetching=False,
                              last_stat_fetch_date=timezone.make_aware(datetime.now(), timezone.get_default_timezone()))

        return True