Пример #1
0
def add_to_subverbify_query_q(link):
    if g.shard_subverbify_query_queues:
        subverbify_shard = link.sr_id % 10
        queue_name = "subverbify_query_%s_q" % subverbify_shard
    else:
        queue_name = "subverbify_query_q"
    amqp.add_item(queue_name, link._fullname)
Пример #2
0
def add_to_author_query_q(link):
    if g.shard_author_query_queues:
        author_shard = link.author_id % 10
        queue_name = "author_query_%s_q" % author_shard
    else:
        queue_name = "author_query_q"
    amqp.add_item(queue_name, link._fullname)
Пример #3
0
def queue_modmail_email(message):
    amqp.add_item(
        "modmail_email_q",
        json.dumps({
            "event": "new_message",
            "message_id36": message._id36,
        }),
    )
Пример #4
0
def queue_blocked_muted_email(sr, parent, sender_email, incoming_email_id):
    amqp.add_item(
        "modmail_email_q",
        json.dumps({
            "event": "blocked_muted",
            "subverbify_id36": sr._id36,
            "parent_id36": parent._id36,
            "sender_email": sender_email,
            "incoming_email_id": incoming_email_id,
        }),
    )
Пример #5
0
def add_to_domain_query_q(link):
    parsed = UrlParser(link.url)
    if not parsed.domain_permutations():
        # no valid domains found
        return

    if g.shard_domain_query_queues:
        domain_shard = hash(parsed.hostname) % 10
        queue_name = "domain_query_%s_q" % domain_shard
    else:
        queue_name = "domain_query_q"
    amqp.add_item(queue_name, link._fullname)
Пример #6
0
def send_broadcast(namespace, type, payload):
    """Broadcast an object to all WebSocket listeners in a namespace.

    The message type is used to differentiate between different kinds of
    payloads that may be sent. The payload will be encoded as a JSON object
    before being sent to the client.

    """
    frame = {
        "type": type,
        "payload": payload,
    }
    amqp.add_item(routing_key=namespace,
                  body=json.dumps(frame),
                  exchange=_WEBSOCKET_EXCHANGE)
Пример #7
0
def _set_media(link, force=False, **kwargs):
    sr = link.subverbify_slow

    # Do not process thumbnails for quarantined subverbifys
    if sr.quarantine:
        return

    if not link.is_self:
        if not force and (link.has_thumbnail or link.media_object):
            return

    if not force and link.promoted:
        return

    scrape_url = _get_scrape_url(link)

    if not scrape_url:
        if link.preview_object:
            # If the user edited out an image from a self post, we need to make
            # sure to remove its metadata.
            link.set_preview_object(None)
            link._commit()
        return

    youtube_scraper = feature.is_enabled("youtube_scraper", subverbify=sr.name)
    media = _scrape_media(scrape_url,
                          force=force,
                          use_youtube_scraper=youtube_scraper,
                          **kwargs)

    if media and not link.promoted:
        # While we want to add preview images to self posts for the new apps,
        # let's not muck about with the old-style thumbnails in case that
        # breaks assumptions.
        if not link.is_self:
            link.thumbnail_url = media.thumbnail_url
            link.thumbnail_size = media.thumbnail_size

            link.set_media_object(media.media_object)
            link.set_secure_media_object(media.secure_media_object)
        link.set_preview_object(media.preview_object)

        link._commit()

        hooks.get_hook("scraper.set_media").call(link=link)

        if media.media_object or media.secure_media_object:
            amqp.add_item("new_media_embed", link._fullname)
Пример #8
0
def cast_vote(user, thing, direction, **data):
    """Register a vote and queue it for processing."""
    if not isinstance(thing, (Link, Comment)):
        return

    update_vote_lookups(user, thing, direction)

    vote_data = {
        "user_id": user._id,
        "thing_fullname": thing._fullname,
        "direction": direction,
        "date": int(epoch_timestamp(datetime.now(g.tz))),
    }

    data['ip'] = getattr(request, "ip", None)
    if data['ip'] is not None:
        data['org'] = organization_by_ips(data['ip'])
    vote_data['data'] = data

    hooks.get_hook("vote.get_vote_data").call(
        data=vote_data["data"],
        user=user,
        thing=thing,
        request=request,
        context=c,
    )

    # The vote event will actually be sent from an async queue processor, so
    # we need to pull out the context data at this point
    if not g.running_as_script:
        vote_data["event_data"] = {
            "context": Event.get_context_data(request, c),
            "sensitive": Event.get_sensitive_context_data(request, c),
        }

    try:
        vote_dump = json.dumps(vote_data)
    except UnicodeDecodeError:
        g.log.error("Got weird unicode in the vote data: %r", vote_data)
        return

    if isinstance(thing, Link):
        queue = "vote_link_q"
    elif isinstance(thing, Comment):
        queue = "vote_comment_q"

    amqp.add_item(queue, vote_dump)
