Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 84 |
|
0.00% |
0 / 10 |
CRAP | |
0.00% |
0 / 1 |
CospendSearchProvider | |
0.00% |
0 / 84 |
|
0.00% |
0 / 10 |
930 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
getId | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getName | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getOrder | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
search | |
0.00% |
0 / 37 |
|
0.00% |
0 / 1 |
56 | |||
getMainText | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
132 | |||
getSubline | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
2 | |||
getDeepLinkToCospendApp | |
0.00% |
0 / 6 |
|
0.00% |
0 / 1 |
2 | |||
getThumbnailUrl | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
truncate | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | /** |
6 | * @copyright Copyright (c) 2020, Julien Veyssier |
7 | * |
8 | * @author Julien Veyssier <eneiluj@posteo.net> |
9 | * |
10 | * @license AGPL-3.0 |
11 | * |
12 | * This code is free software: you can redistribute it and/or modify |
13 | * it under the terms of the GNU Affero General Public License, version 3, |
14 | * as published by the Free Software Foundation. |
15 | * |
16 | * This program is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU Affero General Public License for more details. |
20 | * |
21 | * You should have received a copy of the GNU Affero General Public License, version 3, |
22 | * along with this program. If not, see <http://www.gnu.org/licenses/> |
23 | * |
24 | */ |
25 | namespace OCA\Cospend\Search; |
26 | |
27 | use OCA\Cospend\Service\ProjectService; |
28 | use OCA\Cospend\AppInfo\Application; |
29 | use OCP\App\IAppManager; |
30 | use OCP\IL10N; |
31 | use OCP\IConfig; |
32 | use OCP\IURLGenerator; |
33 | use OCP\IUser; |
34 | use OCP\Search\IProvider; |
35 | use OCP\Search\ISearchQuery; |
36 | use OCP\Search\SearchResult; |
37 | |
38 | use OCP\IDateTimeFormatter; |
39 | use DateTime; |
40 | |
41 | class CospendSearchProvider implements IProvider { |
42 | |
43 | /** @var IAppManager */ |
44 | private $appManager; |
45 | |
46 | /** @var IL10N */ |
47 | private $l10n; |
48 | |
49 | /** @var IURLGenerator */ |
50 | private $urlGenerator; |
51 | /** |
52 | * @var IConfig |
53 | */ |
54 | private $config; |
55 | /** |
56 | * @var IDateTimeFormatter |
57 | */ |
58 | private $dateFormatter; |
59 | /** |
60 | * @var ProjectService |
61 | */ |
62 | private $projectService; |
63 | |
64 | /** |
65 | * CospendSearchProvider constructor. |
66 | * |
67 | * @param IAppManager $appManager |
68 | * @param IL10N $l10n |
69 | * @param IConfig $config |
70 | * @param IURLGenerator $urlGenerator |
71 | * @param IDateTimeFormatter $dateFormatter |
72 | * @param ProjectService $projectService |
73 | */ |
74 | public function __construct(IAppManager $appManager, |
75 | IL10N $l10n, |
76 | IConfig $config, |
77 | IURLGenerator $urlGenerator, |
78 | IDateTimeFormatter $dateFormatter, |
79 | ProjectService $projectService) { |
80 | $this->appManager = $appManager; |
81 | $this->l10n = $l10n; |
82 | $this->config = $config; |
83 | $this->urlGenerator = $urlGenerator; |
84 | $this->dateFormatter = $dateFormatter; |
85 | $this->projectService = $projectService; |
86 | } |
87 | |
88 | /** |
89 | * @inheritDoc |
90 | */ |
91 | public function getId(): string { |
92 | return 'cospend-search'; |
93 | } |
94 | |
95 | /** |
96 | * @inheritDoc |
97 | */ |
98 | public function getName(): string { |
99 | return $this->l10n->t('Cospend'); |
100 | } |
101 | |
102 | /** |
103 | * @inheritDoc |
104 | */ |
105 | public function getOrder(string $route, array $routeParameters): int { |
106 | if (strpos($route, Application::APP_ID . '.') === 0) { |
107 | // Active app, prefer Cospend results |
108 | return -1; |
109 | } |
110 | |
111 | return 20; |
112 | } |
113 | |
114 | /** |
115 | * @inheritDoc |
116 | */ |
117 | public function search(IUser $user, ISearchQuery $query): SearchResult { |
118 | if (!$this->appManager->isEnabledForUser('cospend', $user)) { |
119 | return SearchResult::complete($this->getName(), []); |
120 | } |
121 | |
122 | $limit = $query->getLimit(); |
123 | $term = $query->getTerm(); |
124 | $offset = $query->getCursor(); |
125 | $offset = $offset ? (int) $offset : 0; |
126 | |
127 | $resultBills = []; |
128 | |
129 | // get user's projects |
130 | $projects = $this->projectService->getProjects($user->getUID()); |
131 | $projectsById = []; |
132 | foreach ($projects as $project) { |
133 | $projectsById[$project['id']] = $project; |
134 | } |
135 | |
136 | // search bills for each project |
137 | foreach ($projects as $project) { |
138 | $searchResults = $this->projectService->searchBills($project['id'], $term); |
139 | $resultBills = array_merge($resultBills, $searchResults); |
140 | } |
141 | |
142 | // sort by timestamp |
143 | usort($resultBills, function($a, $b) { |
144 | $ta = $a['timestamp']; |
145 | $tb = $b['timestamp']; |
146 | return ($ta > $tb) ? -1 : 1; |
147 | }); |
148 | |
149 | $resultBills = array_slice($resultBills, $offset, $limit); |
150 | |
151 | // build formatted |
152 | $formattedResults = array_map(function (array $bill) use ($projectsById):CospendSearchResultEntry { |
153 | $projectId = $bill['projectId']; |
154 | $thumbnailUrl = $this->getThumbnailUrl($bill); |
155 | return new CospendSearchResultEntry( |
156 | $thumbnailUrl, |
157 | $this->getMainText($bill, $projectsById[$projectId]), |
158 | $this->getSubline($bill, $projectsById[$projectId]), |
159 | $this->getDeepLinkToCospendApp($projectId, $bill['id']), |
160 | $thumbnailUrl === '' ? 'icon-cospend-search-fallback' : '', |
161 | true |
162 | ); |
163 | }, $resultBills); |
164 | |
165 | return SearchResult::paginated( |
166 | $this->getName(), |
167 | $formattedResults, |
168 | $offset + $limit |
169 | ); |
170 | } |
171 | |
172 | /** |
173 | * @param array $bill |
174 | * @param array $project |
175 | * @return string |
176 | */ |
177 | protected function getMainText(array $bill, array $project): string { |
178 | $currency = $bill['currencyname'] ?? ''; |
179 | $currency = $currency ? ' ' . $currency : ''; |
180 | $what = $this->truncate($bill['what'], 24); |
181 | $catPmChars = ''; |
182 | if (isset($bill['categoryid']) |
183 | && !is_null($bill['categoryid']) |
184 | && $bill['categoryid'] !== 0 |
185 | ) { |
186 | if (isset($project['categories'][$bill['categoryid']])) { |
187 | $catPmChars .= $project['categories'][$bill['categoryid']]['icon'] . ' '; |
188 | } elseif (isset(Application::HARDCODED_CATEGORIES[$bill['categoryid']])) { |
189 | $catPmChars .= Application::HARDCODED_CATEGORIES[$bill['categoryid']]['icon']; |
190 | } |
191 | } |
192 | if (isset($bill['paymentmodeid']) |
193 | && !is_null($bill['paymentmodeid']) |
194 | && $bill['paymentmodeid'] !== 0 |
195 | ) { |
196 | if (isset($project['paymentmodes'][$bill['paymentmodeid']])) { |
197 | $catPmChars .= $project['paymentmodes'][$bill['paymentmodeid']]['icon'] . ' '; |
198 | } |
199 | } |
200 | $amount = number_format($bill['amount'], 2); |
201 | return $what. ' ('. $amount . $currency . ') ' . $catPmChars; |
202 | } |
203 | |
204 | /** |
205 | * @param array $bill |
206 | * @param array $project |
207 | * @return string |
208 | */ |
209 | protected function getSubline(array $bill, array $project): string { |
210 | $d = new DateTime(); |
211 | $d->setTimestamp($bill['timestamp']); |
212 | $fd = $this->dateFormatter->formatDate($d, 'short'); |
213 | return '[' . $fd . '] ' . $this->l10n->t('in %1$s', [$project['name']]); |
214 | } |
215 | |
216 | /** |
217 | * @param string $projectId |
218 | * @return string |
219 | */ |
220 | protected function getDeepLinkToCospendApp(string $projectId, int $billId): string { |
221 | return $this->urlGenerator->getAbsoluteURL( |
222 | $this->urlGenerator->linkToRoute('cospend.page.indexBill', [ |
223 | 'projectId' => $projectId, |
224 | 'billId' => $billId, |
225 | ]) |
226 | ); |
227 | } |
228 | |
229 | protected function getThumbnailUrl(array $bill): string { |
230 | if ($bill['payer_user_id']) { |
231 | return $this->urlGenerator->linkToRouteAbsolute('core.avatar.getAvatar', ['userId' => $bill['payer_user_id'], 'size' => 44]); |
232 | } elseif ($bill['payer_name']) { |
233 | return $this->urlGenerator->linkToRouteAbsolute('core.GuestAvatar.getAvatar', ['guestName' => $bill['payer_name'], 'size' => 44]); |
234 | } |
235 | return ''; |
236 | } |
237 | |
238 | /** |
239 | * @param string $s |
240 | * @param int $len |
241 | * @return string |
242 | */ |
243 | private function truncate(string $s, int $len): string { |
244 | return strlen($s) > $len |
245 | ? substr($s, 0, $len) . '…' |
246 | : $s; |
247 | } |
248 | } |