<commit_before>import logging
from bson.objectid import ObjectId
from eve.utils import ParsedRequest
from superdesk.notification import push_notification
from superdesk.resource import Resource, build_custom_hateoas
from superdesk import get_resource_service
from apps.archive import ArchiveVersionsResource
from apps.archive.archive import ArchiveResource, ArchiveService
from superdesk.services import BaseService
from superdesk.metadata.packages import LINKED_IN_PACKAGES
from flask import current_app as app
import flask
from superdesk.utc import utcnow
from superdesk.users.services import current_user_has_privilege
from superdesk.errors import SuperdeskApiError
from superdesk import get_resource_service
from liveblog.common import check_comment_length


logger = logging.getLogger('superdesk')
DEFAULT_POSTS_ORDER = [('order', -1), ('firstcreated', -1)]


def private_draft_filter():
    """Filter out users private drafts.
    As private we treat items where user is creator
    """
    private_filter = {'should': [{'term': {'post_status': 'open'}},
                                 {'term': {'post_status': 'submitted'}},
                                 {'term': {'post_status': 'comment'}}]}
    user = getattr(flask.g, 'user', None)
    if user:
        private_filter['should'].append(
            {'term': {'original_creator': str(user['_id'])}}
        )
    return {'bool': private_filter}


class PostsVersionsResource(ArchiveVersionsResource):
    """
    Resource class for versions of archive_media
    """

    datasource = {
        'source': 'archive' + '_versions',
        'filter': {'type': 'composite'}
    }


class PostsVersionsService(BaseService):
    def get(self, req, lookup):
        if req is None:
            req = ParsedRequest()
        return self.backend.get('archive_versions', req=req, lookup=lookup)


class PostsResource(ArchiveResource):
    datasource = {
        'source': 'archive',
        'elastic_filter_callback': private_draft_filter,
        'elastic_filter': {'term': {'particular_type': 'post'}},
        'default_sort': DEFAULT_POSTS_ORDER
    }

    item_methods = ['GET', 'PATCH', 'DELETE']

    schema = {}
    schema.update(ArchiveResource.schema)
    schema.update({
        'blog': Resource.rel('blogs', True),
        'particular_type': {
            'type': 'string',
            'allowed': ['post', 'item'],
            'default': 'post'
        },
        'post_status': {
            'type': 'string',
            'allowed': ['open', 'draft', 'submitted', 'comment'],
            'default': 'open'
        },
        'highlight': {
            'type': 'boolean',
            'default': False
        },
        'sticky': {
            'type': 'boolean',
            'default': False
        },
        'deleted': {
            'type': 'boolean',
            'default': False
        },
        'order': {
            'type': 'float',
            'default': 0.00
        },
        'published_date': {
            'type': 'datetime'
        },
        'unpublished_date': {
            'type': 'datetime'
        },
        'publisher': Resource.rel('users', True),
        'content_updated_date': {
            'type': 'datetime'
        },
        'syndication_in': Resource.rel('syndication_in', embeddable=True, required=False, nullable=True),
        'producer_post_id': {
            'type': 'string',
            'nullable': True
        }
    })
    privileges = {'GET': 'posts', 'POST': 'posts', 'PATCH': 'posts', 'DELETE': 'posts'}


