Bladeren bron

File Perm Sync add custom tables sync

Piotr Labudda 11 jaren geleden
bovenliggende
commit
93a1572ae0
4 gewijzigde bestanden met toevoegingen van 1211 en 131 verwijderingen
  1. 1 1
      SE/VERSION
  2. 1019 103
      SE/bash_sync_perms.php
  3. 39 25
      SE/se-lib/FileUploader.php
  4. 152 2
      SE/se-lib/TableAjax.php

+ 1 - 1
SE/VERSION

@@ -1 +1 @@
-3.9.8-10
+3.9.9

+ 1019 - 103
SE/bash_sync_perms.php

@@ -1,9 +1,4 @@
 <?php
-//author Arkadiusz Binder 2013-07-30
-//todo do przepisania na PHP i dodania opcji generowania Symlinkow 
-//todo @2013-08-04 do skonczenia funkcja
-//if(file_exists(".config.php")) require_once(".config.php");
-
 /**
  * by plabudda 2013-10-09:
  * 
@@ -30,10 +25,10 @@
  * 		 /SE/se-dev-pl/bash_sync_perms.php?task=task&PROJ_ID={projID}  -- force update project
  * 
  * 
- * 4. Sync users: `ADMIN_USERS`.`A_STATUS`
+ * 4. Sync users: `ADMIN_USERS`.`A_STATUS` - OFF - manual sync from users table (groups from CRM_LISTA_ZASOBOW)
  *   'WAITING' - Kandydaci
  *   'NORMAL' - Aktywni pracownicy
- *   'DELETED' - Wy‘?Ž?czone konta
+ *   'DELETED' - Wyłączone konta
  *   'OFF_SOFT' - ?
  *   'OFF_HARD' - ?
  *
@@ -54,12 +49,18 @@
  * DONE: koresp format: PISMA/ID/...
  * DONE: projekty -> koresp hardlink PROJEKTY/ID..../_PISMA/{HL:pismo.pdf}
  * TODO: PROJEKTY/ID..../_PISMA/ permy tylko read/listing
- * TODO: hardlink druki: mkdir DRUKI/ID.{DESC}/_PROJEKT/{proj_folder}/{HL:pliki z proj bez podkatalogƈw}
+ * TODO: hardlink druki: mkdir DRUKI/ID.{DESC}/_PROJEKT/{proj_folder}/{HL:pliki z proj bez podkatalogów}
  * TODO: DRUKI/ID.{DESC}/_PROJEKT/{proj_folder} permy tylko read/listing
  * -- TODO: DRUKI/ID.{DESC}/ - permy z bazy danych A_ADM_COMPANY, A_CLASSIFIED
  * 
  * 
- * DONE: Trigger po update/insert Koresp po aktualizacji permƈw plikƈw projektu
+ * DONE: Trigger po update/insert Koresp po aktualizacji permów plików projektu
+ * 
+ * 5. Sync custom tables
+ *     TEST 2014-10-27: # php /Users/plabudda/rsync-dev/SE/bash_sync_perms.php biuro.biall-net.pl SyncPermsCustomTables
+ * 5.1 Table list in CRM_CONFIG(key=_SYNC_TABLE_FILE_PERMS__TablesList)
+ *     table must be defined in .cnf--folders-{domain}.ini.php as section [{tblName}_COLUMN]
+ *     table must have fields: ID, L_APPOITMENT_USER, A_ADM_COMPANY, A_CLASSIFIED @see generateTasksNewRecords
  */
 
 ini_set('max_execution_time', 300);
