Ejemplo n.º 1
0
def check_can_moderate_moderated_object(user, moderated_object):
    content_object = moderated_object.content_object

    is_global_moderator = user.is_global_moderator()

    if is_global_moderator:
        return

    PostComment = get_post_comment_model()
    Post = get_post_model()

    if isinstance(content_object, Post):
        if content_object.community:
            if not user.is_staff_of_community_with_name(
                    community_name=content_object.community.name):
                raise ValidationError(
                    _('Only community staff can moderate community posts'))
        else:
            raise ValidationError(
                _('Only global moderators can moderate non-community posts'))
    elif isinstance(content_object, PostComment):
        if content_object.post.community:
            if not user.is_staff_of_community_with_name(
                    community_name=content_object.post.community.name):
                raise ValidationError(
                    _('Only community staff can moderate community post comments'
                      ))
        else:
            raise ValidationError(
                _('Only global moderators can moderate non-community post comments'
                  ))
    else:
        raise ValidationError(
            _('Non global moderators can only moderate posts and post comments.'
              ))
Ejemplo n.º 2
0
def check_can_translate_comment_with_id(user, post_comment_id):
    PostComment = get_post_comment_model()
    post_comment = PostComment.objects.get(pk=post_comment_id)
    if post_comment.post.is_encircled_post():
        raise ValidationError(_('Only public post comments can be translated'))
    if post_comment.text is None:
        raise ValidationError(_('Post comment has no text to be translated'))
    if post_comment.language is None:
        raise ValidationError(
            _('Post comment has no assigned language to be able to translate'))
    if user.translation_language is None:
        raise ValidationError(
            _('User\'s preferred translation language not set'))
Ejemplo n.º 3
0
    def assign_language_comments(self):
        PostComment = get_post_comment_model()
        post_comments = PostComment.objects.filter(text__isnull=False)
        for post_comment in post_comments:
            try:
                language = get_language_for_text(post_comment.text)
            except LangDetectException as e:
                print('Caught exception while detecting language, skipping')

            if language:
                post_comment.language = language
                post_comment.save()
            else:
                print('Could not detect language for id', post_comment.id)
Ejemplo n.º 4
0
    def handle(self, *args, **options):
        PostComment = get_post_comment_model()

        comments_to_process = PostComment.objects.filter(hashtags__isnull=True,
                                                         text__icontains='#').only('id', 'text').all()
        migrated_postComments = 0

        for comment in _chunked_queryset_iterator(comments_to_process, 100):
            try:
                comment._process_post_comment_hashtags()
            except Exception as e:
                logger.info('Failed to process hashtags with error %s' % str(e))
            logger.info('Processed hashtags for post comment with id:' + str(comment.pk))
            migrated_postComments = migrated_postComments + 1

        logger.info('Processed %d post comments for hashtags' % migrated_postComments)
Ejemplo n.º 5
0
def check_can_edit_comment_with_id_for_post(user, post_comment_id, post):
    check_can_see_post(user=user, post=post)
    # Check that the comment belongs to the post
    PostComment = get_post_comment_model()

    if not PostComment.objects.filter(id=post_comment_id, post_id=post.pk).exists():
        raise ValidationError(
            _('The comment does not belong to the specified post.')
        )

    if post.community and post.is_closed:
        is_administrator = user.is_administrator_of_community_with_name(post.community.name)
        is_moderator = user.is_moderator_of_community_with_name(post.community.name)
        if not is_moderator and not is_administrator:
            raise ValidationError(
                _('Only administrators/moderators can edit a closed post.')
            )