class PostsService(ArchiveService):
    def find_one(self, req, **lookup):
        doc = super().find_one(req, **lookup)
        try:
            # include items in the response
            for assoc in self.packageService._get_associations(doc):
                if assoc.get('residRef'):
                    item = get_resource_service('archive').find_one(req=None, _id=assoc['residRef'])
                    assoc['item'] = item
        except Exception:
            pass
        return doc

    def get_next_order_sequence(self, blog_id):
        if blog_id is None:
            return 0.00
        # get next order sequence and increment it
        blog = get_resource_service('blogs').find_and_modify(
            query={'_id': blog_id},
            update={'$inc': {'posts_order_sequence': 1}},
            upsert=False)
        if blog:
            order = blog and blog.get('posts_order_sequence') or None
            # support previous LB version when the sequence was not save into the blog
            if order is None:
                # find the highest order in the blog
                req = ParsedRequest()
                req.sort = '-order'
                req.max_results = 1
                post = next(self.get_from_mongo(req=req, lookup={'blog': blog_id}), None)
                if post and post.get('order') is not None:
                    order = post.get('order') + 1
                    # save the order into the blog
                    get_resource_service('blogs').update(blog_id, {'posts_order_sequence': order + 1}, blog)
                else:
                    order = 0.00
        else:
            order = 0.00
        return float(order)

    def check_post_permission(self, post):
        to_be_checked = (
            dict(status='open', privilege_required='publish_post'),
            dict(status='submitted', privilege_required='submit_post')
        )
        for rule in to_be_checked:
            if 'post_status' in post and post['post_status'] == rule['status']:
                if not current_user_has_privilege(rule['privilege_required']):
                    raise SuperdeskApiError.forbiddenError(
                        message='User does not have sufficient permissions.')

    def on_create(self, docs):
        for doc in docs:
            # check permission
            self.check_post_permission(doc)
            doc['type'] = 'composite'
            doc['order'] = self.get_next_order_sequence(doc.get('blog'))
            # if you publish a post directly which is not a draft it will have a published_date assigned
            if doc['post_status'] == 'open':
                doc['published_date'] = utcnow()
                doc['content_updated_date'] = doc['published_date']
                doc['publisher'] = getattr(flask.g, 'user', None)
        super().on_create(docs)

    def on_created(self, docs):
        super().on_created(docs)
        # invalidate cache for updated blog
        post_ids = []
        out_service = get_resource_service('syndication_out')
        for doc in docs:
            post_ids.append(doc.get('_id'))
            app.blog_cache.invalidate(doc.get('blog'))
            # send post to consumer webhook
            if doc['post_status'] == 'open':
                logger.info('Send document to consumers (if syndicated): {}'.format(doc['_id']))
                out_service.send_syndication_post(doc, action='created')

        # send notifications
        push_notification('posts', created=True, post_status=doc['post_status'], post_ids=post_ids)

    def on_update(self, updates, original):
        # check if the timeline is reordered
        if updates.get('order'):
            blog = get_resource_service('blogs').find_one(req=None, _id=original['blog'])
            if blog['posts_order_sequence'] == updates['order']:
                blog['posts_order_sequence'] = self.get_next_order_sequence(original.get('blog'))
        # in the case we have a comment
        if original['post_status'] == 'comment':
            original['blog'] = original['groups'][1]['refs'][0]['item']['client_blog']
            updates['blog'] = original['groups'][1]['refs'][0]['item']['client_blog']
            # if the length of the comment is not between 1 and 300 then we get an error
            check_comment_length(original['groups'][1]['refs'][0]['item']['text'])
        # check if updates `content` is diffrent then the original.
        content_diff = False
        if not updates.get('groups', False):
            content_diff = False
        elif len(original['groups'][1]['refs']) != len(updates['groups'][1]['refs']):
            content_diff = True
        else:
            for index, val in enumerate(updates['groups'][1]['refs']):
                item = get_resource_service('archive').find_one(req=None, _id=val['residRef'])
                if item['text'] != original['groups'][1]['refs'][index]['item']['text']:
                    content_diff = True
                    break
        if content_diff:
            updates['content_updated_date'] = utcnow()

        # assure that the item is keept if the content wasn't changed.
        if not content_diff and updates.get('groups', False):<commit_msg>Modified the on create push notification<commit_after>import logging
