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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
def test_it_does_not_crash_if_id_is_invalid(self, db_session): assert storage.fetch_annotation(db_session, 'foo') is None
def __getitem__(self, annotation_id): annotation = storage.fetch_annotation(self.request.db, annotation_id) if annotation is None: raise KeyError() return AnnotationContext(annotation)
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
def test_it_does_not_crash_if_id_is_invalid(self, db_session): assert storage.fetch_annotation(db_session, "foo") is None