[mb-commits] branch, beta, updated. Merge branch 'mbs-4108-wikipedia-abstract' into beta MBS-4108: add tests MBS-...

MusicBrainz Git Server <[email protected]>
Newsgroups gmane.comp.audio.musicbrainz.cvs
Message-ID <E1TdO3L-0006Z0-FT@wiley>
The branch, beta has been updated
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=f3ec53f76a666887da99daf6d2f25bbbef0ed75f (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=0980b5784b237dd3ef7dde7dd721f15a2a46170c (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=14610b4dbbd035ce96911a5515c75d7946bd9db5 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=bbac5ef52d678a14ceaad6c4a8da54ff796943f3 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=b0491433b58ebc62363e6ef23744e811d6982aeb (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=94a84cc18badbbf833bb31cb679bb6552e3d05db (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=3cd8cb99255cf40b8344585ff05767112e66294f (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=ba9aef0abe1c4e886d131293340ae9cecd37b0c4 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=5c582219f6c1a6afd0fdd774deb9c32bd0a012d5 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=00ae5da085ab0b1f2037d4ac8639cca1c83ba05c (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=ebf1b4c9f0f22ffe57dcc5d7ebea100a88c74727 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=cd037d00fe21e82c7d0487686bbe9a088ca94344 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=17690bcc4d06d0575337400997db498d506b3844 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=a1ef210204d514a6a5ed0b189a1f80b2dcf3017b (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=c65039dc3ad96e3198f2981b280130765b5b9502 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=396bd51c68ee773271b09e58eaea95995ac67d11 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=5dfaeba3b4550d3fb493c432ed64bb60936b145e (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=3c886524a56cd9bbed1966f16527b13617e899f2 (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=6ac1e7a274b6f8aa7c787073152fb8f28b441fec (commit)
       via  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=00dfb90267e7b7f37b097dab416c77ed922b17c6 (commit)
      from  http://git.musicbrainz.org/gitweb/?p=musicbrainz-server/core.git;a=commit;h=667064ed94d95f4a5cb04d28cadf59079440266f (commit)

Summary of changes:
 lib/MusicBrainz/Server/Controller/Artist.pm        |    1 +
 lib/MusicBrainz/Server/Controller/JS.pm            |   24 +++-
 lib/MusicBrainz/Server/Controller/Label.pm         |    1 +
 lib/MusicBrainz/Server/Controller/ReleaseGroup.pm  |    1 +
 .../Server/Controller/Role/WikipediaExtract.pm     |   71 ++++++++
 lib/MusicBrainz/Server/Controller/Work.pm          |    1 +
 lib/MusicBrainz/Server/Data/FileCache.pm           |   42 +++++
 lib/MusicBrainz/Server/Data/WikipediaExtract.pm    |  172 ++++++++++++++++++++
 lib/MusicBrainz/Server/Entity/URL/Wikipedia.pm     |   32 +++-
 .../Entity/{WikiDocPage.pm => WikipediaExtract.pm} |   26 ++--
 root/artist/index.tt                               |    2 +
 root/components/common-macros.tt                   |   15 ++
 root/components/wikipedia_extract.tt               |    5 +
 root/label/index.tt                                |    2 +
 root/layout.tt                                     |    9 +-
 root/release_group/index.tt                        |    3 +
 root/statistics/timeline.tt                        |    9 +-
 root/work/index.tt                                 |    3 +
 .../t/MusicBrainz/Server/Data/WikipediaExtract.pm  |   75 +++++++++
 t/lwp-sessions/data_wikipedia.en-en.lwp-mock       |  Bin 0 -> 1617 bytes
 t/lwp-sessions/data_wikipedia.ja-en.lwp-mock       |  Bin 0 -> 3358 bytes
 .../data_wikipedia.nl-en-fallback.lwp-mock         |  Bin 0 -> 3527 bytes
 22 files changed, 470 insertions(+), 24 deletions(-)
 create mode 100644 lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
 create mode 100644 lib/MusicBrainz/Server/Data/WikipediaExtract.pm
 copy lib/MusicBrainz/Server/Entity/{WikiDocPage.pm => WikipediaExtract.pm} (77%)
 create mode 100644 root/components/wikipedia_extract.tt
 create mode 100644 t/lib/t/MusicBrainz/Server/Data/WikipediaExtract.pm
 create mode 100644 t/lwp-sessions/data_wikipedia.en-en.lwp-mock
 create mode 100644 t/lwp-sessions/data_wikipedia.ja-en.lwp-mock
 create mode 100644 t/lwp-sessions/data_wikipedia.nl-en-fallback.lwp-mock

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit f3ec53f76a666887da99daf6d2f25bbbef0ed75f
Merge: 0980b57 b049143
Author: Ian McEwen <[email protected]>
Date:   Tue Nov 27 09:23:19 2012 -0700

    Merge branch 'mbs-4108-wikipedia-abstract' into beta


commit 0980b5784b237dd3ef7dde7dd721f15a2a46170c
Merge: 667064e 14610b4
Author: Ian McEwen <[email protected]>
Date:   Tue Nov 27 09:22:47 2012 -0700

    Merge branch 'mbs-5260-new' into beta


commit 14610b4dbbd035ce96911a5515c75d7946bd9db5
Author: Ian McEwen <[email protected]>
Date:   Tue Nov 27 09:19:23 2012 -0700

    MBS-5260: Don't set expires header on development servers

diff --git a/lib/MusicBrainz/Server/Controller/JS.pm b/lib/MusicBrainz/Server/Controller/JS.pm
index ba0121f..a992650 100644
--- a/lib/MusicBrainz/Server/Controller/JS.pm
+++ b/lib/MusicBrainz/Server/Controller/JS.pm
@@ -2,6 +2,7 @@ package MusicBrainz::Server::Controller::JS;
 use Moose;
 use MusicBrainz::Server::Data::Utils qw( generate_gid );
 use Date::Calc qw( Today Add_Delta_Days Date_to_Time );
+use DBDefs;
 
 BEGIN { extends 'Catalyst::Controller' }
 
@@ -13,9 +14,11 @@ sub js_text_setup : Chained('/') PathPart('scripts') CaptureArgs(2) {
     # We rely on templates to correctly pass hash/language;
     # They're just here to ensure a different URL
 
-    # Far in the future - 1 year
-    my $expiration = Date_to_Time(Add_Delta_Days(Today(1), 365), 0, 0, 0);
-    $c->res->headers->expires($expiration);
+    unless (DBDefs->DEVELOPMENT_SERVER) {
+        # Far in the future - 1 year
+        my $expiration = Date_to_Time(Add_Delta_Days(Today(1), 365), 0, 0, 0);
+        $c->res->headers->expires($expiration);
+    }
 }
 
 sub js_text_strings : Chained('js_text_setup') PathPart('text.js') {

commit bbac5ef52d678a14ceaad6c4a8da54ff796943f3
Merge: 94a84cc 996b98e
Author: Ian McEwen <[email protected]>
Date:   Tue Nov 27 09:17:31 2012 -0700

    Merge branch 'master' into mbs-5260-new


commit b0491433b58ebc62363e6ef23744e811d6982aeb
Author: Ian McEwen <[email protected]>
Date:   Mon Nov 5 13:41:39 2012 -0700

    MBS-4108: add tests
    
     * Note: cache is not tested because t::Context uses Cache::Memory,
       whose expiration time format is incompatible with Cache::Memcached

diff --git a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
index a65415a..28898e1 100644
--- a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
@@ -103,7 +103,7 @@ sub _get_cache_and_key
 {
     my ($self, $prefix, $title, $language) = @_;
     $title = uri_escape($title);
-    my $cache = $self->c->cache('wp');
+    my $cache = $self->c->cache;
     my $cache_key = "wp:$prefix:$title:$language";
 
     return ($cache, $cache_key)
diff --git a/t/lib/t/MusicBrainz/Server/Data/WikipediaExtract.pm b/t/lib/t/MusicBrainz/Server/Data/WikipediaExtract.pm
new file mode 100644
index 0000000..eff9748
--- /dev/null
+++ b/t/lib/t/MusicBrainz/Server/Data/WikipediaExtract.pm
@@ -0,0 +1,75 @@
+package t::MusicBrainz::Server::Data::WikipediaExtract;
+use Test::Routine;
+use Test::More;
+use Test::Fatal;
+use utf8;
+
+use FindBin qw($Bin);
+use LWP::UserAgent::Mockable;
+
+with 't::Context';
+
+test 'Get ja page from en' => sub {
+    my $test = shift;
+    my $c = $test->c;
+
+    LWP::UserAgent::Mockable->reset(
+        playback => $Bin.'/lwp-sessions/data_wikipedia.ja-en.lwp-mock'
+    );
+
+    # No cache
+    my $extract = $c->model('WikipediaExtract')->get_extract('Perfume (Japanese band)', 'ja', 'en', cache_only => 1);
+    ok(!defined $extract);
+
+    # Now let it prime the cache
+    $extract = $c->model('WikipediaExtract')->get_extract('Perfume (Japanese band)', 'ja', 'en', cache_only => 0);
+    ok(defined $extract);
+
+    like($extract->content, qr{は、広島県出身の女性3人組テクノポップユニットである。}, "contains japanese text");
+
+    LWP::UserAgent::Mockable->finished;
+};
+
+test 'Get en page from en' => sub {
+    my $test = shift;
+    my $c = $test->c;
+
+    LWP::UserAgent::Mockable->reset(
+        playback => $Bin.'/lwp-sessions/data_wikipedia.en-en.lwp-mock'
+    );
+
+    # No cache
+    my $extract = $c->model('WikipediaExtract')->get_extract('Perfume (Japanese band)', 'en', 'en', cache_only => 1);
+    ok(!defined $extract);
+
+    # Now let it use the network
+    $extract = $c->model('WikipediaExtract')->get_extract('Perfume (Japanese band)', 'en', 'en', cache_only => 0);
+    ok(defined $extract);
+
+    like($extract->content, qr{Japanese pop girl group}, "contains english text");
+
+    LWP::UserAgent::Mockable->finished;
+};
+
+test 'Get nl page from en, fallback to en' => sub {
+    my $test = shift;
+    my $c = $test->c;
+
+    LWP::UserAgent::Mockable->reset(
+        playback => $Bin.'/lwp-sessions/data_wikipedia.nl-en-fallback.lwp-mock'
+    );
+
+    # No cache
+    my $extract = $c->model('WikipediaExtract')->get_extract('Perfume (Japanese band)', 'nl', 'en', cache_only => 1);
+    ok(!defined $extract);
+
+    # Now let it use the network
+    $extract = $c->model('WikipediaExtract')->get_extract('Perfume (Japanese band)', 'nl', 'en', cache_only => 0);
+    ok(defined $extract);
+
+    like($extract->content, qr{Japanese pop girl group}, "contains english text");
+
+    LWP::UserAgent::Mockable->finished;
+};
+
+1;
diff --git a/t/lwp-sessions/data_wikipedia.en-en.lwp-mock b/t/lwp-sessions/data_wikipedia.en-en.lwp-mock
new file mode 100644
index 0000000..d00d0e6
Binary files /dev/null and b/t/lwp-sessions/data_wikipedia.en-en.lwp-mock differ
diff --git a/t/lwp-sessions/data_wikipedia.ja-en.lwp-mock b/t/lwp-sessions/data_wikipedia.ja-en.lwp-mock
new file mode 100644
index 0000000..4c1183a
Binary files /dev/null and b/t/lwp-sessions/data_wikipedia.ja-en.lwp-mock differ
diff --git a/t/lwp-sessions/data_wikipedia.nl-en-fallback.lwp-mock b/t/lwp-sessions/data_wikipedia.nl-en-fallback.lwp-mock
new file mode 100644
index 0000000..95ad75c
Binary files /dev/null and b/t/lwp-sessions/data_wikipedia.nl-en-fallback.lwp-mock differ

commit 94a84cc18badbbf833bb31cb679bb6552e3d05db
Author: Ian McEwen <[email protected]>
Date:   Wed Oct 31 12:12:40 2012 -0700

    MBS-5260: assorted stylistic cleanups recommended by ocharles

diff --git a/lib/MusicBrainz/Server/Data/FileCache.pm b/lib/MusicBrainz/Server/Data/FileCache.pm
index 0fc3d57..6c8da4b 100644
--- a/lib/MusicBrainz/Server/Data/FileCache.pm
+++ b/lib/MusicBrainz/Server/Data/FileCache.pm
@@ -43,28 +43,36 @@ sub manifest_signature {
 
 sub template_signature {
     my ($self, $template) = @_;
-    unless (exists $self->file_signatures->{'template' . $template}) {
-        $self->file_signatures->{'template' . $template} = file_md5_hex(DBDefs::MB_SERVER_ROOT . "/root/" . $template);
+    my $signature_key = 'template' . $template;
+    unless (exists $self->file_signatures->{$signature_key}) {
+        $self->file_signatures->{$signature_key} = file_md5_hex(DBDefs::MB_SERVER_ROOT . "/root/" . $template);
     }
 
-    return $self->file_signatures->{'template' . $template};
+    return $self->file_signatures->{$signature_key};
 }
 
 sub pofile_signature {
     my ($self, $domain, $language) = @_;
-    unless (exists $self->file_signatures->{'pofile' . $domain . $language}) {
+    my $signature_key = 'pofile' . $domain . $language;
+    unless (exists $self->file_signatures->{$signature_key}) {
         # First try the language as given, then fall back to the language without a country code.
         my $hash = try {
-            file_md5_hex(DBDefs::MB_SERVER_ROOT . "/po/" . $domain . '.' . $language . '.po');
+            file_md5_hex(_pofile_path($domain, $language));
         } catch {
             $language =~ s/[-_][A-Za-z]+$//;
-            file_md5_hex(DBDefs::MB_SERVER_ROOT . "/po/" . $domain . '.' . $language . '.po');
+            file_md5_hex(_pofile_path($domain, $language));
         };
 
-        $self->file_signatures->{'pofile' . $domain . $language} = $hash;
+        $self->file_signatures->{$signature_key} = $hash;
     }
 
-    return $self->file_signatures->{'pofile' . $domain . $language};
+    return $self->file_signatures->{$signature_key};
+}
+
+sub _pofile_path
+{
+    my ($domain, $language) = @_;
+    return DBDefs::MB_SERVER_ROOT . "/po/" . $domain . "." . $language . ".po";
 }
 
 sub _expand {
diff --git a/root/layout.tt b/root/layout.tt
index 643c4f5..deefc76 100644
--- a/root/layout.tt
+++ b/root/layout.tt
@@ -27,7 +27,8 @@
             [%- script_manifest('common.js.manifest') -%]
             <script type="text/javascript" src="
                 [%- lang_hash = current_language;
-                    IF current_language != 'en'; lang_hash = lang_hash _ '-' _ c.model('FileCache').pofile_signature('mb_server', current_language);
+                    IF current_language != 'en';
+                        lang_hash = lang_hash _ '-' _ c.model('FileCache').pofile_signature('mb_server', current_language);
                     END;
                     c.uri_for('/scripts', lang_hash
                         c.model('FileCache').template_signature('scripts/text_strings.tt'),
diff --git a/root/statistics/timeline.tt b/root/statistics/timeline.tt
index 40cb213..af4098d 100644
--- a/root/statistics/timeline.tt
+++ b/root/statistics/timeline.tt
@@ -10,7 +10,8 @@
 [% BLOCK layout_head %]
   <script type="text/javascript" src="
       [%- lang_hash = current_language;
-          IF current_language != 'en'; lang_hash = lang_hash _ '-' _ c.model('FileCache').pofile_signature('statistics', current_language);
+          IF current_language != 'en';
+              lang_hash = lang_hash _ '-' _ c.model('FileCache').pofile_signature('statistics', current_language);
           END;
           c.uri_for('/scripts', lang_hash
               c.model('FileCache').template_signature('statistics/view_js.tt'),

commit 3cd8cb99255cf40b8344585ff05767112e66294f
Author: Ian McEwen <[email protected]>
Date:   Wed Oct 31 02:29:26 2012 -0700

    MBS-5260: fix a lurking bug with i18n; country codes sometimes need to be dropped to find the correct .po file

diff --git a/lib/MusicBrainz/Server/Data/FileCache.pm b/lib/MusicBrainz/Server/Data/FileCache.pm
index 4374cf1..0fc3d57 100644
--- a/lib/MusicBrainz/Server/Data/FileCache.pm
+++ b/lib/MusicBrainz/Server/Data/FileCache.pm
@@ -11,6 +11,7 @@ use List::MoreUtils qw( uniq );
 use Path::Class qw( dir file );
 use MooseX::Types::Moose qw( Str );
 use MooseX::Types::Structured qw( Map );
+use Try::Tiny;
 
 has manifest_signatures => (
     isa => Map[Str, Str],
@@ -52,7 +53,15 @@ sub template_signature {
 sub pofile_signature {
     my ($self, $domain, $language) = @_;
     unless (exists $self->file_signatures->{'pofile' . $domain . $language}) {
-        $self->file_signatures->{'pofile' . $domain . $language} = file_md5_hex(DBDefs::MB_SERVER_ROOT . "/po/" . $domain . '.' . $language . '.po');
+        # First try the language as given, then fall back to the language without a country code.
+        my $hash = try {
+            file_md5_hex(DBDefs::MB_SERVER_ROOT . "/po/" . $domain . '.' . $language . '.po');
+        } catch {
+            $language =~ s/[-_][A-Za-z]+$//;
+            file_md5_hex(DBDefs::MB_SERVER_ROOT . "/po/" . $domain . '.' . $language . '.po');
+        };
+
+        $self->file_signatures->{'pofile' . $domain . $language} = $hash;
     }
 
     return $self->file_signatures->{'pofile' . $domain . $language};

commit ba9aef0abe1c4e886d131293340ae9cecd37b0c4
Merge: 396bd51 40ecdee
Author: Ian McEwen <[email protected]>
Date:   Wed Oct 31 02:11:36 2012 -0700

    Merge branch 'master' into mbs-5260-wtf
    
    Conflicts:
    	root/edit/relationship/create_batch.tt


commit 5c582219f6c1a6afd0fdd774deb9c32bd0a012d5
Author: Ian McEwen <[email protected]>
Date:   Wed Oct 31 01:46:12 2012 -0700

    MBS-4108: change to uri_for_action and action_for; keep the URI generation in the role, though

diff --git a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
index 88e74c5..a2ab947 100644
--- a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
@@ -41,7 +41,7 @@ sub _get_extract
         if ($wp_extract) {
             $c->stash->{wikipedia_extract} = $wp_extract;
         } else {
-            $c->stash->{wikipedia_extract_url} = $c->req->uri . '/wikipedia-extract';
+            $c->stash->{wikipedia_extract_url} = $c->uri_for_action($self->action_for('wikipedia_extract'), [ $entity->gid ]);
         }
     }
 }

commit 00ae5da085ab0b1f2037d4ac8639cca1c83ba05c
Merge: ebf1b4c 082e608
Author: Ian McEwen <[email protected]>
Date:   Fri Oct 26 12:38:04 2012 -0700

    Merge branch 'master' into mbs-4108-wikipedia-abstract
    
    Conflicts:
    	root/components/common-macros.tt

diff --cc root/components/common-macros.tt
index 7d0f5fb,e6adf62..2318bd7
--- a/root/components/common-macros.tt
+++ b/root/components/common-macros.tt
@@@ -773,17 -806,25 +806,40 @@@ http://[%- server -%]/[%- id -%]
      [% type_id == 1 ? l('Died:') : type_id == 2 ? l('Dissolved:') : l('End date:') %]
  [%- END -%]
  
 +[%- MACRO show_wikipedia_extract BLOCK -%]
 +    [%- IF wikipedia_extract -%]
 +        [%- INCLUDE 'components/wikipedia_extract.tt' -%]
 +    [%- ELSIF wikipedia_extract_url -%]
 +        <span style="display:none" id="wikipedia-insertion-point"></span>
 +        <script type="text/javascript">//<![CDATA[
 +            $.get('[% wikipedia_extract_url %]',
 +                  function (data) {
 +                      $('#wikipedia-insertion-point').replaceWith(data);
 +                  },
 +                  'html');
 +        //]]></script>
 +    [%- END -%]
 +[%- END -%]
++
+ [%- MACRO track_duration_changes(loop_over, old_base, new_base, old_prop, new_prop) BLOCK -%]
+   [% USE Diff %]
+   [%- FOR i = loop_over %]
+      [%- IF old_prop;
+        old_length = old_base.${ loop.index }.${ old_prop } | format_length;
+          ELSE;
+        old_length = old_base.${ loop.index } | format_length;
+          END;
+          IF new_prop;
+        new_length = new_base.${ loop.index }.${ new_prop } | format_length;
+          ELSE;
+        new_length = new_base.${ loop.index } | format_length;
+          END %]
+      <table class="wrap-block details">
+          <tr>
+              <td class="old">[%- Diff.diff_side(old_length, new_length, '-', '') -%]</td>
+          </tr><tr>
+              <td class="new">[%- Diff.diff_side(old_length, new_length, '+', '') -%]</td>
+          </tr>
+      </table>
+   [%- END -%]
+ [%- END -%]

commit ebf1b4c9f0f22ffe57dcc5d7ebea100a88c74727
Author: Ian McEwen <[email protected]>
Date:   Mon Oct 15 14:27:50 2012 -0700

    MBS-4108: condense and abstract Data::WikipediaExtract extensively
    
     * condense the giant if/elsif/else block by fudging $english a bit: if
       $wikipedia_language eq 'en', use a fake object with the same
       structure, rather than processing the list
     * Having done this, simply create a $use_obj with chained || to do the
       fallbacks
     * Additionally, deal with the structural similarity of getting from
       cache-or-a-url for extracts or language links by abstrating it out
       into a new private function

diff --git a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
index e1da43a..a65415a 100644
--- a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
@@ -31,31 +31,14 @@ sub get_extract
 
     if (defined $languages) {
         my $lang_wanted = first { $_->{lang} eq $wanted_language } @$languages;
-        my $english = first { $_->{lang} eq 'en' } @$languages;
-
-        my ($use_title, $use_lang);
-        # Fetched one language, want a different one, but it's there!
-        if ($lang_wanted) {
-            $use_title = $lang_wanted->{'*'};
-            $use_lang = $lang_wanted->{lang};
-        }
-        # Don't have what we want, but we fetched English
-        elsif ($wikipedia_language eq 'en') {
-            $use_title = $title;
-            $use_lang = $wikipedia_language;
-        }
-        # Fetched a language other than English;
-        # desired language wasn't available but English was
-        elsif ($english) {
-            $use_title = $english->{'*'};
-            $use_lang = $english->{lang};
-        }
-        # Neither English nor what we wanted, just display what we have
-        else {
-            $use_title = $title;
-            $use_lang = $wikipedia_language;
-        }
-        return $self->get_extract_by_language($use_title, $use_lang, cache_only => $cache_only);
+        # Make sure if english was $wikipedia_language, we still know to use it
+        my $english = $wikipedia_language eq 'en' ?
+                          {'*' => $title, 'lang' => 'en'} :
+                          first { $_->{lang} eq 'en' } @$languages;
+
+        # Desired language, fallback to english, fall back to "whatever we have"
+        my $use_obj = $lang_wanted || $english || {'*' => $title, 'lang' => $wikipedia_language};
+        return $self->get_extract_by_language($use_obj->{'*'}, $use_obj->{lang}, cache_only => $cache_only);
     } else {
         # We have no language data, probably because we requested cache_only
         return undef;
@@ -65,48 +48,55 @@ sub get_extract
 sub get_extract_by_language
 {
     my ($self, $title, $language, %opts) = @_;
+    my $url_pattern = "http://%s.wikipedia.org/w/api.php?action=query&prop=extracts&exsentences=100&format=json&redirects=1&titles=%s";
+    return $self->_fetch_cache_or_url($url_pattern, 'extract',
+                                      $EXTRACT_CACHE_TIMEOUT,
+                                      $title, $language,
+                                      \&_extract_by_language_callback,
+                                      %opts);
+}
+
+sub get_available_languages
+{
+    my ($self, $title, $language, %opts) = @_;
+    my $url_pattern = "http://%s.wikipedia.org/w/api.php?action=query&prop=langlinks&lllimit=500&format=json&redirects=1&titles=%s";
+    return $self->_fetch_cache_or_url($url_pattern, 'langlinks',
+                                      $LANG_CACHE_TIMEOUT,
+                                      $title, $language,
+                                      sub { my (%opts) = @_; return $opts{fetched}{content}; },
+                                      %opts);
+}
+
+sub _fetch_cache_or_url
+{
+    my ($self, $url_pattern, $json_property, $cache_timeout, $title, $language, $callback, %opts) = @_;
     my $cache_only = $opts{cache_only} // 0;
 
-    my ($cache, $cache_key) = $self->_get_cache_and_key('wp:extract', $title, $language);
+    my ($cache, $cache_key) = $self->_get_cache_and_key($json_property, $title, $language);
 
-    my $extract = $cache->get($cache_key);
+    my $value = $cache->get($cache_key);
 
-    unless (defined $extract || $cache_only) {
-        my $wp_url = sprintf "http://%s.wikipedia.org/w/api.php?action=query&prop=extracts&exsentences=100&format=json&redirects=1&titles=%s", $language, $title;
+    unless (defined $value || $cache_only) {
+        my $wp_url = sprintf $url_pattern, $language, $title;
 
-        my $ret = $self->_get_and_process_json($wp_url, $title, 'extract');
+        my $ret = $self->_get_and_process_json($wp_url, $title, $json_property);
         unless ($ret) { return undef }
 
-        $extract = WikipediaExtract->new( title => $ret->{title},
-                                          content => $ret->{content},
-                                          canonical => $ret->{canonical},
-                                          language => $language );
+        $value = &$callback(fetched => $ret, language => $language);
 
-        $cache->set($cache_key, $extract, $EXTRACT_CACHE_TIMEOUT);
+        $cache->set($cache_key, $value, $cache_timeout);
     }
 
-    return $extract;
+    return $value;
 }
 
-sub get_available_languages
+sub _extract_by_language_callback
 {
-    my ($self, $title, $base_language, %opts) = @_;
-    my $cache_only = $opts{cache_only} // 0;
-
-    my ($cache, $cache_key) = $self->_get_cache_and_key('wp:languages', $title, $base_language);
-
-    my $options = $cache->get($cache_key);
-
-    unless (defined $options || $cache_only) {
-        my $languages_url = sprintf "http://%s.wikipedia.org/w/api.php?action=query&prop=langlinks&lllimit=500&format=json&redirects=1&titles=%s", $base_language, $title;
-
-        my $ret = $self->_get_and_process_json($languages_url, $title, 'langlinks');
-        unless ($ret) { return undef }
-
-        $options = $ret->{content};
-        $cache->set($cache_key, $options, $LANG_CACHE_TIMEOUT);
-    }
-    return $options;
+    my (%opts) = @_;
+    return WikipediaExtract->new( title => $opts{fetched}{title},
+                                  content => $opts{fetched}{content},
+                                  canonical => $opts{fetched}{canonical},
+                                  language => $opts{language} );
 }
 
 sub _get_cache_and_key
@@ -114,7 +104,7 @@ sub _get_cache_and_key
     my ($self, $prefix, $title, $language) = @_;
     $title = uri_escape($title);
     my $cache = $self->c->cache('wp');
-    my $cache_key = "$prefix:$title:$language";
+    my $cache_key = "wp:$prefix:$title:$language";
 
     return ($cache, $cache_key)
 }

commit cd037d00fe21e82c7d0487686bbe9a088ca94344
Author: Ian McEwen <[email protected]>
Date:   Mon Oct 15 14:27:25 2012 -0700

    MBS-4108: remove __PACKAGE__->meta->make_immutable since it doesn't work

diff --git a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
index b9493f5..88e74c5 100644
--- a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
@@ -46,7 +46,6 @@ sub _get_extract
     }
 }
 
-__PACKAGE__->meta->make_immutable;
 no Moose::Role;
 1;
 

commit 17690bcc4d06d0575337400997db498d506b3844
Author: Ian McEwen <[email protected]>
Date:   Mon Oct 15 13:16:59 2012 -0700

    MBS-4108: clean up Controller::Role::WikipediaExtract

diff --git a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
index e131f5e..b9493f5 100644
--- a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
@@ -1,7 +1,6 @@
 package MusicBrainz::Server::Controller::Role::WikipediaExtract;
 use Moose::Role -traits => 'MooseX::MethodAttributes::Role::Meta::Role';
 use namespace::autoclean;
-use List::Util qw( first );
 
 after show => sub {
     my ($self, $c) = @_;
@@ -24,25 +23,19 @@ sub _get_extract
 
     my $entity = $c->stash->{entity};
     my $wanted_lang = $c->stash->{current_language} // 'en';
-    # remove country codes
+    # Remove country codes, at least for now
     $wanted_lang =~ s/[_-][A-Za-z]+$//;
 
-    my $entity_direction = 'entity1';
-    if ($self->isa('MusicBrainz::Server::Controller::Work')) {
-        $entity_direction = 'entity0';
-    }
-
-    my @wp_links = sort {
-        if (defined $_) {
-            my $l = $_->$entity_direction;
-            $l->language eq $wanted_lang;
-        }
-    } @{ $entity->relationships_by_link_type_names('wikipedia') };
-
-    my $wp_link = shift @wp_links;
+    my ($wp_link) = map {
+            $_->target;
+        } sort {
+            if (defined $_) {
+                my $l = $_->target;
+                $l->language eq $wanted_lang;
+            }
+        } @{ $entity->relationships_by_link_type_names('wikipedia') };
 
     if ($wp_link) {
-        $wp_link = $wp_link->$entity_direction;
 
         my $wp_extract = $c->model('WikipediaExtract')->get_extract($wp_link->page_name, $wanted_lang, $wp_link->language, cache_only => $cache_only);
         if ($wp_extract) {
@@ -53,6 +46,7 @@ sub _get_extract
     }
 }
 
+__PACKAGE__->meta->make_immutable;
 no Moose::Role;
 1;
 

commit a1ef210204d514a6a5ed0b189a1f80b2dcf3017b
Author: Ian McEwen <[email protected]>
Date:   Mon Oct 15 13:14:40 2012 -0700

    MBS-4108: remove duplicate country-code trimming

diff --git a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
index cacffee..e1da43a 100644
--- a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
@@ -22,9 +22,6 @@ sub get_extract
     my ($self, $title, $wanted_language, $wikipedia_language, %opts) = @_;
     my $cache_only = $opts{cache_only} // 0;
 
-    # trim country codes (at least for now)
-    $wanted_language =~ s/[_-][A-Za-z]+$//;
-
     if ($wanted_language eq $wikipedia_language) {
         return $self->get_extract_by_language($title, $wikipedia_language, cache_only => $cache_only);
     }

commit c65039dc3ad96e3198f2981b280130765b5b9502
Author: Ian McEwen <[email protected]>
Date:   Thu Oct 11 21:01:58 2012 -0700

    MBS-4108: where the cache is cold, load wikipedia extracts asynchronously

diff --git a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
index dd726f6..e131f5e 100644
--- a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
@@ -1,27 +1,59 @@
 package MusicBrainz::Server::Controller::Role::WikipediaExtract;
-use Moose::Role;
+use Moose::Role -traits => 'MooseX::MethodAttributes::Role::Meta::Role';
 use namespace::autoclean;
+use List::Util qw( first );
 
 after show => sub {
     my ($self, $c) = @_;
 
+    $self->_get_extract($c, 1);
+};
+
+sub wikipedia_extract : Chained('load') PathPart('wikipedia-extract')
+{
+    my ($self, $c) = @_;
+
+    $self->_get_extract($c, 0);
+
+    $c->stash->{template} = 'components/wikipedia_extract.tt';
+}
+
+sub _get_extract
+{
+    my ($self, $c, $cache_only) = @_;
+
     my $entity = $c->stash->{entity};
-    my $wp_link = shift @{ $entity->relationships_by_link_type_names('wikipedia') };
+    my $wanted_lang = $c->stash->{current_language} // 'en';
+    # remove country codes
+    $wanted_lang =~ s/[_-][A-Za-z]+$//;
 
-    if ($wp_link) {
-        my $wanted_lang = $c->stash->{current_language} // 'en';
-        if ($self->isa('MusicBrainz::Server::Controller::Work')) {
-            $wp_link = $wp_link->entity0;
-        } else {
-            $wp_link = $wp_link->entity1;
+    my $entity_direction = 'entity1';
+    if ($self->isa('MusicBrainz::Server::Controller::Work')) {
+        $entity_direction = 'entity0';
+    }
+
+    my @wp_links = sort {
+        if (defined $_) {
+            my $l = $_->$entity_direction;
+            $l->language eq $wanted_lang;
         }
+    } @{ $entity->relationships_by_link_type_names('wikipedia') };
+
+    my $wp_link = shift @wp_links;
+
+    if ($wp_link) {
+        $wp_link = $wp_link->$entity_direction;
 
-        my $wp_extract = $c->model('WikipediaExtract')->get_extract($wp_link->page_name, $wanted_lang, $wp_link->language);
+        my $wp_extract = $c->model('WikipediaExtract')->get_extract($wp_link->page_name, $wanted_lang, $wp_link->language, cache_only => $cache_only);
         if ($wp_extract) {
             $c->stash->{wikipedia_extract} = $wp_extract;
+        } else {
+            $c->stash->{wikipedia_extract_url} = $c->req->uri . '/wikipedia-extract';
         }
     }
-};
+}
+
+no Moose::Role;
 1;
 
 =head1 COPYRIGHT
diff --git a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
index 08f412d..cacffee 100644
--- a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
@@ -6,49 +6,75 @@ use Readonly;
 use aliased 'MusicBrainz::Server::Entity::WikipediaExtract';
 use JSON;
 use Encode qw( encode );
+use URI::Escape qw( uri_escape );
 use List::Util qw( first );
 
 with 'MusicBrainz::Server::Data::Role::Context';
 
-Readonly my $LANG_CACHE_TIMEOUT => 60 * 60; # 1 hour
-Readonly my $EXTRACT_CACHE_TIMEOUT => 60 * 60 * 24; # 1 day
+# We'll assume interlanguage links don't change much
+Readonly my $LANG_CACHE_TIMEOUT => 60 * 60 * 24 * 7; # 1 week
+# Extracts will change more often, but
+# we still want to keep them around a while
+Readonly my $EXTRACT_CACHE_TIMEOUT => 60 * 60 * 24 * 3; # 3 days
 
 sub get_extract
 {
-    my ($self, $title, $wanted_language, $wikipedia_language) = @_;
+    my ($self, $title, $wanted_language, $wikipedia_language, %opts) = @_;
+    my $cache_only = $opts{cache_only} // 0;
 
     # trim country codes (at least for now)
     $wanted_language =~ s/[_-][A-Za-z]+$//;
 
     if ($wanted_language eq $wikipedia_language) {
-        return $self->get_extract_by_language($title, $wikipedia_language);
+        return $self->get_extract_by_language($title, $wikipedia_language, cache_only => $cache_only);
     }
 
-    my $languages = $self->get_available_languages($title, $wikipedia_language);
-
-    my $lang_wanted = first { $_->{lang} eq $wanted_language } @$languages;
-    my $english = first { $_->{lang} eq 'en' } @$languages;
-
-    if ($lang_wanted) {
-        return $self->get_extract_by_language($lang_wanted->{'*'}, $lang_wanted->{lang});
-    } elsif ($wikipedia_language eq 'en') {
-        return $self->get_extract_by_language($title, $wikipedia_language);
-    } elsif ($english) {
-        return $self->get_extract_by_language($english->{'*'}, $english->{lang});
+    # We didn't by luck get a link in the right language
+    my $languages = $self->get_available_languages($title, $wikipedia_language, cache_only => $cache_only);
+
+    if (defined $languages) {
+        my $lang_wanted = first { $_->{lang} eq $wanted_language } @$languages;
+        my $english = first { $_->{lang} eq 'en' } @$languages;
+
+        my ($use_title, $use_lang);
+        # Fetched one language, want a different one, but it's there!
+        if ($lang_wanted) {
+            $use_title = $lang_wanted->{'*'};
+            $use_lang = $lang_wanted->{lang};
+        }
+        # Don't have what we want, but we fetched English
+        elsif ($wikipedia_language eq 'en') {
+            $use_title = $title;
+            $use_lang = $wikipedia_language;
+        }
+        # Fetched a language other than English;
+        # desired language wasn't available but English was
+        elsif ($english) {
+            $use_title = $english->{'*'};
+            $use_lang = $english->{lang};
+        }
+        # Neither English nor what we wanted, just display what we have
+        else {
+            $use_title = $title;
+            $use_lang = $wikipedia_language;
+        }
+        return $self->get_extract_by_language($use_title, $use_lang, cache_only => $cache_only);
     } else {
-        return $self->get_extract_by_language($title, $wikipedia_language);
+        # We have no language data, probably because we requested cache_only
+        return undef;
     }
 }
 
 sub get_extract_by_language
 {
-    my ($self, $title, $language) = @_;
+    my ($self, $title, $language, %opts) = @_;
+    my $cache_only = $opts{cache_only} // 0;
 
     my ($cache, $cache_key) = $self->_get_cache_and_key('wp:extract', $title, $language);
 
     my $extract = $cache->get($cache_key);
 
-    unless (defined $extract) {
+    unless (defined $extract || $cache_only) {
         my $wp_url = sprintf "http://%s.wikipedia.org/w/api.php?action=query&prop=extracts&exsentences=100&format=json&redirects=1&titles=%s", $language, $title;
 
         my $ret = $self->_get_and_process_json($wp_url, $title, 'extract');
@@ -67,13 +93,14 @@ sub get_extract_by_language
 
 sub get_available_languages
 {
-    my ($self, $title, $base_language) = @_;
+    my ($self, $title, $base_language, %opts) = @_;
+    my $cache_only = $opts{cache_only} // 0;
 
     my ($cache, $cache_key) = $self->_get_cache_and_key('wp:languages', $title, $base_language);
 
     my $options = $cache->get($cache_key);
 
-    unless (defined $options) {
+    unless (defined $options || $cache_only) {
         my $languages_url = sprintf "http://%s.wikipedia.org/w/api.php?action=query&prop=langlinks&lllimit=500&format=json&redirects=1&titles=%s", $base_language, $title;
 
         my $ret = $self->_get_and_process_json($languages_url, $title, 'langlinks');
@@ -88,7 +115,8 @@ sub get_available_languages
 sub _get_cache_and_key
 {
     my ($self, $prefix, $title, $language) = @_;
-    my $cache = $self->c->cache($prefix);
+    $title = uri_escape($title);
+    my $cache = $self->c->cache('wp');
     my $cache_key = "$prefix:$title:$language";
 
     return ($cache, $cache_key)
diff --git a/root/components/common-macros.tt b/root/components/common-macros.tt
index 4b3efe6..7d0f5fb 100644
--- a/root/components/common-macros.tt
+++ b/root/components/common-macros.tt
@@ -775,8 +775,15 @@ http://[%- server -%]/[%- id -%]"
 
 [%- MACRO show_wikipedia_extract BLOCK -%]
     [%- IF wikipedia_extract -%]
-    <h2 class="wikipedia">[% l('Wikipedia') %]</h2>
-        [%- wikipedia_extract.content -%]
-        <a href="[% wikipedia_extract.url %]">[% l('Read more...') %]</a>
+        [%- INCLUDE 'components/wikipedia_extract.tt' -%]
+    [%- ELSIF wikipedia_extract_url -%]
+        <span style="display:none" id="wikipedia-insertion-point"></span>
+        <script type="text/javascript">//<![CDATA[
+            $.get('[% wikipedia_extract_url %]',
+                  function (data) {
+                      $('#wikipedia-insertion-point').replaceWith(data);
+                  },
+                  'html');
+        //]]></script>
     [%- END -%]
 [%- END -%]
diff --git a/root/components/wikipedia_extract.tt b/root/components/wikipedia_extract.tt
new file mode 100644
index 0000000..d6e032a
--- /dev/null
+++ b/root/components/wikipedia_extract.tt
@@ -0,0 +1,5 @@
+[%- IF wikipedia_extract -%]
+<h2 class="wikipedia">[% l('Wikipedia') %]</h2>
+    [%- wikipedia_extract.content -%]
+    <a href="[% wikipedia_extract.url %]">[% l('Read more...') %]</a>
+[%- END -%]

commit 396bd51c68ee773271b09e58eaea95995ac67d11
Author: Ian McEwen <[email protected]>
Date:   Wed Oct 10 09:45:43 2012 -0700

    MBS-5260: make translated .js files depend on .po file state too

diff --git a/lib/MusicBrainz/Server/Controller/JS.pm b/lib/MusicBrainz/Server/Controller/JS.pm
index 117ed68..ba0121f 100644
--- a/lib/MusicBrainz/Server/Controller/JS.pm
+++ b/lib/MusicBrainz/Server/Controller/JS.pm
@@ -9,7 +9,7 @@ sub begin : Private {}
 sub end : ActionClass('RenderView') { }
 
 sub js_text_setup : Chained('/') PathPart('scripts') CaptureArgs(2) {
-    my ($self, $c, $lang, $hash) = @_;
+    my ($self, $c, $lang_hash, $hash) = @_;
     # We rely on templates to correctly pass hash/language;
     # They're just here to ensure a different URL
 
diff --git a/lib/MusicBrainz/Server/Data/FileCache.pm b/lib/MusicBrainz/Server/Data/FileCache.pm
index 03ca056..4374cf1 100644
--- a/lib/MusicBrainz/Server/Data/FileCache.pm
+++ b/lib/MusicBrainz/Server/Data/FileCache.pm
@@ -49,6 +49,15 @@ sub template_signature {
     return $self->file_signatures->{'template' . $template};
 }
 
+sub pofile_signature {
+    my ($self, $domain, $language) = @_;
+    unless (exists $self->file_signatures->{'pofile' . $domain . $language}) {
+        $self->file_signatures->{'pofile' . $domain . $language} = file_md5_hex(DBDefs::MB_SERVER_ROOT . "/po/" . $domain . '.' . $language . '.po');
+    }
+
+    return $self->file_signatures->{'pofile' . $domain . $language};
+}
+
 sub _expand {
     my ($path, $type) = @_;
     if (-d $path) {
diff --git a/root/layout.tt b/root/layout.tt
index a97ebde..36b35ff 100644
--- a/root/layout.tt
+++ b/root/layout.tt
@@ -26,7 +26,13 @@
             </style>
         [%- ELSE -%]
             [%- script_manifest('common.js.manifest') -%]
-            <script type="text/javascript" src="[% c.uri_for('/scripts', current_language, c.model('FileCache').template_signature('scripts/text_strings.tt'), 'text.js') %]"></script>
+            <script type="text/javascript" src="
+                [%- lang_hash = current_language;
+                    IF current_language != 'en'; lang_hash = lang_hash _ '-' _ c.model('FileCache').pofile_signature('mb_server', current_language);
+                    END;
+                    c.uri_for('/scripts', lang_hash
+                        c.model('FileCache').template_signature('scripts/text_strings.tt'),
+                        'text.js') -%]"></script>
         [%- END -%]
         <script type="text/javascript">//<![CDATA[
             $(document).ready (function () {
diff --git a/root/statistics/timeline.tt b/root/statistics/timeline.tt
index 4a8a298..41e4f50 100644
--- a/root/statistics/timeline.tt
+++ b/root/statistics/timeline.tt
@@ -7,7 +7,13 @@
 [% END %]
 
 [% BLOCK layout_head %]
-  <script type="text/javascript" src="[% c.uri_for('/scripts', current_language, c.model('FileCache').template_signature('statistics/view_js.tt'), 'statistics/view.js') %]"></script>
+  <script type="text/javascript" src="
+      [%- lang_hash = current_language;
+          IF current_language != 'en'; lang_hash = lang_hash _ '-' _ c.model('FileCache').pofile_signature('statistics', current_language);
+          END;
+          c.uri_for('/scripts', lang_hash
+              c.model('FileCache').template_signature('statistics/view_js.tt'),
+              'statistics/view.js') -%]"></script>
   [% script_manifest('statistics.js.manifest') %]
   <style type="text/css">
       h2#graph-toggle-header {

commit 5dfaeba3b4550d3fb493c432ed64bb60936b145e
Author: Ian McEwen <[email protected]>
Date:   Wed Oct 10 09:21:28 2012 -0700

    MBS-5260: switch to template_signature and using file_signatures

diff --git a/lib/MusicBrainz/Server/Data/FileCache.pm b/lib/MusicBrainz/Server/Data/FileCache.pm
index 199a20e..03ca056 100644
--- a/lib/MusicBrainz/Server/Data/FileCache.pm
+++ b/lib/MusicBrainz/Server/Data/FileCache.pm
@@ -19,6 +19,13 @@ has manifest_signatures => (
     default => sub { {} }
 );
 
+has file_signatures => (
+    isa => Map[Str, Str],
+    is => 'ro',
+    traits => [ 'Hash' ],
+    default => sub { {} }
+);
+
 sub manifest_signature {
     my ($self, $manifest, $type) = @_;
     unless (exists $self->manifest_signatures->{$manifest}) {
@@ -33,13 +40,13 @@ sub manifest_signature {
     return $self->manifest_signatures->{$manifest};
 }
 
-sub textjs_signature {
+sub template_signature {
     my ($self, $template) = @_;
-    unless (exists $self->manifest_signatures->{'textjs' . $template}) {
-        $self->manifest_signatures->{'textjs' . $template} = file_md5_hex(DBDefs::MB_SERVER_ROOT . "/root/" . $template);
+    unless (exists $self->file_signatures->{'template' . $template}) {
+        $self->file_signatures->{'template' . $template} = file_md5_hex(DBDefs::MB_SERVER_ROOT . "/root/" . $template);
     }
 
-    return $self->manifest_signatures->{'textjs' . $template};
+    return $self->file_signatures->{'template' . $template};
 }
 
 sub _expand {
diff --git a/root/layout.tt b/root/layout.tt
index c0cc645..a97ebde 100644
--- a/root/layout.tt
+++ b/root/layout.tt
@@ -26,7 +26,7 @@
             </style>
         [%- ELSE -%]
             [%- script_manifest('common.js.manifest') -%]
-            <script type="text/javascript" src="[% c.uri_for('/scripts', current_language, c.model('FileCache').textjs_signature('scripts/text_strings.tt'), 'text.js') %]"></script>
+            <script type="text/javascript" src="[% c.uri_for('/scripts', current_language, c.model('FileCache').template_signature('scripts/text_strings.tt'), 'text.js') %]"></script>
         [%- END -%]
         <script type="text/javascript">//<![CDATA[
             $(document).ready (function () {
diff --git a/root/statistics/timeline.tt b/root/statistics/timeline.tt
index 5588c5a..4a8a298 100644
--- a/root/statistics/timeline.tt
+++ b/root/statistics/timeline.tt
@@ -7,7 +7,7 @@
 [% END %]
 
 [% BLOCK layout_head %]
-  <script type="text/javascript" src="[% c.uri_for('/scripts', current_language, c.model('FileCache').textjs_signature('statistics/view_js.tt'), 'statistics/view.js') %]"></script>
+  <script type="text/javascript" src="[% c.uri_for('/scripts', current_language, c.model('FileCache').template_signature('statistics/view_js.tt'), 'statistics/view.js') %]"></script>
   [% script_manifest('statistics.js.manifest') %]
   <style type="text/css">
       h2#graph-toggle-header {

commit 3c886524a56cd9bbed1966f16527b13617e899f2
Author: Ian McEwen <[email protected]>
Date:   Tue Oct 9 20:19:08 2012 -0700

    MBS-5260: cache text.js and statistics/view.js

diff --git a/lib/MusicBrainz/Server/Controller/JS.pm b/lib/MusicBrainz/Server/Controller/JS.pm
index 48cfb8d..117ed68 100644
--- a/lib/MusicBrainz/Server/Controller/JS.pm
+++ b/lib/MusicBrainz/Server/Controller/JS.pm
@@ -1,19 +1,30 @@
 package MusicBrainz::Server::Controller::JS;
 use Moose;
 use MusicBrainz::Server::Data::Utils qw( generate_gid );
+use Date::Calc qw( Today Add_Delta_Days Date_to_Time );
 
 BEGIN { extends 'Catalyst::Controller' }
 
 sub begin : Private {}
 sub end : ActionClass('RenderView') { }
 
-sub js_text_strings : Path('/text.js') {
+sub js_text_setup : Chained('/') PathPart('scripts') CaptureArgs(2) {
+    my ($self, $c, $lang, $hash) = @_;
+    # We rely on templates to correctly pass hash/language;
+    # They're just here to ensure a different URL
+
+    # Far in the future - 1 year
+    my $expiration = Date_to_Time(Add_Delta_Days(Today(1), 365), 0, 0, 0);
+    $c->res->headers->expires($expiration);
+}
+
+sub js_text_strings : Chained('js_text_setup') PathPart('text.js') {
     my ($self, $c) = @_;
     $c->res->content_type('text/javascript');
     $c->stash->{template} = 'scripts/text_strings.tt';
 }
 
-sub statistics_js_text_strings : Path('/statistics/view.js') {
+sub statistics_js_text_strings : Chained('js_text_setup') PathPart('statistics/view.js') {
     my ($self, $c) = @_;
     my %countries = map { $_->iso_code => $_ } $c->model('Country')->get_all();
     my %languages = map { $_->iso_code_3 => $_ }
@@ -23,9 +34,9 @@ sub statistics_js_text_strings : Path('/statistics/view.js') {
     my @rel_pairs = $c->model('Relationship')->all_pairs;
     $c->stash(
         template => 'statistics/view_js.tt',
-	countries => \%countries,
-	languages => \%languages,
-	scripts => \%scripts,
+        countries => \%countries,
+        languages => \%languages,
+        scripts => \%scripts,
         formats => \%formats,
         relationships => \@rel_pairs,
     );
diff --git a/lib/MusicBrainz/Server/Data/FileCache.pm b/lib/MusicBrainz/Server/Data/FileCache.pm
index c0563a0..199a20e 100644
--- a/lib/MusicBrainz/Server/Data/FileCache.pm
+++ b/lib/MusicBrainz/Server/Data/FileCache.pm
@@ -33,6 +33,15 @@ sub manifest_signature {
     return $self->manifest_signatures->{$manifest};
 }
 
+sub textjs_signature {
+    my ($self, $template) = @_;
+    unless (exists $self->manifest_signatures->{'textjs' . $template}) {
+        $self->manifest_signatures->{'textjs' . $template} = file_md5_hex(DBDefs::MB_SERVER_ROOT . "/root/" . $template);
+    }
+
+    return $self->manifest_signatures->{'textjs' . $template};
+}
+
 sub _expand {
     my ($path, $type) = @_;
     if (-d $path) {
diff --git a/root/edit/relationship/create_batch.tt b/root/edit/relationship/create_batch.tt
index a12aaac..c8a35c2 100644
--- a/root/edit/relationship/create_batch.tt
+++ b/root/edit/relationship/create_batch.tt
@@ -4,7 +4,6 @@
       'scripts/MB/html.js',
       'scripts/ar.js',
     ) %]"></script>
-   <script src="[% c.uri_for('/text.js') %]" type="text/javascript"></script>
 [% END %]
 
 [%- WRAPPER 'layout.tt' title=l('Edit Relationship') full_width=1 -%]
diff --git a/root/layout.tt b/root/layout.tt
index ce014f6..c0cc645 100644
--- a/root/layout.tt
+++ b/root/layout.tt
@@ -26,7 +26,7 @@
             </style>
         [%- ELSE -%]
             [%- script_manifest('common.js.manifest') -%]
-            <script type="text/javascript" src="[% c.uri_for('/text.js') %]"></script>
+            <script type="text/javascript" src="[% c.uri_for('/scripts', current_language, c.model('FileCache').textjs_signature('scripts/text_strings.tt'), 'text.js') %]"></script>
         [%- END -%]
         <script type="text/javascript">//<![CDATA[
             $(document).ready (function () {
diff --git a/root/statistics/timeline.tt b/root/statistics/timeline.tt
index 7f3bfb2..5588c5a 100644
--- a/root/statistics/timeline.tt
+++ b/root/statistics/timeline.tt
@@ -7,7 +7,7 @@
 [% END %]
 
 [% BLOCK layout_head %]
-  <script type="text/javascript" src="[% c.uri_for('view.js') %]"></script>
+  <script type="text/javascript" src="[% c.uri_for('/scripts', current_language, c.model('FileCache').textjs_signature('statistics/view_js.tt'), 'statistics/view.js') %]"></script>
   [% script_manifest('statistics.js.manifest') %]
   <style type="text/css">
       h2#graph-toggle-header {

commit 6ac1e7a274b6f8aa7c787073152fb8f28b441fec
Author: Ian McEwen <[email protected]>
Date:   Mon Oct 8 13:21:38 2012 -0700

    MBS-4108: update copyright notices

diff --git a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
index c3cf136..dd726f6 100644
--- a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
@@ -23,3 +23,24 @@ after show => sub {
     }
 };
 1;
+
+=head1 COPYRIGHT
+
+Copyright (C) 2012 Ian McEwen
+Copyright (C) 2012 MetaBrainz Foundation
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+=cut
diff --git a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
index afc8281..08f412d 100644
--- a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
+++ b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
@@ -137,7 +137,8 @@ no Moose;
 
 =head1 COPYRIGHT
 
-Copyright (C) 2009 Lukas Lalinsky
+Copyright (C) 2012 Ian McEwen
+Copyright (C) 2012 MetaBrainz Foundation
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
diff --git a/lib/MusicBrainz/Server/Entity/URL/Wikipedia.pm b/lib/MusicBrainz/Server/Entity/URL/Wikipedia.pm
index e341086..8697aa1 100644
--- a/lib/MusicBrainz/Server/Entity/URL/Wikipedia.pm
+++ b/lib/MusicBrainz/Server/Entity/URL/Wikipedia.pm
@@ -67,7 +67,7 @@ no Moose;
 
 =head1 COPYRIGHT
 
-Copyright (C) 2010 MetaBrainz Foundation
+Copyright (C) 2012 MetaBrainz Foundation
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by

commit 00dfb90267e7b7f37b097dab416c77ed922b17c6
Author: Ian McEwen <[email protected]>
Date:   Mon Oct 8 02:55:54 2012 -0700

    MBS-4108: Show Wikipedia extracts on entity pages

diff --git a/lib/MusicBrainz/Server/Controller/Artist.pm b/lib/MusicBrainz/Server/Controller/Artist.pm
index abe1db9..6e69da7 100644
--- a/lib/MusicBrainz/Server/Controller/Artist.pm
+++ b/lib/MusicBrainz/Server/Controller/Artist.pm
@@ -17,6 +17,7 @@ with 'MusicBrainz::Server::Controller::Role::Rating';
 with 'MusicBrainz::Server::Controller::Role::Tag';
 with 'MusicBrainz::Server::Controller::Role::Subscribe';
 with 'MusicBrainz::Server::Controller::Role::Cleanup';
+with 'MusicBrainz::Server::Controller::Role::WikipediaExtract';
 
 use Data::Page;
 use HTTP::Status qw( :constants );
diff --git a/lib/MusicBrainz/Server/Controller/Label.pm b/lib/MusicBrainz/Server/Controller/Label.pm
index 25429c7..4f88ae0 100644
--- a/lib/MusicBrainz/Server/Controller/Label.pm
+++ b/lib/MusicBrainz/Server/Controller/Label.pm
@@ -17,6 +17,7 @@ with 'MusicBrainz::Server::Controller::Role::Relationship';
 with 'MusicBrainz::Server::Controller::Role::Rating';
 with 'MusicBrainz::Server::Controller::Role::Tag';
 with 'MusicBrainz::Server::Controller::Role::Subscribe';
+with 'MusicBrainz::Server::Controller::Role::WikipediaExtract';
 
 use MusicBrainz::Server::Constants qw( $DLABEL_ID $EDIT_LABEL_CREATE $EDIT_LABEL_DELETE $EDIT_LABEL_EDIT $EDIT_LABEL_MERGE );
 use Data::Page;
diff --git a/lib/MusicBrainz/Server/Controller/ReleaseGroup.pm b/lib/MusicBrainz/Server/Controller/ReleaseGroup.pm
index ef797cc..871f9d8 100644
--- a/lib/MusicBrainz/Server/Controller/ReleaseGroup.pm
+++ b/lib/MusicBrainz/Server/Controller/ReleaseGroup.pm
@@ -22,6 +22,7 @@ with 'MusicBrainz::Server::Controller::Role::Relationship';
 with 'MusicBrainz::Server::Controller::Role::Rating';
 with 'MusicBrainz::Server::Controller::Role::Tag';
 with 'MusicBrainz::Server::Controller::Role::EditListing';
+with 'MusicBrainz::Server::Controller::Role::WikipediaExtract';
 
 use aliased 'MusicBrainz::Server::Entity::ArtistCredit';
 
diff --git a/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
new file mode 100644
index 0000000..c3cf136
--- /dev/null
+++ b/lib/MusicBrainz/Server/Controller/Role/WikipediaExtract.pm
@@ -0,0 +1,25 @@
+package MusicBrainz::Server::Controller::Role::WikipediaExtract;
+use Moose::Role;
+use namespace::autoclean;
+
+after show => sub {
+    my ($self, $c) = @_;
+
+    my $entity = $c->stash->{entity};
+    my $wp_link = shift @{ $entity->relationships_by_link_type_names('wikipedia') };
+
+    if ($wp_link) {
+        my $wanted_lang = $c->stash->{current_language} // 'en';
+        if ($self->isa('MusicBrainz::Server::Controller::Work')) {
+            $wp_link = $wp_link->entity0;
+        } else {
+            $wp_link = $wp_link->entity1;
+        }
+
+        my $wp_extract = $c->model('WikipediaExtract')->get_extract($wp_link->page_name, $wanted_lang, $wp_link->language);
+        if ($wp_extract) {
+            $c->stash->{wikipedia_extract} = $wp_extract;
+        }
+    }
+};
+1;
diff --git a/lib/MusicBrainz/Server/Controller/Work.pm b/lib/MusicBrainz/Server/Controller/Work.pm
index f478c42..a46b94c 100644
--- a/lib/MusicBrainz/Server/Controller/Work.pm
+++ b/lib/MusicBrainz/Server/Controller/Work.pm
@@ -23,6 +23,7 @@ with 'MusicBrainz::Server::Controller::Role::Rating';
 with 'MusicBrainz::Server::Controller::Role::Tag';
 with 'MusicBrainz::Server::Controller::Role::EditListing';
 with 'MusicBrainz::Server::Controller::Role::Cleanup';
+with 'MusicBrainz::Server::Controller::Role::WikipediaExtract';
 
 use aliased 'MusicBrainz::Server::Entity::ArtistCredit';
 
diff --git a/lib/MusicBrainz/Server/Data/WikipediaExtract.pm b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
new file mode 100644
index 0000000..afc8281
--- /dev/null
+++ b/lib/MusicBrainz/Server/Data/WikipediaExtract.pm
@@ -0,0 +1,156 @@
+package MusicBrainz::Server::Data::WikipediaExtract;
+use Moose;
+use namespace::autoclean;
+
+use Readonly;
+use aliased 'MusicBrainz::Server::Entity::WikipediaExtract';
+use JSON;
+use Encode qw( encode );
+use List::Util qw( first );
+
+with 'MusicBrainz::Server::Data::Role::Context';
+
+Readonly my $LANG_CACHE_TIMEOUT => 60 * 60; # 1 hour
+Readonly my $EXTRACT_CACHE_TIMEOUT => 60 * 60 * 24; # 1 day
+
+sub get_extract
+{
+    my ($self, $title, $wanted_language, $wikipedia_language) = @_;
+
+    # trim country codes (at least for now)
+    $wanted_language =~ s/[_-][A-Za-z]+$//;
+
+    if ($wanted_language eq $wikipedia_language) {
+        return $self->get_extract_by_language($title, $wikipedia_language);
+    }
+
+    my $languages = $self->get_available_languages($title, $wikipedia_language);
+
+    my $lang_wanted = first { $_->{lang} eq $wanted_language } @$languages;
+    my $english = first { $_->{lang} eq 'en' } @$languages;
+
+    if ($lang_wanted) {
+        return $self->get_extract_by_language($lang_wanted->{'*'}, $lang_wanted->{lang});
+    } elsif ($wikipedia_language eq 'en') {
+        return $self->get_extract_by_language($title, $wikipedia_language);
+    } elsif ($english) {
+        return $self->get_extract_by_language($english->{'*'}, $english->{lang});
+    } else {
+        return $self->get_extract_by_language($title, $wikipedia_language);
+    }
+}
+
+sub get_extract_by_language
+{
+    my ($self, $title, $language) = @_;
+
+    my ($cache, $cache_key) = $self->_get_cache_and_key('wp:extract', $title, $language);
+
+    my $extract = $cache->get($cache_key);
+
+    unless (defined $extract) {
+        my $wp_url = sprintf "http://%s.wikipedia.org/w/api.php?action=query&prop=extracts&exsentences=100&format=json&redirects=1&titles=%s", $language, $title;
+
+        my $ret = $self->_get_and_process_json($wp_url, $title, 'extract');
+        unless ($ret) { return undef }
+
+        $extract = WikipediaExtract->new( title => $ret->{title},
+                                          content => $ret->{content},
+                                          canonical => $ret->{canonical},
+                                          language => $language );
+
+        $cache->set($cache_key, $extract, $EXTRACT_CACHE_TIMEOUT);
+    }
+
+    return $extract;
+}
+
+sub get_available_languages
+{
+    my ($self, $title, $base_language) = @_;
+
+    my ($cache, $cache_key) = $self->_get_cache_and_key('wp:languages', $title, $base_language);
+
+    my $options = $cache->get($cache_key);
+
+    unless (defined $options) {
+        my $languages_url = sprintf "http://%s.wikipedia.org/w/api.php?action=query&prop=langlinks&lllimit=500&format=json&redirects=1&titles=%s", $base_language, $title;
+
+        my $ret = $self->_get_and_process_json($languages_url, $title, 'langlinks');
+        unless ($ret) { return undef }
+
+        $options = $ret->{content};
+        $cache->set($cache_key, $options, $LANG_CACHE_TIMEOUT);
+    }
+    return $options;
+}
+
+sub _get_cache_and_key
+{
+    my ($self, $prefix, $title, $language) = @_;
+    my $cache = $self->c->cache($prefix);
+    my $cache_key = "$prefix:$title:$language";
+
+    return ($cache, $cache_key)
+}
+
+sub _get_and_process_json
+{
+    my ($self, $url, $title, $property) = @_;
+
+    # request JSON
+    my $response = $self->c->lwp->get($url);
+    unless ($response->is_success) {
+        return undef;
+    }
+
+    # decode JSON
+    my $content = decode_json(encode("utf-8", $response->content));
+    unless ($content->{query}) { return undef }
+    else { $content = $content->{query} }
+
+    # save title as passed in
+    my $noncanonical = $title;
+
+    # capitalization normalizations
+    my $normalized = first { $_->{from} eq $title } $content->{normalized} if $content->{normalized};
+    if ($normalized) {
+        $title = $normalized->{to};
+    }
+
+    # wiki redirects
+    my $redirects = first { $_->{from} eq $title } $content->{redirects} if $content->{redirects};
+    if ($redirects) {
+        $title = $redirects->{to};
+    }
+
+    # pull out the correct page, though there should only be one
+    my $ret = first { $_->{title} eq $title } values $content->{pages};
+    unless ($ret && $ret->{$property}) { return undef; }
+
+    return {content => $ret->{$property}, title => $noncanonical, canonical => $title}
+}
+
+__PACKAGE__->meta->make_immutable;
+no Moose;
+1;
+
+=head1 COPYRIGHT
+
+Copyright (C) 2009 Lukas Lalinsky
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+=cut
diff --git a/lib/MusicBrainz/Server/Entity/URL/Wikipedia.pm b/lib/MusicBrainz/Server/Entity/URL/Wikipedia.pm
index 5400fbd..e341086 100644
--- a/lib/MusicBrainz/Server/Entity/URL/Wikipedia.pm
+++ b/lib/MusicBrainz/Server/Entity/URL/Wikipedia.pm
@@ -18,11 +18,9 @@ sub pretty_name
     my $self = shift;
     return $self->url->as_string unless defined($self->utf8_decoded);
 
-    my $name = MusicBrainz::Server::Filters::uri_decode($self->url->path);
-    $name =~ s{^/wiki/}{};
-    $name =~ s{_}{ }g;
+    my $name = $self->page_name;
 
-    if (my ($language) = $self->url->host =~ /(.*)\.wikipedia/) {
+    if (my $language = $self->language) {
         $name = "$language: $name";
     }
 
@@ -31,6 +29,30 @@ sub pretty_name
 
 sub sidebar_name { shift->pretty_name }
 
+sub page_name
+{
+    my $self = shift;
+    return undef unless defined($self->utf8_decoded);
+
+    my $name = MusicBrainz::Server::Filters::uri_decode($self->url->path);
+    $name =~ s{^/wiki/}{};
+    $name =~ s{_}{ }g;
+
+    return $name;
+}
+
+sub language
+{
+    my $self = shift;
+    return undef unless defined($self->utf8_decoded);
+
+    if (my ($language) = $self->url->host =~ /(.*)\.wikipedia/) {
+        return $language
+    } else {
+        return undef;
+    }
+}
+
 =method show_in_sidebar
 
 Wikipedia URLs are only show in the sidebar if the URL can be decoded from utf-8
diff --git a/lib/MusicBrainz/Server/Entity/WikipediaExtract.pm b/lib/MusicBrainz/Server/Entity/WikipediaExtract.pm
new file mode 100644
index 0000000..90c6340
--- /dev/null
+++ b/lib/MusicBrainz/Server/Entity/WikipediaExtract.pm
@@ -0,0 +1,54 @@
+package MusicBrainz::Server::Entity::WikipediaExtract;
+
+use Moose;
+
+has 'title' => (
+    is => 'rw',
+    isa => 'Str',
+);
+
+has 'content' => (
+    is => 'rw',
+    isa => 'Str'
+);
+
+has 'canonical' => (
+    is => 'rw',
+    isa => 'Str',
+);
+
+has 'language' => (
+    is => 'rw',
+    isa => 'Str',
+);
+
+sub url
+{
+    my $self = shift;
+    return sprintf "//%s.wikipedia.org/wiki/%s", $self->language, $self->title;
+}
+
+__PACKAGE__->meta->make_immutable;
+no Moose;
+1;
+
+=head1 COPYRIGHT
+
+Copyright (C) 2012 Ian McEwen
+Copyright (C) 2012 MetaBrainz Foundation
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+=cut
diff --git a/root/artist/index.tt b/root/artist/index.tt
index b655a74..a47021a 100644
--- a/root/artist/index.tt
+++ b/root/artist/index.tt
@@ -35,6 +35,8 @@
       </p>
     [% END %]
 
+    [%- show_wikipedia_extract() -%]
+
     [%- filter_button() -%]
     <h2 class="discography">[% l('Discography') %]</h2>
 
diff --git a/root/components/common-macros.tt b/root/components/common-macros.tt
index 31c2bdd..4b3efe6 100644
--- a/root/components/common-macros.tt
+++ b/root/components/common-macros.tt
@@ -772,3 +772,11 @@ http://[%- server -%]/[%- id -%]"
 [%- MACRO artist_end_label_from_type(type_id) BLOCK -%]
     [% type_id == 1 ? l('Died:') : type_id == 2 ? l('Dissolved:') : l('End date:') %]
 [%- END -%]
+
+[%- MACRO show_wikipedia_extract BLOCK -%]
+    [%- IF wikipedia_extract -%]
+    <h2 class="wikipedia">[% l('Wikipedia') %]</h2>
+        [%- wikipedia_extract.content -%]
+        <a href="[% wikipedia_extract.url %]">[% l('Read more...') %]</a>
+    [%- END -%]
+[%- END -%]
diff --git a/root/label/index.tt b/root/label/index.tt
index 771c072..2a90c37 100644
--- a/root/label/index.tt
+++ b/root/label/index.tt
@@ -1,6 +1,8 @@
 [%- WRAPPER "label/layout.tt" page='index' -%]
     [%- INCLUDE 'label/annotation.tt' summary=1 -%]
 
+    [%- show_wikipedia_extract() -%]
+
     <h2 class="releases">[% l('Releases') %]</h2>
     [%- IF releases.size -%]
       <form action="[% c.uri_for_action('/release/merge_queue') %]"
diff --git a/root/release_group/index.tt b/root/release_group/index.tt
index 4b318ff..2e29989 100644
--- a/root/release_group/index.tt
+++ b/root/release_group/index.tt
@@ -1,5 +1,8 @@
 [%- WRAPPER 'release_group/layout.tt' page='index' %]
     [%- INCLUDE 'release_group/annotation.tt' summary=1 -%]
+
+    [%- show_wikipedia_extract() -%]
+
     [%- IF releases.size -%]
       <h2>[% rg.l_type_name %]</h2>
       <form action="[% c.uri_for_action('/release/merge_queue') %]"
diff --git a/root/work/index.tt b/root/work/index.tt
index eef0054..5a6f846 100644
--- a/root/work/index.tt
+++ b/root/work/index.tt
@@ -7,6 +7,9 @@
       </p>
     [% END %]
     [%- INCLUDE 'work/annotation.tt' summary=1 -%]
+
+    [%- show_wikipedia_extract() -%]
+
     <h2 class="relationships">[% l("Relationships") %]</h2>
     [%- INCLUDE "components/relationships.tt" source=work -%]
 [%- END -%]

-----------------------------------------------------------------------


hooks/post-receive
-- 
mb_server

_______________________________________________
MusicBrainz-commits mailing list
[email protected]
http://lists.musicbrainz.org/mailman/listinfo/musicbrainz-commits
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.