Пример #9
0
    def unspam(self,
               things,
               moderator_unbanned=True,
               unbanner=None,
               train_spam=True,
               insert=True):
        from v1.lib.db import queries

        things = tup(things)

        # We want to make unban-all moderately efficient, so when
        # mass-unbanning, we're going to skip the code below on links that
        # are already not banned.  However, when someone manually clicks
        # "approve" on an unbanned link, and there's just one, we want do
        # want to run the code below. That way, the little green checkmark
        # will have the right mouseover details, the reports will be
        # cleared, etc.

        if len(things) > 1:
            things = [x for x in things if x._spam]

        Report.accept(things, False)
        for t in things:
            ban_info = copy(getattr(t, 'ban_info', {}))
            ban_info['unbanned_at'] = datetime.now(g.tz)
            if unbanner:
                ban_info['unbanner'] = unbanner
            if ban_info.get('reset_used', None) == None:
                ban_info['reset_used'] = False
            else:
                ban_info['reset_used'] = True
            t.ban_info = ban_info
            t._spam = False
            if moderator_unbanned:
                t.verdict = 'mod-approved'
            else:
                t.verdict = 'admin-approved'
            t._commit()

            if isinstance(t, Comment):
                amqp.add_item("approved_comment", t._fullname)
            elif isinstance(t, Link):
                amqp.add_item("approved_link", t._fullname)

        self.author_spammer(things, False)
        self.set_last_sr_ban(things)
        queries.unban(things, insert)
Пример #10
0
def backfill_deleted_accounts(resume_id=None):
    del_accts = Account._query(Account.c._deleted == True, sort=desc('_date'))
    if resume_id:
        del_accts._filter(Account.c._id < resume_id)

    for i, account in enumerate(progress(fetch_things2(del_accts))):
        # Don't kill the rabbit! Wait for the relevant queues to calm down.
        if i % 1000 == 0:
            del_len = get_queue_length('del_account_q')
            cs_len = get_queue_length('cloudsearch_changes')
            while (del_len > 1000 or
                    cs_len > 10000):
                sys.stderr.write(("CS: %d, DEL: %d" % (cs_len, del_len)) + "\n")
                sys.stderr.flush()
                time.sleep(1)
                del_len = get_queue_length('del_account_q')
                cs_len = get_queue_length('cloudsearch_changes')
        amqp.add_item('account_deleted', account._fullname)
Пример #11
0
    def delete(self, delete_message=None):
        self.delete_message = delete_message
        self.delete_time = datetime.now(g.tz)
        self._deleted = True
        self._commit()

        #update caches
        Account._by_name(self.name, allow_deleted=True, _update=True)
        #we need to catch an exception here since it will have been
        #recently deleted
        try:
            Account._by_name(self.name, _update=True)
        except NotFound:
            pass

        # Mark this account for immediate cleanup tasks
        amqp.add_item('account_deleted', self._fullname)

        # schedule further cleanup after a possible recovery period
        TryLater.schedule("account_deletion",
                          self._id36,
                          delay=timedelta(days=90))
Пример #12
0
    def processor(msgs, chan):
        events = []
        test_events = []

        for msg in msgs:
            headers = msg.properties.get("application_headers", {})
            truncatable_field = headers.get("truncatable_field")

            event = PublishableEvent(msg.body, truncatable_field)
            if msg.delivery_info["routing_key"] == "event_collector_test":
                test_events.append(event)
            else:
                events.append(event)

        to_publish = itertools.chain(
            publisher.publish(events),
            test_publisher.publish(test_events),
        )
        for response, sent in to_publish:
            if response.ok:
                g.log.info("Published %s events", len(sent))
            else:
                g.log.warning(
                    "Event send failed %s - %s",
                    response.status_code,
                    _get_reason(response),
                )
                g.log.warning("Response headers: %r", response.headers)

                # if the events were too large, move them into a separate
                # queue to get them out of here, since they'll always fail
                if response.status_code == 413:
                    for event in sent:
                        amqp.add_item("event_collector_failed", event)
                else:
                    response.raise_for_status()