Ejemplo n.º 6
0
def check_can_delete_comment_with_id_for_post(user, post_comment_id, post):
    check_can_see_post(user=user, post=post)

    # Check that the comment belongs to the post
    PostComment = get_post_comment_model()
    Post = get_post_model()

    if not PostComment.objects.filter(id=post_comment_id,
                                      post_id=post.pk).exists():
        raise ValidationError(
            _('The comment does not belong to the specified post.'))
    is_comment_creator = user.posts_comments.filter(
        id=post_comment_id).exists()

    if post.community:
        is_moderator = user.is_moderator_of_community_with_name(
            post.community.name)
        is_administrator = user.is_administrator_of_community_with_name(
            post.community.name)
        if not is_administrator and not is_moderator:
            if post.is_closed:
                raise ValidationError(
                    _('Only moderators/administrators can remove closed community posts.'
                      ), )
            elif not is_comment_creator:
                raise ValidationError(
                    _('You cannot remove a comment that does not belong to you'
                      ))
        else:
            # is admin or mod
            post_comment = PostComment.objects.select_related('commenter').get(
                pk=post_comment_id)
            if post_comment.parent_comment is not None:
                post.community.create_remove_post_comment_reply_log(
                    source_user=user, target_user=post_comment.commenter)
            else:
                post.community.create_remove_post_comment_log(
                    source_user=user, target_user=post_comment.commenter)
    elif not post.creator_id == user.pk and not is_comment_creator:
        # not a community post
        raise ValidationError(
            _('You cannot remove a comment that does not belong to you'))
Ejemplo n.º 7
0
    def unverify_with_actor_with_id(self, actor_id):
        current_verified = self.verified
        self.verified = False
        ModeratedObjectVerifiedChangedLog.create_moderated_object_verified_changed_log(
            changed_from=current_verified, changed_to=self.verified, moderated_object_id=self.pk, actor_id=actor_id)
        self.user_penalties.all().delete()
        content_object = self.content_object

        Post = get_post_model()
        PostComment = get_post_comment_model()
        Community = get_community_model()
        moderation_severity = self.category.severity

        if (isinstance(content_object, Post) or isinstance(content_object, PostComment) or isinstance(
                content_object,
                Community)) or (
                isinstance(content_object, User) and moderation_severity == ModerationCategory.SEVERITY_CRITICAL):
            content_object.unsoft_delete()
        self.save()
        content_object.save()
Ejemplo n.º 8
0
    def to_representation(self, post_comment):
        request = self.context.get('request')
        request_user = request.user

        if request_user.is_anonymous:
            PostComment = get_post_comment_model()
            reaction_emoji_count = PostComment.get_emoji_counts_for_post_comment_with_id(
                post_comment.pk)
        else:
            reaction_emoji_count = request_user.get_emoji_counts_for_post_comment(
                post_comment=post_comment)

        post_comment_reactions_serializer = self.emoji_count_serializer(
            reaction_emoji_count,
            many=True,
            context={
                "request": request,
                'post_comment': post_comment
            })

        return post_comment_reactions_serializer.data
Ejemplo n.º 9
0
    def approve_with_actor_with_id(self, actor_id):
        Post = get_post_model()
        PostComment = get_post_comment_model()
        Community = get_community_model()
        User = get_user_model()

        content_object = self.content_object
        moderation_severity = self.category.severity
        current_status = self.status
        self.status = ModeratedObject.STATUS_APPROVED
        ModeratedObjectStatusChangedLog.create_moderated_object_status_changed_log(
            changed_from=current_status, changed_to=self.status, moderated_object_id=self.pk, actor_id=actor_id)

        if isinstance(content_object, Post) or \
                isinstance(content_object, PostComment) or \
                isinstance(content_object, Community):
            content_object.delete_notifications()

        if isinstance(content_object, User) and moderation_severity == ModerationCategory.SEVERITY_CRITICAL:
            content_object.delete_outgoing_notifications()

        self.save()