from bson.objectid import ObjectId
from eve.utils import ParsedRequest
from superdesk.notification import push_notification
from superdesk.resource import Resource, build_custom_hateoas
from superdesk import get_resource_service
from apps.archive import ArchiveVersionsResource
from apps.archive.archive import ArchiveResource, ArchiveService
from superdesk.services import BaseService
from superdesk.metadata.packages import LINKED_IN_PACKAGES
from flask import current_app as app
import flask
from superdesk.utc import utcnow
from superdesk.users.services import current_user_has_privilege
from superdesk.errors import SuperdeskApiError
from superdesk import get_resource_service
from liveblog.common import check_comment_length


logger = logging.getLogger('superdesk')
DEFAULT_POSTS_ORDER = [('order', -1), ('firstcreated', -1)]


def private_draft_filter():
    """Filter out users private drafts.
    As private we treat items where user is creator
    """
    private_filter = {'should': [{'term': {'post_status': 'open'}},
                                 {'term': {'post_status': 'submitted'}},
                                 {'term': {'post_status': 'comment'}}]}
    user = getattr(flask.g, 'user', None)
    if user:
        private_filter['should'].append(
            {'term': {'original_creator': str(user['_id'])}}
        )
    return {'bool': private_filter}


class PostsVersionsResource(ArchiveVersionsResource):
    """
    Resource class for versions of archive_media
    """

    datasource = {
        'source': 'archive' + '_versions',
        'filter': {'type': 'composite'}
    }


class PostsVersionsService(BaseService):
    def get(self, req, lookup):
        if req is None:
            req = ParsedRequest()
        return self.backend.get('archive_versions', req=req, lookup=lookup)


class PostsResource(ArchiveResource):
    datasource = {
        'source': 'archive',
        'elastic_filter_callback': private_draft_filter,
        'elastic_filter': {'term': {'particular_type': 'post'}},
        'default_sort': DEFAULT_POSTS_ORDER
    }

    item_methods = ['GET', 'PATCH', 'DELETE']

    schema = {}
    schema.update(ArchiveResource.schema)
    schema.update({
        'blog': Resource.rel('blogs', True),
        'particular_type': {
            'type': 'string',
            'allowed': ['post', 'item'],
            'default': 'post'
        },
        'post_status': {
            'type': 'string',
            'allowed': ['open', 'draft', 'submitted', 'comment'],
            'default': 'open'
        },
        'highlight': {
            'type': 'boolean',
            'default': False
        },
        'sticky': {
            'type': 'boolean',
            'default': False
        },
        'deleted': {
            'type': 'boolean',
            'default': False
        },
        'order': {
            'type': 'float',
            'default': 0.00
        },
        'published_date': {
            'type': 'datetime'
        },
        'unpublished_date': {
            'type': 'datetime'
        },
        'publisher': Resource.rel('users', True),
        'content_updated_date': {
            'type': 'datetime'
        },
        'syndication_in': Resource.rel('syndication_in', embeddable=True, required=False, nullable=True),
        'producer_post_id': {
            'type': 'string',
            'nullable': True
        }
    })
    privileges = {'GET': 'posts', 'POST': 'posts', 'PATCH': 'posts', 'DELETE': 'posts'}


