def execute(request, query, page_size): search_result = _execute_search(request, query, page_size) result = ActivityResults(total=search_result.total, aggregations=search_result.aggregations, timeframes=[]) if result.total == 0: return result # Load all referenced annotations from the database, bucket them, and add # the buckets to result.timeframes. anns = fetch_annotations(request.db, search_result.annotation_ids) result.timeframes.extend(bucketing.bucket(anns)) # Fetch all groups group_pubids = set([a.groupid for t in result.timeframes for b in t.document_buckets.values() for a in b.annotations]) groups = {g.pubid: g for g in _fetch_groups(request.db, group_pubids)} # Add group information to buckets and present annotations for timeframe in result.timeframes: for bucket in timeframe.document_buckets.values(): bucket.presented_annotations = [] for annotation in bucket.annotations: bucket.presented_annotations.append({ 'annotation': presenters.AnnotationHTMLPresenter(annotation), 'group': groups.get(annotation.groupid), 'html_link': links.html_link(request, annotation), 'incontext_link': links.incontext_link(request, annotation) }) return result
def test_incontext_link_is_none_for_replies(api_request): annotation = FakeAnnotation() annotation.references = ['parent'] link = links.incontext_link(api_request, annotation) assert link is None
def _incontext_link(self, request): """ Mimic the incontext_link method of the DocumentBucket class. """ if len(self.annotations) == 0: return None return links.incontext_link(request, self.annotations[0])
def test_incontext_link_skips_uri_for_pdfs_with_no_document(pyramid_request): annotation = FakeAnnotation() annotation.target_uri = 'urn:x-pdf:the-fingerprint' link = links.incontext_link(pyramid_request, annotation) assert link == 'https://hyp.is/123'
def generate(request, notification): """ Generate an email for a reply notification. :param request: the current request :type request: pyramid.request.Request :param notification: the reply notification data structure :type notification: h.notifications.reply.Notification :returns: a 4-element tuple containing: recipients, subject, text, html """ document_title = notification.document.title if not document_title: document_title = notification.parent.target_uri parent_user = notification.parent_user parent_user_url = request.route_url("stream.user_query", user=parent_user.username) parent_user_display_name = parent_user.display_name or parent_user.username reply_url = links.incontext_link(request, notification.reply) if not reply_url: reply_url = request.route_url("annotation", id=notification.reply.id) reply_user = notification.reply_user reply_user_url = request.route_url("stream.user_query", user=reply_user.username) reply_user_display_name = reply_user.display_name or reply_user.username unsubscribe_token = _unsubscribe_token(request, parent_user) unsubscribe_url = request.route_url("unsubscribe", token=unsubscribe_token) if notification.reply_user.authority != request.default_authority: reply_user_url = None if notification.parent_user.authority != request.default_authority: parent_user_url = None context = { "document_title": document_title, "document_url": notification.parent.target_uri, "parent": notification.parent, "parent_user_display_name": parent_user_display_name, "parent_user_url": parent_user_url, "reply": notification.reply, "reply_url": reply_url, "reply_user_display_name": reply_user_display_name, "reply_user_url": reply_user_url, "unsubscribe_url": unsubscribe_url, } subject = "{user} has replied to your annotation".format( user=reply_user_display_name ) text = render( "h:templates/emails/reply_notification.txt.jinja2", context, request=request ) html = render( "h:templates/emails/reply_notification.html.jinja2", context, request=request ) return [notification.parent_user.email], subject, text, html
def execute(request, query, page_size): search_result = _execute_search(request, query, page_size) result = ActivityResults(total=search_result.total, aggregations=search_result.aggregations, timeframes=[]) if result.total == 0: return result # Load all referenced annotations from the database, bucket them, and add # the buckets to result.timeframes. anns = fetch_annotations(request.db, search_result.annotation_ids) result.timeframes.extend(bucketing.bucket(anns)) # Fetch all groups group_pubids = set([a.groupid for t in result.timeframes for b in t.document_buckets.values() for a in b.annotations]) groups = {g.pubid: g for g in _fetch_groups(request.db, group_pubids)} # Add group information to buckets and present annotations for timeframe in result.timeframes: for bucket in timeframe.document_buckets.values(): bucket.presented_annotations = [] for annotation in bucket.annotations: bucket.presented_annotations.append({ 'annotation': presenters.AnnotationHTMLPresenter(annotation), 'group': groups.get(annotation.groupid), 'incontext_link': links.incontext_link(request, annotation) }) return result
def test_incontext_link_appends_schemaless_uri_if_present( pyramid_request, target_uri, expected): annotation = FakeAnnotation() annotation.target_uri = target_uri link = links.incontext_link(pyramid_request, annotation) assert link == expected
def test_incontext_link_appends_schemaless_uri_if_present(pyramid_request, target_uri, expected): annotation = FakeAnnotation() annotation.target_uri = target_uri link = links.incontext_link(pyramid_request, annotation) assert link == expected
def generate(request, notification): """ Generate an email for a reply notification. :param request: the current request :type request: pyramid.request.Request :param notification: the reply notification data structure :type notification: h.notifications.reply.Notification :returns: a 4-element tuple containing: recipients, subject, text, html """ document_title = notification.document.title if not document_title: document_title = notification.parent.target_uri parent_user = notification.parent_user parent_user_url = request.route_url('stream.user_query', user=parent_user.username) parent_user_display_name = parent_user.display_name or parent_user.username reply_url = links.incontext_link(request, notification.reply) if not reply_url: reply_url = request.route_url('annotation', id=notification.reply.id) reply_user = notification.reply_user reply_user_url = request.route_url('stream.user_query', user=reply_user.username) reply_user_display_name = reply_user.display_name or reply_user.username unsubscribe_token = _unsubscribe_token(request, parent_user) unsubscribe_url = request.route_url('unsubscribe', token=unsubscribe_token) context = { 'document_title': document_title, 'document_url': notification.parent.target_uri, 'parent': notification.parent, 'parent_user_display_name': parent_user_display_name, 'parent_user_url': parent_user_url, 'reply': notification.reply, 'reply_url': reply_url, 'reply_user_display_name': reply_user_display_name, 'reply_user_url': reply_user_url, 'unsubscribe_url': unsubscribe_url, } subject = '{user} has replied to your annotation'.format( user=reply_user_display_name) text = render('h:templates/emails/reply_notification.txt.jinja2', context, request=request) html = render('h:templates/emails/reply_notification.html.jinja2', context, request=request) return [notification.parent_user.email], subject, text, html
def _email_group_admin(request, annotation): group_service = request.find_service(IGroupService) group = group_service.find(annotation.groupid) incontext_link = links.incontext_link(request, annotation) if incontext_link is None: incontext_link = annotation.target_uri if group.creator is not None: send_params = flag_notification.generate(request, group.creator.email, incontext_link) mailer.send.delay(*send_params)
def _email_group_admin(request, annotation): incontext_link = links.incontext_link(request, annotation) if incontext_link is None: incontext_link = annotation.target_uri group = annotation.group if group.creator and group.creator.email: send_params = flag_notification.generate( request, group.creator.email, incontext_link ) mailer.send.delay(*send_params)
def incontext_link(self, request): """ Return a link to view this bucket's annotations in context. The bouncer service and Hypothesis client do not currently provide direct links to view a document's annotations without specifying a specific annotation, so here we just link to the first annotation in the document. """ if len(self.annotations) == 0: return None return links.incontext_link(request, self.annotations[0])
def generate(request, notification): """ Generate an email for a reply notification. :param request: the current request :type request: pyramid.request.Request :param notification: the reply notification data structure :type notification: h.notifications.reply.Notification :returns: a 4-element tuple containing: recipients, subject, text, html """ context = { "document_title": notification.document.title or notification.parent.target_uri, "document_url": notification.parent.target_uri, # Parent related "parent": notification.parent, "parent_user_display_name": notification.parent_user.display_name or notification.parent_user.username, "parent_user_url": _get_user_url(notification.parent_user, request), "unsubscribe_url": request.route_url( "unsubscribe", token=_unsubscribe_token(request, notification.parent_user), ), # Reply related "reply": notification.reply, "reply_url": links.incontext_link(request, notification.reply) or request.route_url("annotation", id=notification.reply.id), "reply_user_display_name": notification.reply_user.display_name or notification.reply_user.username, "reply_user_url": _get_user_url(notification.reply_user, request), } subject = f"{context['reply_user_display_name']} has replied to your annotation" text = render("h:templates/emails/reply_notification.txt.jinja2", context, request=request) html = render("h:templates/emails/reply_notification.html.jinja2", context, request=request) return [notification.parent_user.email], subject, text, html
def generate(request, notification): """ Generate an email for a reply notification. :param request: the current request :type request: pyramid.request.Request :param notification: the reply notification data structure :type notification: h.notifications.reply.Notification :returns: a 4-element tuple containing: recipients, subject, text, html """ document_title = notification.document.title if not document_title: document_title = notification.parent.target_uri parent_user_url = request.route_url('stream.user_query', user=notification.parent_user.username) reply_url = links.incontext_link(request, notification.reply) if not reply_url: reply_url = request.route_url('annotation', id=notification.reply.id) reply_user_url = request.route_url('stream.user_query', user=notification.reply_user.username) unsubscribe_token = _unsubscribe_token(request, notification.parent_user) unsubscribe_url = request.route_url('unsubscribe', token=unsubscribe_token) context = { 'document_title': document_title, 'document_url': notification.parent.target_uri, 'parent': notification.parent, 'parent_user': notification.parent_user, 'parent_user_url': parent_user_url, 'reply': notification.reply, 'reply_url': reply_url, 'reply_user': notification.reply_user, 'reply_user_url': reply_user_url, 'unsubscribe_url': unsubscribe_url, } subject = '{user} has replied to your annotation'.format( user=notification.reply_user.username) text = render('h:templates/emails/reply_notification.txt.jinja2', context, request=request) html = render('h:templates/emails/reply_notification.html.jinja2', context, request=request) return [notification.parent_user.email], subject, text, html
def test_incontext_link_appends_first_schemaless_uri_for_pdfs_with_document(pyramid_request): doc = FakeDocument() docuri1 = FakeDocumentURI() docuri1.uri = 'http://example.com/foo.pdf' docuri2 = FakeDocumentURI() docuri2.uri = 'http://example.com/bar.pdf' doc.document_uris = [docuri1, docuri2] annotation = FakeAnnotation() annotation.document = doc annotation.target_uri = 'urn:x-pdf:the-fingerprint' link = links.incontext_link(pyramid_request, annotation) assert link == 'https://hyp.is/123/example.com/foo.pdf'
def test_incontext_link(pyramid_request): annotation = FakeAnnotation() link = links.incontext_link(pyramid_request, annotation) assert link == 'https://hyp.is/123/example.com/foo/bar'
def execute(request, query, page_size): search_result = _execute_search(request, query, page_size) result = ActivityResults(total=search_result.total, aggregations=search_result.aggregations, timeframes=[]) if result.total == 0: return result # Load all referenced annotations from the database, bucket them, and add # the buckets to result.timeframes. anns = fetch_annotations(request.db, search_result.annotation_ids) result.timeframes.extend(bucketing.bucket(anns)) # Fetch all groups group_pubids = set([a.groupid for t in result.timeframes for b in t.document_buckets.values() for a in b.annotations]) groups = {g.pubid: g for g in _fetch_groups(request.db, group_pubids)} # Add group information to buckets and present annotations result.docs = dict() for timeframe in result.timeframes: for bucket in timeframe.document_buckets.values(): bucket.presented_annotations = [] for annotation in bucket.annotations: bucket.presented_annotations.append({ 'annotation': presenters.AnnotationHTMLPresenter(annotation), 'group': groups.get(annotation.groupid), 'html_link': links.html_link(request, annotation), 'incontext_link': links.incontext_link(request, annotation) }) # XXX: redo the bucketing, fake a bucket if annotation.document.title not in result.docs: result.docs[annotation.document.title] = doc = lambda: None doc.title = annotation.document.title doc.annotations = [] doc.tags = set() doc.users = set() doc.annotations_count = 0 doc.incontext_link = types.MethodType(_incontext_link, doc) presented_document = presenters.DocumentHTMLPresenter(annotation.document) if presented_document.web_uri: parsed = urlparse.urlparse(presented_document.web_uri) doc.uri = parsed.geturl() doc.domain = parsed.netloc else: doc.domain = _('Local file') doc = result.docs[annotation.document.title] doc.annotations.append(annotation) doc.tags.update(set(annotation.tags)) doc.users.add(annotation.userid) doc.annotations_count += 1 for key in result.docs: doc = result.docs[key] doc.annotations = sorted(doc.annotations, cmp=_sort_by_position) doc.presented_annotations = [] for annotation in doc.annotations: doc.presented_annotations.append({ 'annotation': presenters.AnnotationHTMLPresenter(annotation), 'group': groups.get(annotation.groupid), 'html_link': links.html_link(request, annotation), 'incontext_link': links.incontext_link(request, annotation) }) return result