source: server/trunk/web/lib/Sophie/Controller/Search.pm @ 122

Last change on this file since 122 was 122, checked in by nanardon, 13 years ago
  • add search dependencies functions
File size: 16.3 KB
Line 
1package Sophie::Controller::Search;
2use Moose;
3use namespace::autoclean;
4use Sophie;
5
6BEGIN {extends 'Catalyst::Controller'; }
7
8=head1 NAME
9
10Sophie::Controller::Search - Catalyst Controller
11
12=head1 DESCRIPTION
13
14Catalyst Controller.
15
16=head1 METHODS
17
18=cut
19
20
21=head2 index
22
23=cut
24
25sub index :Path :Args(0) {
26    my ($self, $c) = @_;
27
28    if ($c->req->param('page')) {
29        $c->req->params->{search} = $c->session->{search};
30        $c->req->params->{type} = $c->session->{type};
31    } else {
32        $c->session->{search} = $c->req->params->{search};
33        $c->session->{type} = $c->req->params->{type};
34    }
35
36    my $searchspec = {
37        page => $c->req->param('page') || undef,
38    };
39
40    for ($c->req->param('type')) {
41        /^byname$/ and do {
42            $c->forward('byname', [ $searchspec, $c->req->param('search') ||
43                    undef ]);
44            last;
45        };
46    }
47
48}
49
50sub results :Local {
51    my ( $self, $c ) = @_;
52
53    if ($c->req->param('page')) {
54        $c->req->params->{search} ||= $c->session->{search};
55    }
56
57    if ($c->req->param('search')) {
58        $c->session->{search} = $c->req->param('search');
59        $c->forward('quick', [
60                {
61                    page => $c->req->param('page') || undef,
62                    src => 0,
63                } , grep { $_ } split(/\s/, $c->req->param('search')) ]);
64
65    }
66}
67
68sub distrib_search : Private {
69    my ( $self, $c, $searchspec, $asfilter ) = @_;
70
71    # if asfilter is set, return undef if nothing would have been filter
72    if (my $rs = $c->forward('/distrib/distrib_rs', [ $searchspec, $asfilter ]))
73    {
74        return $rs
75            ->search_related('MediasPaths')
76            ->search_related('Paths')
77            ->search_related('Rpmfiles');
78        } else {
79            return;
80        }
81}
82
83sub format_search : Private {
84    my ( $self, $c, $searchspec ) = @_;
85    $searchspec ||= {};
86
87    my $rs = $c->stash->{rs}->search(
88        {},
89        {
90            page => $searchspec->{page} || 1,
91            rows => $searchspec->{rows} || 10,
92        },
93    );
94
95    $c->stash->{rs} = $rs;
96    $c->stash->{column} ||= 'pkgid';
97    my @results;
98    if (ref $c->stash->{column}) {
99        while (my $i = $rs->next) {
100            push(@results, {
101                map { $_ => $i->get_column($_) } @{$c->stash->{column}} 
102            });
103        }
104    } else {
105        @results = $rs->get_column($c->stash->{column})->all;
106    }
107    if (1 || !$searchspec->{page}) {
108        my $pager = $c->stash->{rs}->pager;
109        $c->stash->{pager} = $pager;
110        $c->stash->{xmlrpc} = {
111                pages => $pager->last_page,
112                current_page => $pager->current_page,
113                total_entries => $pager->total_entries,
114                entries_per_page => $pager->entries_per_page,
115        };
116    }
117    $c->stash->{xmlrpc}{results} = \@results;
118    return $c->stash->{xmlrpc};
119}
120
121=head2 search.rpms.bydate (SEARCHSPEC, TIMESTAMP)
122
123Return a list of rpms files added since TIMESTAMP.
124TIMESTAMP must the number of second since 1970-01-01 (eq UNIX epoch).
125
126SEARCHSPEC is a struct with following key/value:
127
128=over 4
129
130=item distribution
131
132Limit search to this distribution
133
134=item release
135
136Limit search to this release
137
138=item arch
139
140Limit search to distribution of this arch
141
142=item src
143
144If set to true, limit search to source package, If set to false, limit search to
145binary package.
146
147=item name
148
149Limit search to rpm having this name
150
151=item rows
152
153Set maximum of results, the default is 10000.
154
155=back
156
157Each elements of the output is a struct:
158
159=over 4
160
161=item filename
162
163the rpm filename
164
165=item pkgid
166
167the identifier of the package
168
169=item distribution
170
171the distribution containing this package
172
173=item release
174
175the release containing this package
176
177=item arch
178
179the arch containing this package
180
181=item media
182
183the media containing this package
184
185=back
186
187=cut
188
189sub bydate : XMLRPCPath('/search/rpms/bydate') {
190    my ( $self, $c, $searchspec, $date ) = @_;
191    $searchspec ||= {};
192
193    return $c->stash->{xmlrpc} = [
194        map {
195            { 
196                filename => $_->get_column('filename'),
197                pkgid    => $_->get_column('pkgid'), 
198                distribution => $_->get_column('name'),
199                release => $_->get_column('version'),
200                arch => $_->get_column('arch'),
201                media => $_->get_column('label'),
202            }
203        }
204        $c->forward('/distrib/distrib_rs', [ $searchspec ])
205        ->search_related('MediasPaths')
206        ->search_related('Paths')
207        ->search_related('Rpmfiles',
208            {
209                -nest => \[
210                    "Rpmfiles.added > '1970-01-01'::date + ?::interval",
211                    [ plain_text => "$date seconds" ],   
212                ],
213                pkgid => {
214                    IN => $c->model('Base::Rpms')->search(
215                        {
216                            (exists($searchspec->{name})
217                                ? (name => $searchspec->{name})
218                                : ()
219                            ),
220                            (exists($searchspec->{src})
221                                ? (issrc => $searchspec->{src} ? 1 : 0)
222                                : ()
223                            ),
224                        }
225                    )->get_column('pkgid')->as_query,
226                }
227            },
228            {
229                select => [qw(filename pkgid name version arch label) ],
230                rows => $searchspec->{rows} || 10000,
231                order_by => [ 'Rpmfiles.added desc' ],
232            },
233        )->all ];
234}
235
236sub bypkgid : XMLRPCPath('/search/rpm/bypkgid') {
237    my ( $self, $c, $searchspec, $pkgid ) = @_;
238    $searchspec ||= {};
239
240    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
241
242    $c->stash->{rs} = $c->model('Base')->resultset('Rpms')->search(
243        {
244            -and => [ 
245                (exists($searchspec->{src})
246                    ? { issrc => $searchspec->{src} ? 1 : 0 }
247                    : ()),
248                { pkgid => $pkgid },
249                $distrs
250                    ? { pkgid => { IN => $distrs->get_column('pkgid')->as_query, } }
251                    : ()
252            ]     
253        },
254    );
255
256    $c->forward('format_search', $searchspec);
257}
258
259=head2 search.rpm.byname (SEARCHSPEC, NAME, [SENSE, EVR])
260
261Search package by its NAME. SENSE and EVR are optional version filter where
262SENSE is dependency sign (C<E<gt>>, C<=>, ...) and EVR the search version as
263either C<VERSION>, C<VERSION-RELEASE> or C<EPOCH:VERSION-RELEASE>.
264
265SEARCHSPEC is a struct with search options.
266
267=cut
268
269sub byname : XMLRPCPath('/search/rpm/byname') {
270    my ( $self, $c, $searchspec, $name, $sense, $evr ) = @_;
271    $searchspec ||= {};
272
273    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
274
275    $c->stash->{rs} = $c->model('Base')->resultset('Rpms')->search(
276        {
277            -and => [ 
278                (exists($searchspec->{src})
279                    ? { issrc => $searchspec->{src} ? 1 : 0 }
280                    : ()),
281                { name => $name },
282                ( $evr
283                    ? { -nest => \[ 
284                        "rpmdepmatch(rpmsenseflag('='), evr, rpmsenseflag(?), ?)",
285                        [ plain_text => $sense],
286                        [ plain_text => $evr ],
287                    ] }
288                    : ()),
289                $distrs
290                    ? { pkgid => { IN => $distrs->get_column('pkgid')->as_query, }, }
291                    : (),
292            ]     
293        },
294        {
295                order_by => [ 'name', 'evr using >>', 'issrc' ],
296        }
297    );
298    $c->forward('format_search', $searchspec);
299
300}
301
302sub bytag : XMLRPCPath('/search/rpm/bytag') {
303    my ( $self, $c, $searchspec, $tag, $tagvalue ) = @_;
304    $searchspec ||= {};
305
306    my $tagrs = $c->model('Base')->resultset('Tags')
307        ->search({ tagname => lc($tag), value => $tagvalue})
308        ->get_column('pkgid');
309    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
310    $c->stash->{rs} = $c->model('Base')->resultset('Rpms')->search(
311        {
312            -and => [ 
313                (exists($searchspec->{src})
314                    ? { issrc => $searchspec->{src} ? 1 : 0 }
315                    : ()),
316                { pkgid => 
317                    { IN => $tagrs->as_query, },
318                },
319                $distrs
320                    ? { pkgid => { IN => $distrs->get_column('pkgid')->as_query, }, }
321                    : (),
322            ]     
323        },
324    );
325    $c->forward('format_search', $searchspec);
326
327}
328
329sub bydep : XMLRPCPath('/search/rpm/bydep') {
330    my ( $self, $c, $searchspec, $deptype, $depname, $depsense, $depevr ) = @_;
331    $searchspec ||= {};
332
333    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
334
335    my $deprs = $c->model('Base::Deps')->search(
336        {
337            deptype => $deptype,
338            depname => $depname,
339            ($depsense
340                ? (-nest => \[
341                    'rpmdepmatch(flags, evr, rpmsenseflag(?), ?)',
342                    [ plain_text => $depsense],
343                    [ plain_text => $depevr ]
344                ])
345            : ()),
346        }
347    )->get_column('pkgid');
348    $c->stash->{rs} = $c->model('Base')->resultset('Rpms')->search(
349        {
350            -and => [ 
351                (exists($searchspec->{src})
352                    ? { issrc => $searchspec->{src} ? 1 : 0 }
353                    : ()),
354                { pkgid => 
355                    { IN => $deprs->as_query, },
356                },
357                $distrs
358                    ? { pkgid => { IN => $distrs->get_column('pkgid')->as_query, }, }
359                    : (),
360            ]     
361        },
362    );
363    $c->forward('format_search', $searchspec);
364}
365
366sub byfile : XMLRPCPath('/search/rpm/byfile') {
367    my ( $self, $c, $searchspec, $file) = @_;
368    my ($dirname, $basename) = $file =~ m:^(.*/)?([^/]+)$:;
369    $searchspec ||= {};
370
371    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
372    my $filers = $c->model('Base')->resultset('Files')
373    ->search({
374            ($dirname
375                ? (dirname => $dirname)
376                : ()),
377            basename => $basename,
378        })
379    ->get_column('pkgid');
380    $c->stash->{rs} = $c->model('Base')->resultset('Rpms')->search(
381        {
382            -and => [ 
383                (exists($searchspec->{src})
384                    ? { issrc => $searchspec->{src} ? 1 : 0 }
385                    : ()),
386                { pkgid => 
387                    { IN => $filers->as_query, },
388                },
389                $distrs
390                    ? { pkgid => { IN => $distrs->get_column('pkgid')->as_query, }, }
391                    : (),
392            ]     
393        },
394    );
395    $c->forward('format_search', $searchspec);
396}
397
398sub fuzzy : XMLRPCPath('/search/rpm/fuzzy') {
399    my ($self, $c, $searchspec, $name) = @_;
400    $searchspec ||= {};
401
402    my $deprs = $c->model('Base')->resultset('Deps')->search(
403        { deptype => 'P', depname => { '~*' => $name } }
404    )->get_column('pkgid');
405    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
406
407    $c->stash->{rs} = 
408
409        $c->model('Base')->resultset('Rpms')->search(
410        {
411            -and => [
412                (exists($searchspec->{src})
413                    ? { issrc => $searchspec->{src} ? 1 : 0 }
414                    : ()),
415                { -or => [
416                    { name => 
417                        { '~*' => $name, },
418                    },
419#                    { pkgid =>
420#                        { IN => $deprs->as_query, },
421#                    },
422                     ]
423                },
424                $distrs
425                    ? { pkgid => { IN => $distrs->get_column('pkgid')->as_query, }, }
426                    : (),
427            ]     
428        },
429    );
430   
431    $c->forward('format_search', $searchspec);
432}
433
434sub quick : XMLRPCPath('/search/rpm/quick') {
435    my ($self, $c, $searchspec, @keywords) = @_;
436    $searchspec ||= {};
437    my $tsquery = join(' & ', map { $_ =~ s/ /\\ /g; $_ } @keywords);
438   
439    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
440
441    $c->stash->{rs} = $c->model('Base')->resultset('Rpms')->search(
442            {
443                -or => [
444#                    { -nest => \[
445#                        "to_tsvector('english', description) @@ to_tsquery(?)",
446#                        [ plain_text => $tsquery],
447#                    ], },
448                    {
449                    name => { '~*' => [ @keywords ] },
450                    },
451                ],
452            (exists($searchspec->{src})
453                ? (issrc => $searchspec->{src} ? 1 : 0)
454                : ()),
455            ($distrs 
456                ? (pkgid => { IN => $distrs->get_column('pkgid')->as_query, },)
457                : ()),
458        },
459    );
460    $c->forward('format_search', $searchspec);
461}
462
463sub description : XMLRPCPath('/search/rpm/description') {
464    my ($self, $c, $searchspec, @keywords) = @_;
465    $searchspec ||= {};
466    my $tsquery = join(' & ', map { $_ =~ s/ /\\ /g; $_ } @keywords);
467    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
468    $c->stash->{rs} = $c->model('Base')->resultset('Rpms')->search(
469        {
470            -nest => \[
471                    "to_tsvector('english', description) @@ to_tsquery(?)",
472                    [ plain_text => $tsquery],
473                ],
474                (exists($searchspec->{src})
475                    ? (issrc => $searchspec->{src} ? 1 : 0)
476                    : ()),
477                ($distrs 
478                    ? (pkgid => { IN => $distrs->get_column('pkgid')->as_query, },)
479                    : ()),
480        },
481        {
482            select => [ 
483                "ts_rank_cd(to_tsvector('english', description),to_tsquery(?)) as rank",
484                'pkgid'
485            ],
486            bind => [ $tsquery ], 
487            order_by => [ 'rank desc', 'name', 'evr using >>', 'issrc' ],
488        },
489    )->as_subselect_rs;
490    $c->forward('format_search', $searchspec);
491}
492
493sub file_search : XMLRPCPath('/search/file/byname') {
494    my ( $self, $c, $searchspec, $file) = @_;
495    my ($dirname, $basename) = $file =~ m:^(.*/)?([^/]+)$:;
496    $searchspec ||= {};
497
498    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
499    my @col = qw(dirname basename md5 size pkgid count);
500    $c->stash->{rs} = $c->model('Base::Files')
501    ->search(
502        {
503            -and => [
504                ($dirname
505                    ? (dirname => $dirname)
506                    : ()),
507                basename => $basename,
508                ($searchspec->{content} ? { has_content => 1 } : ()),
509                ($distrs 
510                    ? (pkgid => { IN => $distrs->get_column('pkgid')->as_query, },)
511                    : ()),
512            ],
513        },
514        {
515            'select' => [ 'contents is NOT NULL as has_content',
516                'rpmfilesmode(mode) as perm', @col, '"group"',
517                '"user"' ],
518            as => [ qw(has_content perm), @col,
519                'group', 'user' ],
520        }
521    );
522   
523    $c->stash->{column} = [
524        @col, qw(has_content perm user group)
525    ];
526   
527    $c->forward('format_search', $searchspec);
528}
529
530sub dep_search : XMLRPCPath('/search/dep/match') {
531    my ($self, $c, $searchspec, $deptype, $depname, $depsense, $depevr) = @_;
532
533    my $distrs = $c->forward('distrib_search', [ $searchspec, 1 ]);
534    $c->stash->{rs} = $c->model('Base::Deps')->search(
535        {
536            -and => [
537            { deptype => $deptype },
538            { depname => $depname },
539            ($depsense
540                ? ({-nest => \[
541                    'rpmdepmatch(flags, evr, rpmsenseflag(?), ?)',
542                    [ plain_text => $depsense],
543                    [ plain_text => $depevr ]
544                ]})
545            : ()),
546            ($distrs 
547                ? ({ pkgid => { IN => $distrs->get_column('pkgid')->as_query,
548                        },})
549                : ()),
550            (exists($searchspec->{src})
551                ? { pkgid => { IN => $c->model('Base::Rpms')->search(
552                            { issrc => $searchspec->{src} ? 1 : 0 }
553                        )->get_column('pkgid')->as_query, }, }
554                : ()),
555            ]
556        },
557        {
558            'select' => [ 'rpmsenseflag("flags")', qw(depname evr flags pkgid) ],
559            'as'     => [ qw(sense name evr flags pkgid) ],
560
561        }
562    );
563
564    $c->stash->{column} = [ qw(name sense evr flags pkgid) ];
565    $c->forward('format_search', $searchspec);
566}
567
568=head1 AUTHOR
569
570Olivier Thauvin
571
572=head1 LICENSE
573
574This library is free software. You can redistribute it and/or modify
575it under the same terms as Perl itself.
576
577=cut
578
579__PACKAGE__->meta->make_immutable;
580
5811;
Note: See TracBrowser for help on using the repository browser.