+ my $json = _couchdb_get($url);
+
+ if ( exists $json->{error} ) {
+ warn "creating CouchDB view because of ", dump($json);
+ my $url = "/" . $self->param('database') . "/_design/registration";
+ _couchdb_put $url, {
+ _id => '_design/registration',
+ language => 'javascript',
+ views => {
+ organizations => {
+ map => q| function(doc) {
+if ( doc.user.organization != '' ) {
+ if ( doc.user.organization )
+ emit(doc.user.organization, 1);
+ if ( doc.user.persons ) {
+ doc.user.persons.forEach( function(person) {
+ if ( person.organization )
+ emit(person.organization, 1);
+ });
+ }
+}
+ }q|,
+ reduce => q| function(keys,values,rereduce) { return sum(values); } |,
+ }
+ }
+ };
+ $json = _couchdb_get($url)
+ || die "give up!";
+ }
+
+ if ( $format eq 'key_array' ) { # array of keys sorted by value
+ $json->{rows} = [ map { $_->{key} } sort { $b->{value} <=> $a->{value} } @{ $json->{rows} } ];
+ }
+
+ $view_cache->{$url}->{time} = time();
+ $view_cache->{$url}->{json} = $json;
+
+ warn "# view_cache ",dump($view_cache);
+
+ _render_jsonp( $self, $json );
+};
+
+# http://showmetheco.de/articles/2010/10/adding-etag-caching-to-your-mojolicious-app.html
+
+hook after_dispatch => sub {
+ my $self = shift;
+
+ return unless $self->req->method eq 'GET';
+
+ my $body = $self->res->body;
+ return unless defined $body;
+
+ return if $self->res->headers->header('ETag');
+
+ my $our_etag = Mojo::ByteStream->new($body . $VERSION)->md5_sum;
+ $self->res->headers->header('ETag' => $our_etag);
+
+ my $browser_etag = $self->req->headers->header('If-None-Match');
+ return unless $browser_etag && $browser_etag eq $our_etag;
+
+ $self->app->log->debug("HTTP cache hit " . $self->req->url->to_string . " $our_etag" );
+
+ $self->res->code(304);
+ $self->res->body('');