Exemple #1
0
def add_annotation(id_):
    annotation = storage.fetch_annotation(celery.request.db, id_)
    if annotation:
        index(celery.request.es, annotation, celery.request)

        if celery.request.feature('index_es6'):
            index(celery.request.es6, annotation, celery.request)

        # If a reindex is running at the moment, add annotation to the new index
        # as well.
        future_index = _current_reindex_new_name(celery.request,
                                                 'reindex.new_index')
        if future_index is not None:
            index(celery.request.es,
                  annotation,
                  celery.request,
                  target_index=future_index)

        future_es6_index = _current_reindex_new_name(celery.request,
                                                     'reindex.new_es6_index')
        if future_es6_index is not None:
            index(celery.request.es6,
                  annotation,
                  celery.request,
                  target_index=future_es6_index)

        if annotation.is_reply:
            add_annotation.delay(annotation.thread_root_id)
Exemple #2
0
    def __getitem__(self, id):
        annotation = storage.fetch_annotation(self.request.db, id)
        if annotation is None:
            raise KeyError()

        group_service = self.request.find_service(IGroupService)
        links_service = self.request.find_service(name='links')
        return AnnotationResource(annotation, group_service, links_service)
Exemple #3
0
    def __getitem__(self, id_):
        annotation = storage.fetch_annotation(self.request.db, id_)
        if annotation is None:
            raise KeyError()

        group_service = self.request.find_service(IGroupService)
        links_service = self.request.find_service(name="links")
        return AnnotationContext(annotation, group_service, links_service)
Exemple #4
0
    def __getitem__(self, id):
        annotation = storage.fetch_annotation(self.request.db, id)
        if annotation is None:
            raise KeyError()

        group_service = self.request.find_service(IGroupService)
        links_service = self.request.find_service(name="links")
        return contexts.AnnotationContext(annotation, group_service, links_service)
Exemple #5
0
def add_annotation(id_):
    annotation = storage.fetch_annotation(celery.request.db, id_)
    if annotation:
        index(celery.request.es, annotation, celery.request)

        # If a reindex is running at the moment, add annotation to the new index
        # as well.
        future_index = _current_reindex_new_name(celery.request)
        if future_index is not None:
            index(celery.request.es, annotation, celery.request,
                  target_index=future_index)
Exemple #6
0
def send_reply_notifications(event,
                             get_notification=reply.get_notification,
                             generate_mail=emails.reply_notification.generate,
                             send=mailer.send.delay):
    """Queue any reply notification emails triggered by an annotation event."""
    request = event.request
    with request.tm:
        annotation = storage.fetch_annotation(event.request.db,
                                              event.annotation_id)
        notification = get_notification(request, annotation, event.action)
        if notification is None:
            return
        send_params = generate_mail(request, notification)
        send(*send_params)
Exemple #7
0
def add_annotation(id_):
    annotation = storage.fetch_annotation(celery.request.db, id_)
    if annotation:
        index(celery.request.es, annotation, celery.request)

        # If a reindex is running at the moment, add annotation to the new index
        # as well.
        future_index = _current_reindex_new_name(celery.request)
        if future_index is not None:
            index(celery.request.es, annotation, celery.request,
                  target_index=future_index)

        if annotation.is_reply:
            add_annotation.delay(annotation.thread_root_id)
Exemple #8
0
def handle_annotation_event(message, sockets, request, session):
    id_ = message["annotation_id"]
    annotation = storage.fetch_annotation(session, id_)

    if annotation is None:
        log.warning("received annotation event for missing annotation: %s",
                    id_)
        return

    # Find connected clients which are interested in this annotation.
    matching_sockets = SocketFilter.matching(sockets, annotation, session)

    try:
        # Check to see if the generator has any items
        first_socket = next(matching_sockets)
    except StopIteration:
        # Nothing matched
        return

    # Create a generator which has the first socket back again
    matching_sockets = chain(  # pylint: disable=redefined-variable-type
        (first_socket, ), matching_sockets)

    resource = AnnotationNotificationContext(
        annotation,
        group_service=request.find_service(IGroupService),
        links_service=request.find_service(name="links"),
    )
    read_principals = principals_allowed_by_permission(resource, "read")
    reply = _generate_annotation_event(session, request, message, resource)

    annotator_nipsad = request.find_service(name="nipsa").is_flagged(
        annotation.userid)

    for socket in matching_sockets:
        # Don't send notifications back to the person who sent them
        if message["src_client_id"] == socket.client_id:
            continue

        # Only send NIPSA'd annotations to the author
        if annotator_nipsad and socket.authenticated_userid != annotation.userid:
            continue

        # Check whether client is authorized to read this annotation.
        if not set(read_principals).intersection(socket.effective_principals):
            continue

        socket.send_json(reply)
