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)
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)
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"})
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