]> git.agnieray.net Git - galette.git/blob - galette/lib/Galette/Controllers/AjaxController.php
955bfe7d10a803bc4404b0491f918a36f525c577
[galette.git] / galette / lib / Galette / Controllers / AjaxController.php
1 <?php
2
3 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
4
5 /**
6 * Galette ajax controller
7 *
8 * PHP version 5
9 *
10 * Copyright © 2023 The Galette Team
11 *
12 * This file is part of Galette (http://galette.tuxfamily.org).
13 *
14 * Galette is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation, either version 3 of the License, or
17 * (at your option) any later version.
18 *
19 * Galette is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with Galette. If not, see <http://www.gnu.org/licenses/>.
26 *
27 * @category Controllers
28 * @package Galette
29 *
30 * @author Johan Cwiklinski <johan@x-tnd.be>
31 * @copyright 2023 The Galette Team
32 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
33 * @link https://galette.eu
34 * @since 2023-02-01
35 */
36
37 namespace Galette\Controllers;
38
39 use Analog\Analog;
40 use Galette\Entity\Adherent;
41 use Galette\Entity\Contribution;
42 use Galette\Filters\MembersList;
43 use Galette\Repository\Members;
44 use Galette\Util\Password;
45 use Galette\Util\Telemetry;
46 use Slim\Psr7\Request;
47 use Slim\Psr7\Response;
48 use Throwable;
49
50 /**
51 * Galette ajax controller
52 *
53 * @category Controllers
54 * @name GaletteController
55 * @package Galette
56 * @author Johan Cwiklinski <johan@x-tnd.be>
57 * @copyright 2023 The Galette Team
58 * @license http://www.gnu.org/licenses/gpl-3.0.html GPL License 3.0 or (at your option) any later version
59 * @link https://galette.eu
60 * @since 2023-02-01
61 */
62
63 class AjaxController extends AbstractController
64 {
65 /**
66 * Messages as JSON array
67 *
68 * @param Request $request PSR Request
69 * @param Response $response PSR Response
70 *
71 * @return Response
72 */
73 public function messages(Request $request, Response $response): Response
74 {
75 $messages = [];
76
77 $errors = $this->flash->getMessage('loginfault') ?? [];
78 $errors = array_merge($errors, $this->flash->getMessage('error_detected') ?? []);
79 $errors = array_merge($errors, $this->flash->getMessage('error') ?? []);
80
81 if (count($errors) > 0) {
82 $messages['error'] = [
83 'title' => _T('- ERROR -'),
84 'icon' => 'exclamation circle',
85 'messages' => $errors
86 ];
87 }
88
89 $warnings = $this->flash->getMessage('warning_detected') ?? [];
90 $warnings = array_merge($warnings, $this->flash->getMessage('warning') ?? []);
91
92 if (count($warnings) > 0) {
93 $messages['warning'] = [
94 'title' => _T('- WARNING -'),
95 'icon' => 'exclamation triangle',
96 'messages' => $warnings
97 ];
98 }
99
100 $info = $this->flash->getMessage('info_detected') ?? [];
101 $info = array_merge($info, $this->flash->getMessage('info') ?? []);
102
103 if (count($info) > 0) {
104 $messages['info'] = [
105 'title' => '',
106 'icon' => 'info',
107 'messages' => $info
108 ];
109 }
110
111 $success = $this->flash->getMessage('success_detected') ?? [];
112 $success = array_merge($success, $this->flash->getMessage('succes') ?? []);
113
114 if (count($success) > 0) {
115 $messages['success'] = [
116 'title' => '',
117 'icon' => 'check circle outline',
118 'messages' => $success
119 ];
120 }
121
122 return $this->withJson($response, $messages);
123 }
124
125 /**
126 * Ajax Drag'N'Drop photo
127 *
128 * @param Request $request PSR Request
129 * @param Response $response PSR Response
130 *
131 * @return Response
132 */
133 public function photo(Request $request, Response $response): Response
134 {
135 $post = $request->getParsedBody();
136 $ret = ['result' => false];
137
138 if (
139 !isset($post['member_id'])
140 || !isset($post['file'])
141 || !isset($post['filename'])
142 || !isset($post['filesize'])
143 ) {
144 $this->flash->addMessage(
145 'error_detected',
146 _T("Required argument not present!")
147 );
148 return $this->withJson($response, $ret);
149 }
150
151 $mid = $post['member_id'];
152 $fsize = $post['filesize'];
153 $fname = $post['filename'];
154 $cropping = null;
155 if ($post['cropping'] != false) {
156 $cropping = $post['cropping'];
157 }
158 $tmpname = GALETTE_TEMPIMAGES_PATH . 'ajax_upload_' . $fname;
159
160 $temp = explode('base64,', $post['file']);
161 $raw_file = base64_decode($temp[1]);
162
163 //write temporary file
164 $fp = fopen($tmpname, 'w');
165 fwrite($fp, $raw_file);
166 fclose($fp);
167
168 $adh = new Adherent($this->zdb, (int)$mid);
169
170 $res = $adh->picture->store(
171 array(
172 'name' => $fname,
173 'tmp_name' => $tmpname,
174 'size' => $fsize
175 ),
176 true,
177 $cropping
178 );
179
180 if ($res < 0) {
181 $ret['message'] = $adh->picture->getErrorMessage($res);
182 $this->flash->addMessage(
183 'error_detected',
184 $ret['message']
185 );
186 } else {
187 $ret['result'] = true;
188 $this->flash->addMessage(
189 'success_detected',
190 _T('Member photo has been changed.')
191 );
192 }
193
194 return $this->withJson($response, $ret);
195 }
196
197 /**
198 * Ajax town suggestion
199 *
200 * @param Request $request PSR Request
201 * @param Response $response PSR Response
202 * @param string $term Search term
203 *
204 * @return Response
205 */
206 public function suggestTowns(Request $request, Response $response, string $term): Response
207 {
208 $ret = [];
209
210 try {
211 $select1 = $this->zdb->select(Adherent::TABLE);
212 $select1->columns(['ville_adh']);
213 $select1->where->like('ville_adh', '%' . html_entity_decode($term) . '%');
214
215 $select2 = $this->zdb->select(Adherent::TABLE);
216 $select2->columns(['lieu_naissance']);
217 $select2->where->like('lieu_naissance', '%' . html_entity_decode($term) . '%');
218
219 $select1->combine($select2);
220
221 $select = $this->zdb->sql->select();
222 $select->from(['sub' => $select1])
223 ->order('ville_adh ASCC')
224 ->limit(10);
225
226 $towns = $this->zdb->execute($select);
227
228 $ret['success'] = true;
229 $ret['results'] = [];
230 foreach ($towns as $town) {
231 $ret['results'][] = [
232 'title' => $town->ville_adh
233 ];
234 }
235 } catch (Throwable $e) {
236 Analog::log(
237 'Something went wrong is towns suggestion: ' . $e->getMessage(),
238 Analog::WARNING
239 );
240 throw $e;
241 }
242
243 return $this->withJson($response, $ret);
244 }
245
246 /**
247 * Ajax countries suggestion
248 *
249 * @param Request $request PSR Request
250 * @param Response $response PSR Response
251 * @param string $term Search term
252 *
253 * @return Response
254 */
255 public function suggestCountries(Request $request, Response $response, string $term): Response
256 {
257 $ret = [];
258
259 try {
260 $select = $this->zdb->select(Adherent::TABLE);
261 $select->columns(['pays_adh']);
262 $select->where->like('pays_adh', '%' . html_entity_decode($term) . '%');
263 $select->limit(10);
264 $select->order(['pays_adh ASC']);
265
266 $countries = $this->zdb->execute($select);
267
268 $ret['success'] = true;
269 $ret['results'] = [];
270 foreach ($countries as $country) {
271 $ret['results'][] = [
272 'title' => $country->pays_adh
273 ];
274 }
275 } catch (Throwable $e) {
276 Analog::log(
277 'Something went wrong is countries suggestion: ' . $e->getMessage(),
278 Analog::WARNING
279 );
280 throw $e;
281 }
282
283 return $this->withJson($response, $ret);
284 }
285
286 /**
287 * Telemetry info preview
288 *
289 * @param Request $request PSR Request
290 * @param Response $response PSR Response
291 *
292 * @return Response
293 */
294 public function telemetryInfos(Request $request, Response $response): Response
295 {
296 $telemetry = new Telemetry(
297 $this->zdb,
298 $this->preferences,
299 $this->plugins
300 );
301 $body = $response->getBody();
302 $body->write('<pre>' . json_encode($telemetry->getTelemetryInfos(), JSON_PRETTY_PRINT) . '</pre>');
303 return $response;
304 }
305
306 /**
307 * Send telemetry info
308 *
309 * @param Request $request PSR Request
310 * @param Response $response PSR Response
311 *
312 * @return Response
313 */
314 public function telemetrySend(Request $request, Response $response): Response
315 {
316 $telemetry = new Telemetry(
317 $this->zdb,
318 $this->preferences,
319 $this->plugins
320 );
321 try {
322 $telemetry->send();
323 $message = _T('Telemetry information has been sent. Thank you!');
324 $result = [
325 'success' => true,
326 'message' => $message
327 ];
328 } catch (Throwable $e) {
329 $result = [
330 'success' => false,
331 'message' => $e->getMessage()
332 ];
333 }
334 return $this->withJson($response, $result);
335 }
336
337 /**
338 * Successful telemetry registration
339 *
340 * @param Request $request PSR Request
341 * @param Response $response PSR Response
342 *
343 * @return Response
344 */
345 public function telemetryRegistered(Request $request, Response $response): Response
346 {
347 $this->preferences->pref_registration_date = date('Y-m-d H:i:s');
348 $this->preferences->store();
349 return $this->withJson($response, ['message' => _T('Thank you for registering!')]);
350 }
351
352 /**
353 * Contributions dates
354 *
355 * @param Request $request PSR Request
356 * @param Response $response PSR Response
357 *
358 * @return Response
359 */
360 public function contributionDates(Request $request, Response $response): Response
361 {
362 $post = $request->getParsedBody();
363
364 $contrib = new Contribution(
365 $this->zdb,
366 $this->login,
367 [
368 'type' => (int)$post['fee_id'],
369 'adh' => (int)$post['member_id']
370 ]
371 );
372
373 return $this->withJson(
374 $response,
375 [
376 'date_debut_cotis' => $contrib->begin_date,
377 'date_fin_cotis' => $contrib->end_date
378 ]
379 );
380 }
381
382 /**
383 * Contributions dates
384 *
385 * @param Request $request PSR Request
386 * @param Response $response PSR Response
387 * @param int|null $page Page number
388 * @param string|null $search Search string
389 *
390 * @return Response
391 */
392 public function contributionMembers(Request $request, Response $response, int $page = null, string $search = null): Response
393 {
394 $post = $request->getParsedBody();
395 $filters = new MembersList();
396 if (isset($post['page'])) {
397 $filters->current_page = (int)$post['page'];
398 } elseif ($page !== null) {
399 $filters->current_page = $page;
400 }
401
402 if (isset($post['search'])) {
403 $search = $post['search'];
404 }
405 if ($search !== null) {
406 $filters->filter_str = $search;
407 if (is_numeric($search)) {
408 $filters->field_filter = Members::FILTER_ID;
409 }
410 }
411
412 $m = new Members($filters);
413 $list_members = $m->getDropdownMembers($this->zdb, $this->login);
414
415 $members = [];
416 if (count($list_members) > 0) {
417 foreach ($list_members as $pk => $member) {
418 $members[] = [
419 'name' => $member,
420 'value' => $pk
421 ];
422 }
423 }
424
425 return $this->withJson(
426 $response,
427 [
428 'results' => $members
429 ]
430 );
431 }
432
433 /**
434 * Password strength
435 *
436 * @param Request $request PSR Request
437 * @param Response $response PSR Response
438 *
439 * @return Response
440 */
441 public function passwordStrength(Request $request, Response $response): Response
442 {
443 //post params may be passed from security tab test password
444 $post = $request->getParsedBody();
445
446 if (isset($post['pref_password_length'])) {
447 $this->preferences->pref_password_length = $post['pref_password_length'];
448 }
449
450 if (isset($post['pref_password_strength'])) {
451 $this->preferences->pref_password_strength = $post['pref_password_strength'];
452 }
453
454 if (isset($post['pref_password_blacklist'])) {
455 $this->preferences->pref_password_blacklist = $post['pref_password_blacklist'];
456 }
457
458 $pass = new Password($this->preferences);
459 $valid = $pass->isValid($post['value']);
460
461 return $this->withJson(
462 $response,
463 [
464 'valid' => $valid,
465 'score' => $pass->getStrenght(),
466 'errors' => $pass->getErrors(),
467 'warnings' => ($valid ? $pass->getStrenghtErrors() : null)
468 ]
469 );
470 }
471 }