@@ -113,11 +114,8 @@ else if (empty($_SERVER["argv"]) && V::get('task', '', $_GET) == 'newFiles') {
 }
 else if (empty($_SERVER["argv"]) && V::get('task', '', $_GET) == 'testParse') {
 	$cmd = " ls -Rlea . ";
-	//exec("cd \"/Library/Server/Web/Data/Sites/Default/PLIKI/PROJEKTY/1970.Rekrutacja_z_dnia_2013-02-22_na_stanowisko_Specjalista_ds_pozyskiwania_klientow/6/\"; {$cmd} ", $filesWithPerms);
-	//exec("cd \"/Library/Server/Web/Data/Sites/Default/PLIKI/PROJEKTY/1983.Rekrutacja_z_dnia_2013-03-12_na_stanowisko_Przedstawiciel_Handlowy_(D2D)/24/\"; {$cmd} ", $filesWithPerms);
-	//exec("cd '/Library/Server/Web/Data/Sites/Default/PLIKI/PROJEKTY/816.2012-01-01.INNE.Siec_Szerokopasmowa_w_ramach_dofinansowania_unii_dla_woj_pomorskiego__Sprint/2013-06-14.Dokumenty_do_wysylki_po_wysylce_usunac!_AB_co_to_za_katlog_TODO/Zalacznik 1 Studium wykonalnosci/'; {$cmd} ", $filesWithPerms);
 	exec("cd '/Library/Server/Web/Data/Sites/Default/PLIKI/PROJEKTY/1657.Rekrutacja_z_dnia_2012-06_25_na_stanowisko_Przedstawiciel_Handlowy/1/'; {$cmd} ", $filesWithPerms);
-	//$line = "-rwxrwx---+ 1 _www  workgroup  212367 Feb 25  2013 Cv  Malwina Szczepaniec.docx";
+	//$line = "-rwxrwx---+ 1 _www  workgroup  212367 Feb 25  2013 {file_name}";
 echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">$filesWithPerms (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($filesWithPerms);echo'</pre>';
 	$filesWithPermsTree = array();
 
@@ -205,22 +203,15 @@ if (!empty($_SERVER["argv"][0]) && !empty($_SERVER["argv"][1])) {
 	$arg2 = (!empty($_SERVER["argv"][2]))? $_SERVER["argv"][2] : null;
 	$arg3 = (!empty($_SERVER["argv"][3]))? $_SERVER["argv"][3] : null;
 
-	//bash_perms_make_se($_SERVER["argv"][0], $_SERVER["argv"][1], $arg2, $arg3);
 	SyncPerms::run($_SERVER["argv"][0], $_SERVER["argv"][1], $arg2, $arg3);
 }
 
 
-//require(APP_PATH_ROOT."/superedit-SEF.php");
-
-
 class SyncPerms {
 
 	public static function installTable() {
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
-		//  @due to bug in medical trigger install we now install tables using function SQIX_STRUCTURE_SYNC @2014-01-22 
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 		$sql = "
 			CREATE TABLE IF NOT EXISTS `_SYNC_FILE_PERMS` (
 				`ID` int(11) NOT NULL AUTO_INCREMENT,
@@ -268,9 +259,7 @@ class SyncPerms {
 			END
 		";
 		$db->query($sql);
-		
-		
-		
+
 		if (V::get('DBG', '', $_GET, 'int') > 0) {
 			if ($db->has_errors()) {
 				echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">DB errors (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($db->get_errors());echo'</pre>';
@@ -351,46 +340,164 @@ class SyncPerms {
 		else if ($arg2 == 'usersAll') {
 			self::usersAllAction();
 		}
+		else if ($arg2 == 'SyncPermsCustomTables') {
+			$DBG_TIME = true;
+			$dbgTime = new stdClass();
+			$dbgTime->startTime = microtime(true);
+			$dbgTime->lastTime = $dbgTime->startTime;
+
+			$customSync = new SyncPermsCustomTables();
+			// TODO: $customSync->run();
+			$customSync->fetchConfig();
+			if ($DBG_TIME) {
+				$dbgTime->curTime = microtime(true);
+				trigger_error("DBG:time after-fetchConfig (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+				$dbgTime->lastTime = $dbgTime->curTime;
+			}
+			$customSync->installTable();
+			if ($DBG_TIME) {
+				$dbgTime->curTime = microtime(true);
+				trigger_error("DBG:time after-installTable (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+				$dbgTime->lastTime = $dbgTime->curTime;
+			}
+
+			$rowId = (int)$arg3;
+			if ($rowId > 0) {
+				$customSync->executeTask('DEALS_TABLE', $rowId);
+			}
+			else {
+				$customSync->generateTasksNewRecords();
+				if ($DBG_TIME) {
+					$dbgTime->curTime = microtime(true);
+					trigger_error("DBG:time after-generateTasksNewRecords (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+					$dbgTime->lastTime = $dbgTime->curTime;
+				}
+				$customSync->generateTasksUpdated();
+				if ($DBG_TIME) {
+					$dbgTime->curTime = microtime(true);
+					trigger_error("DBG:time after-generateTasksUpdated (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+					$dbgTime->lastTime = $dbgTime->curTime;
+				}
+				$customSync->newFilesAction();
+				if ($DBG_TIME) {
+					$dbgTime->curTime = microtime(true);
+					trigger_error("DBG:time after-newFilesAction (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+					$dbgTime->lastTime = $dbgTime->curTime;
+				}
+				$limit = 1000;
+				for ($i = 0; $i < $limit; $i++) {
+					$loopTasksFired = 0;
+					foreach ($customSync->_tbls as $tblName => $tblConf) {
+						$task = $customSync->nextTaskAction($tblName);
+						if ($DBG_TIME) {
+							$dbgTime->curTime = microtime(true);
+							trigger_error("DBG:time after-nextTaskAction (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+							$dbgTime->lastTime = $dbgTime->curTime;
+						}
+						if (!$task) {
+							// TODO: rm $tblName from config to prevent searching for task in next loops
+							unset($customSync->_tbls[$tblName]);
+							continue;
+						}
+						$loopTasksFired++;
+					}
+					if (!$loopTasksFired) {
+						if ($DBG_TIME) {
+							$dbgTime->curTime = microtime(true);
+							trigger_error("DBG:time after-nextTaskAction (loop:{$i}) (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+							$dbgTime->lastTime = $dbgTime->curTime;
+						}
+						break;
+					}
+					$i += $loopTasksFired;
+				}
+			}
+
+			$dbgTime->endTime = microtime(true);
+			trigger_error("Notice: sync end OK (time:" . number_format($dbgTime->endTime - $dbgTime->startTime, 6) . "s) !", E_USER_NOTICE);
+		}
 		else {
+			$DBG_TIME = false;
 			$DBG_MEMORY = false;
-			$time = new stdClass();
-			$time->start = time();
+			$dbgTime = new stdClass();
+			$dbgTime->start = time();
+			$dbgTime->startTime = microtime(true);
+			$dbgTime->lastTime = $dbgTime->startTime;
 
 			self::installTable();
+
+			if ($DBG_TIME) {
+				$dbgTime->curTime = microtime(true);
+				trigger_error("DBG:time after-installTable (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+				$dbgTime->lastTime = $dbgTime->curTime;
+			}
+
 			self::generateTasksNewRecords();
+
 			if($DBG_MEMORY)trigger_error("DBG:mem usage after-generateTasksNewRecords " . memory_get_usage(true) . ".", E_USER_NOTICE);
+			if ($DBG_TIME) {
+				$dbgTime->curTime = microtime(true);
+				trigger_error("DBG:time after-generateTasksNewRecords (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+				$dbgTime->lastTime = $dbgTime->curTime;
+			}
 
 			self::generateTasksUpdated();
+
 			if($DBG_MEMORY)trigger_error("DBG:mem usage after-generateTasksUpdated " . memory_get_usage(true) . ".", E_USER_NOTICE);
+			if ($DBG_TIME) {
+				$dbgTime->curTime = microtime(true);
+				trigger_error("DBG:time after-generateTasksUpdated (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+				$dbgTime->lastTime = $dbgTime->curTime;
+			}
 
-			$time->cur = time();
-			if ($time->cur - $time->start > 60 * 5) {
-				trigger_error("Error: time end after-init " . ($time->cur - $time->start) . " !", E_USER_NOTICE);
+			$dbgTime->cur = time();
+			if ($dbgTime->cur - $dbgTime->start > 60 * 5) {
+				trigger_error("Error: time end after-init " . ($dbgTime->cur - $dbgTime->start) . " !", E_USER_NOTICE);
 				return;
 			}
 
 			self::newFilesAction();
+
 			if($DBG_MEMORY)trigger_error("DBG:mem usage after-newFilesAction " . memory_get_usage(true) . ".", E_USER_NOTICE);
+			if ($DBG_TIME) {
+				$dbgTime->curTime = microtime(true);
+				trigger_error("DBG:time after-newFilesAction (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+				$dbgTime->lastTime = $dbgTime->curTime;
+			}
 
 			$limit = 100;
 			for ($i = 0; $i < $limit; $i++) {
-				$time->cur = time();
-				if ($time->cur - $time->start > 60 * 5) {
-					trigger_error("Error: time end after-nextTaskAction(loop:{$i}) " . ($time->cur - $time->start) . " !", E_USER_NOTICE);
+				$dbgTime->cur = time();
+				if ($dbgTime->cur - $dbgTime->start > 60 * 5) {
+					trigger_error("Error: time end after-nextTaskAction(loop:{$i}) " . ($dbgTime->cur - $dbgTime->start) . " !", E_USER_NOTICE);
 					return;
 				}
 
 				$task = self::nextTaskAction();
 				if($DBG_MEMORY)trigger_error("DBG:mem usage after-nextTaskAction (loop:{$i}) " . memory_get_usage(true) . ".", E_USER_NOTICE);
+				if ($DBG_TIME) {
+					$dbgTime->curTime = microtime(true);
+					trigger_error("DBG:time after-nextTaskAction (loop:{$i}) (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+					$dbgTime->lastTime = $dbgTime->curTime;
+				}
+
 				if (!$task) {
-					$time->cur = time();
-					trigger_error("Notice: sync end OK no-task " . ($time->cur - $time->start) . "", E_USER_WARNING);
-					return;
+					$dbgTime->cur = time();
+					break;
 				}
 			}
 
-			$time->cur = time();
-			trigger_error("Notice: sync end OK " . ($time->cur - $time->start) . " !", E_USER_NOTICE);
+			$customSync = new SyncPermsCustomTables();
+			$customSync->run();
+
+			$dbgTime->cur = time();
+			$dbgTime->endTime = microtime(true);
+			trigger_error("Notice: sync end OK (time:" . number_format($dbgTime->endTime - $dbgTime->startTime, 6) . "s) !", E_USER_NOTICE);
+			if ($DBG_TIME) {
+				$dbgTime->curTime = microtime(true);
+				trigger_error("DBG:time sync end OK (time:" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s)", E_USER_NOTICE);
+				$dbgTime->lastTime = $dbgTime->curTime;
+			}
 		}
 	}
 
@@ -424,9 +531,7 @@ class SyncPerms {
 
 	public static function generateTasksUpdated() {
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 		$sqlTest = "select p.ID, p.`L_APPOITMENT_USER`, p.`A_ADM_COMPANY`, p.`A_CLASSIFIED`, s. * 
 			from `_SYNC_FILE_PERMS` as s, `IN7_MK_BAZA_DYSTRYBUCJI` as p, `IN7_MK_BAZA_DYSTRYBUCJI` as pp
 			where
@@ -460,9 +565,7 @@ class SyncPerms {
 
 	public static function generateTasksNewRecords() {
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 		$sql = "insert ignore into `_SYNC_FILE_PERMS` (`ID_PROJECT`, `L_APPOITMENT_USER`, `A_ADM_COMPANY`, `A_CLASSIFIED`, `PARENT_L_APPOITMENT_USER`)
 			values (-1, '', '', '', '');
 		";
@@ -478,14 +581,12 @@ class SyncPerms {
 	}
 
 	/**
-	 * Znajd‘­ najstarszy aktualizowany projekt.
+	 * Znajdź najstarszy aktualizowany projekt.
 	 */
 	public static function getTask() {
 		$task = null;
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 
 		$sqlWhereProjID = " s.`A_SYNCHRONIZED`=0 ";
 		if (($projID = V::get('PROJ_ID', '', $_GET, 'int')) > 0){
@@ -519,9 +620,7 @@ class SyncPerms {
 	public static function getTaskNewerUsers() {
 		$task = null;
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 		$sql = "select s.*
 			from `_SYNC_FILE_PERMS` as s
 			where s.`ID_PROJECT`=-2
@@ -544,9 +643,7 @@ class SyncPerms {
 	public static function getTaskNewFiles() {
 		$task = null;
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 		$sql = "select s.*
 			from `_SYNC_FILE_PERMS` as s
 			where s.`ID_PROJECT`=-1
@@ -569,9 +666,7 @@ class SyncPerms {
 	public static function saveTask($idProject, $taskDone = 1, $result = null) {
 		$task = null;
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 		$sqlResult = '';
 		if ($result) {
 			$resultJson = json_encode($result);
@@ -623,7 +718,7 @@ class SyncPerms {
 			mkdir($mainFolderPath, 0770, true);
 			@chmod($mainFolderPath, 0770);
 			if (!file_exists($mainFolderPath)) {
-				trigger_error("Error: Nie uda‘?o siŽ? utworzyŽ? folderu! ({$mainFolder})", E_USER_NOTICE);
+				trigger_error("Error: Nie udało się utworzyć folderu! ({$mainFolder})", E_USER_NOTICE);
 				return false;
 			}
 			$requirePermsExt = self::getRequiredPermsExtByRecord($project);
@@ -654,14 +749,6 @@ class SyncPerms {
 					$cmdList[] = $vCmd;
 				}
 			}
-
-			if (V::get('TEST_DRUKI', '', $_GET, 'int') > 0) {
-				// $project->CRM_LISTA_ZASOBOW_ID
-				if ($project->CRM_LISTA_ZASOBOW_ID > 0) {
-					
-				}
-				// TODO: $cmdDrukiList = self::fixProjectDruki($project, $mainFolder, $PROJ_mount_point);
-			}
 		}
 		if (!empty($cmdList)) {
 			foreach ($cmdList as $vCmd) {
@@ -755,9 +842,7 @@ class SyncPerms {
 	 */
 	public static function fixLastModifiedFiles($task) {
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 
 		if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">fixLastModifiedFiles (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r("fixLastModifiedFiles");echo'</pre>';}
 
@@ -866,25 +951,9 @@ class SyncPerms {
 		}
 	}
 
-	public static function fixProjectDruki() {
-		if ($project->CRM_LISTA_ZASOBOW_ID <= 0) {
-			return false;
-		}
-
-		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
-
-		
-
-	}
-
 	public static function fixProjectKoresp($project, $folderPismaPath) {
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 
 		$PISMA_mount_point = FoldersConfig::get('IN7_DZIENNIK_KORESP_COLUMN', 'mount_point');
 		$PISMA_mount_point = rtrim($PISMA_mount_point, '/');
@@ -992,7 +1061,8 @@ class SyncPerms {
 			}
 
 			// if folder _PISMA not exists then create
-			$fname = end(explode('/', $vFile->path));
+			$fname = explode('/', $vFile->path);
+			$fname = end($fname);
 			$cmdList []= "if [ ! -f '{$folderPismaPath}/{$fname}' ] ; then ln '{$PISMA_mount_point}/{$vFile->path}' '{$folderPismaPath}'/; fi; ";
 		}
 		return $cmdList;
@@ -1019,7 +1089,7 @@ class SyncPerms {
 	public static function fixProject($r, $mainFolder, $PROJ_mount_point, &$task) {
 		$time = time();
 		if ($r->ID == 1695) {// TODO: biall-net - 8853 pliki w katalog - stary HANDLOWY
-			if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">TODO: pomin - za du‘«o plikƈw ('.$r->ID.'/'.$mainFolder.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($r);echo'</pre>';}
+			if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">TODO: pomin - za dużo plików ('.$r->ID.'/'.$mainFolder.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($r);echo'</pre>';}
 			//return false;
 		}
 
@@ -1253,9 +1323,7 @@ R		list,         search,                              readattr,          readext
 	 */
 	public static function fixLastModifiedByFiles() {// TODO: RMME
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 
 		if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">fixLastModifiedByFiles (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r("fixLastModifiedByFiles");echo'</pre>';}
 
@@ -1328,9 +1396,7 @@ R		list,         search,                              readattr,          readext
 
 	public static function fixLastModifiedByDB($fixedProjIds) {// TODO: RMME
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 
 		if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">fixLastModifiedByDB (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r("fixLastModifiedByDB");echo'</pre>';}
 
@@ -1387,7 +1453,6 @@ R		list,         search,                              readattr,          readext
 		return $lastRunDate;
 	}
 
-
 	public static function usersAction() {
 		$task = self::getTaskNewerUsers();
 
@@ -1450,9 +1515,7 @@ R		list,         search,                              readattr,          readext
 	public static function getUsersNewerThen($datetime) {
 		$users = array();
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 		$sqlWhereAdd = "";
 		if ($datetime) {
 			$sqlWhereAdd = " and ( u.`A_RECORD_CREATE_DATE`>'{$datetime}' or u.`A_RECORD_UPDATE_DATE`>'{$datetime}' )";
@@ -1477,9 +1540,7 @@ R		list,         search,                              readattr,          readext
 	public static function getUsersAll() {
 		$users = array();
 		$db = DB::getDB();
-		if (!$db) {
-			die("DB Error: No DB!");
-		}
+		if (!$db) die("DB Error: No DB! L." . __LINE__);
 		$sql = "select u.ID
 				, u.`ADM_ACCOUNT`
 				, u.`ADM_NAME`
@@ -1497,8 +1558,863 @@ R		list,         search,                              readattr,          readext
 
 }
 
-//dodatkowo synchronizacja automatyczna uprawnien
-//SEF('KIKE_MIGRACJA_KIKE_AUTH');
-//if(strstr($_SESSION['SYSTEM_PROFILE_STRING'],'KIKE' ))  KIKE_MIGRACJA_KIKE_AUTH($LAST_TIMESTAMP);
+
+class SyncPermsCustomTables {
+
+	public $_tbls;
+	private $_db;
+	private $_syncTblName = '_SYNC_TABLE_FILE_PERMS';
+	private $_activeLoginList;
+
+	public function run() {
+		if (!$this->fetchConfig()) return;
+
+		$this->installTable();
+		$this->generateTasksNewRecords();
+		$this->generateTasksUpdated();
+		$this->newFilesAction();
+		$limit = 100;
+		for ($i = 0; $i < $limit; $i++) {
+			$loopTasksFired = 0;
+			foreach ($this->_tbls as $tblName => $tblConf) {
+				$task = $this->nextTaskAction($tblName);
+				if (!$task) {
+					// TODO: rm $tblName from config to prevent searching for task in next loops
+					unset($this->_tbls[$tblName]);
+					continue;
+				}
+				$loopTasksFired++;
+			}
+			if (!$loopTasksFired) break;
+			$i += $loopTasksFired;
+		}
+	}
+
+	public function fetchConfig() {
+		$this->_db = DB::getDB();
+		if (!$this->_db) die("DB Error: No DB! L." . __LINE__);
+
+		$tbls = array();
+		$sql = "select c.`CONF_VAL` as tbl_names
+			from `CRM_CONFIG` as c
+			where c.`CONF_KEY`='_SYNC_TABLE_FILE_PERMS__TablesList'
+		";
+		$res = $this->_db->query($sql);
+		while ($r = $this->_db->fetch($res)) {
+			if (!empty($r->tbl_names)) {
+				$tbls = explode("\n", $r->tbl_names);
+			}
+		}
+		//echo "DBG:" . __LINE__ . ":" . __FUNCTION__ . "(): tbls [" . implode(',', $tbls) . "]\n";
+		$configTbls = array();
+		Lib::loadClass('FoldersConfig');
+		if (!empty($tbls)) {
+			$folderConfAll = FoldersConfig::getRawData();
+			foreach ($tbls as $tblName) {
+				$tblName = trim($tblName);
+				if (empty($tblName)) continue;
+				$confTblName = "{$tblName}_COLUMN";
+				if (FoldersConfig::hasConfig($confTblName)) {
+					$configTbls[$tblName] = FoldersConfig::getAll($confTblName);
+				}
+			}
+		}
+		//echo "DBG:" . __LINE__ . ":" . __FUNCTION__ . "(): tbls [" . implode(',', array_keys($configTbls)) . "]\n";
+		if (!empty($configTbls)) {
+			$this->_tbls = $configTbls;
+		}
+		return $this->_tbls;
+	}
+
+	public function installTable() {
+		if (!$this->_tbls) return;
+		if (!$this->_db) die("DB Error: No DB! L." . __LINE__);
+		$sql = "
+			CREATE TABLE IF NOT EXISTS `{$this->_syncTblName}` (
+				`ID` int(11) NOT NULL AUTO_INCREMENT,
+				`TBL_NAME` varchar(64),
+				`TBL_ID` int(11) NOT NULL,
+				`L_APPOITMENT_USER` varchar(64) DEFAULT '',
+				`A_ADM_COMPANY` varchar(64) NOT NULL DEFAULT '',
+				`A_CLASSIFIED` varchar(64) NOT NULL DEFAULT '',
+				`PARENT_L_APPOITMENT_USER` varchar(64) NOT NULL DEFAULT '',
+				`A_LAST_SYNC` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
+				`A_SYNCHRONIZED` tinyint(4) NOT NULL DEFAULT '0',
+				`A_SYNC_RESULT` varchar(255) NOT NULL DEFAULT '',
+				`A_POMIN_SYNC` tinyint(1) NOT NULL DEFAULT '0',
+				PRIMARY KEY (`ID`),
+				UNIQUE KEY `TBL` (`TBL_NAME`, `TBL_ID`)
+			) ENGINE=MyISAM  DEFAULT CHARSET=latin2 ;
+		";
+		$this->_db->query($sql);
+		if ($this->_db->has_errors()) {
+			print_r($this->_db->get_errors());
+		}
+	}
+
+	public function generateTasksNewRecords() {
+		if (!$this->_tbls) return;
+		if (!$this->_db) die("DB Error: No DB! L." . __LINE__);
+
+		$sqlValues = array();
+		foreach ($this->_tbls as $tblName => $tblConf) {
+			$sqlValues[] = "('{$tblName}', -1, '', '', '', '')";
+		}
+		$sqlValues = implode(',', $sqlValues);
+		$sql = "insert ignore into `{$this->_syncTblName}` (`TBL_NAME`, `TBL_ID`, `L_APPOITMENT_USER`, `A_ADM_COMPANY`, `A_CLASSIFIED`, `PARENT_L_APPOITMENT_USER`)
+			values {$sqlValues};
+		";
+		$res = $this->_db->query($sql);
+		if ($this->_db->has_errors()) {
+			print_r($this->_db->get_errors());
+		}
+
+		foreach ($this->_tbls as $tblName => $tblConf) {
+			$sql = "insert ignore into `{$this->_syncTblName}` (`TBL_NAME`, `TBL_ID`, `L_APPOITMENT_USER`, `A_ADM_COMPANY`, `A_CLASSIFIED`, `PARENT_L_APPOITMENT_USER`)
+				select '{$tblName}' as TBL_NAME
+					, t.`ID`, t.`L_APPOITMENT_USER`, t.`A_ADM_COMPANY`, t.`A_CLASSIFIED`
+					, '' as PARENT_L_APPOITMENT_USER	-- pp.`L_APPOITMENT_USER`
+				from `{$tblName}` as t
+				where t.`A_STATUS`!='DELETED'
+			";
+			$res = $this->_db->query($sql);
+			if ($this->_db->has_errors()) {
+				print_r($this->_db->get_errors());
+			}
+		}
+	}
+
+	public function generateTasksUpdated() {
+		if (!$this->_tbls) return;
+		if (!$this->_db) die("DB Error: No DB! L." . __LINE__);
+
+		foreach ($this->_tbls as $tblName => $tblConf) {
+			$sql = "update `{$this->_syncTblName}` as s
+					, `{$tblName}` as t
+					-- , `IN7_MK_BAZA_DYSTRYBUCJI` as pt
+				set
+					s.`L_APPOITMENT_USER`=t.`L_APPOITMENT_USER`
+					, s.`A_ADM_COMPANY`=t.`A_ADM_COMPANY`
+					, s.`A_CLASSIFIED`=t.`A_CLASSIFIED`
+					, s.`PARENT_L_APPOITMENT_USER`=''  -- pt.`L_APPOITMENT_USER`
+					, s.`A_SYNCHRONIZED`=0
+				where
+					s.`TBL_ID`=t.`ID`
+					and s.`TBL_NAME`='{$tblName}'
+			--		 and pt.`ID`=t.`P_ID`
+					and (
+						s.`L_APPOITMENT_USER`!=t.`L_APPOITMENT_USER`
+						or s.`A_ADM_COMPANY`!=t.`A_ADM_COMPANY`
+						or s.`A_CLASSIFIED`!=t.`A_CLASSIFIED`
+			--			or s.`PARENT_L_APPOITMENT_USER`!=pt.`L_APPOITMENT_USER`
+					)
+			";
+			$res = $this->_db->query($sql);
+			if ($this->_db->has_errors()) {
+				print_r($this->_db->get_errors());
+			}
+		}
+	}
+
+	public function newFilesAction() {
+		if (!$this->_tbls) return;
+
+		foreach ($this->_tbls as $tblName => $tblConf) {
+			$task = $this->_getTaskNewFiles($tblName);
+			$taskResult = $this->_fixLastModifiedFiles($task);
+			$this->_saveTask($tblName, -1);
+		}
+	}
+
+	private function _getTaskNewFiles($tblName) {
+		$task = null;
+		if (!$this->_db) die("DB Error: No DB! L." . __LINE__);
+
+		$sql = "select s.*
+			from `{$this->_syncTblName}` as s
+			where s.`TBL_ID`=-1 and s.`TBL_NAME`='{$tblName}'
+		";
+		$res = $this->_db->query($sql);
+		if ($r = $this->_db->fetch($res)) {
+			$task = $r;
+		}
+
+		if (!$task) {
+			$task = new stdClass();
+			$task->TBL_NAME = $tblName;
+			$task->TBL_ID = -1;
+			$task->A_SYNC_RESULT = new stdClass();
+			$task->A_LAST_SYNC = mktime(date("H"), date("i") - 10, date("s"), date("n"), date("j"), date("Y"));
+			$task->A_LAST_SYNC = date("Y-m-d H:i", $task->A_LAST_SYNC);
+		}
+		return $task;
+	}
+
+	private function _fixLastModifiedFiles($task) {
+		if (!$this->_db) die("DB Error: No DB! L." . __LINE__);
+		$tblName = $task->TBL_NAME;
+
+		if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">fixLastModifiedFiles (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r("fixLastModifiedFiles");echo'</pre>';}
+
+		$confTblName = "{$task->TBL_NAME}_COLUMN";
+		$TBL_mount_point = FoldersConfig::get($confTblName, 'mount_point');
+		$record = $task->record;
+		$folderConf = FoldersConfig::getAll($confTblName);
+		$uploader = new FileUploader($confTblName, $record);
+		if (!$uploader->setConfig($folderConf, $errMsg)) {
+			trigger_error("Error: folders config!", E_USER_NOTICE);
+			die("Error: folders config!");
+		}
+		$hasRecordOwnFolder = $uploader->hasRecordOwnFolder();
+
+		$foundTblFiles = array();
+		if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">$lastRunDate (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($task->A_LAST_SYNC);echo'</pre>';}
+		//exec("cd {$TBL_mount_point}; find . -newermt '{$task->A_LAST_SYNC}' ", $foundPaths);
+		$filesWithPerms = array();
+		$cmd = "cd {$TBL_mount_point}; find . -newermt '{$task->A_LAST_SYNC}' -type f -exec ls -le '{}' \;";
+		exec($cmd, $filesWithPerms);// TODO: head -{$lastTotal + 10000}| tail 
+		if (!empty($filesWithPerms)) {
+			$filesWithPermsTree = array();
+			$lastName = '';
+			foreach ($filesWithPerms as $line) {
+				if (substr($line, 0, 1) == '-') {// file name
+					$fileParts = array();
+					$filePartsArr = explode(' ', $line);
+					$lastInd = 0;
+					foreach ($filePartsArr as $vPart) {
+						if ($lastInd > 7) {// file name
+							$fileParts[8] = ($lastInd > 8)? "{$fileParts[8]} {$vPart}" : $vPart;
+							$lastInd++;
+						}
+						else if (!empty($vPart) || $vPart === '0') {
+							$fileParts[] = $vPart;
+							$lastInd++;
+						}
+					}
+
+					$file = new stdClass();
+
+					if (!isset($fileParts[8])) {
+						echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Error parse file name (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r(array('line'=>$line, 'fileParts'=>$fileParts));echo'</pre>';
+						//continue;
+					}
+
+					$file->name = end($fileParts);
+					$file->path = end($fileParts);
+					//$file->owner = $fileParts[2];
+					//$file->group = $fileParts[3];
+					//$file->perms = $fileParts[0];
+					$file->isDir = (substr($line, 0, 1) == 'd');
+					$file->permsExt = array();
+					$filesWithPermsTree[$file->name] = $file;
+					$lastName = $file->name;
+				}
+				else if (substr($line, 0, 1) == ' ') {// extended perm line
+					if ($lastName == '..') {
+						continue;
+					}
+					$filesWithPermsTree[$file->name]->permsExt[] = trim($line);
+				}
+				else {// parse error
+					$lastName = '..';
+				}
+			}
+
+			foreach ($filesWithPermsTree as $vFile) {
+				$vFile->path = ltrim($vFile->path, './');
+				$vFile->path = explode('/', $vFile->path);
+				$vFile->recordFolder = array_shift($vFile->path);// $vFile->projectFolder -> recordFolder
+				$vFile->path = implode('/', $vFile->path);
+				// TODO: _getTableIdFromFolderName($task->TBL_NAME, $vFile->recordFolder);
+
+				$tblId = 0;
+				if ($hasRecordOwnFolder) {
+					$tblId = explode('.', $vFile->recordFolder);
+					$tblId = reset($tblId);
+				}
+				else {
+					$tblId = explode('.', $vFile->path);
+					$tblId = reset($tblId);
+				}
+
+				if (is_numeric($tblId) && $tblId > 0) {
+					$foundTblFiles[$tblId][] = $vFile;
+				}
+			}
+		}
+		if(V::get('DBG', '', $_GET, 'int') > 1){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">filesWithPerms (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): '."path: {$TBL_mount_point}\n";print_r($filesWithPerms);echo'</pre>';}
+		if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">foundTblFiles (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): '."path: {$TBL_mount_point}\n";print_r($foundTblFiles);echo'</pre>';}
+
+		if (!empty($foundTblFiles)) {
+			$rowsIds = array_keys($foundTblFiles);
+			$sql = "select t.`ID`
+					, t.`L_APPOITMENT_USER`
+					, t.`A_ADM_COMPANY`
+					, t.`A_CLASSIFIED`
+			--		, pt.`L_APPOITMENT_USER` as PARENT_L_APPOITMENT_USER
+				from `{$task->TBL_NAME}` as t
+			--		left join `{$task->TBL_NAME}` as pt on (pt.ID=t.P_ID)
+				where t.`ID` in (" . implode(',', $rowsIds) . ")
+			";
+			$res = $this->_db->query($sql);
+			while ($r = $this->_db->fetch($res)) {
+
+				$requirePermsExt = $this->_getRequiredPermsExtByRecord($r);
+
+				foreach ($foundTblFiles[$r->ID] as $vFile) {
+					$cmdList = $this->_fixFilePerms($vFile, $requirePermsExt, "{$TBL_mount_point}/{$vFile->recordFolder}", $r);
+					if (!empty($cmdList)) {
+						if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">$cmdList P('.$r->ID.') total('.count($cmdList).') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($cmdList);echo'</pre>';}
+
+						foreach ($cmdList as $vCmd) {
+							if(V::get('DBG', '', $_GET, 'int') > 1){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Exec-cmdList-P('.$r->ID.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($vCmd);echo'</pre>';}
+
+							exec($vCmd, $out, $outValue);
+
+							if(V::get('DBG', '', $_GET, 'int') > 1){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Done-cmdList-P('.$r->ID.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r(array($outValue, $out));echo'</pre>';}
+							if ($outValue != 0) {
+								trigger_error("Error-cmd: {$vCmd}", E_USER_NOTICE);
+							}
+						}
+					} else {
+						if(V::get('DBG', '', $_GET, 'int') > 1){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">$cmdList is empty P('.$r->ID.') total('.count($cmdList).') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r("empty");echo'</pre>';}
+					}
+				}
+			}
+		}
+
+	}
+
+	private function _getRequiredPermsExtByRecord($record) {
+		// TODO: need to check if user is correct in field L_APPOITMENT_USER
+		$requirePermsExt = array();
+		if (!$record->L_APPOITMENT_USER && !$record->A_ADM_COMPANY) {// no owner, no write group
+			// TODO: group PODMIOT
+			$requirePermsExt["group:workgroup"] = array('write', 'read');
+		}
+		else {
+			if ($record->L_APPOITMENT_USER) {
+				if ($this->_isActiveUser($record->L_APPOITMENT_USER)) {
+					$requirePermsExt["user:{$record->L_APPOITMENT_USER}"] = array('write', 'read');
+				} else {
+					// TODO: trigger error $record->L_APPOITMENT_USER is not active user!
+				}
+			}
+
+			if (!empty($record->A_ADM_COMPANY) && $record->A_ADM_COMPANY == $record->A_CLASSIFIED) {
+				$requirePermsExt["group:{$record->A_ADM_COMPANY}"] = array('read', 'write');
+			}
+			else if (empty($record->A_ADM_COMPANY) && empty($record->A_CLASSIFIED)) {
+				$requirePermsExt["group:workgroup"] = array('write', 'read');
+			}
+			else {
+				if ($record->A_ADM_COMPANY) {
+					$requirePermsExt["group:{$record->A_ADM_COMPANY}"] = array('write');
+				}
+				if ($record->A_CLASSIFIED) {
+					$requirePermsExt["group:{$record->A_CLASSIFIED}"] = array('read');
+				}
+			}
+		}
+
+		// add parent owner
+		if (!empty($record->PARENT_L_APPOITMENT_USER) && $record->PARENT_L_APPOITMENT_USER != $record->L_APPOITMENT_USER) {
+			if ($this->_isActiveUser($record->PARENT_L_APPOITMENT_USER)) {
+				$requirePermsExt["user:{$record->PARENT_L_APPOITMENT_USER}"] = array('write', 'read');
+			} else {
+				// TODO: trigger error $record->PARENT_L_APPOITMENT_USER is not active user!
+			}
+		}
+
+		// add user:_www perms read, write
+		$requirePermsExt["user:_www"] = array('write', 'read');
+
+		return $requirePermsExt;
+	}
+
+	private function _fixFilePerms($vFile, $requirePermsExt, $mainPath, $r) {
+		//trigger_error("fixFilePerms: " . json_encode($vFile), E_USER_NOTICE);
+		$cmdList = array();
+		$vReqPermsExt = array();
+		foreach ($requirePermsExt as $kPermObj => $vPerms) {
+			$vReqPermsExt[$kPermObj] = array();
+			foreach ($vPerms as $vPerm) {
+				if ($vFile->isDir) {
+					if ($vPerm == 'read') {
+						$vReqPermsExt[$kPermObj]['list'] = 0;
+						$vReqPermsExt[$kPermObj]['search'] = 0;
+						$vReqPermsExt[$kPermObj]['readattr'] = 0;
+						$vReqPermsExt[$kPermObj]['readextattr'] = 0;
+						$vReqPermsExt[$kPermObj]['readsecurity'] = 0;
+						$vReqPermsExt[$kPermObj]['file_inherit'] = 0;
+						$vReqPermsExt[$kPermObj]['directory_inherit'] = 0;
+					}
+					else if ($vPerm == 'write') {
+						$vReqPermsExt[$kPermObj]['add_file'] = 0;
+						$vReqPermsExt[$kPermObj]['add_subdirectory'] = 0;
+						$vReqPermsExt[$kPermObj]['delete_child'] = 0;
+						$vReqPermsExt[$kPermObj]['writeattr'] = 0;
+						$vReqPermsExt[$kPermObj]['writeextattr'] = 0;
+						$vReqPermsExt[$kPermObj]['writesecurity'] = 0;
+						$vReqPermsExt[$kPermObj]['chown'] = 0;
+					}
+				}
+				else {
+					if ($vPerm == 'read') {
+						$vReqPermsExt[$kPermObj]['read'] = 0;
+						$vReqPermsExt[$kPermObj]['execute'] = 0;
+						$vReqPermsExt[$kPermObj]['readattr'] = 0;
+						$vReqPermsExt[$kPermObj]['readextattr'] = 0;
+						$vReqPermsExt[$kPermObj]['readsecurity'] = 0;
+					}
+					else if ($vPerm == 'write') {
+						$vReqPermsExt[$kPermObj]['write'] = 0;
+						$vReqPermsExt[$kPermObj]['append'] = 0;
+						$vReqPermsExt[$kPermObj]['writeattr'] = 0;
+						$vReqPermsExt[$kPermObj]['writeextattr'] = 0;
+						$vReqPermsExt[$kPermObj]['writesecurity'] = 0;
+						$vReqPermsExt[$kPermObj]['chown'] = 0;
+					}
+				}
+			}
+		}
+
+		$permsToRemove = array();
+		foreach ($vFile->permsExt as $vPermExtLine) {
+			$vPermExtArr = explode(' ', $vPermExtLine);
+			$vPermExt = new stdClass();
+			$vPermExt->nr = trim($vPermExtArr[0], ' :');
+			$vPermExt->permObj = $vPermExtArr[1];
+			$vPermExt->perms = '';
+			if (count($vPermExtArr) == 4) {
+				$vPermExt->perms = explode(',', $vPermExtArr[3]);
+			}
+			else if (count($vPermExtArr) == 5 && $vPermExtArr[2] == 'inherited') {
+				$vPermExt->perms = explode(',', $vPermExtArr[4]);
+			}
+			else {
+				echo "Error: Perm Ext Line format! ({$vPermExtLine})";
+				continue;
+			}
+
+			$permFound = false;
+			foreach ($vReqPermsExt as $kPermObj => $vPerms) {
+				if (false !== strpos($vPermExtLine, $kPermObj)) {
+					foreach ($vPerms as $kPerm => $vPermChecked) {
+						if (in_array($kPerm, $vPermExt->perms)) {
+							$vReqPermsExt[$kPermObj][$kPerm] = 1;
+							$permFound = true;
+						}
+					}
+				}
+			}
+			if (!$permFound) {
+				$permsToRemove[] = $vPermExt->nr;
+			}
+			//echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">$vReqPermsExt('.$vFile->name.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($vReqPermsExt);echo'</pre>';
+		}
+
+		if (!empty($permsToRemove)) {
+			if(V::get('DBG', '', $_GET, 'int') > 1){echo'<pre style="max-height:300px;overflow:auto;border:1px solid red;text-align:left;">TO-rm('.$r->ID.'): $permsToRemove('.$vFile->name.') isDir('.$vFile->isDir.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r(array('permsToRemove'=>$permsToRemove, 'vFile->permsExt'=>$vFile->permsExt, 'r'=>$r));echo'</pre>';}
+			$permsToRemove = array_reverse($permsToRemove);
+			foreach ($permsToRemove as $vPermInd) {
+				$cmdList []= "chmod -a# {$vPermInd} '{$mainPath}/{$vFile->path}' ";
+			}
+		}
+
+		$permsToAdd = array();
+		foreach ($vReqPermsExt as $kPermObj => $vPerms) {
+			foreach ($vPerms as $kPerm => $vPermChecked) {
+				if (!$vPermChecked) {
+					$permsToAdd[$kPermObj][$kPerm] = 1;
+				}
+			}
+		}
+		if (!empty($permsToAdd)) {
+			if(V::get('DBG', '', $_GET, 'int') > 1){echo'<pre style="max-height:300px;overflow:auto;border:1px solid red;text-align:left;">TO-add('.$r->ID.'): $permsToAdd('.$vFile->name.') isDir('.$vFile->isDir.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r(array('permsToAdd'=>$permsToAdd, 'vFile->permsExt'=>$vFile->permsExt, 'r'=>$r));echo'</pre>';}
+			foreach ($permsToAdd as $kPermObj => $vPerms) {
+				$cmdList []= "chmod +a \"{$kPermObj} allow " . implode(',', array_keys($vPerms)) . "\" '{$mainPath}/{$vFile->path}' ";
+			}
+		}
+		return $cmdList;
+	}
+
+	private function _isActiveUser($usrLogin) {
+		$activeLoginList = $this->_fetchActiveLoginList();
+		return in_array($usrLogin, $activeLoginList);
+	}
+
+	public function _fetchActiveLoginList() {
+		if (!$this->_db) die('DB Error!');
+		if (!is_array($this->_activeLoginList)) {
+			$this->_activeLoginList = array();
+			$sql = "select u.`ADM_ACCOUNT`
+				from `ADMIN_USERS` as u
+				where u.`A_STATUS` =  'NORMAL'
+			";
+			$res = $this->_db->query($sql);
+			while ($r = $this->_db->fetch($res)) {
+				$this->_activeLoginList[] = $r->ADM_ACCOUNT;
+			}
+		}
+		return $this->_activeLoginList;
+	}
+
+	private function _saveTask($tblName, $tblId, $taskDone = 1, $result = null) {
+		if (!$this->_db) die("DB Error: No DB! L." . __LINE__);
+		$sqlResult = '';
+		if ($result) {
+			$resultJson = json_encode($result);
+			$resultJson = $this->_db->_($resultJson);
+			$sqlResult .= " , s.`A_SYNC_RESULT`='{$resultJson}' ";
+		}
+		$sql = "update `{$this->_syncTblName}` as s
+			set
+				s.`A_LAST_SYNC`=NOW()
+				, s.`A_SYNCHRONIZED`={$taskDone}
+				{$sqlResult}
+			where s.`TBL_ID`={$tblId} and s.`TBL_NAME`='{$tblName}'
+		";
+		$res = $this->_db->query($sql);
+	}
+
+	public function executeTask($tblName, $tblId) {
+		if (!$this->_tbls) return;
+		$task = $this->_getTask($tblName, $tblId);
+		if (!$task) return;
+
+		$this->_executeTask($task);
+		$this->_saveTask($task->TBL_NAME, $task->TBL_ID);
+		return $task;
+	}
+
+	public function nextTaskAction($tblName) {
+		if (!$this->_tbls) return;
+
+		$task = $this->_getTask($tblName);
+		if (!$task) return;
+
+		$this->_executeTask($task);
+
+		/*
+		if (isset($task->A_SYNC_RESULT->total)
+			&& isset($task->A_SYNC_RESULT->lastDone)
+			&& $task->A_SYNC_RESULT->lastDone < $task->A_SYNC_RESULT->total
+		) {
+			$this->_saveTask($task->TBL_NAME, $task->TBL_ID, 0, $task->A_SYNC_RESULT);
+		} else {
+			$this->_saveTask($task->TBL_NAME, $task->TBL_ID);
+		}
+		*/
+		$this->_saveTask($task->TBL_NAME, $task->TBL_ID);
+		return $task;
+	}
+
+	private function _getTask($tblName, $tblId = null) {
+		if (!$this->_db) die("DB Error: No DB! L." . __LINE__);
+		$task = null;
+
+		$recordFieldList = $this->_getRecordFieldList($tblName);
+		$recordFieldList[] = 'L_APPOITMENT_USER';
+		$recordFieldList[] = 'A_ADM_COMPANY';
+		$recordFieldList[] = 'A_CLASSIFIED';
+
+		$sqlRecordFields = array();
+		foreach ($recordFieldList as $fldName) {
+			$sqlRecordFields[] = "t.`{$fldName}` as t__{$fldName}";
+		}
+		$sqlRecordFields = implode(',', $sqlRecordFields);
+
+		$sqlTblId = "and s.`TBL_ID`!=-1";
+		if ($tblId > 0) $sqlTblId = "and s.`TBL_ID`='{$tblId}'";
+
+		$sql = "select s.*
+				, {$sqlRecordFields}
+		--		, pt.`L_APPOITMENT_USER` as p__PARENT_L_APPOITMENT_USER
+			from `{$this->_syncTblName}` as s
+				left join `{$tblName}` as t on(t.`ID`=s.`TBL_ID`)
+		--		left join `{$tblName}` as pt on(pt.`ID`=t.`P_ID`)
+			where
+				s.`TBL_NAME`='{$tblName}'
+				{$sqlTblId}
+				and s.`A_SYNCHRONIZED`=0
+				and s.`A_POMIN_SYNC`=0
+			order by s.`A_LAST_SYNC` asc, s.`ID` asc
+			limit 1
+		";
+		$res = $this->_db->query($sql);
+		if ($r = $this->_db->fetch($res)) {
+			$r->A_SYNC_RESULT = (!$r->A_SYNC_RESULT)? new stdClass() : json_decode($r->A_SYNC_RESULT);
+			$task = $r;
+			$task->record = new stdClass();
+			foreach ($recordFieldList as $fldName) {
+				$aliasFldName = "t__{$fldName}";
+				$task->record->{$fldName} = $task->{$aliasFldName};
+				unset($task->{$aliasFldName});
+			}
+		}
+		return $task;
+	}
+
+	private function _getRecordFieldList($tblName) {
+		if (empty($this->_tbls[$tblName])) return;
+		$conf = $this->_tbls[$tblName];
+
+		$fldNames = array();
+
+		$fldName = V::get("LOOKAT_FOLDER_VARNAME", '', $conf);
+		$fldName = trim($fldName);
+		if (!empty($fldName)) $fldNames[$fldName] = true;
+
+		for ($i = 1; $i < 5; $i++) {
+			$fldName = V::get("LOOKAT_FOLDER_VARNAME{$i}", '', $conf);
+			$fldName = trim($fldName);
+			if (!empty($fldName)) $fldNames[$fldName] = true;
+
+			$fldName = V::get("DEST_FOLDER_VARNAME{$i}", '', $conf);
+			$fldName = trim($fldName);
+			if (!empty($fldName)) $fldNames[$fldName] = true;
+		}
+
+		if (!in_array('ID', $fldNames)) {
+			$fldNames['ID'] = true;
+		}
+		return array_keys($fldNames);
+	}
+
+	private function _executeTask($task) {
+		if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">executeTask (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($task);echo'</pre>';}
+
+$DBG_TIME = false;
+$dbgTime = new stdClass();
+$dbgTime->startTime = microtime(true);
+$dbgTime->lastTime = $dbgTime->startTime;
+
+		$confTblName = "{$task->TBL_NAME}_COLUMN";
+		$TBL_mount_point = FoldersConfig::get($confTblName, 'mount_point');
+
+		$record = $task->record;
+
+		$folderConf = FoldersConfig::getAll($confTblName);
+		$uploader = new FileUploader($confTblName, $record);
+		$errMsg = '';
+		if (!$uploader->setConfig($folderConf, $errMsg)) {
+			trigger_error("Error: folders config!", E_USER_NOTICE);
+			die("Error: folders config!");
+		}
+
+if ($DBG_TIME) {
+	$dbgTime->curTime = microtime(true);
+	echo "DBG:(" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s):" . __LINE__ . ":_executeTask({$task->TBL_NAME}/{$task->TBL_ID}]: after-FileUploader->setConfig" . "\n";
+	$dbgTime->lastTime = $dbgTime->curTime;
+}
+
+		$uploader->findFolder();
+		$mainFolder = $uploader->getDestFolder();
+
+if ($DBG_TIME) {
+	$dbgTime->curTime = microtime(true);
+	echo "DBG:(" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s):" . __LINE__ . ":_executeTask({$task->TBL_NAME}/{$task->TBL_ID}]:time after-FileUploader->getDestFolder" . "\n";
+	$dbgTime->lastTime = $dbgTime->curTime;
+}
+
+		if(V::get('DBG', '', $_GET, 'int') > 2){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">generated folderName('.$record->ID.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';var_dump($uploader);echo'</pre>';}
+		if (!$mainFolder) {
+			$mainFolder = $uploader->generateFolderName();
+			$mainFolderPath = rtrim($TBL_mount_point, '/') . '/' . $mainFolder;
+			if(V::get('DBG', '', $_GET, 'int') > 2){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">generated folderName('.$record->ID.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r(array($mainFolder, $mainFolderPath));echo'</pre>';}
+
+			@mkdir($mainFolderPath, 0770, true);
+			@chmod($mainFolderPath, 0770);
+			if (!file_exists($mainFolderPath)) {
+				trigger_error("Error: Nie udało się utworzyć folderu! ({$mainFolder})", E_USER_NOTICE);
+				return false;
+			}
+			$requirePermsExt = $this->_getRequiredPermsExtByRecord($record);
+			$file = new stdClass();
+			$file->name = '.';
+			$file->path = '.';
+			//$file->owner = '';
+			//$file->group = '';
+			//$file->perms = '';
+			$file->isDir = true;
+			$file->permsExt = array();
+			$cmdList = $this->_fixFilePerms($file, $requirePermsExt, "{$TBL_mount_point}/{$mainFolder}", $record);
+			if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">cmdList-P('.$record->ID.') fixFilePerms (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($cmdList);echo'</pre>';}
+		}
+		else {
+			$cmdList = $this->_fixRecord($record, $uploader, $mainFolder, $TBL_mount_point, $task);
+		}
+
+if ($DBG_TIME) {
+	$dbgTime->curTime = microtime(true);
+	echo "DBG:(" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s):" . __LINE__ . ":_executeTask({$task->TBL_NAME}/{$task->TBL_ID}]: after-generate cmdList - mainFolder(" . (($mainFolder)? 1 : 0) . ")" . "\n";
+	$dbgTime->lastTime = $dbgTime->curTime;
+}
+
+		if (!empty($cmdList)) {
+			foreach ($cmdList as $vCmd) {
+				if(V::get('DBG', '', $_GET, 'int') > 1){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Exec-cmdList-P('.$record->ID.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($vCmd);echo'</pre>';}
+
+				exec($vCmd, $out, $outValue);
+
+				if(V::get('DBG', '', $_GET, 'int') > 1){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Done-cmdList-P('.$record->ID.') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r(array($outValue, $out));echo'</pre>';}
+				if ($outValue != 0) {
+					trigger_error("Error-cmd: {$vCmd}", E_USER_NOTICE);
+				}
+			}
+		}
+
+if ($DBG_TIME) {
+	$dbgTime->curTime = microtime(true);
+	echo "DBG:(" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s):" . __LINE__ . ":_executeTask({$task->TBL_NAME}/{$task->TBL_ID}]: after-executed cmdList " . "\n";
+	$dbgTime->lastTime = $dbgTime->curTime;
+}
+
+		if(V::get('DBG', '', $_GET, 'int') > 0){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">';print_r("executeTask finished OK");echo'</pre>';}
+	}
+
+	public function _fixRecord($r, $uploader, $mainFolder, $TBL_mount_point, &$task) {
+		$requirePermsExt = $this->_getRequiredPermsExtByRecord($r);
+
+		$DBG_TIME = false;
+		$dbgTime = new stdClass();
+		$dbgTime->startTime = microtime(true);
+		$dbgTime->lastTime = $dbgTime->startTime;
+
+		$filesWithPerms = array();
+		if ($uploader->hasRecordOwnFolder()) {
+			$cmd = " ls -Rlea . ";
+			$cmd = "cd '{$TBL_mount_point}/{$mainFolder}' && {$cmd} ";
+			exec($cmd, $filesWithPerms);
+		}
+		else {
+			$lookGlob = $uploader->getFileSearchRegex();
+			$cmd = " ls -Rlea {$lookGlob} ";
+			$cmd = "cd '{$TBL_mount_point}/{$mainFolder}' && {$cmd} ";
+			exec($cmd, $filesWithPerms);
+		}
+
+//echo "\n-----------------------\n";
+//echo "filesWithPerms: ";print_r($filesWithPerms);echo "\n";
+
+if ($DBG_TIME) {
+	$dbgTime->curTime = microtime(true);
+	echo "DBG:(" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s):_fixRecord: cd '{$TBL_mount_point}/{$mainFolder}' && {$cmd} " . "\n";
+	$dbgTime->lastTime = $dbgTime->curTime;
+}
+
+		$filesWithPermsTree = array();
+		$lastName = '';
+		$folderParent = '';
+		foreach ($filesWithPerms as $line) {
+			if (substr($line, 0, 1) == '-' || substr($line, 0, 1) == 'd') {// file name
+				$fileParts = array();
+				$filePartsArr = explode(' ', $line);
+				$lastInd = 0;
+				foreach ($filePartsArr as $vPart) {
+					if ($lastInd > 7) {// file name
+						$fileParts[8] = ($lastInd > 8)? "{$fileParts[8]} {$vPart}" : $vPart;
+						$lastInd++;
+					}
+					else if (!empty($vPart) || $vPart === '0') {
+						$fileParts[] = $vPart;
+						$lastInd++;
+					}
+				}
+
+				if (end($fileParts) == '..' || (end($fileParts) == '.' && $folderParent)) {
+					$lastName = '..';
+					continue;
+				}
+
+				$file = new stdClass();
+
+				if (!isset($fileParts[8])) {
+					echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">Error parse file name (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r(array('line'=>$line, 'fileParts'=>$fileParts));echo'</pre>';
+					//continue;
+				}
+
+				$file->name = end($fileParts);
+				$file->path = array();
+				if ($folderParent) $file->path[] = $folderParent;
+				$file->path[] = end($fileParts);
+				$file->path = implode('/', $file->path);
+				//$file->owner = $fileParts[2];
+				//$file->group = $fileParts[3];
+				//$file->perms = $fileParts[0];
+				$file->isDir = (substr($line, 0, 1) == 'd');
+				$file->permsExt = array();
+				$filesWithPermsTree[$file->name] = $file;
+				$lastName = $file;
+			}
+			else if (substr($line, 0, 1) == ' ') {// extended perm line
+				if ($lastName == '..') {
+					continue;
+				}
+				$filesWithPermsTree[$file->name]->permsExt[] = trim($line);
+			}
+			else if (substr($line, 0, 2) == './' && substr($line, -1) == ':') {// folder
+				$folderParent = substr($line, 2, -1);
+			}
+			else if (substr($line, 0, 5) == 'total') {
+				continue;
+			}
+			else if (empty($line)) {
+				$folderParent = '';
+				continue;
+			}
+		}
+
+//echo "filesWithPermsTree: ";print_r($filesWithPermsTree);echo "\n";
+
+if ($DBG_TIME) {
+	$dbgTime->curTime = microtime(true);
+	echo "DBG:(" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s):_fixRecord: parse cmd output" . "\n";
+	$dbgTime->lastTime = $dbgTime->curTime;
+}
+
+		if(V::get('DBG', '', $_GET, 'int') > 1){echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">$filesWithPermsTree (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($filesWithPermsTree);echo'</pre>';}
+
+		// check perms
+		/*
+files:
+W		read,write,execute,append,readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,chown
+W		read,write,execute,append,readattr,writeattr,readextattr,writeextattr,readsecurity
+R		read,      execute,       readattr,          readextattr,             readsecurity
+
+dir:
+W		list,add_file,search,add_subdirectory,delete_child,readattr,writeattr,readextattr,writeextattr,readsecurity,writesecurity,chown,file_inherit,directory_inherit
+W		list,add_file,search,add_subdirectory,delete_child,readattr,writeattr,readextattr,writeextattr,readsecurity,                    file_inherit,directory_inherit
+R		list,         search,                              readattr,          readextattr,             readsecurity,                    file_inherit,directory_inherit
+		 */
+		$cmdList = array();
+		foreach ($filesWithPermsTree as $kFileName => $vFile) {
+			if (false) {
+				// TODO: $kFileName == '_PISMA' - readonly
+				// TODO: $vFile->path => _PISMA/...
+			}
+			else {
+				$cmdFile = $this->_fixFilePerms($vFile, $requirePermsExt, "{$TBL_mount_point}/{$mainFolder}", $r);
+				if (!empty($cmdFile)) {
+					foreach ($cmdFile as $vCmd) {
+						$cmdList[] = $vCmd;
+					}
+				}
+			}
+		}
+//echo "cmdList: ";print_r($cmdList);echo "\n";
+//echo "\n-----------------------\n";
+
+if ($DBG_TIME) {
+	$dbgTime->curTime = microtime(true);
+	echo "DBG:(" . number_format($dbgTime->curTime - $dbgTime->lastTime, 6) . "s):_fixRecord: end" . "\n";
+	$dbgTime->lastTime = $dbgTime->curTime;
+}
+
+		return $cmdList;
+	}
+
+}
 
 ?>

+ 39 - 25
SE/se-lib/FileUploader.php

@@ -18,6 +18,16 @@ class FileUploader {
 		$this->OK_FILE_SIGNS  = array('-', '_', '--', '---', 'a', 'c', 'e', 'l', 'n', 'o', 's', 'z', 'z', 'A', 'C', 'E', 'L', 'N', 'O', 'S', 'Z', 'Z');
 	}
 
+	public function hasRecordOwnFolder() {
+		$fldLookAt = V::get('LOOK_GLOB', '', $this->_cnf['LOOKAT_FOLDER']);
+		if ($fldLookAt) {
+			if (false !== strpos($fldLookAt, '<VARNAME')) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	public function setConfig($conf, &$errMsg = '') {
 		$DBG = (V::get('DBG_F', 0, $_GET, 'int') > 0);
 		$this->_cnf['LOCAL_PATH'] = V::get('mount_point', null, $conf);
@@ -203,12 +213,11 @@ class FileUploader {
 		if (empty($this->_foundFolders)) {
 			if ($show_if_not_found) {
 				return $this->generateFolderName();
-			} else {
-				return null;
 			}
 		} else {
 			return reset($this->_foundFolders);
 		}
+		return null;
 	}
 
 	function getDestPathShare($show_if_not_found = false) {
@@ -236,29 +245,8 @@ class FileUploader {
 		if (empty($folder)) {
 			return false;
 		}
-		$look = new stdClass();
-		if ($this->_cnf['LOOKAT_FILES']) {
-			//$look->regex = V::get('LOOK_REGEX', '', $this->_cnf['LOOKAT_FOLDER']);
-			$look->glob = V::get('LOOK_GLOB', '', $this->_cnf['LOOKAT_FILES']);
-			$look->varname = array();
-			$look->varname['VARNAME']  = V::get('VARNAME', '', $this->_cnf['LOOKAT_FILES']);
-			$look->varname['VARNAME1'] = V::get('VARNAME1', '', $this->_cnf['LOOKAT_FILES']);
-			$look->varname['VARNAME2'] = V::get('VARNAME2', '', $this->_cnf['LOOKAT_FILES']);
-			$look->varname['VARNAME3'] = V::get('VARNAME3', '', $this->_cnf['LOOKAT_FILES']);
-			if($DBG){ echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">$look (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($look);echo'</pre>'; }
-			foreach ($look->varname as $kName => $vVar) {
-				if ($vVar) {
-					if (isset($this->_record->{$vVar})) {
-						$vVar = $this->_record->{$vVar};
-					}
-
-					$look->glob = str_replace("<{$kName}>", $vVar, $look->glob);
-				}
-			}
-		} else {
-			$look->glob = "*.*";
-		}
-		$ret = glob("{$this->_cnf['LOCAL_PATH']}/{$folder}/{$look->glob}", GLOB_NOSORT);
+		$lookGlob = $this->getFileSearchRegex();
+		$ret = glob("{$this->_cnf['LOCAL_PATH']}/{$folder}/{$lookGlob}", GLOB_NOSORT);
 		if($DBG){ echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">glob('."{$this->_cnf['LOCAL_PATH']}/{$folder}/*.*".') (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($ret);echo'</pre>'; }
 		if ($recursive) {
 			$retSubFolderFiles = glob("{$this->_cnf['LOCAL_PATH']}/{$folder}/*/*.*", GLOB_NOSORT);
@@ -287,6 +275,32 @@ class FileUploader {
 		return $ret;
 	}
 
+	public function getFileSearchRegex() {
+		$look = new stdClass();
+		if ($this->_cnf['LOOKAT_FILES']) {
+			//$look->regex = V::get('LOOK_REGEX', '', $this->_cnf['LOOKAT_FOLDER']);
+			$look->glob = V::get('LOOK_GLOB', '', $this->_cnf['LOOKAT_FILES']);
+			$look->varname = array();
+			$look->varname['VARNAME']  = V::get('VARNAME', '', $this->_cnf['LOOKAT_FILES']);
+			$look->varname['VARNAME1'] = V::get('VARNAME1', '', $this->_cnf['LOOKAT_FILES']);
+			$look->varname['VARNAME2'] = V::get('VARNAME2', '', $this->_cnf['LOOKAT_FILES']);
+			$look->varname['VARNAME3'] = V::get('VARNAME3', '', $this->_cnf['LOOKAT_FILES']);
+			if($DBG){ echo'<pre style="max-height:200px;overflow:auto;border:1px solid red;text-align:left;">$look (' . __CLASS__ . '::' . __FUNCTION__ . ':' . __LINE__ . '): ';print_r($look);echo'</pre>'; }
+			foreach ($look->varname as $kName => $vVar) {
+				if ($vVar) {
+					if (isset($this->_record->{$vVar})) {
+						$vVar = $this->_record->{$vVar};
+					}
+
+					$look->glob = str_replace("<{$kName}>", $vVar, $look->glob);
+				}
+			}
+		} else {
+			$look->glob = "*.*";
+		}
+		return $look->glob;
+	}
+
 	function getFilesFromSkany($skanyConf, $fileNamesOnly = false) {
 		$DBG = (V::get('DBG_F', 0, $_GET, 'int') > 0);
 		if (empty($skanyConf)) {

+ 152 - 2
SE/se-lib/TableAjax.php

@@ -2812,6 +2812,10 @@ function hidePopover() {
 				}
 				break;
 			}
+			case 'filePermsRefresh': {
+				$this->sendAjaxResponseJson('ajaxFilePermsRefresh', $_REQUEST);
+				break;
+			}
 			case 'FILES_CONN_TBL_LIST': {
 				$id = V::get('ID', 0, $_REQUEST, 'int');
 				if ($id > 0) {
@@ -3883,6 +3887,85 @@ jQuery(document).ready(function(){
 		exit;
 	}
 
+	private function ajaxFilePermsRefresh($args) {
+		header("Content-type: application/json");
+
+		$id = V::get('ID', 0, $args, 'int');
+		if ($id <= 0) throw new HttpException("Wrong param ID", 404);
+
+		$dbID = $this->_acl->getDB();
+		$db = DB::getDB($dbID);
+		if (!$db) throw new HttpException("No DB", 406);
+
+		$record = $this->_dataSource->getItem($id);
+		if (!$record) throw new Exception("No item ID({$rowID})", 404);
+
+		$tblName = $this->_acl->getName();
+
+		// TODO: SyncPermsCustomTables->getRecordTask($tbl, $id);
+		$sql_L_APPOITMENT_USER = V::get('L_APPOITMENT_USER', '', $record);
+		$sql_A_ADM_COMPANY = V::get('A_ADM_COMPANY', '', $record);
+		$sql_A_CLASSIFIED = V::get('A_CLASSIFIED', '', $record);
+		$mainDB = DB::getDB();
+		$sql = "insert into `_SYNC_TABLE_FILE_PERMS` (
+				`TBL_NAME`,
+				`TBL_ID`,
+				`L_APPOITMENT_USER`,
+				`A_ADM_COMPANY`,
+				`A_CLASSIFIED`,
+				`A_SYNCHRONIZED`
+			)
+			values (
+				'{$tblName}'
+				, '{$id}'
+				, '{$sql_L_APPOITMENT_USER}'
+				, '{$sql_A_ADM_COMPANY}'
+				, '{$sql_A_CLASSIFIED}'
+				, 0
+			)
+			ON DUPLICATE KEY UPDATE
+				`A_SYNCHRONIZED`=0
+		";
+		$res = $mainDB->query($sql);
+		if ($mainDB->has_errors()) {
+			throw new Exception("Nie udało się dodać zadania");
+		}
+
+		// TODO: this blocks browser ajax query
+		//$limit = 3;
+		//while ($limit--) {
+		//	sleep(10);
+		//	TODO: check if task is done
+		//}
+
+		$confTblName = "{$tblName}_COLUMN";
+		Lib::loadClass('FoldersConfig');
+		$folderConfAll = FoldersConfig::getRawData();
+		if (!FoldersConfig::hasConfig($confTblName)) {
+			throw new Exception("Brak danych konfiguracyjnych ({$tblName})", 404);
+		}
+
+		$folderConf = FoldersConfig::getAll($confTblName);
+
+		Lib::loadClass('FileUploader');
+		$uploader = new FileUploader($confTblName, $record);
+		if (!$uploader->setConfig($folderConf)) {
+			throw new Exception("Błąd danych konfiguracyjnych ({$tblName})", 404);
+		}
+		$uploader->findFolder();
+
+		$mainFolder = $uploader->getDestFolder();
+
+		$files = $uploader->getFilesFromFolder($mainFolder, false, true);
+		$localPath = $uploader->getLocalPath();
+		$folderWeb = $uploader->getFolderWeb();
+		$jsonData = new stdClass();
+		$jsonData->msg = 'Zadanie dodane';
+		$jsonData->type = 'success';
+		$jsonData->files = $this->convertFileListToJson($files, $folderWeb, $localPath, $mainFolder);
+		return $jsonData;
+	}
+
 	private function sendAjaxFilesConnTblList($id, $args) {
 		header("Content-type: application/json");
 		$DBG = ('1' == V::get('DBG', '', $_REQUEST));
@@ -4110,9 +4193,12 @@ jQuery(document).ready(function(){
 			<?php else : ?>
 				<code><?php echo $mainFolder; ?></code>
 			<?php endif; ?>
-			<span class="pull-right valign-btns-bottom"><?php echo $rowFunctionsOut; ?></span>
+			<span class="pull-right valign-btns-bottom">
+				<span id="FILES_LIST_ACTIONS_<?php echo $this->_htmlID; ?>"></span>
+				<?php echo $rowFunctionsOut; ?>
+			</span>
 		</h4>
-		<div style="max-height:180px; overflow:auto; border-bottom:1px solid #ddd;">
+		<div style="clear:both; max-height:180px; overflow:auto; border-bottom:1px solid #ddd;">
 		<table class="table table-bordered table-hover">
 			<colgroup>
 				<col style="">
@@ -4405,6 +4491,68 @@ function connTblListUpdate<?php echo $this->_htmlID; ?>(fileListJson) {
 	});
 }
 
+function fileListActions<?php echo $this->_htmlID; ?>() {
+	var filePermsReload = jQuery('#FILES_LIST_ACTIONS_<?php echo $this->_htmlID; ?>');
+	var btnReload = jQuery('<button class="btn-link btn-small" title="odśwież uprawnienia do plików"><span class="ico-refresh"></span>Odśwież</button>');
+	btnReload.on('click', function(e) {
+		console.log('TODO: click reload perms...');
+
+		function notifyAjaxCallback(data) {
+			var notify = {};
+			notify.type = (data && data.type)? data.type : '';
+			notify.msg = (data && data.msg)? data.msg : '';
+			switch (notify.type) {
+				case 'success':
+					if (!notify.msg) notify.msg = 'OK';
+					break;
+				case 'info':
+					if (!notify.msg) notify.msg = '';
+					break;
+				case 'error':
+					if (!notify.msg) notify.msg = 'Wystąpiły błędy';
+					break;
+				case 'warning':
+					notify.type = 'warn';
+					if (!notify.msg) notify.msg = 'Wystąpiły błędy';
+					break;
+				default:
+					notify.msg = 'Nieznany błąd';
+					if (data && data.errorCode) notify.msg += ' ' + data.errorCode;
+					notify.type = '';
+			}
+			jQuery.notify(notify.msg, notify.type);
+		}
+
+		var reqData = {};
+		jQuery.ajax({
+			data: reqData,
+			dataType: 'json',
+			type: "GET",
+			url: 'index-ajax.php?_zasobID=<?php echo $this->_zasobID; ?>&_cls=<?php echo __CLASS__; ?>&_hash=<?php echo $this->_htmlID; ?>&_task=filePermsRefresh&ID=<?php echo $record->ID; ?>',
+		})
+		.done(function(data, textStatus, jqXHR){
+			notifyAjaxCallback(data);
+			if (data && data.files) {
+				fileListUpdate<?php echo $this->_htmlID; ?>(data.files);
+			}
+		})
+		.fail(function(jqXHR){// jqXHR.fail(function( jqXHR, textStatus, errorThrown ) {});
+			if (jqXHR.responseJSON) {
+				notifyAjaxCallback(jqXHR.responseJSON);
+			}
+			else {
+				var txt = jqXHR.responseText || 'Wystąpiły błędy';
+				if (jqXHR.status == 404) {
+					jQuery.notify(jqXHR.responseText, 'error');
+				} else {
+					jQuery.notify(jqXHR.responseText, 'warn');
+				}
+			}
+		});
+	});
+	filePermsReload.append(btnReload);
+}
+
 jQuery(document).ready(function(){
 
 	jQuery('#FILES_FRM_<?php echo $this->_htmlID; ?>').ajaxForm({
@@ -4464,6 +4612,8 @@ jQuery(document).ready(function(){
 		}
 	});
 
+	fileListActions<?php echo $this->_htmlID; ?>();
+
 	var fileList = <?php echo json_encode($jsonFiles); ?>;
 
 	fileListUpdate<?php echo $this->_htmlID; ?>(fileList);