Skip to content

Commit 6926f5c

Browse files
authored
Add scope param for contact search (#9902)
* add scope param for contact search * fix failing tests * add test for contact search scope * test scope on advanced search form * use str_contains
1 parent c2b785f commit 6926f5c

File tree

14 files changed

+147
-15
lines changed

14 files changed

+147
-15
lines changed

program/actions/contacts/search.php

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,20 +45,27 @@ public static function contact_search()
4545
$adv = isset($_POST['_adv']);
4646
$sid = rcube_utils::get_input_string('_sid', rcube_utils::INPUT_GET);
4747
$search = null;
48+
$scope = null;
4849

4950
// get search criteria from saved search
5051
if ($sid && ($search = $rcmail->user->get_search($sid))) {
5152
$fields = $search['data']['fields'];
53+
// scope param added in 1.7, existence check for backwards compatibility
54+
$scope = $search['data']['scope'] ?? null;
5255
$search = $search['data']['search'];
5356
}
5457
// get fields/values from advanced search form
5558
elseif ($adv) {
5659
$fields = [];
5760
foreach (array_keys($_POST) as $key) {
5861
$s = trim(rcube_utils::get_input_string($key, rcube_utils::INPUT_POST, true));
59-
if (strlen($s) && preg_match('/^_search_([a-zA-Z0-9_-]+)$/', $key, $m)) {
60-
$search[] = $s;
61-
$fields[] = $m[1];
62+
if (strlen($s)) {
63+
if (preg_match('/^_search_([a-zA-Z0-9_-]+)$/', $key, $m)) {
64+
$search[] = $s;
65+
$fields[] = $m[1];
66+
} elseif ($key == '_scope') {
67+
$scope = $s;
68+
}
6269
}
6370
}
6471

@@ -71,6 +78,7 @@ public static function contact_search()
7178
else {
7279
$search = trim(rcube_utils::get_input_string('_q', rcube_utils::INPUT_GET, true));
7380
$fields = rcube_utils::get_input_string('_headers', rcube_utils::INPUT_GET);
81+
$scope = isset($_GET['_scope']) && strlen($_GET['_scope']) ? rcube_utils::get_input_string('_scope', rcube_utils::INPUT_GET) : null;
7482

7583
if (empty($fields)) {
7684
$fields = array_keys(self::$SEARCH_MODS_DEFAULT);
@@ -104,6 +112,10 @@ public static function contact_search()
104112
$records = [];
105113

106114
foreach ($sources as $s) {
115+
if (isset($scope) && $scope !== $s['id']) {
116+
continue;
117+
}
118+
107119
$source = $rcmail->get_address_book($s['id']);
108120

109121
// check if search fields are supported....
@@ -167,7 +179,7 @@ public static function contact_search()
167179

168180
// save search settings in session
169181
$_SESSION['contact_search'][$search_request] = $search_set;
170-
$_SESSION['contact_search_params'] = ['id' => $search_request, 'data' => [$fields, $search]];
182+
$_SESSION['contact_search_params'] = ['id' => $search_request, 'data' => [$fields, $search], 'scope' => $scope];
171183
$_SESSION['page'] = 1;
172184

173185
if ($adv) {
@@ -249,6 +261,20 @@ public static function contact_search_form($attrib)
249261
}
250262
}
251263

264+
// add search scope field
265+
$coltypes['_scope'] = [
266+
'id' => 'scope',
267+
'type' => 'select',
268+
'category' => 'main',
269+
'label' => $rcmail->gettext('searchscope'),
270+
'options' => [
271+
'base' => $rcmail->gettext('currentaddressbook'),
272+
'all' => $rcmail->gettext('alladdressbooks'),
273+
],
274+
'value' => 'all',
275+
'skip-empty' => true,
276+
];
277+
252278
// build form fields list
253279
foreach ($coltypes as $col => $colprop) {
254280
if (!isset($colprop['type'])) {
@@ -266,11 +292,12 @@ public static function contact_search_form($attrib)
266292
$colprop['size'] = $i_size;
267293
}
268294

269-
$colprop['id'] = '_search_' . $col;
295+
$fname = !empty($colprop['id']) ? $colprop['id'] : 'search_' . $col;
296+
$colprop['id'] = !empty($colprop['id']) ? '_' . $colprop['id'] : '_search_' . $col;
270297

271298
$content = html::div('row',
272299
html::label(['class' => 'contactfieldlabel label', 'for' => $colprop['id']], rcube::Q($label))
273-
. html::div('contactfieldcontent', rcube_output::get_edit_field('search_' . $col, '', $colprop, $ftype))
300+
. html::div('contactfieldcontent', rcube_output::get_edit_field($fname, $colprop['value'] ?? '', $colprop, $ftype))
274301
);
275302

276303
$form[$category]['content'][] = $content;

program/actions/contacts/search_create.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public function run($args = [])
4747
'data' => [
4848
'fields' => $params['data'][0],
4949
'search' => $params['data'][1],
50+
'scope' => $params['scope'],
5051
],
5152
];
5253

program/actions/mail/search_contacts.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ public function run($args = [])
117117

118118
// save search settings in session
119119
$_SESSION['contact_search'][$search_request] = $search_set;
120-
$_SESSION['contact_search_params'] = ['id' => $search_request, 'data' => [$afields, $search]];
120+
$_SESSION['contact_search_params'] = ['id' => $search_request, 'data' => [$afields, $search], 'scope' => null];
121121

122122
$rcmail->output->show_message('contactsearchsuccessful', 'confirmation', ['nr' => $result->count]);
123123

program/js/app.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5832,6 +5832,8 @@ function rcube_webmail() {
58325832
this.clear_message_list();
58335833
} else if (this.contact_list) {
58345834
this.list_contacts_clear();
5835+
// use env.last_source as env.source is overwritten by search action
5836+
url._scope = this.env.search_scope == 'base' ? this.env.last_source : null;
58355837
}
58365838

58375839
if (this.env.source) {
@@ -7489,6 +7491,9 @@ function rcube_webmail() {
74897491
if (this.name.match(/^_search/) && this.value != '') {
74907492
form[this.name] = this.value;
74917493
valid = true;
7494+
} else if (this.name == '_scope' && this.value == 'base') {
7495+
// use env.last_source as env.source is overwritten by search action
7496+
form[this.name] = ref.env.last_source;
74927497
}
74937498
});
74947499

program/localization/en_US/labels.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,8 @@ $labels['searchinterval-1Y'] = 'older than a year';
263263
$labels['searchinterval1W'] = 'younger than a week';
264264
$labels['searchinterval1M'] = 'younger than a month';
265265
$labels['searchinterval1Y'] = 'younger than a year';
266+
$labels['currentaddressbook'] = 'Current address book';
267+
$labels['alladdressbooks'] = 'All address books';
266268

267269
$labels['openinextwin'] = 'Open in new window';
268270
$labels['emlsave'] = 'Download (.eml)';

skins/elastic/templates/addressbook.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ <h3 id="aria-label-search-menu" class="voice"><roundcube:label name="searchmod"
4242
<li><label><input type="checkbox" name="s_mods[]" value="email" /><roundcube:label name="email" /></label></li>
4343
<li><label><input type="checkbox" name="s_mods[]" value="*" /><roundcube:label name="allfields" /></label></li>
4444
</ul>
45+
<div class="input-group">
46+
<div class="input-group-prepend">
47+
<label for="s_scope" class="input-group-text"><roundcube:label name="searchscope" /></label>
48+
</div>
49+
<select name="s_scope" id="s_scope" class="custom-select">
50+
<option value="base"><roundcube:label name="currentaddressbook" /></option>
51+
<option value="all"><roundcube:label name="alladdressbooks" /></option>
52+
</select>
53+
</div>
4554
</div>
4655
<div class="formbuttons">
4756
<button type="button" class="btn btn-primary icon search" onclick="return rcmail.command('search')"><roundcube:label name="search" /></button>

skins/elastic/ui.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2843,7 +2843,7 @@ function rcube_elastic_ui() {
28432843
interval_select = $('#s_interval', obj),
28442844
mbox = rcmail.env.mailbox,
28452845
mods = rcmail.env.search_mods,
2846-
scope = rcmail.env.search_scope || 'base';
2846+
scope = rcmail.env.search_scope || (rcmail.task == 'addressbook' ? 'all' : 'base');
28472847

28482848
if (!$(obj).data('initialized')) {
28492849
$(obj).data('initialized', true);

tests/Actions/Contacts/DeleteTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public function test_delete_single_existing_contact()
4141
$this->assertSame('delete', $result['action']);
4242
$this->assertSame(1, $result['env']['pagecount']);
4343
$this->assertTrue(str_contains($result['exec'], 'this.display_message("Contact(s) deleted successfully.","confirmation",0);'));
44-
$this->assertTrue(str_contains($result['exec'], 'this.set_rowcount("Contacts 1 to 5 of 5")'));
44+
$this->assertTrue(str_contains($result['exec'], 'this.set_rowcount("Contacts 1 to 6 of 6")'));
4545

4646
$query = $db->query('SELECT * FROM `contacts` WHERE `contact_id` = ?', $cid);
4747
$result = $db->fetch_assoc($query);

tests/Actions/Contacts/ExportTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ public function test_export_all()
4444

4545
$this->assertContains('Content-Type: text/vcard; charset=UTF-8', $output->headers);
4646
$this->assertContains('Content-Disposition: attachment; filename="contacts.vcf"', $output->headers);
47-
$this->assertSame(6, substr_count($vcf, 'BEGIN:VCARD'));
48-
$this->assertSame(6, substr_count($vcf, 'END:VCARD'));
47+
$this->assertSame(7, substr_count($vcf, 'BEGIN:VCARD'));
48+
$this->assertSame(7, substr_count($vcf, 'END:VCARD'));
4949
$this->assertSame(1, substr_count($vcf, 'FN:Jane Stalone'));
5050
}
5151

tests/Actions/Contacts/ListTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ public function test_list()
3333

3434
$commands = explode("\n", trim($result['exec']));
3535

36-
$this->assertCount(8, $commands);
36+
$this->assertCount(9, $commands);
3737
$this->assertSame('this.set_group_prop(null);', $commands[0]);
38-
$this->assertSame('this.set_rowcount("Contacts 1 to 6 of 6");', $commands[1]);
38+
$this->assertSame('this.set_rowcount("Contacts 1 to 7 of 7");', $commands[1]);
3939
$this->assertStringMatchesFormat(
4040
'this.add_contact_row("%i",{"name":"George Bush"},"person",'
4141
. '{"name":"George Bush","email":"g.bush@gov.com","ID":"%i"});',

0 commit comments

Comments
 (0)