Implement the search page

This commit is contained in:
swagg boi 2023-10-27 23:03:32 -04:00
parent 77e1483c11
commit fd10bb4f4a
5 changed files with 122 additions and 0 deletions

View file

@ -146,6 +146,9 @@ sub startup($self) {
$r->get('/feeds')->to('page#feeds')->name('feeds_page');
# Not-so-static but I mean they're all 'pages' c'mon
$r->get('/search')->to('page#search')->name('search_page');
$r->any([qw{GET POST}], '/captcha/*return_url')
->to('page#captcha')
->name('captcha_page');

View file

@ -50,4 +50,32 @@ sub captcha($self) {
$self->render;
}
sub search($self) {
my $v = $self->validation;
my $search_results = [];
my ($search_query, $this_page, $last_page, $base_path);
if ($v->has_data) {
$v->required('q' )->size(1, 2_047);
$v->optional('page');
$search_query = $v->param('q');
$this_page = $v->param('page') || 1;
$last_page = $self->page->last_page_for($search_query);
$base_path = $self->url_for->query(q => $search_query);
$search_results = $self->page->search($search_query, $this_page);
$self->stash(status => 400) if $v->has_error;
}
$self->stash(
this_page => $this_page,
last_page => $last_page,
base_path => $base_path,
search_results => $search_results
);
$self->render;
}
1;

View file

@ -37,5 +37,28 @@ sub search($self, $search_query, $this_page = 1) {
END_SQL
}
sub count_for($self, $search_query) {
$self->pg->db->query(<<~'END_SQL', $search_query)->hash->{'post_tally'}
SELECT COUNT(*) AS post_tally
FROM (SELECT thread_date AS post_date
FROM threads
WHERE search_tokens @@ PLAINTO_TSQUERY('english', $1)
UNION ALL
SELECT remark_date
FROM remarks
WHERE search_tokens @@ PLAINTO_TSQUERY('english', $1))
AS posts;
END_SQL
}
sub last_page_for($self, $search_query) {
my $post_count = $self->count_for($search_query);
my $last_page = int($post_count / $self->per_page);
# Add a page for 'remainder' posts
$last_page++ if $post_count % $self->per_page;
return $last_page;
}
1;

18
t/search.t Normal file
View file

@ -0,0 +1,18 @@
use Mojo::Base -strict;
use Test::More;
use Test::Mojo;
my $t = Test::Mojo->new('PostText');
my $invalid_query = 'aaaaaaaa' x 300;
subtest Search => sub {
$t->get_ok('/search')->status_is(200)->text_like(h2 => qr/Search/);
$t->get_ok('/search?q=test')->status_is(200)
->text_like(h3 => qr/Results/);
$t->get_ok("/search?q=$invalid_query")->status_is(400)
->text_like(p => qr/Must be between/);
};
done_testing;

View file

@ -0,0 +1,50 @@
% layout 'default';
% title 'Search Posts';
<h2 class="page-title"><%= title %></h2>
<form method="get" class="form-body">
<div class="form-field">
<% if (my $error = validation->error('q')) { =%>
<p class="field-with-error">Must be between <%= $error->[2] %>
and <%= $error->[3] %> characters.</p>
<% } =%>
<%= label_for search => 'Search' %>
<%= text_field q => (
id => 'search',
maxlength => 2047,
minlength => 1,
required => undef
) %>
</div>
<button type="submit" class="form-button">Search</button>
</form>
<% if (scalar @{$search_results}) { =%>
<main class="pager" id="results">
<h3 class="pager__title">Results</h3>
<% for my $result (@{$search_results}) { =%>
<article class="post">
<h4 class="post__title">
<span>
<%= $result->{'post_date'} %>
</span>
<% if ($result->{'post_type'} eq 'thread') { =%>
<%= link_to "#$result->{'post_id'}", single_thread =>
{thread_id => $result->{'post_id'}}, (class => 'post__id') %>
<% } else { =%>
<%= link_to "#$result->{'post_id'}", single_remark =>
{remark_id => $result->{'post_id'}}, (class => 'post__id') %>
<% } =%>
</h4>
<h5 class="post__author"><%= $result->{'post_author'} %></h5>
<div class="post__body">
<%== markdown $result->{'post_body'} =%>
</div>
</article>
<% } =%>
<% if ($last_page && $last_page != 1) { =%>
<nav class="pager__nav">
<%= pagination $this_page, $last_page,
($base_path . '&page={page}#results') %>
</nav>
<% } =%>
</main>
<% } =%>