1<?php
2/* Copyright (C) 2003-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2013 Laurent Destailleur  <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2012 Regis Houssin        <regis.houssin@inodbox.com>
5 * Copyright (C) 2015       Jean-François Ferry		<jfefe@aternatik.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21/**
22 *   \file       htdocs/admin/boxes.php
23 *   \brief      Page to setup boxes
24 */
25
26require '../main.inc.php';
27include_once DOL_DOCUMENT_ROOT.'/core/boxes/modules_boxes.php';
28require_once DOL_DOCUMENT_ROOT.'/core/class/infobox.class.php';
29include_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php';
30
31// Load translation files required by the page
32$langs->loadLangs(array('admin', 'boxes', 'accountancy'));
33
34if (!$user->admin) {
35	accessforbidden();
36}
37
38$rowid = GETPOST('rowid', 'int');
39$action = GETPOST('action', 'aZ09');
40
41
42// Define possible position of boxes
43$pos_name = InfoBox::getListOfPagesForBoxes();
44$boxes = array();
45
46
47/*
48 * Actions
49 */
50
51if ($action == 'addconst') {
52	dolibarr_set_const($db, "MAIN_BOXES_MAXLINES", $_POST["MAIN_BOXES_MAXLINES"], '', 0, '', $conf->entity);
53	dolibarr_set_const($db, "MAIN_ACTIVATE_FILECACHE", $_POST["MAIN_ACTIVATE_FILECACHE"], 'chaine', 0, '', $conf->entity);
54}
55
56if ($action == 'add') {
57	$error = 0;
58	$boxids = GETPOST('boxid', 'array');
59
60	$db->begin();
61	if (is_array($boxids)) {
62		foreach ($boxids as $boxid) {
63			if (is_numeric($boxid['pos']) && $boxid['pos'] >= 0) {	// 0=Home, 1=...
64				$pos = $boxid['pos'];
65
66				// Initialize distinct fk_user with all already existing values of fk_user (user that use a personalized view of boxes for page "pos")
67				$distinctfkuser = array();
68				if (!$error) {
69					$sql = "SELECT fk_user";
70					$sql .= " FROM ".MAIN_DB_PREFIX."user_param";
71					$sql .= " WHERE param = 'MAIN_BOXES_".$db->escape($pos)."' AND value = '1'";
72					$sql .= " AND entity = ".$conf->entity;
73					dol_syslog("boxes.php search fk_user to activate box for", LOG_DEBUG);
74					$resql = $db->query($sql);
75					if ($resql) {
76						$num = $db->num_rows($resql);
77						$i = 0;
78						while ($i < $num) {
79							$obj = $db->fetch_object($resql);
80							$distinctfkuser[$obj->fk_user] = $obj->fk_user;
81							$i++;
82						}
83					} else {
84						setEventMessages($db->lasterror(), null, 'errors');
85						$error++;
86					}
87				}
88
89				$distinctfkuser['0'] = '0'; // Add entry for fk_user = 0. We must use string as key and val
90
91				foreach ($distinctfkuser as $fk_user) {
92					if (!$error && $fk_user != '') {
93						$arrayofexistingboxid = array();
94						$nbboxonleft = $nbboxonright = 0;
95						$sql = "SELECT box_id, box_order FROM ".MAIN_DB_PREFIX."boxes";
96						$sql .= " WHERE position = ".$pos." AND fk_user = ".$fk_user." AND entity = ".$conf->entity;
97						dol_syslog("boxes.php activate box", LOG_DEBUG);
98						$resql = $db->query($sql);
99						if ($resql) {
100							while ($obj = $db->fetch_object($resql)) {
101								$boxorder = $obj->box_order;
102								if (preg_match('/A/', $boxorder)) {
103									$nbboxonleft++;
104								}
105								if (preg_match('/B/', $boxorder)) {
106									$nbboxonright++;
107								}
108								$arrayofexistingboxid[$obj->box_id] = 1;
109							}
110						} else {
111							dol_print_error($db);
112						}
113
114						if (empty($arrayofexistingboxid[$boxid['value']])) {
115							$sql = "INSERT INTO ".MAIN_DB_PREFIX."boxes (";
116							$sql .= "box_id, position, box_order, fk_user, entity";
117							$sql .= ") values (";
118							$sql .= $boxid['value'].", ".$pos.", '".(($nbboxonleft > $nbboxonright) ? 'B01' : 'A01')."', ".$fk_user.", ".$conf->entity;
119							$sql .= ")";
120
121							dol_syslog("boxes.php activate box", LOG_DEBUG);
122							$resql = $db->query($sql);
123							if (!$resql) {
124								setEventMessages($db->lasterror(), null, 'errors');
125								$error++;
126							}
127						} else {
128							dol_syslog("boxes.php activate box - already exists in database", LOG_DEBUG);
129						}
130					}
131				}
132			}
133		}
134	}
135	if (!$error) {
136		$db->commit();
137		$action = '';
138	} else {
139		$db->rollback();
140	}
141}
142
143if ($action == 'delete') {
144	$sql = "SELECT box_id FROM ".MAIN_DB_PREFIX."boxes";
145	$sql .= " WHERE rowid=".((int) $rowid);
146
147	$resql = $db->query($sql);
148	$obj = $db->fetch_object($resql);
149	if (!empty($obj->box_id)) {
150		$db->begin();
151
152		// Remove all personalized setup when a box is activated or disabled (why removing all ? We removed only removed boxes)
153		//	$sql = "DELETE FROM ".MAIN_DB_PREFIX."user_param";
154		//	$sql.= " WHERE param LIKE 'MAIN_BOXES_%'";
155		//	$resql = $db->query($sql);
156
157		$sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes";
158		$sql .= " WHERE entity = ".$conf->entity;
159		$sql .= " AND box_id=".$obj->box_id;
160
161		$resql = $db->query($sql);
162
163		$db->commit();
164	}
165}
166
167if ($action == 'switch') {
168	// We switch values of field box_order for the 2 lines of table boxes
169	$db->begin();
170
171	$objfrom = new ModeleBoxes($db);
172	$objfrom->fetch(GETPOST("switchfrom", 'int'));
173
174	$objto = new ModeleBoxes($db);
175	$objto->fetch(GETPOST('switchto', 'int'));
176
177	$resultupdatefrom = 0;
178	$resultupdateto = 0;
179	if (is_object($objfrom) && is_object($objto)) {
180		$newfirst = $objto->box_order;
181		$newsecond = $objfrom->box_order;
182		if ($newfirst == $newsecond) {
183			 $newsecondchar = preg_replace('/[0-9]+/', '', $newsecond);
184			 $newsecondnum = preg_replace('/[a-zA-Z]+/', '', $newsecond);
185			 $newsecond = sprintf("%s%02d", $newsecondchar ? $newsecondchar : 'A', $newsecondnum + 1);
186		}
187		$sql = "UPDATE ".MAIN_DB_PREFIX."boxes SET box_order='".$db->escape($newfirst)."' WHERE rowid=".((int) $objfrom->rowid);
188		dol_syslog($sql);
189		$resultupdatefrom = $db->query($sql);
190		if (!$resultupdatefrom) {
191			dol_print_error($db);
192		}
193
194		$sql = "UPDATE ".MAIN_DB_PREFIX."boxes SET box_order='".$db->escape($newsecond)."' WHERE rowid=".((int) $objto->rowid);
195		dol_syslog($sql);
196		$resultupdateto = $db->query($sql);
197		if (!$resultupdateto) {
198			dol_print_error($db);
199		}
200	}
201
202	if ($resultupdatefrom && $resultupdateto) {
203		$db->commit();
204	} else {
205		$db->rollback();
206	}
207}
208
209
210/*
211 * View
212 */
213
214$form = new Form($db);
215
216llxHeader('', $langs->trans("Boxes"));
217
218print load_fiche_titre($langs->trans("Boxes"), '', 'title_setup');
219
220print '<span class="opacitymedium">'.$langs->trans("BoxesDesc")." ".$langs->trans("OnlyActiveElementsAreShown")."</span><br>\n";
221
222/*
223 * Search for the default active boxes for each possible position
224 * We store the active boxes by default in $boxes[position][id_boite]=1
225 */
226
227$actives = array();
228
229$sql = "SELECT b.rowid, b.box_id, b.position, b.box_order,";
230$sql .= " bd.rowid as boxid";
231$sql .= " FROM ".MAIN_DB_PREFIX."boxes as b, ".MAIN_DB_PREFIX."boxes_def as bd";
232$sql .= " WHERE b.box_id = bd.rowid";
233$sql .= " AND b.entity IN (0,".$conf->entity.")";
234$sql .= " AND b.fk_user=0";
235$sql .= " ORDER by b.position, b.box_order";
236
237dol_syslog("Search available boxes", LOG_DEBUG);
238$resql = $db->query($sql);
239if ($resql) {
240	$num = $db->num_rows($resql);
241
242	// Check record to know if we must recalculate sort order
243	$i = 0;
244	$decalage = 0;
245	while ($i < $num) {
246		$obj = $db->fetch_object($resql);
247		$boxes[$obj->position][$obj->box_id] = 1;
248		$i++;
249
250		array_push($actives, $obj->box_id);
251
252		if ($obj->box_order == '' || $obj->box_order == '0' || $decalage) {
253			$decalage++;
254		}
255		// We renumber the order of the boxes if one of them is in ''
256		// This occurs just after an insert.
257		if ($decalage) {
258			$sql = "UPDATE ".MAIN_DB_PREFIX."boxes SET box_order='".$db->escape($decalage)."' WHERE rowid=".$obj->rowid;
259			$db->query($sql);
260		}
261	}
262
263	if ($decalage) {
264		// If we have renumbered, we correct the field box_order
265		// This occurs just after an insert.
266		$sql = "SELECT box_order";
267		$sql .= " FROM ".MAIN_DB_PREFIX."boxes";
268		$sql .= " WHERE entity = ".$conf->entity;
269		$sql .= " AND LENGTH(box_order) <= 2";
270
271		dol_syslog("Execute requests to renumber box order", LOG_DEBUG);
272		$result = $db->query($sql);
273		if ($result) {
274			while ($record = $db->fetch_array($result)) {
275				if (dol_strlen($record['box_order']) == 1) {
276					if (preg_match("/[13579]{1}/", substr($record['box_order'], -1))) {
277						$box_order = "A0".$record['box_order'];
278						$sql = "UPDATE ".MAIN_DB_PREFIX."boxes SET box_order = '".$db->escape($box_order)."' WHERE entity = ".$conf->entity." AND box_order = '".$db->escape($record['box_order'])."'";
279						$resql = $db->query($sql);
280					} elseif (preg_match("/[02468]{1}/", substr($record['box_order'], -1))) {
281						$box_order = "B0".$record['box_order'];
282						$sql = "UPDATE ".MAIN_DB_PREFIX."boxes SET box_order = '".$db->escape($box_order)."' WHERE entity = ".$conf->entity." AND box_order = '".$db->escape($record['box_order'])."'";
283						$resql = $db->query($sql);
284					}
285				} elseif (dol_strlen($record['box_order']) == 2) {
286					if (preg_match("/[13579]{1}/", substr($record['box_order'], -1))) {
287						$box_order = "A".$record['box_order'];
288						$sql = "UPDATE ".MAIN_DB_PREFIX."boxes SET box_order = '".$db->escape($box_order)."' WHERE entity = ".$conf->entity." AND box_order = '".$db->escape($record['box_order'])."'";
289						$resql = $db->query($sql);
290					} elseif (preg_match("/[02468]{1}/", substr($record['box_order'], -1))) {
291						$box_order = "B".$record['box_order'];
292						$sql = "UPDATE ".MAIN_DB_PREFIX."boxes SET box_order = '".$db->escape($box_order)."' WHERE entity = ".$conf->entity." AND box_order = '".$db->escape($record['box_order'])."'";
293						$resql = $db->query($sql);
294					}
295				}
296			}
297		}
298	}
299	$db->free($resql);
300}
301
302// Available boxes to activate
303$boxtoadd = InfoBox::listBoxes($db, 'available', -1, null, $actives);
304// Activated boxes
305$boxactivated = InfoBox::listBoxes($db, 'activated', -1, null);
306
307print "<br>\n";
308print "\n\n".'<!-- Boxes Available -->'."\n";
309print load_fiche_titre($langs->trans("BoxesAvailable"), '', '');
310
311print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">'."\n";
312print '<input type="hidden" name="token" value="'.newToken().'">'."\n";
313print '<input type="hidden" name="action" value="add">'."\n";
314
315print '<div class="div-table-responsive-no-min">';
316print '<table class="tagtable liste centpercent">'."\n";
317
318print '<tr class="liste_titre">';
319print '<td width="300">'.$langs->trans("Box").'</td>';
320print '<td>'.$langs->trans("Note").'/'.$langs->trans("Parameters").'</td>';
321print '<td>'.$langs->trans("SourceFile").'</td>';
322print '<td width="160" class="center">'.$langs->trans("ActivateOn").'</td>';
323print "</tr>\n";
324
325foreach ($boxtoadd as $box) {
326	if (preg_match('/^([^@]+)@([^@]+)$/i', $box->boximg)) {
327		$logo = $box->boximg;
328	} else {
329		$logo = preg_replace("/^object_/i", "", $box->boximg);
330	}
331
332	print "\n".'<!-- Box '.$box->boxcode.' -->'."\n";
333	print '<tr class="oddeven">'."\n";
334	print '<td>'.img_object("", $logo, 'height="14px"').' '.$langs->transnoentitiesnoconv($box->boxlabel);
335	if (!empty($box->class) && preg_match('/graph_/', $box->class)) {
336		print ' ('.$langs->trans("Graph").')';
337	}
338	print '</td>'."\n";
339	print '<td>';
340	if ($box->note == '(WarningUsingThisBoxSlowDown)') {
341		$langs->load("errors");
342		print $langs->trans("WarningUsingThisBoxSlowDown");
343	} else {
344		print ($box->note ? $box->note : '&nbsp;');
345	}
346	print '</td>'."\n";
347	print '<td>'.$box->sourcefile.'</td>'."\n";
348
349	// For each possible position, an activation link is displayed if the box is not already active for that position
350	print '<td class="center">';
351	print $form->selectarray("boxid[".$box->box_id."][pos]", $pos_name, -1, 1, 0, 0, '', 1)."\n";
352	print '<input type="hidden" name="boxid['.$box->box_id.'][value]" value="'.$box->box_id.'">'."\n";
353	print '</td>';
354
355	print '</tr>'."\n";
356}
357if (!count($boxtoadd) && count($boxactivated)) {
358	print '<tr><td class="opacitymedium" colspan="4">'.$langs->trans("AllWidgetsWereEnabled").'</td></tr>';
359}
360print '</table>'."\n";
361print '</div>';
362
363print '<div class="right">';
364print '<input type="submit" class="button"'.(count($boxtoadd) ? '' : ' disabled').' value="'.$langs->trans("Activate").'">';
365print '</div>'."\n";
366print '</form>';
367print "\n".'<!-- End Boxes Available -->'."\n";
368
369
370//var_dump($boxactivated);
371print "<br>\n\n";
372print load_fiche_titre($langs->trans("BoxesActivated"), '', '');
373
374print '<div class="div-table-responsive-no-min">';
375print '<table class="tagtable liste">'."\n";
376
377print '<tr class="liste_titre">';
378print '<td width="300">'.$langs->trans("Box").'</td>';
379print '<td>'.$langs->trans("Note").'/'.$langs->trans("Parameters").'</td>';
380print '<td class="center" width="160">'.$langs->trans("ActiveOn").'</td>';
381print '<td class="center" width="60" colspan="2">'.$langs->trans("PositionByDefault").'</td>';
382print '<td class="center" width="80">'.$langs->trans("Disable").'</td>';
383print '</tr>'."\n";
384
385$box_order = 1;
386$foundrupture = 1;
387foreach ($boxactivated as $key => $box) {
388	if (preg_match('/^([^@]+)@([^@]+)$/i', $box->boximg)) {
389		$logo = $box->boximg;
390	} else {
391		$logo = preg_replace("/^object_/i", "", $box->boximg);
392	}
393
394	print "\n".'<!-- Box '.$box->boxcode.' -->'."\n";
395	print '<tr class="oddeven">';
396	print '<td>'.img_object("", $logo, 'height="14px"').' '.$langs->transnoentitiesnoconv($box->boxlabel);
397	if (!empty($box->class) && preg_match('/graph_/', $box->class)) {
398		print ' ('.$langs->trans("Graph").')';
399	}
400	print '</td>';
401	print '<td>';
402	if ($box->note == '(WarningUsingThisBoxSlowDown)') {
403		$langs->load("errors");
404		print img_warning('', 0).' '.$langs->trans("WarningUsingThisBoxSlowDown");
405	} else {
406		print ($box->note ? $box->note : '&nbsp;');
407	}
408	print '</td>';
409	print '<td class="center">'.(empty($pos_name[$box->position]) ? '' : $langs->trans($pos_name[$box->position])).'</td>';
410	$hasnext = ($key < (count($boxactivated) - 1));
411	$hasprevious = ($key != 0);
412	print '<td class="center">'.($key + 1).'</td>';
413	print '<td class="center">';
414	print ($hasnext ? '<a href="boxes.php?action=switch&amp;switchfrom='.$box->rowid.'&amp;switchto='.$boxactivated[$key + 1]->rowid.'">'.img_down().'</a>&nbsp;' : '');
415	print ($hasprevious ? '<a href="boxes.php?action=switch&amp;switchfrom='.$box->rowid.'&amp;switchto='.$boxactivated[$key - 1]->rowid.'">'.img_up().'</a>' : '');
416	print '</td>';
417	print '<td class="center">';
418	print '<a href="boxes.php?rowid='.$box->rowid.'&action=delete&token='.newToken().'">'.img_delete().'</a>';
419	print '</td>';
420
421	print '</tr>'."\n";
422}
423
424print '</table>';
425print '</div>';
426print '<br>';
427
428
429// Other parameters
430
431print "\n\n".'<!-- Other Const -->'."\n";
432print load_fiche_titre($langs->trans("Other"), '', '');
433print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
434print '<input type="hidden" name="token" value="'.newToken().'">';
435print '<input type="hidden" name="action" value="addconst">';
436print '<div class="div-table-responsive-no-min">';
437print '<table class="noborder centpercent">';
438
439print '<tr class="liste_titre">';
440print '<td class="liste_titre">'.$langs->trans("Parameter").'</td>';
441print '<td class="liste_titre">'.$langs->trans("Value").'</td>';
442print '</tr>';
443
444print '<tr class="oddeven">';
445print '<td>';
446print $langs->trans("MaxNbOfLinesForBoxes");
447print '</td>'."\n";
448print '<td>';
449print '<input type="text" class="flat" size="6" name="MAIN_BOXES_MAXLINES" value="'.$conf->global->MAIN_BOXES_MAXLINES.'">';
450print '</td>';
451print '</tr>';
452
453// Activate FileCache - Developement
454if ($conf->global->MAIN_FEATURES_LEVEL == 2 || !empty($conf->global->MAIN_ACTIVATE_FILECACHE)) {
455	print '<tr class="oddeven"><td width="35%">'.$langs->trans("EnableFileCache").'</td><td>';
456	print $form->selectyesno('MAIN_ACTIVATE_FILECACHE', $conf->global->MAIN_ACTIVATE_FILECACHE, 1);
457	print '</td>';
458	print '</tr>';
459}
460
461print '</table>';
462print '</div>';
463
464print '<br>';
465print '<div class="center"><input type="submit" class="button button-save" value="'.$langs->trans("Save").'" name="Button"></div>';
466print '<br>';
467
468print '</form>';
469print "\n".'<!-- End Other Const -->'."\n";
470
471// End of page
472llxFooter();
473$db->close();
474