-
Notifications
You must be signed in to change notification settings - Fork 3
/
Searcher.php
168 lines (139 loc) · 4.88 KB
/
Searcher.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
<?php
// This file is part of Bileto.
// Copyright 2022-2024 Probesys
// SPDX-License-Identifier: AGPL-3.0-or-later
namespace App\SearchEngine\Ticket;
use App\Entity;
use App\SearchEngine;
use App\Security;
use App\Utils;
/**
* @phpstan-import-type PaginationOptions from Utils\Pagination
*/
class Searcher
{
public const QUERY_DEFAULT = 'status:open';
public const QUERY_OWNED = 'status:open,resolved requester:@me';
public const QUERY_ASSIGNED_ME = 'status:open assignee:@me';
public const QUERY_UNASSIGNED = 'status:open no:assignee';
private SearchEngine\Query $orgaQuery;
public function __construct(
private QueryBuilder $ticketQueryBuilder,
private Security\Authorizer $authorizer,
) {
// The default query makes sure that the SearchEngine only returns
// tickets related to the current user.
$this->orgaQuery = SearchEngine\Query::fromString('involves:@me');
}
public function setOrganization(Entity\Organization $organization): self
{
return $this->setOrganizations([$organization]);
}
/**
* @param Entity\Organization[] $organizations
*/
public function setOrganizations(array $organizations): self
{
$queries = [];
$permissions = [
'all' => [],
'involves' => [],
];
foreach ($organizations as $organization) {
if ($this->authorizer->isGranted('orga:see:tickets:all', $organization)) {
$permissions['all'][] = "#{$organization->getId()}";
} else {
// Note that we don't check for the orga:see permission here.
// We consider that a user should be able to access the tickets
// in which he's involved whether he has access to the
// organization or not.
$permissions['involves'][] = "#{$organization->getId()}";
}
}
$listOrgaIds = implode(',', $permissions['all']);
if ($listOrgaIds) {
$queries[] = "(org:{$listOrgaIds})";
}
$listOrgaIds = implode(',', $permissions['involves']);
if ($listOrgaIds) {
$queries[] = "(org:{$listOrgaIds} AND involves:@me)";
}
if (!empty($queries)) {
$queryString = implode(' OR ', $queries);
$this->orgaQuery = SearchEngine\Query::fromString($queryString);
}
return $this;
}
/**
* @param ?PaginationOptions $paginationOptions
*
* @return Utils\Pagination<Entity\Ticket>
*/
public function getTickets(
?SearchEngine\Query $query = null,
string $sort = '',
?array $paginationOptions = null
): Utils\Pagination {
if ($paginationOptions === null) {
$paginationOptions = [
'page' => 1,
'maxResults' => 25,
];
}
$sort = $this->processSort($sort);
$queries = [$this->orgaQuery];
if ($query) {
$queries[] = $query;
}
$queryBuilder = $this->ticketQueryBuilder->create($queries);
$queryBuilder->orderBy("t.{$sort[0]}", $sort[1]);
/** @var Utils\Pagination<Entity\Ticket> */
$pagination = Utils\Pagination::paginate($queryBuilder->getQuery(), $paginationOptions);
return $pagination;
}
public function countTickets(?SearchEngine\Query $query = null): int
{
$queries = [$this->orgaQuery];
if ($query) {
$queries[] = $query;
}
$queryBuilder = $this->ticketQueryBuilder->create($queries);
$queryBuilder->select($queryBuilder->expr()->countDistinct('t.id'));
return (int) $queryBuilder->getQuery()->getSingleScalarResult();
}
public static function queryDefault(): SearchEngine\Query
{
return SearchEngine\Query::fromString(self::QUERY_DEFAULT);
}
public static function queryOwned(): SearchEngine\Query
{
return SearchEngine\Query::fromString(self::QUERY_OWNED);
}
public static function queryAssignedMe(): SearchEngine\Query
{
return SearchEngine\Query::fromString(self::QUERY_ASSIGNED_ME);
}
public static function queryUnassigned(): SearchEngine\Query
{
return SearchEngine\Query::fromString(self::QUERY_UNASSIGNED);
}
/**
* @return array{string, 'ASC'|'DESC'}
*/
private function processSort(string $sort): array
{
if ($sort === 'title-asc') {
return ['title', 'ASC'];
} elseif ($sort === 'title-desc') {
return ['title', 'DESC'];
} elseif ($sort === 'created-asc') {
return ['createdAt', 'ASC'];
} elseif ($sort === 'created-desc') {
return ['createdAt', 'DESC'];
} elseif ($sort === 'updated-asc') {
return ['updatedAt', 'ASC'];
} else {
return ['updatedAt', 'DESC'];
}
}
}