Пример #1
0
def add_notification_override(request):
    """
    Tags: notifications
    ---
    Add a notification override with the specified properties
    ---
    notification:
      in: path
      type: string
      required: true
    """
    auth_context = auth_context_from_request(request)
    params = params_from_request(request)
    ntf_id = params.get("notification_id")
    if not ntf_id:
        raise RequiredParameterMissingError("notification_id")
    try:
        ntf = Notification.objects.get(id=ntf_id, owner=auth_context.owner)
        ntf.channel.dismiss(auth_context.user)
    except Notification.DoesNotExist:
        raise NotFoundError()
    try:
        np = UserNotificationPolicy.objects.get(owner=auth_context.owner,
                                                user_id=auth_context.user.id)
    except UserNotificationPolicy.DoesNotExist:
        np = UserNotificationPolicy(owner=auth_context.owner,
                                    user_id=auth_context.user.id)
    if not np.has_overriden(ntf):
        override = NotificationOverride()
        override.rid = ntf.rid
        override.rtype = ntf.rtype
        override.channel = ntf.channel.ctype
        np.overrides.append(override)
        np.save()
        # Dismiss relevant notifications in order to not show up again.
        InAppNotification.objects(
            owner=auth_context.owner,
            rid=ntf.rid,
            rtype=ntf.rtype,
            dismissed_by__ne=auth_context.user.id).update(
                push__dismissed_by=auth_context.user.id)
    return Response('OK', 200)
Пример #2
0
def request_unsubscription(request):
    """
    Tags: notifications
    ---
    Returns an unsubscription request page.
    Accepts a request, validates the unsubscribe token and returns a rendered
    template, with a link and another token to confirm unsubscribing.
    ---
    """
    params = params_from_request(request)

    # Decrypt URL params.
    try:
        decrypted_str = decrypt(params["token"])
        decrypted_json = json.loads(decrypted_str)
    except Exception as exc:
        log.exception(repr(exc))
        raise BadRequestError(ERROR_MSG)

    # Verify HMAC.
    try:
        mac_verify(decrypted_json)
    except Exception as exc:
        raise BadRequestError(exc)

    try:
        org_id = decrypted_json["org_id"]
    except KeyError as err:
        log.exception(repr(err))
        raise BadRequestError(ERROR_MSG)

    # Get Organization.
    try:
        org = Organization.objects.get(id=org_id)
    except Organization.DoesNotExist:
        raise OrganizationNotFound()

    # Verify required parameters are present.
    rid = decrypted_json.get("rid", "")
    rtype = decrypted_json.get("rtype", "")
    email = decrypted_json.get("email")
    user_id = decrypted_json.get("user_id")
    channel = decrypted_json.get("channel")
    if not (email or user_id) and channel in CHANNELS:
        log.critical("Got invalid/insufficient data: %s", decrypted_json)
        raise BadRequestError(ERROR_MSG)

    inputs = {
        "uri": config.CORE_URI,
        "csrf_token": get_csrf_token(request),
        "rid": rid,
        "rype": rtype,
        "channel": channel,
        "org": org.id
    }

    unsubscribe_options = [{"id": "all", "title": "all mist.io emails"}]
    if channel == "EmailReports":
        unsubscribe_options.insert(0, {
            "id": "channel",
            "title": "mist.io weekly reports"
        })
    else:  # channel == "EmailAlert":
        unsubscribe_options.insert(0, {
            "id": "channel",
            "title": "all mist.io email alerts"
        })
        if rtype == 'rule':
            unsubscribe_options.insert(0, {
                "id": "rule",
                "title": "alerts about this rule"
            })

    inputs.update({'options': unsubscribe_options})
    # Get the user's notification policy.
    qr = me.Q(owner=org)
    qr &= me.Q(user_id=user_id) if user_id else me.Q(email=email)
    np = UserNotificationPolicy.objects(qr).first()

    # Check if an override already exists.
    if np:
        for override in np.overrides:
            if override.blocks(channel, rtype, rid):
                return render_to_response('templates/is_unsubscribed.pt',
                                          inputs)

    # Render template to unsubscribe.
    try:
        hmac_params = decrypted_json.copy()
        mac_sign(hmac_params)
        encrypted = encrypt(json.dumps(hmac_params))
        inputs.update({
            "token": encrypted,
            # TODO Make the template customizable/dynamic based on the action.
            "action": decrypted_json["action"],
            "csrf_token": get_csrf_token(request),
        })
    except Exception as exc:
        log.exception(repr(exc))
        raise BadRequestError(ERROR_MSG)

    return render_to_response('templates/unsubscribe.pt', inputs)
