Beispiel #1
0
def create_post(user, sync=False, **kw):
    """ Creates a proper platform Post given a user and post components.
        Special args:
        sync - <bool:default=False> forces synchronous postprocessing
        skip_acl_check - <bool:default=False> creates post w/o checking acl permissions on parent channel (e.g. bots)
    """
    """ Creates a proper platform Post given a user and post components.

        Special args:

        sync - <bool:default=False> forces synchronous postprocessing
    """
    # Set user in thread local storage
    from solariat_bottle.db.user import set_user
    set_user(user)

    from solariat_bottle.db.post.utils import get_platform_class
    from solariat_bottle.utils.post import get_language
    from solariat_bottle.db.channel.base import Channel
    from solariat_bottle.utils.posts_tracking import log_state, PostState, get_post_natural_id

    log_state(kw.get('channel', kw.get('channels', None)),
              get_post_natural_id(kw), PostState.DELIVERED_TO_TANGO)

    post_lang = get_language(kw)
    if post_lang.support_level == Support.NO:
        logger.info("Detect message for unsupported language: %s" %
                    post_lang.lang)
        logger.info("Unsupported message value is: %s" % str(kw))
        return
    else:
        kw['lang'] = post_lang
    kw = normalize_post_params(user, kw)
    klass = get_platform_class(kw['_platform'], event_type=kw['event_type'])

    # we have channels resolved in normalize_post_params
    channels = kw['channels']
    accounts = set([ch.account for ch in channels])
    for account in accounts:
        if _check_account_volume(user, account):
            msg = u"Account '{} ({})' has reached its monthly volume threshold.".format(
                account.name, account.id)
            LOGGER.warning(msg)
        if _check_account_daily_volume(user, account):
            msg = u"Account '{} ({})' has reached its daily volume threshold.".format(
                account.name, account.id)
            LOGGER.warning(msg)

    return klass.objects.create_by_user(user,
                                        safe_create=True,
                                        sync=sync,
                                        **kw)
Beispiel #2
0
    def create_by_user(self, user, **kw):
        post_lang = get_language(kw)
        kw['lang'] = post_lang

        if 'content' not in kw:
            kw['content'] = 'No verbatim provided'

        assert kw.get('case_number'), kw
        kw['is_inbound'] = True
        kw['safe_create'] = True
        # We need to override posts for NPS,
        # so we need to check if post exist,
        # if post exist let remove it and re-create
        if kw.get('actor_id'):
            CustomerProfile = user.account.get_customer_profile_class()
            actor_num = CustomerProfile.objects.get(
                kw.get('actor_id')).actor_num
        elif kw.get('user_profile'):
            # TODO: [gsejop] create anonymous CustomerProfile?
            # actor_num = kw['user_profile'].customer_profile.actor_num
            actor_num = kw['user_profile'].actor_num
        else:
            actor_num = 0

        if kw['user_profile']:
            kw['profile_data'] = kw['user_profile'].data
        nps_event_id = pack_event_id(actor_num, kw['_created'])
        try:
            nps_post = self.get(id=nps_event_id)
            raise Exception('NPSOutcome with nps_event_id: %s exists already' %
                            nps_event_id)
        except NPSOutcome.DoesNotExist:
            pass
        try:
            nps_post = NPSOutcome.get_by_native_id(kw['native_id'])
            raise Exception('NPSOutcome with native_id: %s exists already' %
                            kw['native_id'])
        except NPSOutcome.DoesNotExist:
            pass

        normalize_post_params(user, kw)
        post = super(NPSOutcomeManager, self).create_by_user(user, **kw)
        # self._postprocess_new_post(user, post, sync)
        # _set_channel_and_tag_assignments(post)

        # post.compute_journey_information()  # why we needed this? PostManager.create_by_user already did this
        return post
Beispiel #3
0
 def test_unicode(self):
     post_dict = dict(content=u'\u0938\u0941\u091c\u0928')
     lang = get_language(post_dict)
     self.assertIn(lang.lang, ['ja', 'hi'])
Beispiel #4
0
 def test_invalid_utf(self):
     post_dict = dict(content="\xc3\x28")
     lang = get_language(post_dict)
     self.assertEqual(lang.lang, 'en')
Beispiel #5
0
 def test_invalid_text(self):
     post_dict = dict(content='$$$')
     lang = get_language(post_dict)
     self.assertEqual(lang.lang, 'en')
