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

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