Ejemplo n.º 10
0
    def verify_with_actor_with_id(self, actor_id):
        current_verified = self.verified
        self.verified = True
        ModeratedObjectVerifiedChangedLog.create_moderated_object_verified_changed_log(
            changed_from=current_verified, changed_to=self.verified, moderated_object_id=self.pk, actor_id=actor_id)

        Post = get_post_model()
        Hashtag = get_hashtag_model()
        PostComment = get_post_comment_model()
        Community = get_community_model()
        User = get_user_model()
        ModerationPenalty = get_moderation_penalty_model()

        content_object = self.content_object
        moderation_severity = self.category.severity
        penalty_targets = None

        if self.is_approved():
            if isinstance(content_object, User):
                penalty_targets = [content_object]
            elif isinstance(content_object, Post):
                penalty_targets = [content_object.creator]
            elif isinstance(content_object, PostComment):
                penalty_targets = [content_object.commenter]
            elif isinstance(content_object, Community):
                penalty_targets = content_object.get_staff_members()
            elif isinstance(content_object, ModeratedObject):
                penalty_targets = content_object.get_reporters()
            elif isinstance(content_object, Hashtag):
                penalty_targets = []

            for penalty_target in penalty_targets:
                duration_of_penalty = None
                penalties_count = penalty_target.count_moderation_penalties_for_moderation_severity(
                    moderation_severity=moderation_severity) + 1

                if moderation_severity == ModerationCategory.SEVERITY_CRITICAL:
                    duration_of_penalty = timezone.timedelta(weeks=5000)
                elif moderation_severity == ModerationCategory.SEVERITY_HIGH:
                    duration_of_penalty = timezone.timedelta(days=penalties_count ** 4)
                elif moderation_severity == ModerationCategory.SEVERITY_MEDIUM:
                    duration_of_penalty = timezone.timedelta(hours=penalties_count ** 3)
                elif moderation_severity == ModerationCategory.SEVERITY_LOW:
                    duration_of_penalty = timezone.timedelta(minutes=penalties_count ** 2)

                moderation_expiration = timezone.now() + duration_of_penalty

                ModerationPenalty.create_suspension_moderation_penalty(moderated_object=self,
                                                                       user_id=penalty_target.pk,
                                                                       expiration=moderation_expiration)

            if (isinstance(content_object, Post) or isinstance(content_object, PostComment) or isinstance(
                    content_object,
                    Community)) or (
                    isinstance(content_object, User) and moderation_severity == ModerationCategory.SEVERITY_CRITICAL):
                content_object.soft_delete()

                if moderation_severity == ModerationCategory.SEVERITY_CRITICAL and isinstance(content_object, Post):
                    # We have hashes
                    content_object.delete_media()

        content_object.save()
        self.save()
Ejemplo n.º 11
0
    def __init__(self):
        PostReaction = get_post_reaction_model()
        PostComment = get_post_comment_model()
        User = get_user_model()
        Emoji = get_emoji_model()
        Post = get_post_model()
        CommunityInvite = get_community_invite_model()
        Community = get_community_model()

        class NotificationUserSerializer(serializers.ModelSerializer):
            class Meta:
                model = User
                fields = (
                    'id',
                    'username',
                )

        class NotificationEmojiSerializer(serializers.ModelSerializer):
            class Meta:
                model = Emoji
                fields = (
                    'id',
                    'keyword',
                )

        class NotificationPostSerializer(serializers.ModelSerializer):
            class Meta:
                model = Post
                fields = (
                    'id',
                    'uuid',
                )

        class NotificationPostReactionSerializer(serializers.ModelSerializer):
            reactor = NotificationUserSerializer()
            emoji = NotificationEmojiSerializer()
            post = NotificationPostSerializer()

            class Meta:
                model = PostReaction
                fields = ('id', 'reactor', 'emoji', 'post')

        self.NotificationPostReactionSerializer = NotificationPostReactionSerializer

        class NotificationCommunitySerializer(serializers.ModelSerializer):
            class Meta:
                model = Community
                fields = ('id', 'name', 'title')

        class NotificationCommunityInviteSerializer(serializers.ModelSerializer
                                                    ):
            creator = NotificationUserSerializer()
            invited_user = NotificationUserSerializer()
            community = NotificationCommunitySerializer()

            class Meta:
                model = CommunityInvite
                fields = ('id', 'creator', 'invited_user', 'community')

        self.NotificationCommunityInviteSerializer = NotificationCommunityInviteSerializer

        class NotificationPostCommentSerializer(serializers.ModelSerializer):
            commenter = NotificationUserSerializer()
            post = NotificationPostSerializer()

            class Meta:
                model = PostComment
                fields = ('id', 'commenter', 'post')

        self.NotificationPostCommentSerializer = NotificationPostCommentSerializer

        class NotificationPostCommentReplySerializer(
                serializers.ModelSerializer):
            commenter = NotificationUserSerializer()
            post = NotificationPostSerializer()

            class Meta:
                model = PostComment
                fields = ('id', 'commenter', 'post')

        self.NotificationPostCommentReplySerializer = NotificationPostCommentReplySerializer

        class FollowNotificationSerializer(serializers.Serializer):
            following_user = NotificationUserSerializer()

        self.FollowNotificationSerializer = FollowNotificationSerializer

        class ConnectionRequestNotificationSerializer(serializers.Serializer):
            connection_requester = NotificationUserSerializer()

        self.ConnectionRequestNotificationSerializer = ConnectionRequestNotificationSerializer
