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
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
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
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
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