Exemple #9
0
def handle_annotation_event(message, sockets, request, session):
    id_ = message["annotation_id"]
    annotation = storage.fetch_annotation(session, id_)

    if annotation is None:
        log.warning("received annotation event for missing annotation: %s",
                    id_)
        return

    # Find connected clients which are interested in this annotation.
    matching_sockets = SocketFilter.matching(sockets, annotation, session)

    try:
        # Check to see if the generator has any items
        first_socket = next(matching_sockets)
    except StopIteration:
        # Nothing matched
        return

    # Create a generator which has the first socket back again
    matching_sockets = chain(  # pylint: disable=redefined-variable-type
        (first_socket, ), matching_sockets)

    reply = _generate_annotation_event(request, message, annotation)

    annotator_nipsad = request.find_service(name="nipsa").is_flagged(
        annotation.userid)
    annotation_context = AnnotationContext(annotation)

    for socket in matching_sockets:
        # Don't send notifications back to the person who sent them
        if message["src_client_id"] == socket.client_id:
            continue

        # Only send NIPSA'd annotations to the author
        if (annotator_nipsad and socket.identity
                and socket.identity.user.userid != annotation.userid):
            continue

        # Check whether client is authorized to read this annotation.
        if not identity_permits(
                socket.identity,
                annotation_context,
                Permission.Annotation.READ_REALTIME_UPDATES,
        ):
            continue

        socket.send_json(reply)
Exemple #10
0
def handle_annotation_event(message, sockets, settings, session):
    id_ = message['annotation_id']
    annotation = storage.fetch_annotation(session, id_)

    if annotation is None:
        log.warn('received annotation event for missing annotation: %s', id_)
        return

    nipsa_service = NipsaService(session)
    user_nipsad = nipsa_service.is_flagged(annotation.userid)

    authority = text_type(settings.get('h.authority', 'localhost'))
    group_service = GroupfinderService(session, authority)

    for socket in sockets:
        reply = _generate_annotation_event(message, socket, annotation, user_nipsad, group_service)
        if reply is None:
            continue
        socket.send_json(reply)
Exemple #11
0
def handle_annotation_event(message, sockets, settings, session):
    id_ = message['annotation_id']
    annotation = storage.fetch_annotation(session, id_)

    if annotation is None:
        log.warn('received annotation event for missing annotation: %s', id_)
        return

    nipsa_service = NipsaService(session)
    user_nipsad = nipsa_service.is_flagged(annotation.userid)

    authority = text_type(settings.get('h.authority', 'localhost'))
    group_service = GroupfinderService(session, authority)

    for socket in sockets:
        reply = _generate_annotation_event(message, socket, annotation, user_nipsad, group_service)
        if reply is None:
            continue
        socket.send_json(reply)
Exemple #12
0
    def add_annotation_by_id(self, annotation_id):
        """
        Add an annotation into the search index by id.

        A new annotation document will be created in the search index or,
        if the index already contains an annotation document with the same Id
        as the given annotation then it will be updated.

        If no annotation is found, nothing happens.

        :param annotation_id: Id of the annotation to add.
        """
        annotation = storage.fetch_annotation(self._db, annotation_id)
        if not annotation or annotation.deleted:
            return

        self.add_annotation(annotation)

        if annotation.is_reply:
            self.add_annotation_by_id(annotation.thread_root_id)