Ejemplo n.º 12
0
def curate_top_posts():
    """
    Curates the top posts.
    This job should be scheduled to be run every n hours.
    """
    Post = get_post_model()
    Community = get_community_model()
    PostComment = get_post_comment_model()
    ModeratedObject = get_moderated_object_model()
    TopPost = get_top_post_model()
    logger.info('Processing top posts at %s...' % timezone.now())

    top_posts_community_query = Q(top_post__isnull=True)
    top_posts_community_query.add(
        Q(community__isnull=False,
          community__type=Community.COMMUNITY_TYPE_PUBLIC), Q.AND)
    top_posts_community_query.add(
        Q(is_closed=False, is_deleted=False, status=Post.STATUS_PUBLISHED),
        Q.AND)
    top_posts_community_query.add(
        ~Q(moderated_object__status=ModeratedObject.STATUS_APPROVED), Q.AND)

    top_posts_criteria_query = Q(total_comments_count__gte=settings.MIN_UNIQUE_TOP_POST_COMMENTS_COUNT) | \
                               Q(reactions_count__gte=settings.MIN_UNIQUE_TOP_POST_REACTIONS_COUNT)

    posts_select_related = 'community'
    posts_prefetch_related = ('comments__commenter', 'reactions__reactor')
    posts_only = ('id', 'status', 'is_deleted', 'is_closed', 'community__type')

    posts = Post.objects. \
        select_related(posts_select_related). \
        prefetch_related(*posts_prefetch_related). \
        only(*posts_only). \
        filter(top_posts_community_query). \
        annotate(total_comments_count=Count('comments__commenter_id'),
                 reactions_count=Count('reactions__reactor_id')). \
        filter(top_posts_criteria_query)

    top_posts_objects = []
    total_checked_posts = 0
    total_curated_posts = 0

    for post in _chunked_queryset_iterator(posts, 1000):
        total_checked_posts = total_checked_posts + 1
        if not post.reactions_count >= settings.MIN_UNIQUE_TOP_POST_REACTIONS_COUNT:
            unique_comments_count = PostComment.objects.filter(post=post). \
                values('commenter_id'). \
                annotate(user_comments_count=Count('commenter_id')).count()

            if unique_comments_count >= settings.MIN_UNIQUE_TOP_POST_COMMENTS_COUNT:
                top_post = _add_post_to_top_post(post=post)
                if top_post is not None:
                    top_posts_objects.append(top_post)
        else:
            top_post = _add_post_to_top_post(post=post)
            if top_post is not None:
                top_posts_objects.append(top_post)

        if len(top_posts_objects) > 1000:
            TopPost.objects.bulk_create(top_posts_objects)
            total_curated_posts += len(top_posts_objects)
            top_posts_objects = []

    if len(top_posts_objects) > 0:
        total_curated_posts += len(top_posts_objects)
        TopPost.objects.bulk_create(top_posts_objects)

    return 'Checked: %d. Curated: %d' % (total_checked_posts,
                                         total_curated_posts)
