user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
From: "Eric Wong (Contractor, The Linux Foundation)" <e@80x24.org>
To: meta@public-inbox.org
Subject: [PATCH 06/11] view: permalink (per-message) view shows multiple messages
Date: Tue, 27 Mar 2018 11:11:27 +0000	[thread overview]
Message-ID: <20180327111132.20681-7-e@80x24.org> (raw)
In-Reply-To: <20180327111132.20681-1-e@80x24.org>

This needs tests and further refinement, but current tests pass.
---
 lib/PublicInbox/Mbox.pm      |  12 ++---
 lib/PublicInbox/SearchMsg.pm |   7 +++
 lib/PublicInbox/View.pm      | 107 ++++++++++++++++++++++++++++++++++++++-----
 lib/PublicInbox/WWW.pm       |   7 +--
 t/psgi_v2.t                  |  12 +++++
 5 files changed, 118 insertions(+), 27 deletions(-)

diff --git a/lib/PublicInbox/Mbox.pm b/lib/PublicInbox/Mbox.pm
index 79e09a7..c14037f 100644
--- a/lib/PublicInbox/Mbox.pm
+++ b/lib/PublicInbox/Mbox.pm
@@ -26,13 +26,6 @@ sub subject_fn ($) {
 	$fn eq '' ? 'no-subject' : $fn;
 }
 