Exemple #13
0
def handle_annotation_event(message, sockets, settings, session):
    id_ = message["annotation_id"]
    annotation = storage.fetch_annotation(session, id_)

    if annotation is None:
        log.warning("received annotation event for missing annotation: %s", id_)
        return

    nipsa_service = NipsaService(session)
    user_nipsad = nipsa_service.is_flagged(annotation.userid)

    authority = text_type(settings.get("h.authority", "localhost"))
    group_service = GroupfinderService(session, authority)
    user_service = UserService(authority, session)
    formatters = [AnnotationUserInfoFormatter(session, user_service)]

    for socket in sockets:
        reply = _generate_annotation_event(
            message, socket, annotation, user_nipsad, group_service, formatters
        )
        if reply is None:
            continue
        socket.send_json(reply)
Exemple #14
0
def handle_annotation_event(message, sockets, settings, session):
    id_ = message["annotation_id"]
    annotation = storage.fetch_annotation(session, id_)

    if annotation is None:
        log.warning("received annotation event for missing annotation: %s",
                    id_)
        return

    # Find connected clients which are interested in this annotation.
    matching_sockets = SocketFilter.matching(sockets, annotation)

    try:
        # Check to see if the generator has any items
        first_socket = next(matching_sockets)
    except StopIteration:
        # Nothing matched
        return

    # Create a generator which has the first socket back again
    matching_sockets = chain((first_socket, ), matching_sockets)

    nipsa_service = NipsaService(session)
    user_nipsad = nipsa_service.is_flagged(annotation.userid)

    authority = settings.get("h.authority", "localhost")
    group_service = GroupfinderService(session, authority)
    user_service = UserService(authority, session)
    formatters = [AnnotationUserInfoFormatter(session, user_service)]

    for socket in matching_sockets:
        reply = _generate_annotation_event(message, socket, annotation,
                                           user_nipsad, group_service,
                                           formatters)
        if reply is None:
            continue
        socket.send_json(reply)
Exemple #15
0
def handle_annotation_event(message, sockets, settings, session):
    id_ = message["annotation_id"]
    annotation = storage.fetch_annotation(session, id_)

    if annotation is None:
        log.warning("received annotation event for missing annotation: %s",
                    id_)
        return

    nipsa_service = NipsaService(session)
    user_nipsad = nipsa_service.is_flagged(annotation.userid)

    authority = text_type(settings.get("h.authority", "localhost"))
    group_service = GroupfinderService(session, authority)
    user_service = UserService(authority, session)
    formatters = [AnnotationUserInfoFormatter(session, user_service)]

    for socket in sockets:
        reply = _generate_annotation_event(message, socket, annotation,
                                           user_nipsad, group_service,
                                           formatters)
        if reply is None:
            continue
        socket.send_json(reply)
Exemple #16
0
def get_notification(request, annotation, action):
    """
    Check if the passed annotation and action pair should send a notification.

    Checks to see if the annotation event represented by the passed annotation
    and action should trigger a notification. If it should, this function
    returns the relevant :py:class:`~h.notification.reply.Notification` object.
    Otherwise, it returns None.

    :param request: the current request object
    :type request: pyramid.request.Request
    :param annotation: the reply annotation
    :type annotation: h.models.Annotation
    :param action: the event action
    :type action: str

    :returns: a :py:class:`~h.notification.reply.Notification`, or None
    """
    # Only send notifications when new annotations are created
    if action != 'create':
        return

    # If the annotation doesn't have a parent, or we can't find its parent,
    # then we can't send a notification email.
    parent_id = annotation.parent_id
    if parent_id is None:
        return

    # Now we know we're dealing with a reply
    reply = annotation

    parent = storage.fetch_annotation(request.db, parent_id)
    if parent is None:
        return

    user_service = request.find_service(name='user')

    # If the parent user doesn't exist (anymore), we can't send an email.
    parent_user = user_service.fetch(parent.userid)
    if parent_user is None:
        return

    # If the parent user doesn't have an email address we can't email them.
    if not parent_user.email:
        return

    # If the reply user doesn't exist (anymore), we can't send an email, but
    # this would be super weird, so log a warning.
    reply_user = user_service.fetch(reply.userid)
    if reply_user is None:
        log.warning('user who just replied no longer exists: %s', reply.userid)
        return

    # Do not notify users about their own replies
    if parent_user == reply_user:
        return

    # Don't send reply notifications to the author of the parent annotation if
    # the reply was private.
    if not reply.shared:
        return

    # FIXME: we should be retrieving the document from the root annotation, not
    # the reply, and dealing with the possibility that we have no document
    # metadata.
    if reply.document is None:
        return

    # Bail if there is no active 'reply' subscription for the user being
    # replied to.
    sub = request.db.query(Subscriptions).filter_by(active=True,
                                                    type='reply',
                                                    uri=parent.userid).first()
    if sub is None:
        return

    return Notification(reply, reply_user, parent, parent_user, reply.document)