Пример #13
0
def handle_register(controller,
                    form,
                    responder,
                    name,
                    email,
                    password,
                    rem=None,
                    newsletter_subscribe=False,
                    sponsor=False,
                    signature=None,
                    **kwargs):
    def _event(error):
        g.events.login_event('register_attempt',
                             error_msg=error,
                             user_name=request.urlvars.get('url_user'),
                             email=request.POST.get('email'),
                             remember_me=rem,
                             newsletter=newsletter_subscribe,
                             signature=signature,
                             request=request,
                             context=c)

    if signature and not signature.is_valid():
        _event(error="SIGNATURE")
        abort(403)

    if responder.has_errors('user', errors.USERNAME_TOO_SHORT):
        _event(error='USERNAME_TOO_SHORT')

    elif responder.has_errors('user', errors.USERNAME_INVALID_CHARACTERS):
        _event(error='USERNAME_INVALID_CHARACTERS')

    elif responder.has_errors('user', errors.USERNAME_TAKEN_DEL):
        _event(error='USERNAME_TAKEN_DEL')

    elif responder.has_errors('user', errors.USERNAME_TAKEN):
        _event(error='USERNAME_TAKEN')

    elif responder.has_errors('email', errors.BAD_EMAIL):
        _event(error='BAD_EMAIL')

    elif responder.has_errors('passwd', errors.SHORT_PASSWORD):
        _event(error='SHORT_PASSWORD')

    elif responder.has_errors('passwd', errors.BAD_PASSWORD):
        # BAD_PASSWORD is set when SHORT_PASSWORD is set
        _event(error='BAD_PASSWORD')

    elif responder.has_errors('passwd2', errors.BAD_PASSWORD_MATCH):
        _event(error='BAD_PASSWORD_MATCH')

    elif responder.has_errors('ratelimit', errors.RATELIMIT):
        _event(error='RATELIMIT')

    elif (not g.disable_captcha
          and responder.has_errors('captcha', errors.BAD_CAPTCHA)):
        _event(error='BAD_CAPTCHA')

    elif newsletter_subscribe and not email:
        c.errors.add(errors.NEWSLETTER_NO_EMAIL, field="email")
        form.has_errors("email", errors.NEWSLETTER_NO_EMAIL)
        _event(error='NEWSLETTER_NO_EMAIL')

    elif sponsor and not email:
        c.errors.add(errors.SPONSOR_NO_EMAIL, field="email")
        form.has_errors("email", errors.SPONSOR_NO_EMAIL)
        _event(error='SPONSOR_NO_EMAIL')

    else:
        try:
            user = register(name, password, request.ip)
        except AccountExists:
            c.errors.add(errors.USERNAME_TAKEN, field="user")
            form.has_errors("user", errors.USERNAME_TAKEN)
            _event(error='USERNAME_TAKEN')
            return

        VRatelimit.ratelimit(rate_ip=True, prefix="rate_register_")

        # anything else we know (email, languages)?
        if email:
            user.set_email(email)
            emailer.verify_email(user)

        user.pref_lang = c.lang
        user._commit()

        amqp.add_item('new_account', user._fullname)

        hooks.get_hook("account.registered").call(user=user)

        reject = hooks.get_hook("account.spotcheck").call(account=user)
        if any(reject):
            _event(error='ACCOUNT_SPOTCHECK')
            return

        if newsletter_subscribe and email:
            try:
                newsletter.add_subscriber(email, source="register")
            except newsletter.NewsletterError as e:
                g.log.warning("Failed to subscribe: %r" % e)

        controller._login(responder, user, rem)
        _event(error=None)
Пример #14
0
    def spam(self,
             things,
             auto=True,
             moderator_banned=False,
             banner=None,
             date=None,
             train_spam=True,
             **kw):
        from v1.lib.db import queries

        all_things = tup(things)
        new_things = [x for x in all_things if not x._spam]

        Report.accept(all_things, True)

        for t in all_things:
            if getattr(t, "promoted", None) is not None:
                g.log.debug("Refusing to mark promotion %r as spam" % t)
                continue

            if not t._spam and train_spam:
                note = 'spam'
            elif not t._spam and not train_spam:
                note = 'remove not spam'
            elif t._spam and not train_spam:
                note = 'confirm spam'
            elif t._spam and train_spam:
                note = 'reinforce spam'

            t._spam = True

            if moderator_banned:
                t.verdict = 'mod-removed'
            elif not auto:
                t.verdict = 'admin-removed'

            ban_info = copy(getattr(t, 'ban_info', {}))
            if isinstance(banner, dict):
                ban_info['banner'] = banner[t._fullname]
            else:
                ban_info['banner'] = banner
            ban_info.update(auto=auto,
                            moderator_banned=moderator_banned,
                            banned_at=date or datetime.now(g.tz),
                            **kw)
            ban_info['note'] = note

            t.ban_info = ban_info
            t._commit()

            if auto:
                amqp.add_item("auto_removed", t._fullname)

        if not auto:
            self.author_spammer(new_things, True)
            self.set_last_sr_ban(new_things)

        queries.ban(all_things, filtered=auto)

        for t in all_things:
            if auto:
                amqp.add_item("auto_removed", t._fullname)

            if isinstance(t, Comment):
                amqp.add_item("removed_comment", t._fullname)
            elif isinstance(t, Link):
                amqp.add_item("removed_link", t._fullname)