1# This Source Code Form is subject to the terms of the Mozilla Public
2# License, v. 2.0. If a copy of the MPL was not distributed with this
3# file, You can obtain one at http://mozilla.org/MPL/2.0/.
4#
5# This Source Code Form is "Incompatible With Secondary Licenses", as
6# defined by the Mozilla Public License, v. 2.0.
7
8package Bugzilla::Search::Recent;
9use strict;
10use base qw(Bugzilla::Object);
11
12use Bugzilla::Constants;
13use Bugzilla::Error;
14use Bugzilla::Util;
15
16#############
17# Constants #
18#############
19
20use constant DB_TABLE => 'profile_search';
21use constant LIST_ORDER => 'id DESC';
22# Do not track buglists viewed by users.
23use constant AUDIT_CREATES => 0;
24use constant AUDIT_UPDATES => 0;
25use constant AUDIT_REMOVES => 0;
26
27use constant DB_COLUMNS => qw(
28    id
29    user_id
30    bug_list
31    list_order
32);
33
34use constant VALIDATORS => {
35    user_id    => \&_check_user_id,
36    bug_list   => \&_check_bug_list,
37    list_order => \&_check_list_order,
38};
39
40use constant UPDATE_COLUMNS => qw(bug_list list_order);
41
42###################
43# DB Manipulation #
44###################
45
46sub create {
47    my $class = shift;
48    my $dbh = Bugzilla->dbh;
49    $dbh->bz_start_transaction();
50    my $search = $class->SUPER::create(@_);
51    my $user_id = $search->user_id;
52
53    # Enforce there only being SAVE_NUM_SEARCHES per user.
54    my @ids = @{ $dbh->selectcol_arrayref(
55        "SELECT id FROM profile_search WHERE user_id = ? ORDER BY id",
56        undef, $user_id) };
57    if (scalar(@ids) > SAVE_NUM_SEARCHES) {
58        splice(@ids, - SAVE_NUM_SEARCHES);
59        $dbh->do(
60            "DELETE FROM profile_search WHERE id IN (" . join(',', @ids) . ")");
61    }
62    $dbh->bz_commit_transaction();
63    return $search;
64}
65
66sub create_placeholder {
67    my $class = shift;
68    return $class->create({ user_id  => Bugzilla->user->id,
69                            bug_list => '' });
70}
71
72###############
73# Constructor #
74###############
75
76sub check {
77    my $class = shift;
78    my $search = $class->SUPER::check(@_);
79    my $user = Bugzilla->user;
80    if ($search->user_id != $user->id) {
81        ThrowUserError('object_does_not_exist', { id => $search->id });
82    }
83    return $search;
84}
85
86sub check_quietly {
87    my $class = shift;
88    my $error_mode = Bugzilla->error_mode;
89    Bugzilla->error_mode(ERROR_MODE_DIE);
90    my $search = eval { $class->check(@_) };
91    Bugzilla->error_mode($error_mode);
92    return $search;
93}
94
95sub new_from_cookie {
96    my ($invocant, $bug_ids) = @_;
97    my $class = ref($invocant) || $invocant;
98
99    my $search = { id       => 'cookie',
100                   user_id  => Bugzilla->user->id,
101                   bug_list => join(',', @$bug_ids) };
102
103    bless $search, $class;
104    return $search;
105}
106
107####################
108# Simple Accessors #
109####################
110
111sub bug_list   { return [split(',', $_[0]->{'bug_list'})]; }
112sub list_order { return $_[0]->{'list_order'}; }
113sub user_id    { return $_[0]->{'user_id'}; }
114
115############
116# Mutators #
117############
118
119sub set_bug_list   { $_[0]->set('bug_list',   $_[1]); }
120sub set_list_order { $_[0]->set('list_order', $_[1]); }
121
122##############
123# Validators #
124##############
125
126sub _check_user_id {
127    my ($invocant, $id) = @_;
128    require Bugzilla::User;
129    return Bugzilla::User->check({ id => $id })->id;
130}
131
132sub _check_bug_list {
133    my ($invocant, $list) = @_;
134
135    my @bug_ids = ref($list) ? @$list : split(',', $list || '');
136    detaint_natural($_) foreach @bug_ids;
137    return join(',', @bug_ids);
138}
139
140sub _check_list_order { defined $_[1] ? trim($_[1]) : '' }
141
1421;
143
144__END__
145
146=head1 NAME
147
148Bugzilla::Search::Recent - A search recently run by a logged-in user.
149
150=head1 SYNOPSIS
151
152 use Bugzilla::Search::Recent;
153
154
155=head1 DESCRIPTION
156
157This is an implementation of L<Bugzilla::Object>, and so has all the
158same methods available as L<Bugzilla::Object>, in addition to what is
159documented below.
160