dolibarr 24.0.0-beta
interface.php
1<?php
2/* Copyright (C) 2024 John BOTELLA
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18//if (! defined('NOREQUIREDB')) define('NOREQUIREDB', '1'); // Do not create database handler $db
19//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER', '1'); // Do not load object $user
20//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC', '1'); // Do not load object $mysoc
21//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN', '1'); // Do not load object $langs
22//if (! defined('NOSCANGETFORINJECTION')) define('NOSCANGETFORINJECTION', '1'); // Do not check injection attack on GET parameters
23//if (! defined('NOSCANPOSTFORINJECTION')) define('NOSCANPOSTFORINJECTION', '1'); // Do not check injection attack on POST parameters
24//if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK', '1'); // Do not check CSRF attack (test on referer + on token if option MAIN_SECURITY_CSRF_WITH_TOKEN is on).
25if (!defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL', '1'); // Do not roll the Anti CSRF token (used if MAIN_SECURITY_CSRF_WITH_TOKEN is on)
26//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK', '1'); // Do not check style html tag into posted data
27if (!defined('NOREQUIREMENU')) define('NOREQUIREMENU', '1'); // If there is no need to load and show top and left menu
28if (!defined('NOREQUIREHTML')) define('NOREQUIREHTML', '1'); // If we don't need to load the html.form.class.php
29//if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX', '1'); // Do not load ajax.lib.php library
30//if (! defined("NOLOGIN")) define("NOLOGIN", '1'); // If this page is public (can be called outside logged session). This include the NOIPCHECK too.
31//if (! defined('NOIPCHECK')) define('NOIPCHECK', '1'); // Do not check IP defined into conf $dolibarr_main_restrict_ip
32//if (! defined("MAIN_LANG_DEFAULT")) define('MAIN_LANG_DEFAULT', 'auto'); // Force lang to a particular value
33//if (! defined("MAIN_AUTHENTICATION_MODE")) define('MAIN_AUTHENTICATION_MODE', 'aloginmodule'); // Force authentication handler
34if (! defined("NOREDIRECTBYMAINTOLOGIN")) define('NOREDIRECTBYMAINTOLOGIN', 1); // The main.inc.php does not make a redirect if not logged, instead show simple error message
35//if (! defined("FORCECSP")) define('FORCECSP', 'none'); // Disable all Content Security Policies
36//if (! defined('CSRFCHECK_WITH_TOKEN')) define('CSRFCHECK_WITH_TOKEN', '1'); // Force use of CSRF protection with tokens even for GET
37//if (! defined('NOBROWSERNOTIF')) define('NOBROWSERNOTIF', '1'); // Disable browser notification
38
39
40// Load Dolibarr environment
41require '../main.inc.php';
48// Load required classes
49require_once DOL_DOCUMENT_ROOT . '/core/class/jsonResponse.class.php';
50require_once __DIR__ . '/class/memo.class.php';
51if (!class_exists('Validate')) {
52 require_once DOL_DOCUMENT_ROOT . '/core/class/validate.class.php';
53}
54
55// Initialize hooks for the interface
56$hookmanager->initHooks(['quickmemoInterface']);
57
58// Load translation files required by the page
59$langs->loadLangs(["quickmemo", "other", 'main']);
60
61$action = GETPOST('action');
62
63// Security check: check if the module is enabled
64if (!isModEnabled('quickmemo')) accessforbidden('Module not enabled');
65
66$jsonResponse = new JsonResponse();
67
68// Security check: basic read permission
69if (!$user || !$user->hasRight('quickmemo', 'memo', 'read')) {
70 $jsonResponse->msg = $langs->trans('NotEnoughRights');
71 $jsonResponse->result = 0;
72 print $jsonResponse->getResponse();
73 $db->close(); // Close $db database opened handler
74 exit;
75}
76
77// Execute hooks before standard actions
78$reshook = $hookmanager->executeHooks('quickMemoInterface', [], $jsonResponse, $action);
79if ($reshook < 0) {
80 $jsonResponse->msg = $hookmanager->error;
81 if (!empty($hookmanager->errors)) {
82 $jsonResponse->msg = (!empty($hookmanager->error) ? '<br>' : '') . implode('<br>', $hookmanager->errors);
83 }
84 $jsonResponse->result = 0;
85 print $jsonResponse->getResponse();
86 $db->close(); // Close $db database opened handler
87 exit;
88}
89
90// Action Dispatcher: Routes the request to the appropriate function based on the 'action' parameter
91if ($reshook > 0) {
92 // Action handled by hook
93} elseif ($action === 'update_position') {
94 quickMemoIntefaceActionUpdatePosition($jsonResponse);
95} elseif ($action === 'update_all_positions') {
96 quickMemoIntefaceActionUpdateAllPositions($jsonResponse);
97} elseif ($action === 'list') {
98 quickMemoIntefaceActionList($jsonResponse);
99} elseif ($action === 'list_models') {
100 quickMemoIntefaceActionListModels($jsonResponse);
101} elseif ($action === 'update-color') {
102 quickMemoIntefaceActionUpdateColor($jsonResponse);
103} elseif ($action === 'update-shared-on-element') {
104 quickMemoIntefaceActionUpdateSharedOnElement($jsonResponse);
105} elseif ($action === 'update-private') {
106 quickMemoIntefaceActionUpdatePrivate($jsonResponse);
107} elseif ($action === 'archive') {
108 quickMemoIntefaceActionArchiveNote($jsonResponse);
109} elseif ($action === 'delete') {
110 quickMemoIntefaceActionDeleteNote($jsonResponse);
111} elseif ($action === 'create') {
112 quickMemoIntefaceActionCreate($jsonResponse);
113} elseif ($action === 'create_model') {
114 quickMemoIntefaceActionCreateModel($jsonResponse);
115} elseif ($action === 'delete_model') {
116 quickMemoIntefaceActionDeleteModel($jsonResponse);
117} elseif ($action === 'update_model_rank') {
118 quickMemoIntefaceActionUpdateModelRank($jsonResponse);
119} elseif ($action === 'update_note') {
120 quickMemoIntefaceActionUpdateNote($jsonResponse);
121} else {
122 $jsonResponse->msg = 'Action not found';
123}
124
125print $jsonResponse->getResponse();
126
127$db->close(); // Close $db database opened handler
128
134function quickMemoIntefaceActionUpdatePosition($jsonResponse)
135{
136 global $user, $langs, $db;
137
138 // Read permission is sufficient as this only affects the current user's view
139 if (!$user->hasRight('quickmemo', 'memo', 'read')) {
140 $jsonResponse->msg = $langs->trans('NotEnoughRights');
141 $jsonResponse->result = 0;
142 return false;
143 }
144
145 $id = GETPOSTINT("id");
146
147 if (empty($id) && !is_numeric($id)) {
148 $jsonResponse->msg = 'Need memo Id';
149 return false;
150 }
151
152 $memo = new Memo($db);
153 if ($memo->fetch($id) <= 0) {
154 $jsonResponse->msg = 'Memo not found';
155 return false;
156 }
157
158 // Prevent moving a private note belonging to another user
159 if ($user->id != $memo->fk_user_creat && $memo->private) {
160 $jsonResponse->msg = $langs->trans('QuickMemoCantMoveThisPrivateNote');
161 return false;
162 }
163
164 $z = GETPOST("z", "int");
165 $x = GETPOST("x", "int");
166 $y = GETPOST("y", "int");
167 $w = GETPOST("w", "int");
168 $h = GETPOST("h", "int");
169
170 if (!$memo->updatePosition($user, (int) $x, (int) $y, (int) $w, (int) $h, (int) $z)) {
171 $jsonResponse->result = 0;
172 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
173 return false;
174 } else {
175 $jsonResponse->result = 1;
176 $jsonResponse->data = null;
177 return true;
178 }
179}
180
186function quickMemoIntefaceActionUpdateAllPositions($jsonResponse)
187{
188 global $user, $langs, $db;
189
190 // In case of position, read permission is enough because changing position will affect only this user not others.
191 // So he can't modify the content but can move it for himself.
192 if (!$user->hasRight('quickmemo', 'memo', 'read')) {
193 $jsonResponse->msg = $langs->trans('NotEnoughRights');
194 $jsonResponse->result = 0;
195 return false;
196 }
197
198 $json = file_get_contents('php://input');
199 $data = json_decode($json, true);
200
201 if (!is_array($data) || empty($data['memos'])) {
202 $jsonResponse->result = 0;
203 $jsonResponse->msg = 'No data received';
204 return;
205 }
206
207 $db->begin();
208
209 foreach ($data['memos'] as $item) {
210 $memo = new Memo($db);
211 if ($memo->fetch((int) $item['id']) > 0) {
212 // Security check for private notes
213 if ($user->id != $memo->fk_user_creat && $memo->private) continue;
214
215 $memo->updatePosition(
216 $user,
217 (int) $item['x'],
218 (int) $item['y'],
219 (int) $item['w'],
220 (int) $item['h'],
221 (int) $item['z']
222 );
223 }
224 }
225
226 $db->commit();
227 $jsonResponse->result = 1;
228
229 return true;
230}
231
237function quickMemoIntefaceActionCreate($jsonResponse)
238{
239 global $user, $langs, $db;
240
241 if (!$user->hasRight('quickmemo', 'memo', 'write')) {
242 $jsonResponse->msg = $langs->trans('NotEnoughRights');
243 $jsonResponse->result = 0;
244 return false;
245 }
246
247 $element_id = GETPOST("element_id", "int");
248 $element_type = GETPOST("element_type");
249
250
251 if (empty($element_id) && !is_numeric($element_id) && !empty($element_type)) {
252 $jsonResponse->msg = 'Need memo element_id';
253 return false;
254 }
255
256 $memo = new Memo($db);
257 $context_tab = GETPOST('context');
258 if (!in_array($context_tab, $memo->getAvailableMemoContext())) {
259 $jsonResponse->result = 0;
260 $jsonResponse->msg = $langs->trans('UpdateError') . ' : Context unknown';
261 return false;
262 }
263
264 // Handle color selection with preset fallback
265 $colorPresets = Memo::getColorPreset();
266 $firstColor = !empty($colorPresets) ? $colorPresets[0] : null;
267 $memo->color = GETPOST("color");
268 if (!Memo::checkColor($memo->color)) {
269 $memo->color = $firstColor;
270 }
271
272 $memo->quick_note = GETPOST("note", "alphanohtml");
273 $memo->fk_element = $element_id;
274 $memo->element_type = $element_type;
275 $jsonResponse->debug = GETPOST("color", $firstColor);
276 $memo->context_tab = $context_tab;
277 $memo->shared_on_element = GETPOST("shared_on_element", "int") ? 1 : 0;
278 $memo->private = GETPOST("private", "int") ? 1 : 0;
279
280 $memo->pos_x = GETPOST("x", "int");
281 $memo->pos_y = GETPOST("y", "int");
282 $memo->pos_w = GETPOST("w", "int");
283 $memo->pos_h = GETPOST("h", "int");
284 $memo->pos_z = GETPOST("z", "int");
285 $memo->status = Memo::STATUS_VALIDATED;
286
287 $resCre = $memo->create($user);
288 if ($resCre <= 0 ) {
289 $jsonResponse->result = 0;
290 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
291 return false;
292 } else {
293 $jsonResponse->result = 1;
294 $jsonResponse->data = new stdClass();
295 $jsonResponse->data->id = (int) $resCre;
296
297 return true;
298 }
299}
300
301
307function quickMemoIntefaceActionArchiveNote($jsonResponse)
308{
309 global $user, $langs, $db;
310
311 if (!$user->hasRight('quickmemo', 'memo', 'write')) {
312 $jsonResponse->msg = $langs->trans('NotEnoughRights');
313 $jsonResponse->result = 0;
314 return false;
315 }
316
317 $id = GETPOSTINT("id");
318
319 if (empty($id) && !is_numeric($id)) {
320 $jsonResponse->msg = 'Need memo Id';
321 return false;
322 }
323
324 $memo = new Memo($db);
325 if ($memo->fetch($id) <= 0) {
326 $jsonResponse->msg = 'Memo not found';
327 return false;
328 }
329
330 if ($user->id != $memo->fk_user_creat && $memo->private) {
331 $jsonResponse->msg = $langs->trans('QuickMemoCantArchiveThisPrivateNote');
332 return false;
333 }
334
335 if ($memo->setArchived($user) < 0) {
336 $jsonResponse->result = 0;
337 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
338 return false;
339 } else {
340 $jsonResponse->result = 1;
341 $jsonResponse->data = null;
342 return true;
343 }
344}
345
351function quickMemoIntefaceActionCreateModel($jsonResponse)
352{
353 global $user, $langs, $db;
354
355 if (!$user->hasRight('quickmemo', 'memo', 'write')) {
356 $jsonResponse->msg = $langs->trans('NotEnoughRights');
357 $jsonResponse->result = 0;
358 return false;
359 }
360
361 $id = GETPOSTINT("id");
362
363 if (empty($id) && !is_numeric($id)) {
364 $jsonResponse->msg = 'Need memo Id';
365 return false;
366 }
367
368 $memo = new Memo($db);
369 if ($memo->fetch($id) <= 0) {
370 $jsonResponse->msg = 'Memo not found';
371 return false;
372 }
373
374 if ($user->id != $memo->fk_user_creat && $memo->private) {
375 $jsonResponse->msg = $langs->trans('QuickMemoCantChangeThisPrivateNote');
376 return false;
377 }
378
379 $element_type = GETPOST("element_type");
380 if (empty($element_type)) {
381 $memo->element_type = '';
382 }
383
384 $memo->status = Memo::STATUS_TPL;
385 $memo->private_tpl = GETPOST("tpl_private", "int");
386 $memo->name_tpl = GETPOST("tpl_name");
387 $memo->fk_user_creat = $user->id;
388 $memo->date_creation = dol_now();
389 $memo->fk_user_modif = null;
390 $memo->date_modification = null;
391 $memo->fk_user_archived = null;
392 $memo->date_archived = null;
393
394 if ($memo->update($user) < 0) {
395 $jsonResponse->result = 0;
396 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
397 return false;
398 } else {
399 $jsonResponse->result = 1;
400 $jsonResponse->data = null;
401 return true;
402 }
403}
404
405
411function quickMemoIntefaceActionDeleteModel($jsonResponse)
412{
413 global $user, $langs, $db;
414
415 if (!$user->hasRight('quickmemo', 'memo', 'delete')) {
416 $jsonResponse->msg = $langs->trans('NotEnoughRights');
417 $jsonResponse->result = 0;
418 return false;
419 }
420
421 $id = GETPOSTINT("id");
422
423 if (empty($id) && !is_numeric($id)) {
424 $jsonResponse->msg = 'Need model Id';
425 return false;
426 }
427
428 $memo = new Memo($db);
429 if ($memo->fetch($id) <= 0) {
430 $jsonResponse->msg = 'Memo not found';
431 return false;
432 }
433
434 if ($memo->status != Memo::STATUS_TPL) {
435 $jsonResponse->msg = 'Not a model';
436 return false;
437 }
438
439 if ($user->id != $memo->fk_user_creat && $memo->private_tpl) {
440 $jsonResponse->msg = $langs->trans('QuickMemoCantDeleteThisPrivateModel');
441 return false;
442 }
443
444 if ($memo->delete($user) < 0) {
445 $jsonResponse->result = 0;
446 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
447 return false;
448 } else {
449 $jsonResponse->result = 1;
450 $jsonResponse->data = null;
451 return true;
452 }
453}
454
487function quickMemoIntefaceActionUpdateModelRank($jsonResponse)
488{
489 global $user, $langs, $db;
490
491 if (!$user->hasRight('quickmemo', 'memo', 'write')) {
492 $jsonResponse->msg = $langs->trans('NotEnoughRights');
493 $jsonResponse->result = 0;
494 return false;
495 }
496
497 $json = file_get_contents('php://input');
498 $data = json_decode($json, true);
499
500 if (!is_array($data) || empty($data['moved']['id']) || !isset($data['moved']['newPos'])) {
501 $jsonResponse->result = 0;
502 $jsonResponse->msg = 'INVALID MOVED DATA';
503 return false;
504 }
505
506
507
508 $movedId = (int) $data['moved']['id'];
509 $newPos = max(1, (int) $data['moved']['newPos']);
510
511 $tmpMemo = new Memo($db);
512
513 // 1 Retrieve the moved model
514 $sql = 'SELECT rowid, element_type, context_tab
515 FROM '.MAIN_DB_PREFIX.$tmpMemo->table_element.'
516 WHERE rowid = '. (int) $movedId.'
517 AND status = '. (int) Memo::STATUS_TPL;
518
519 $res = $db->query($sql);
520 if (!$res || !$db->num_rows($res)) {
521 $jsonResponse->result = 0;
522 $jsonResponse->msg = 'MODEL NOT FOUND';
523 return false;
524 }
525
526 $movedModel = $db->fetch_object($res);
527
528 // 2 Retrieve ALL compatible models
529 $sqlAll = 'SELECT rowid
530 FROM '.MAIN_DB_PREFIX.$tmpMemo->table_element.'
531 WHERE status = '. (int) Memo::STATUS_TPL.'
532 AND element_type IN (\''.$db->escape($movedModel->element_type).'\', \'\')
533 ORDER BY rank_tpl DESC';
534
535 // AND context_tab = \''.$db->escape($movedModel->context_tab).'\'
536
537 $resAll = $db->query($sqlAll);
538 if (!$resAll) {
539 $jsonResponse->result = 0;
540 $jsonResponse->msg = $db->error();
541 return false;
542 }
543
544 $orderedIds = [];
545 while ($obj = $db->fetch_object($resAll)) {
546 $orderedIds[] = (int) $obj->rowid;
547 }
548
549 // 3 Remove the moved ID
550 $orderedIds = array_values(array_diff($orderedIds, [$movedId]));
551
552 // 4 Calculate actual index (0 based)
553 $newIndex = min(count($orderedIds), $newPos - 1);
554
555 // 5 Insert at new position
556 array_splice($orderedIds, $newIndex, 0, [$movedId]);
557
558 // 6 Clean re-indexing
559 $total = count($orderedIds);
560 $currentRank = $total;
561
562 $db->begin();
563
564 foreach ($orderedIds as $id) {
565 $sqlUp = 'UPDATE '.MAIN_DB_PREFIX.$tmpMemo->table_element.'
566 SET rank_tpl = '.(int) $currentRank.'
567 WHERE rowid = '.(int) $id.'
568 AND status = '. (int) Memo::STATUS_TPL.'
569 AND (private_tpl = 0 OR fk_user_creat = '.(int) $user->id.')';
570
571 if (!$db->query($sqlUp)) {
572 $db->rollback();
573 $jsonResponse->result = 0;
574 $jsonResponse->msg = $db->error();
575 return false;
576 }
577
578 $currentRank--;
579 }
580
581 $db->commit();
582
583 $jsonResponse->result = 1;
584 $jsonResponse->data = null;
585 return true;
586}
592function quickMemoIntefaceActionDeleteNote($jsonResponse)
593{
594 global $user, $langs, $db;
595
596 if (!$user->hasRight('quickmemo', 'memo', 'write')) {
597 $jsonResponse->msg = $langs->trans('NotEnoughRights');
598 $jsonResponse->result = 0;
599 return false;
600 }
601
602 $id = GETPOSTINT("id");
603
604 if (empty($id) && !is_numeric($id)) {
605 $jsonResponse->msg = 'Need memo Id';
606 return false;
607 }
608
609 $memo = new Memo($db);
610 if ($memo->fetch($id) <= 0) {
611 $jsonResponse->msg = 'Memo not found';
612 return false;
613 }
614
615 if ($memo->status == Memo::STATUS_TPL) { // In case of models need check other stuff
616 $jsonResponse->msg = 'Can\'t delete model';
617 return false;
618 }
619
620 if ($user->id != $memo->fk_user_creat && $memo->private) {
621 $jsonResponse->msg = $langs->trans('QuickMemoCantDeleteThisPrivateNote');
622 return false;
623 }
624
625 if ($memo->delete($user) < 0) {
626 $jsonResponse->result = 0;
627 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
628 return false;
629 } else {
630 $jsonResponse->result = 1;
631 $jsonResponse->data = null;
632 return true;
633 }
634}
635
636
642function quickMemoIntefaceActionUpdateNote($jsonResponse)
643{
644 global $user, $langs, $db;
645
646 if (!$user->hasRight('quickmemo', 'memo', 'write')) {
647 $jsonResponse->msg = $langs->trans('NotEnoughRights');
648 $jsonResponse->result = 0;
649 return false;
650 }
651
652 $id = GETPOSTINT("id");
653
654 if (empty($id) && !is_numeric($id)) {
655 $jsonResponse->msg = 'Need memo Id';
656 return false;
657 }
658
659 $memo = new Memo($db);
660 if ($memo->fetch($id) <= 0) {
661 $jsonResponse->msg = 'Memo not found';
662 return false;
663 }
664
665 $memo->quick_note = GETPOST("note", "alphanohtml");
666 $memo->tms = dol_now();
667 $memo->fk_user_modif = $user->id;
668
669 if ($memo->update($user) < 0) {
670 $jsonResponse->result = 0;
671 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
672 return false;
673 } else {
674 $jsonResponse->result = 1;
675 $jsonResponse->data = new stdClass();
676
677 // return new memo
678 $jsonResponse->data->memo = $memo->getJsMemo($user);
679 return true;
680 }
681}
682
688function quickMemoIntefaceActionUpdateColor($jsonResponse)
689{
690 global $user, $langs, $db;
691
692 if (!$user->hasRight('quickmemo', 'memo', 'write')) {
693 $jsonResponse->msg = $langs->trans('NotEnoughRights');
694 $jsonResponse->result = 0;
695 return false;
696 }
697
698 $id = GETPOSTINT("id");
699
700 if (empty($id) && !is_numeric($id)) {
701 $jsonResponse->msg = 'Need memo Id';
702 return false;
703 }
704
705 $color = GETPOST("color");
706 if (!Memo::checkColor($color)) {
707 $jsonResponse->msg = 'Need valide Color';
708 return false;
709 }
710
711 $memo = new Memo($db);
712 if ($memo->fetch($id) <= 0) {
713 $jsonResponse->msg = 'Memo not found';
714 return false;
715 }
716
717 if ($user->id != $memo->fk_user_creat && $memo->private) {
718 $jsonResponse->msg = $langs->trans('QuickMemoCantChangeThisPrivateNote');
719 return false;
720 }
721
722 $memo->color = $color;
723
724 if (!$memo->update($user) < 0) {
725 $jsonResponse->result = 0;
726 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
727 return false;
728 } else {
729 $jsonResponse->result = 1;
730 $jsonResponse->data = new stdClass();
731
732 // return new memo
733 $jsonResponse->data->memo = $memo->getJsMemo($user);
734 return true;
735 }
736}
737
743function quickMemoIntefaceActionUpdateSharedOnElement($jsonResponse)
744{
745 global $user, $langs, $db;
746
747 if (!$user->hasRight('quickmemo', 'memo', 'write')) {
748 $jsonResponse->msg = $langs->trans('NotEnoughRights');
749 $jsonResponse->result = 0;
750 return false;
751 }
752
753 $id = GETPOSTINT("id");
754
755 if (empty($id) && !is_numeric($id)) {
756 $jsonResponse->msg = 'Need memo Id';
757 return false;
758 }
759
760 $shared_on_element = GETPOST("shared_on_element", "int");
761
762 $memo = new Memo($db);
763 if ($memo->fetch($id) <= 0) {
764 $jsonResponse->msg = 'Memo not found';
765 return false;
766 }
767
768 if ($user->id != $memo->fk_user_creat && $memo->private) {
769 $jsonResponse->msg = $langs->trans('QuickMemoCantChangeThisPrivateNote');
770 return false;
771 }
772
773 $memo->shared_on_element = $shared_on_element ? 1 : 0;
774
775 if (!$memo->update($user) < 0) {
776 $jsonResponse->result = 0;
777 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
778 return false;
779 } else {
780 $jsonResponse->result = 1;
781 $jsonResponse->data = null;
782 $jsonResponse->data = new stdClass();
783
784 // return new memo
785 $jsonResponse->data->memo = $memo->getJsMemo($user);
786 return true;
787 }
788}
789
790
796function quickMemoIntefaceActionUpdatePrivate($jsonResponse)
797{
798 global $user, $langs, $db;
799
800 if (!$user->hasRight('quickmemo', 'memo', 'write')) {
801 $jsonResponse->msg = $langs->trans('NotEnoughRights');
802 $jsonResponse->result = 0;
803 return false;
804 }
805
806 $id = GETPOSTINT("id");
807
808 if (empty($id) && !is_numeric($id)) {
809 $jsonResponse->msg = 'Need memo Id';
810 return false;
811 }
812
813 $private = GETPOST("private", "int");
814
815 $memo = new Memo($db);
816 if ($memo->fetch($id) <= 0) {
817 $jsonResponse->msg = 'Memo not found';
818 return false;
819 }
820
821 if ($user->id != $memo->fk_user_creat && $memo->private) {
822 $jsonResponse->msg = $langs->trans('QuickMemoCantChangeThisPrivateNote');
823 return false;
824 }
825
826 $memo->private = $private ? 1 : 0;
827
828 if (!$memo->update($user) < 0) {
829 $jsonResponse->result = 0;
830 $jsonResponse->msg = $langs->trans('UpdateError') . ' : ' . $memo->errorsToString();
831 return false;
832 } else {
833 $jsonResponse->result = 1;
834 $jsonResponse->data = new stdClass();
835
836 // return new memo
837 $jsonResponse->data->memo = $memo->getJsMemo($user);
838 return true;
839 }
840}
841
847function quickMemoIntefaceActionListModels($jsonResponse)
848{
849 global $user, $langs, $db;
850
851 if (!$user->hasRight('quickmemo', 'memo', 'read')) {
852 $jsonResponse->msg = $langs->trans('NotEnoughRights');
853 $jsonResponse->result = 0;
854 return false;
855 }
856
857 $element_type = GETPOST('element_type', 'alpha');
858 $context = GETPOST('context', 'alpha');
859
860 $jsonResponse->data = new stdClass();
861 $jsonResponse->data->modelTemplate = [];
862 $jsonResponse->data->presetTemplate = [];
863
864 // Get standard color list presets
865 $colorList = Memo::getColorPreset();
866
867 foreach ($colorList as $color) {
868 $default = new stdClass();
869 $default->name = '';
870 $default->color = $color;
871 $default->note = '';
872 $default->pos_w = 0;
873 $default->pos_h = 0;
874 $default->pos_x = 0;
875 $default->pos_y = 0;
876 $default->shared_on_element = 0;
877 $default->private = 0;
878 $default->user_name = $user->getFullName($langs);
879 $default->date_creation = dol_print_date(dol_now(), '', 'tzuserrel');
880 $default->date_change = '';
881 $default->user_change_name = '';
882
883
884 $jsonResponse->data->presetTemplate[] = $default;
885 }
886
887 // GET all memo templates (tpl)
888 $memoStatic = new Memo($db);
889 $sql = $memoStatic->getTemplateMemosQuery($element_type, $context);
890 $resql = $db->query($sql);
891 if (!$resql) {
892 $jsonResponse->result = 0;
893 $jsonResponse->msg = $db->lasterror();
894 return;
895 }
896
897 while ($obj = $db->fetch_object($resql)) {
898 // fallback user-specific position
899 $jsonResponse->data->modelTemplate[] = quickMemoInterfacePopulateMemoTplFromQueryObj($obj);
900 }
901
902 $jsonResponse->result = 1;
903}
904
910function quickMemoIntefaceActionList($jsonResponse)
911{
912 global $user, $langs, $db;
913
914 if (!$user->hasRight('quickmemo', 'memo', 'read')) {
915 $jsonResponse->msg = $langs->trans('NotEnoughPermissions');
916 $jsonResponse->result = 0;
917 return;
918 }
919
920 $element_id = GETPOSTINT('element_id');
921 $element_type = GETPOST('element_type', 'alpha');
922 $context = GETPOST('context', 'alpha');
923 $jsonResponse->data = new stdClass();
924 $jsonResponse->data->memos = [];
925 $jsonResponse->data->nbArchives = 0;
926
927 if (empty($element_id) && !empty($element_type)) {
928 $jsonResponse->msg = 'Need element_id ';
929 $jsonResponse->result = 0;
930 return;
931 }
932
933 $staticMemo = new Memo($db);
934
935 // GET all active memos
936 $sql = $staticMemo->getMemosQuery($element_type, $element_id, $context);
937 $resql = $db->query($sql);
938 if (!$resql) {
939 $jsonResponse->result = 0;
940 $jsonResponse->msg = $db->lasterror();
941 return;
942 }
943
944
945 $memos = [];
946 while ($obj = $db->fetch_object($resql)) {
947 // fallback user-specific position
948 $memos[] = quickMemoInterfacePopulateMemoFromQueryObj($obj);
949 }
950
951 $jsonResponse->data->memos = $memos;
952
953 // Count archived notes for display
954 $nbArchives = $staticMemo->countArchivedMemoQuery($element_type, $element_id, $context);
955 if ($nbArchives === false) {
956 $jsonResponse->result = 0;
957 $jsonResponse->msg = 'Error count archive';
958 return;
959 }
960
961 $jsonResponse->data->nbArchives = $nbArchives;
962
963 $jsonResponse->result = 1;
964}
965
966
972function quickMemoInterfacePopulateMemoFromQueryObj($obj)
973{
974 global $db, $langs;
975 $obj->date_creation = $db->jdate($obj->date_creation);
976 $obj->tms = $db->jdate($obj->tms);
977
978 $memo = Memo::getJsMemoDefault();
979 $memo->id = $obj->rowid;
980 $memo->color = $obj->color;
981 $memo->note = $obj->quick_note;
982 // Use user-specific position if available, otherwise fallback to default
983 $memo->pos_x = $obj->user_pos_x !== null ? (int) $obj->user_pos_x : (int) $obj->pos_x;
984 $memo->pos_y = $obj->user_pos_y !== null ? (int) $obj->user_pos_y : (int) $obj->pos_y;
985 $memo->pos_w = $obj->user_pos_w !== null ? (int) $obj->user_pos_w : (int) $obj->pos_w;
986 $memo->pos_h = $obj->user_pos_h !== null ? (int) $obj->user_pos_h : (int) $obj->pos_h;
987 $memo->pos_z = $obj->user_pos_z !== null ? (int) $obj->user_pos_z : (int) $obj->pos_z;
988
989 $memo->shared_on_element = $obj->shared_on_element;
990 $memo->private = (int) $obj->private;
991 $memo->date_creation = dol_print_date($obj->date_creation, '%d/%m/%Y %H:%M', 'tzuserrel');
992 $memo->date_change = '';
993 if (!empty($obj->tms) && ((int) $obj->date_creation !== (int) $obj->tms || (int) $obj->fk_user_modif > 0)) {
994 $memo->date_change = dol_print_date($obj->tms, '%d/%m/%Y %H:%M', 'tzuserrel');
995 }
996
997 $memo->fk_user_creat = $obj->fk_user_creat;
998 $memo->user_name = '';
999 if ((int) $obj->fk_user_creat > 0) {
1000 $userCreate = new User($db);
1001 if ($userCreate->fetch((int) $obj->fk_user_creat) > 0) {
1002 $memo->user_name = $userCreate->getFullName($langs);
1003 }
1004 }
1005
1006 $memo->fk_user_modif = $obj->fk_user_modif;
1007 $memo->user_change_name = '';
1008 if ((int) $obj->fk_user_modif > 0) {
1009 $userMod = new User($db);
1010 if ($userMod->fetch((int) $obj->fk_user_modif) > 0) {
1011 $memo->user_change_name = $userMod->getFullName($langs);
1012 }
1013 }
1014
1015 return $memo;
1016}
1017
1023function quickMemoInterfacePopulateMemoTplFromQueryObj($obj)
1024{
1025 global $db, $langs, $user;
1026 $obj->date_creation = $db->jdate($obj->date_creation);
1027 $obj->tms = $db->jdate($obj->tms);
1028
1029
1030 $memo = new stdClass();
1031 $memo->name = $obj->name_tpl;
1032 $memo->id = $obj->rowid;
1033 $memo->color = $obj->color;
1034 $memo->note = $obj->quick_note;
1035 $memo->pos_x = $obj->user_pos_x !== null ? (int) $obj->user_pos_x : (int) $obj->pos_x;
1036 $memo->pos_y = $obj->user_pos_y !== null ? (int) $obj->user_pos_y : (int) $obj->pos_y;
1037 $memo->pos_w = $obj->user_pos_w !== null ? (int) $obj->user_pos_w : (int) $obj->pos_w;
1038 $memo->pos_h = $obj->user_pos_h !== null ? (int) $obj->user_pos_h : (int) $obj->pos_h;
1039 $memo->pos_z = $obj->user_pos_z !== null ? (int) $obj->user_pos_z : (int) $obj->pos_z;
1040 $memo->rank_tpl = (int) $obj->rank_tpl;
1041
1042 $memo->shared_on_element = $obj->shared_on_element;
1043 $memo->private = (int) $obj->private;
1044 $memo->date_creation = dol_print_date($obj->date_creation, '%d/%m/%Y %H:%M', 'tzuserrel');
1045 $memo->fk_user_creat = $user->id;
1046 $memo->user_name = $user->getFullName($langs);
1047 $memo->date_change = '';
1048 $memo->user_change_name = '';
1049
1050 return $memo;
1051}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
Class JsonResponse used for ajax responses in Dolibarr.
Class for Memo.
static checkColor($color)
Vérifie si une couleur est un code hex valide.
static getJsMemoDefault()
Get JS memo default.
static getColorPreset()
Get color preset.
Class to manage Dolibarr users.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
dol_now($mode='gmt')
Return date for now.
GETPOSTINT($paramname, $method=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
isModEnabled($module)
Is Dolibarr module enabled.
$context
@method int call_trigger(string $triggerName, ?User $user)
Definition logout.php:42
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.