-sub smsg_for ($$$) {
-	my ($head, $db, $mid) = @_;
-	my $doc_id = $head->get_docid;
-	my $doc = $db->get_document($doc_id);
-	PublicInbox::SearchMsg->wrap($doc, $mid)->load_expand;
-}
-
 sub mb_stream {
 	my ($more) = @_;
 	bless $more, 'PublicInbox::Mbox';
@@ -47,7 +40,7 @@ sub getline {
 		return msg_str($ctx, $cur);
 	}
 	for (; !defined($cur) && $head != $tail; $head++) {
-		my $smsg = smsg_for($head, $db, $ctx->{mid});
+		my $smsg = PublicInbox::SearchMsg->get($head, $db, $ctx->{mid});
 		next if $smsg->type ne 'mail';
 		my $mref = $ctx->{-inbox}->msg_by_smsg($smsg) or next;
 		$cur = Email::Simple->new($mref);
@@ -71,7 +64,8 @@ sub emit_raw {
 		$srch->retry_reopen(sub {
 			($head, $tail, $db) = $srch->each_smsg_by_mid($mid);
 			for (; !defined($first) && $head != $tail; $head++) {
-				my $smsg = smsg_for($head, $db, $mid);
+				my @args = ($head, $db, $mid);
+				my $smsg = PublicInbox::SearchMsg->get(@args);
 				next if $smsg->type ne 'mail';
 				my $mref = $ibx->msg_by_smsg($smsg) or next;
 				$first = Email::Simple->new($mref);
diff --git a/lib/PublicInbox/SearchMsg.pm b/lib/PublicInbox/SearchMsg.pm
index dd3d58d..b944868 100644
--- a/lib/PublicInbox/SearchMsg.pm
+++ b/lib/PublicInbox/SearchMsg.pm
@@ -24,6 +24,13 @@ sub wrap {
 	bless { doc => $doc, mime => undef, mid => $mid }, $class;
 }
 
+sub get {
+	my ($class, $head, $db, $mid) = @_;
+	my $doc_id = $head->get_docid;
+	my $doc = $db->get_document($doc_id);
+	load_expand(wrap($class, $doc, $mid))
+}
+
 sub get_val ($$) {
 	my ($doc, $col) = @_;
 	Search::Xapian::sortable_unserialise($doc->get_value($col));
diff --git a/lib/PublicInbox/View.pm b/lib/PublicInbox/View.pm
index 18882af..34ab3e5 100644
--- a/lib/PublicInbox/View.pm
+++ b/lib/PublicInbox/View.pm
@@ -9,7 +9,7 @@ use warnings;
 use PublicInbox::MsgTime qw(msg_datestamp);
 use PublicInbox::Hval qw/ascii_html obfuscate_addrs/;
 use PublicInbox::Linkify;
-use PublicInbox::MID qw/mid_clean id_compress mid_mime mid_escape/;
+use PublicInbox::MID qw/mid_clean id_compress mid_mime mid_escape mids/;
 use PublicInbox::MsgIter;
 use PublicInbox::Address;
 use PublicInbox::WwwStream;
@@ -21,18 +21,23 @@ use constant TCHILD => '` ';
 sub th_pfx ($) { $_[0] == 0 ? '' : TCHILD };
 
 # public functions: (unstable)
+
 sub msg_html {
-	my ($ctx, $mime) = @_;
+	my ($ctx, $mime, $more) = @_;
 	my $hdr = $mime->header_obj;
 	my $ibx = $ctx->{-inbox};
-	my $obfs_ibx = $ibx->{obfuscate} ? $ibx : undef;
-	my $tip = _msg_html_prepare($hdr, $ctx, $obfs_ibx);
+	my $obfs_ibx = $ctx->{-obfs_ibx} = $ibx->{obfuscate} ? $ibx : undef;
+	my $tip = _msg_html_prepare($hdr, $ctx, $more, 0);
+	my $end = 2;
 	PublicInbox::WwwStream->response($ctx, 200, sub {
 		my ($nr, undef) = @_;
 		if ($nr == 1) {
 			$tip . multipart_text_as_html($mime, '', $obfs_ibx) .
 				'</pre><hr>'
-		} elsif ($nr == 2) {
+		} elsif ($more && @$more) {
+			++$end;
+			msg_html_more($ctx, $more, $nr);
+		} elsif ($nr == $end) {
 			# fake an EOF if generating the footer fails;
 			# we want to at least show the message if something
 			# here crashes:
@@ -46,6 +51,63 @@ sub msg_html {
 	});
 }
 
+sub msg_page {
+	my ($ctx) = @_;
+	my $mid = $ctx->{mid};
+	my $ibx = $ctx->{-inbox};
+	my ($first, $more, $head, $tail, $db);
+	if (my $srch = $ibx->search) {
+		$srch->retry_reopen(sub {
+			($head, $tail, $db) = $srch->each_smsg_by_mid($mid);
+			for (; !defined($first) && $head != $tail; $head++) {
+				my @args = ($head, $db, $mid);
+				my $smsg = PublicInbox::SearchMsg->get(@args);
+				next if $smsg->type ne 'mail';
+				$first = $ibx->msg_by_smsg($smsg);
+			}
+			if ($head != $tail) {
+				$more = [ $head, $tail, $db ];
+			}
+		});
+	} else {
+		$first = $ibx->msg_by_mid($mid) or return;
+	}
+	$first ? msg_html($ctx, PublicInbox::MIME->new($first), $more) : undef;
+}
+
+sub msg_html_more {
+	my ($ctx, $more, $nr) = @_;
+	my $str = eval {
+		my $mref;
+		my ($head, $tail, $db) = @$more;
+		for (; !defined($mref) && $head != $tail; $head++) {
+			my $smsg = PublicInbox::SearchMsg->get($head, $db,
+								$ctx->{mid});
+			next if $smsg->type ne 'mail';
+			$mref = $ctx->{-inbox}->msg_by_smsg($smsg);
+		}
+		if ($head == $tail) { # done
+			@$more = ();
+		} else {
+			$more->[0] = $head;
+		}
+		if ($mref) {
+			my $mime = PublicInbox::MIME->new($mref);
+			_msg_html_prepare($mime->header_obj, $ctx, $more, $nr) .
+				multipart_text_as_html($mime, '',
+							$ctx->{-obfs_ibx}) .
+				'</pre><hr>'
+		} else {
+			'';
+		}
+	};
+	if ($@) {
+		warn "Error lookup up additional messages: $@\n";
+		$str = '<pre>Error looking up additional messages</pre>';
+	}
+	$str;
+}
+
 # /$INBOX/$MESSAGE_ID/#R
 sub msg_reply {
 	my ($ctx, $hdr) = @_;
@@ -529,17 +591,26 @@ sub add_text_body {
 }
 
 sub _msg_html_prepare {
-	my ($hdr, $ctx, $obfs_ibx) = @_;
+	my ($hdr, $ctx, $more, $nr) = @_;
 	my $srch = $ctx->{srch} if $ctx;
 	my $atom = '';
-	my $rv = "<pre\nid=b>"; # anchor for body start
-
+	my $obfs_ibx = $ctx->{-obfs_ibx};
+	my $rv = '';
+	my $mids = mids($hdr);
+	my $multiple = scalar(@$mids) > 1; # zero, one, infinity
+	if ($nr == 0) {
+		if ($more) {
+			$rv .=
+"<pre>WARNING: multiple messages refer to this Message-ID\n</pre>";
+		}
+		$rv .= "<pre\nid=b>"; # anchor for body start
+	} else {
+		$rv .= '<pre>';
+	}
 	if ($srch) {
 		$ctx->{-upfx} = '../';
 	}
 	my @title;
-	my $mid = mid_clean($hdr->header_raw('Message-ID'));
-	$mid = PublicInbox::Hval->new_msgid($mid);
 	foreach my $h (qw(From To Cc Subject Date)) {
 		my $v = $hdr->header($h);
 		defined($v) && ($v ne '') or next;
@@ -564,8 +635,20 @@ sub _msg_html_prepare {
 	}
 	$title[0] ||= '(no subject)';
 	$ctx->{-title_html} = join(' - ', @title);
-	$rv .= 'Message-ID: &lt;' . $mid->as_html . '&gt; ';
-	$rv .= "(<a\nhref=\"raw\">raw</a>)\n";
+	foreach (@$mids) {
+		my $mid = PublicInbox::Hval->new_msgid($_) ;
+		my $mhtml = $mid->as_html;
+		if ($multiple) {
+			my $href = $mid->{href};
+			$rv .= "Message-ID: ";
+			$rv .= "<a\nhref=\"../$href/\">";
+			$rv .= "&lt;$mhtml&gt;</a> ";
+			$rv .= "(<a\nhref=\"../$href/raw\">raw</a>)\n";
+		} else {
+			$rv .= "Message-ID: &lt;$mhtml&gt; ";
+			$rv .= "(<a\nhref=\"raw\">raw</a>)\n";
+		}
+	}
 	$rv .= _parent_headers($hdr, $srch);
 	$rv .= "\n";
 }
diff --git a/lib/PublicInbox/WWW.pm b/lib/PublicInbox/WWW.pm
index f86363c..7bf866f 100644
--- a/lib/PublicInbox/WWW.pm
+++ b/lib/PublicInbox/WWW.pm
@@ -225,13 +225,8 @@ sub get_mid_txt {
 # /$INBOX/$MESSAGE_ID/                   -> HTML content (short quotes)
 sub get_mid_html {
 	my ($ctx) = @_;
-	my $x = mid2blob($ctx) or return r404($ctx);
-
 	require PublicInbox::View;
-	require PublicInbox::MIME;
-	my $mime = PublicInbox::MIME->new($x);
-	searcher($ctx);
-	PublicInbox::View::msg_html($ctx, $mime);
+	PublicInbox::View::msg_page($ctx) || r404($ctx);
 }
 
 # /$INBOX/$MESSAGE_ID/t/
diff --git a/t/psgi_v2.t b/t/psgi_v2.t
index 1e45c26..eaa3218 100644
--- a/t/psgi_v2.t
+++ b/t/psgi_v2.t
@@ -127,6 +127,18 @@ test_psgi(sub { $www->call(@_) }, sub {
 		@from_ = ($raw =~ m/^From /mg);
 		is(scalar(@from_), 3, 'three From_ lines in t.mbox.gz');
 	};
+
+	local $SIG{__WARN__} = 'DEFAULT';
+	$res = $cb->(GET('/v2test/a-mid@b/'));
+	$raw = $res->content;
+	like($raw, qr/^hello world$/m, 'got first message');
+	like($raw, qr/^hello world!$/m, 'got second message');
+	like($raw, qr/^hello ghosts$/m, 'got third message');
+	@from_ = ($raw =~ m/>From: /mg);
+	is(scalar(@from_), 3, 'three From: lines');
+	foreach my $mid ('a-mid@b', $new_mid, $third) {
+		like($raw, qr/&lt;\Q$mid\E&gt;/s, "Message-ID $mid shown");
+	}
 });
 
 done_testing();
-- 
EW


  parent reply	other threads:[~2018-03-27 11:11 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-27 11:11 [PATCH 00/11] duplicate support in UI + tests Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` [PATCH 01/11] import: consolidate mid prepend logic, here Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` [PATCH 02/11] www: $MESSAGE_ID/raw endpoint supports "duplicates" Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` [PATCH 03/11] search: reopen DB if each_smsg_by_mid fails Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` [PATCH 04/11] t/psgi_v2: minimal test for Atom feed and t.mbox.gz Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` [PATCH 05/11] feed: fix new.html for v2 Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` Eric Wong (Contractor, The Linux Foundation) [this message]
2018-03-27 11:11 ` [PATCH 07/11] searchidx: warn about vivifying multiple ghosts Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` [PATCH 08/11] v2writable: warn on unseen deleted files Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` [PATCH 09/11] www: get rid of unnecessary 'inbox' name reference Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` [PATCH 10/11] searchview: remove unnecessary imports from MID module Eric Wong (Contractor, The Linux Foundation)
2018-03-27 11:11 ` [PATCH 11/11] view: depend on SearchMsg for Message-ID Eric Wong (Contractor, The Linux Foundation)

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://public-inbox.org/README

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180327111132.20681-7-e@80x24.org \
    --to=e@80x24.org \
    --cc=meta@public-inbox.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/public-inbox.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).