Exemple #17
0
def get_notification(request, annotation, action):
    """
    Check if the passed annotation and action pair should send a notification.

    Checks to see if the annotation event represented by the passed annotation
    and action should trigger a notification. If it should, this function
    returns the relevant :py:class:`~h.notification.reply.Notification` object.
    Otherwise, it returns None.

    :param request: the current request object
    :type request: pyramid.request.Request
    :param annotation: the reply annotation
    :type annotation: h.models.Annotation
    :param action: the event action
    :type action: str

    :returns: a :py:class:`~h.notification.reply.Notification`, or None
    """
    # Only send notifications when new annotations are created
    if action != 'create':
        return

    # If the annotation doesn't have a parent, or we can't find its parent,
    # then we can't send a notification email.
    parent_id = annotation.parent_id
    if parent_id is None:
        return

    # Now we know we're dealing with a reply
    reply = annotation

    parent = storage.fetch_annotation(request.db, parent_id)
    if parent is None:
        return

    user_service = request.find_service(name='user')

    # If the parent user doesn't exist (anymore), we can't send an email.
    parent_user = user_service.fetch(parent.userid)
    if parent_user is None:
        return

    # If the parent user doesn't have an email address we can't email them.
    if not parent_user.email:
        return

    # If the reply user doesn't exist (anymore), we can't send an email, but
    # this would be super weird, so log a warning.
    reply_user = user_service.fetch(reply.userid)
    if reply_user is None:
        log.warn('user who just replied no longer exists: %s', reply.userid)
        return

    # Do not notify users about their own replies
    if parent_user == reply_user:
        return

    # Don't send reply notifications to the author of the parent annotation if
    # the reply was private.
    if not reply.shared:
        return

    # FIXME: we should be retrieving the document from the root annotation, not
    # the reply, and dealing with the possibility that we have no document
    # metadata.
    if reply.document is None:
        return

    # Bail if there is no active 'reply' subscription for the user being
    # replied to.
    sub = request.db.query(Subscriptions).filter_by(active=True,
                                                    type='reply',
                                                    uri=parent.userid).first()
    if sub is None:
        return

    return Notification(reply, reply_user, parent, parent_user, reply.document)
Exemple #18
0
 def test_it_does_not_crash_if_id_is_invalid(self, db_session):
     assert storage.fetch_annotation(db_session, 'foo') is None
Exemple #19
0
    def __getitem__(self, annotation_id):
        annotation = storage.fetch_annotation(self.request.db, annotation_id)
        if annotation is None:
            raise KeyError()

        return AnnotationContext(annotation)
Exemple #20
0
    def test_it_fetches_and_returns_the_annotation(self, db_session, factories):
        annotation = factories.Annotation()

        actual = storage.fetch_annotation(db_session, annotation.id)
        assert annotation == actual
Exemple #21
0
 def test_it_does_not_crash_if_id_is_invalid(self, db_session):
     assert storage.fetch_annotation(db_session, "foo") is None
Exemple #22
0
    def test_it_fetches_and_returns_the_annotation(self, db_session, factories):
        annotation = factories.Annotation()

        actual = storage.fetch_annotation(db_session, annotation.id)
        assert annotation == actual