Support VCs via URL without queries (fixes #207)

Change-Id: Idb8a8353f1128bbbd21b235a2e013ac4ab780661
diff --git a/Changes b/Changes
index 1e6bb97..b943c7c 100644
--- a/Changes
+++ b/Changes
@@ -1,8 +1,9 @@
-0.56 2024-08-28
+0.56 2024-09-23
         - Improve slim test for plugin support
           (korapxml2...; diewald)
         - Fix layerInfo retrieval for relation view. (diewald)
         - Change look of addon logo. (diewald)
+        - Support VCs via URL without queries (diewald)
 
 0.55 2024-07-03
         - Removed deprecated doc_link_to helper. (diewald)
diff --git a/lib/Kalamar/Controller/Search.pm b/lib/Kalamar/Controller/Search.pm
index b2d547d..74143c1 100644
--- a/lib/Kalamar/Controller/Search.pm
+++ b/lib/Kalamar/Controller/Search.pm
@@ -7,6 +7,7 @@
 use POSIX 'ceil';
 
 our @search_fields = qw!ID UID textSigle layerInfos title subTitle pubDate author availability snippet!;
+our $query_placeholder = 'NOQUERY';
 
 # TODO:
 #   Support server timing API
@@ -58,27 +59,38 @@
     $cq = $v->param('collection');
   };
 
-  # No query (Check ignoring validation)
-  unless ($c->param('q')) {
-    return $c->render(
-      $c->loc('Template_intro', 'intro'),
-      robots => 'index,follow'
-    );
-  };
-
-  $c->res->headers->header('X-Robots', 'noindex');
-
   my %query = ();
   $query{q}  = $v->param('q')  // '';
   $query{ql} = $v->param('ql') // 'poliqarp';
 
+  # No query (Check ignoring validation)
+  unless ($c->param('q')) {
+
+    # No corpus query
+    unless ($v->param('cq')) {
+      return $c->render(
+        $c->loc('Template_intro', 'intro'),
+        robots => 'index,follow'
+      );
+    };
+
+    # Corpus query exists
+    $query{q} = $query_placeholder;
+    $query{count} = 0;
+  }
+
+  else {
+    $c->stash(title => $c->loc(
+      'searchtitle',
+      q => $query{'q'},
+      ql => $query{'ql'}
+    ));
+  };
+
+  $c->res->headers->header('X-Robots', 'noindex');
+
   $c->stash(q  => $query{q});
   $c->stash(ql => $query{ql});
-  $c->stash(title => $c->loc(
-    'searchtitle',
-    q => $query{'q'},
-    ql => $query{'ql'}
-  ));
 
   # Check validation
   if ($v->has_error) {
@@ -96,7 +108,6 @@
   my $items_per_page = $c->stash('items_per_page');
 
   $query{count}   = $v->param('count') // $items_per_page;
-
   $query{cq}      = $cq;
   $query{cutoff}  = $cutoff;
   $query{context} = $v->param('context') // $c->stash('context');
@@ -269,6 +280,17 @@
       # Emit after search hook
       $c->app->plugins->emit_hook(after_search => $c);
 
+      # Only corpus query is set
+      if ($c->stash('q') eq $query_placeholder) {
+        $c->stash(q => '');
+        $c->req->query_params->remove('q');
+        $c->req->query_params->remove('count');
+        return $c->render(
+          $c->loc('Template_intro', 'intro'),
+          robots => 'index,follow'
+        );
+      };
+
       # Render result
       return $c->render(template => 'search');
     }
diff --git a/t/intro.t b/t/intro.t
index ef8bec5..6d46466 100644
--- a/t/intro.t
+++ b/t/intro.t
@@ -49,6 +49,20 @@
   ->element_exists('meta[name="DC.description"][content="KorAP - Corpus Analysis Platform"]')
   ->element_exists('meta[name="keywords"][content^="KorAP"]')
   ->element_exists('body[itemscope][itemtype="http://schema.org/WebApplication"]')
+  ->element_exists_not('#koralQuery')
+  ;
+
+$t->get_ok('/?cq=corpusSigle%3DGOE')
+  ->status_is(200)
+  ->text_is('title', 'KorAP - Corpus Analysis Platform')
+  ->text_is('h1 span', 'KorAP - Corpus Analysis Platform')
+  ->element_exists_not('#notifications div.notify')
+  ->element_exists('div.intro')
+  ->text_is('div.intro h2', 'This is a custom intro page!')
+  ->element_exists('meta[name="DC.description"][content="KorAP - Corpus Analysis Platform"]')
+  ->element_exists('meta[name="keywords"][content^="KorAP"]')
+  ->element_exists('body[itemscope][itemtype="http://schema.org/WebApplication"]')
+  ->element_exists('#koralQuery')
   ;
 
 $t->get_ok('/huhuhuhuhu')
diff --git a/t/server/mock.pl b/t/server/mock.pl
index e64f14e..32485fb 100644
--- a/t/server/mock.pl
+++ b/t/server/mock.pl
@@ -168,6 +168,12 @@
     );
   };
 
+  if ($v->param('q') eq $Kalamar::Controller::Search::query_placeholder) {
+    # Get response based on query parameter
+    my $response = $c->load_response('query_baum_o0_c25_cq');
+    return $c->render(%$response);
+  };
+
   my @slug_base = ($v->param('q'));
   push @slug_base, 'o' . $v->param('offset') if defined $v->param('offset');
   push @slug_base, 'c' . $v->param('count') if defined $v->param('count');
diff --git a/templates/layouts/main.html.ep b/templates/layouts/main.html.ep
index 590ce85..062a6b3 100644
--- a/templates/layouts/main.html.ep
+++ b/templates/layouts/main.html.ep
@@ -76,7 +76,10 @@
     </noscript>
     
     <main<% if (stash 'main_class') { %> class="<%= stash 'main_class' %>"<% } %>>
-    %= content
+
+      %= include 'query'
+
+      %= content
     </main>
 
     % unless ($embedded) {
diff --git a/templates/search.html.ep b/templates/search.html.ep
index d91195f..58a8f38 100644
--- a/templates/search.html.ep
+++ b/templates/search.html.ep
@@ -24,8 +24,6 @@
 </p>
 </div>
 
-%= include 'query'
-
 <div id="search">
 % if (stash('results')->size && stash('total_results') != 0) {
   <ol class="align-left">