Пример #3
0
def confirm_unsubscription(request):
    """
    Tags: notifications
    ---
    Creates a new notification override.
    Accepts an override creation request and adds the corresponding override,
    creating a new override policy if it does not exist.
    ---
    """
    params = params_from_request(request)
    try:
        decrypted_str = decrypt(params["token"])
        decrypted_json = json.loads(decrypted_str)
    except Exception as exc:
        log.exception(repr(exc))
        raise BadRequestError(ERROR_MSG)

    option = params.get("option")
    if not option:
        raise RequiredParameterMissingError("option")

    try:
        mac_verify(decrypted_json)
    except Exception as exc:
        raise BadRequestError(exc)

    try:
        org_id = decrypted_json["org_id"]
    except KeyError as err:
        log.exception(repr(err))
        raise BadRequestError(ERROR_MSG)

    try:
        org = Organization.objects.get(id=org_id)
    except Organization.DoesNotExist:
        raise OrganizationNotFound()

    rid = decrypted_json.get("rid", "")
    rtype = decrypted_json.get("rtype", "")
    email = decrypted_json.get("email")
    user_id = decrypted_json.get("user_id")
    channel = decrypted_json.get("channel")
    if not (email or user_id) and channel in CHANNELS:
        log.critical("Got invalid/insufficient data: %s", decrypted_json)
        raise BadRequestError(ERROR_MSG)

    qr = me.Q(owner=org)
    qr &= me.Q(user_id=user_id) if user_id else me.Q(email=email)
    np = UserNotificationPolicy.objects(qr).first()
    if not np:
        np = UserNotificationPolicy(owner=org, user_id=user_id, email=email)
    for override in np.overrides:
        if override.blocks(channel, rtype, rid):
            return json.dumps({"response": "channel_blocked"})
    override = NotificationOverride()
    if option == 'channel':
        override.channel = channel
    elif option == 'rule':
        override.rid = rid
        override.rtype = rtype
        override.channel = channel
    elif option == 'all':
        pass
    else:
        raise BadRequestError("Invalid option '%s'" % option)

    np.overrides.append(override)
    try:
        np.save()
    except me.ValidationError as err:
        log.critical("Failed to save %s: %r", np, err)
        raise BadRequestError(ERROR_MSG)
    return json.dumps({"response": "override_added"})
Пример #4
0
def migrate_policies(collection):
    """Migrate all user notification policies with overrides > 0"""
    total = collection.find().count()
    failed = 0
    migrated = 0

    print
    print 'Will migrate %d notification policies' % total
    print

    for old_np in collection.find({
            'overrides.0': {
                '$exists': True
            },
            'migrated': {
                '$exists': False
            }
    }):
        try:
            print 'Migrating', old_np['_id'],
            try:
                owner = Organization.objects.get(id=old_np['organization'])
            except Exception:
                print '[ERROR]'
                failed += 1
                traceback.print_exc()
                continue
            np = UserNotificationPolicy()
            np.owner = owner
            np.user_id = old_np['user']
            for old_override in old_np['overrides']:
                channel = old_override.get('source', '')
                if channel == 'email_report':
                    channel = 'EmailReport'
                override = NotificationOverride()
                override.channel = channel
                if old_override.get('machine'):
                    override.rid = old_override['machine']['_ref'].id
                    override.rtype = 'machine'
                np.overrides.append(override)
            np.save()
        except Exception:
            print '[ERROR]'
            failed += 1
            traceback.print_exc()
        else:
            try:
                collection.update_one({'_id': old_np['_id']},
                                      {'$set': {
                                          'migrated': True
                                      }})
            except Exception:
                print '[ERROR]'
                failed += 1
                traceback.print_exc()
                try:
                    np.delete()
                except:
                    pass
            else:
                print '[OK]'
                migrated += 1

    print
    print 'Migrated: %d/%d' % (migrated, total)
    print 'Failed: %d' % failed
    print
    print 'Completed %s' % ('with errors!' if failed else 'successfully!')
    print