class PostsService(ArchiveService):
    def find_one(self, req, **lookup):
        doc = super().find_one(req, **lookup)
        try:
            # include items in the response
            for assoc in self.packageService._get_associations(doc):
                if assoc.get('residRef'):
                    item = get_resource_service('archive').find_one(req=None, _id=assoc['residRef'])
                    assoc['item'] = item
        except Exception:
            pass
        return doc

    def get_next_order_sequence(self, blog_id):
        if blog_id is None:
            return 0.00
        # get next order sequence and increment it
        blog = get_resource_service('blogs').find_and_modify(
            query={'_id': blog_id},
            update={'$inc': {'posts_order_sequence': 1}},
            upsert=False)
        if blog:
            order = blog and blog.get('posts_order_sequence') or None
            # support previous LB version when the sequence was not save into the blog
            if order is None:
                # find the highest order in the blog
                req = ParsedRequest()
                req.sort = '-order'
                req.max_results = 1
                post = next(self.get_from_mongo(req=req, lookup={'blog': blog_id}), None)
                if post and post.get('order') is not None:
                    order = post.get('order') + 1
                    # save the order into the blog
                    get_resource_service('blogs').update(blog_id, {'posts_order_sequence': order + 1}, blog)
                else:
                    order = 0.00
        else:
            order = 0.00
        return float(order)

    def check_post_permission(self, post):
        to_be_checked = (
            dict(status='open', privilege_required='publish_post'),
            dict(status='submitted', privilege_required='submit_post')
        )
        for rule in to_be_checked:
            if 'post_status' in post and post['post_status'] == rule['status']:
                if not current_user_has_privilege(rule['privilege_required']):
                    raise SuperdeskApiError.forbiddenError(
                        message='User does not have sufficient permissions.')

    def on_create(self, docs):
        for doc in docs:
            # check permission
            self.check_post_permission(doc)
            doc['type'] = 'composite'
            doc['order'] = self.get_next_order_sequence(doc.get('blog'))
            # if you publish a post directly which is not a draft it will have a published_date assigned
            if doc['post_status'] == 'open':
                doc['published_date'] = utcnow()
                doc['content_updated_date'] = doc['published_date']
                doc['publisher'] = getattr(flask.g, 'user', None)
        super().on_create(docs)

    def on_created(self, docs):
        super().on_created(docs)
        # invalidate cache for updated blog
        posts = []
        out_service = get_resource_service('syndication_out')
        for doc in docs:
            post = {}
            post['id'] = doc.get('_id')
            post['syndication_in'] = doc.get('syndication_in')
            posts.append(post)
            # post_ids.append({ id: doc.get('_id'), str('syndication_in'): doc.get('syndication_in')})
            app.blog_cache.invalidate(doc.get('blog'))
            # send post to consumer webhook
            if doc['post_status'] == 'open':
                logger.info('Send document to consumers (if syndicated): {}'.format(doc['_id']))
                out_service.send_syndication_post(doc, action='created')

        # send notifications
        push_notification('posts', created=True, post_status=doc['post_status'], posts=posts)

    def on_update(self, updates, original):
        # check if the timeline is reordered
        if updates.get('order'):
            blog = get_resource_service('blogs').find_one(req=None, _id=original['blog'])
            if blog['posts_order_sequence'] == updates['order']:
                blog['posts_order_sequence'] = self.get_next_order_sequence(original.get('blog'))
        # in the case we have a comment
        if original['post_status'] == 'comment':
            original['blog'] = original['groups'][1]['refs'][0]['item']['client_blog']
            updates['blog'] = original['groups'][1]['refs'][0]['item']['client_blog']
            # if the length of the comment is not between 1 and 300 then we get an error
            check_comment_length(original['groups'][1]['refs'][0]['item']['text'])
        # check if updates `content` is diffrent then the original.
        content_diff = False
        if not updates.get('groups', False):
            content_diff = False
        elif len(original['groups'][1]['refs']) != len(updates['groups'][1]['refs']):
            content_diff = True
        else:
            for index, val in enumerate(updates['groups'][1]['refs']):
                item = get_resource_service('archive').find_one(req=None, _id=val['residRef'])
                if item['text'] != original['groups'][1]['refs'][index]['item']['text']:
                    content_diff = True
                    break
        if content_diff:
            updates['content_updated_date'] = utcnow()

        # assure that the item is keept if the content wasn't changed.
        if not content_diff and updates.get('groups', False):
{'fraction_non_alphanumeric': 0.12680359870989646, 'fraction_numerical': 0.0036213432920273866, 'mean_word_length': 2.31906103286385, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7635020', 'n_tokens_mistral': 4946, 'n_tokens_neox': 4783, 'n_words': 1192}