Beispiel #6
0
def lookup_tracked_channels(platform_name, post, keywords=None, logger=LOGGER):
    from solariat_bottle.db.channel.base import Channel
    from solariat_bottle.db.channel.twitter import get_sync_usernames_list, \
        KeywordTrackingChannel
    from solariat_bottle.db.tracking import PostFilterEntry, \
        PostFilterEntryPassive, PostFilterStream, get_filter_type_id
    from solariat_bottle.utils.post import get_language, is_retweet, \
        get_service_channel_memoized

    F = PostFilterEntry.F
    normalize = TrackingNLP.normalize_kwd

    post['lang'] = get_language(post)
    lang_code = post['lang'].lang

    if keywords is None:
        keywords = TrackingNLP.extract_all(post)

    def safe_channels(filter_channel_map):
        channel_id_filter_map = defaultdict(set)
        for filter_id, (filter_type,
                        channel_refs) in filter_channel_map.iteritems():
            for ref in channel_refs:
                channel_id_filter_map[ref.id].add((filter_id, filter_type))

        expected_channel_ids = channel_id_filter_map.keys()
        channels = list(
            Channel.objects.coll.find({
                Channel.F.id: {
                    "$in": expected_channel_ids
                },
                Channel.F.status: {
                    "$in": ['Active', 'Interim']
                }
            }))
        channels = map(Channel, channels)
        active_channel_ids = set(ch.id for ch in channels)
        missing_channels = set(expected_channel_ids) - active_channel_ids

        if missing_channels:
            from solariat.db.abstract import DBRef
            models = {ACTIVE: PostFilterEntry, PASSIVE: PostFilterEntryPassive}
            for channel_id in missing_channels:
                channel_ref = DBRef('Channel', channel_id)
                for filter_id, filter_type in channel_id_filter_map[
                        channel_id]:
                    model = models[filter_type]
                    logger.warning("Channel pulled from %s(%s): %s" %
                                   (model.__name__, filter_id, channel_id))
                    model.objects.coll.update(
                        {"_id": filter_id},
                        {"$pull": {
                            model.F('channels'): channel_ref
                        }})
            PostFilterStream.refresh_stats()
            PostFilterEntry.objects.remove(channels=[])
        return channels

    filter_channel_refs_map = {}
    ACTIVE = 0
    PASSIVE = 1
    post_filter_query = {
        F.entry: {
            "$in": keywords
        },
        F.filter_type_id: get_filter_type_id('KEYWORD')
    }
    if lang_code in LANG_CODES:
        post_filter_query[F.lang] = lang_code

    for item in PostFilterEntry.objects.coll.find(post_filter_query,
                                                  fields={F.channels: True}):
        filter_channel_refs_map[item['_id']] = (ACTIVE, item[F.channels])

    sender_user_ids, sender_user_screen_names, recipient_user_screen_names = get_twitter_post_users(
        post)
    user_screen_names = get_sync_usernames_list(
        [name.lower() for name in set(sender_user_screen_names)])
    recipient_user_screen_names = get_sync_usernames_list(
        [name.lower() for name in set(recipient_user_screen_names)])

    if recipient_user_screen_names:
        # lookup recipients among keywords
        for item in PostFilterEntry.objects.coll.find(
            {
                F.entry: {
                    "$in": recipient_user_screen_names
                },
                F.filter_type_id: get_filter_type_id('KEYWORD')
            },
                fields={F.channels: True}):
            filter_channel_refs_map[item['_id']] = (ACTIVE, item[F.channels])

    if user_screen_names:
        # lookup senders among tracked screen names
        for item in PostFilterEntry.objects.coll.find(
            {
                F.entry: {
                    "$in": user_screen_names
                },
                F.filter_type_id: get_filter_type_id('USER_NAME')
            },
                fields={F.channels: True}):
            filter_channel_refs_map[item['_id']] = (ACTIVE, item[F.channels])

    if sender_user_ids:
        # lookup senders among tracked user ids
        for item in PostFilterEntry.objects.coll.find({
                F.entry: {
                    "$in": sender_user_ids
                },
                F.filter_type_id:
                get_filter_type_id('USER_ID')
        }):
            filter_channel_refs_map[item['_id']] = (ACTIVE, item[F.channels])

        for item in PostFilterEntryPassive.objects.coll.find(
            {F.entry: {
                "$in": sender_user_ids
            }}):
            filter_channel_refs_map[item['_id']] = (PASSIVE, item[F.channels])

    channels = safe_channels(filter_channel_refs_map)
    # for channel in list(channels):
    #     if isinstance(channel, KeywordTrackingChannel) and \
    #             set(map(normalize, channel.skipwords)).intersection(set(
    #                     LingualToken.extend_langifyed(keywords, lang=lang_code))):
    #         channels.remove(channel)

    if platform_name == 'Twitter' and is_retweet(post):
        service_channel_map = {
            c: get_service_channel_memoized(c)
            for c in channels
        }
        for channel, sc in service_channel_map.iteritems():
            if sc:
                try:
                    sc.reload()
                except Channel.DoesNotExist:
                    channels.remove(channel)
                    continue

            if sc and sc.skip_retweets is True:
                logger.debug('skipping retweet "%s" for channel %s' %
                             (post['content'], channel))
                channels.remove(channel)

    # For direct messages, also make sure that all the channels actually have access to it
    if post.pop('direct_message', False):
        logger.debug('extra-filtering channels for a direct message')
        sender_handle = post.pop('sender_handle', False)
        recipient_handle = post.pop('recipient_handle', False)
        if not (sender_handle and recipient_handle):
            # We don't have a handle so we don't know who this is adressed to.
            # Just return empty list.
            logger.warning(
                "Need a sender and reciever handle in order to process direct messages, but got none."
            )
            return []
        channels = [
            c for c in channels
            if (get_service_channel_memoized(c)
                and c.has_private_access(sender_handle, recipient_handle))
        ]

    tracked_channels = [c for c in channels if c.platform == platform_name]
    # if app_mode == 'test':
    #     try:
    #         LOGGER.debug(u'channels for post %s\n%s' % (u'%s %s' % (post['content'], post['user_profile']['user_name']),
    #                                                     '\n'.join(u"%s[%s]" % (ch.title, ch) for ch in tracked_channels)))
    #     except:
    #         pass
    return tracked_channels