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