Ejemplo n.º 13
0
def clean_top_posts():
    """
    Cleans up top posts, that no longer meet the criteria.
    """
    Post = get_post_model()
    Community = get_community_model()
    TopPost = get_top_post_model()
    PostComment = get_post_comment_model()
    ModeratedObject = get_moderated_object_model()

    # if any of these is true, we will remove the top post
    top_posts_community_query = Q(
        post__community__type=Community.COMMUNITY_TYPE_PRIVATE)
    top_posts_community_query.add(Q(post__is_closed=True), Q.OR)
    top_posts_community_query.add(Q(post__is_deleted=True), Q.OR)
    top_posts_community_query.add(Q(post__status=Post.STATUS_DRAFT), Q.OR)
    top_posts_community_query.add(Q(post__status=Post.STATUS_PROCESSING), Q.OR)
    top_posts_community_query.add(
        Q(post__moderated_object__status=ModeratedObject.STATUS_APPROVED),
        Q.OR)

    # counts less than minimum
    top_posts_criteria_query = Q(total_comments_count__lt=settings.MIN_UNIQUE_TOP_POST_COMMENTS_COUNT) & \
                               Q(reactions_count__lt=settings.MIN_UNIQUE_TOP_POST_REACTIONS_COUNT)

    posts_select_related = 'post__community'
    posts_prefetch_related = ('post__comments__commenter',
                              'post__reactions__reactor')
    posts_only = ('post__id', 'post__status', 'post__is_deleted',
                  'post__is_closed', 'post__community__type')

    direct_removable_top_posts = TopPost.objects.select_related(posts_select_related). \
        prefetch_related(*posts_prefetch_related). \
        only(*posts_only). \
        filter(top_posts_community_query). \
        annotate(total_comments_count=Count('post__comments__commenter_id'),
                 reactions_count=Count('post__reactions__reactor_id')). \
        filter(top_posts_criteria_query)

    # bulk delete all that definitely dont meet the criteria anymore
    direct_removable_top_posts.delete()

    # Now we need to only check the ones where the unique comments count might have dropped,
    # while all other criteria is fine

    top_posts_community_query = Q(
        post__community__isnull=False,
        post__community__type=Community.COMMUNITY_TYPE_PUBLIC)
    top_posts_community_query.add(
        Q(post__is_closed=False,
          post__is_deleted=False,
          post__status=Post.STATUS_PUBLISHED), Q.AND)
    top_posts_community_query.add(
        ~Q(post__moderated_object__status=ModeratedObject.STATUS_APPROVED),
        Q.AND)

    top_posts_criteria_query = Q(total_comments_count__gte=settings.MIN_UNIQUE_TOP_POST_COMMENTS_COUNT) | \
                               Q(reactions_count__gte=settings.MIN_UNIQUE_TOP_POST_REACTIONS_COUNT)

    top_posts = TopPost.objects.select_related(posts_select_related). \
        prefetch_related(*posts_prefetch_related). \
        only(*posts_only). \
        filter(top_posts_community_query). \
        annotate(total_comments_count=Count('post__comments__commenter_id'),
                 reactions_count=Count('post__reactions__reactor_id')). \
        filter(top_posts_criteria_query)

    delete_ids = []

    for top_post in _chunked_queryset_iterator(top_posts, 1000):
        if not top_post.reactions_count >= settings.MIN_UNIQUE_TOP_POST_REACTIONS_COUNT:
            unique_comments_count = PostComment.objects.filter(post=top_post.post). \
                values('commenter_id'). \
                annotate(user_comments_count=Count('commenter_id')).count()

            if unique_comments_count < settings.MIN_UNIQUE_TOP_POST_COMMENTS_COUNT:
                delete_ids.append(top_post.pk)

    # bulk delete ids
    TopPost.objects.filter(id__in=delete_ids).delete()
Ejemplo n.º 14
0
def post_comment_id_exists_for_post_with_uuid(post_comment_id, post_uuid):
    PostComment = get_post_comment_model()

    if not PostComment.objects.filter(id=post_comment_id,
                                      post__uuid=post_uuid).exists():
        raise ValidationError(_('The post comment does not exist.'), )