Explorar o código

added upload multiple files in TableAjax

Piotr Labudda %!s(int64=8) %!d(string=hai) anos
pai
achega
02819bfe35
Modificáronse 2 ficheiros con 292 adicións e 39 borrados
  1. 111 0
      SE/se-lib/Route/ViewTableAjax.php
  2. 181 39
      SE/se-lib/TableAjax.php

+ 111 - 0
SE/se-lib/Route/ViewTableAjax.php

@@ -716,4 +716,115 @@ class Route_ViewTableAjax extends RouteBase {
 		Response::sendTryCatchJson(array($tbl, 'ajaxData'), $args = $_GET);
 	}
 
+	public function uploadFilesAjaxAction() {
+		Response::sendTryCatchJson([$this, 'uploadFilesAjax'], $args = $_POST);
+	}
+	public function uploadFilesAjax($args) {
+		DBG::log($_FILES, 'array', "\$_FILES");
+		DBG::log($args, 'array', "\$args");
+
+		$namespace = V::get('namespace', '', $args, 'word');
+		if (!$namespace) throw new Exception("Missing namespace");
+		$primaryKey = V::get('primaryKey', '', $args, 'int');
+		if ($primaryKey <= 0) throw new Exception("Missing primaryKey");
+		if (empty($_FILES)) throw new Exception("Missing files");
+
+		$acl = Core_AclHelper::getAclByNamespace($namespace, $forceTblAclInit = ('1' == V::get('_force', '', $_GET)));
+
+		Lib::loadClass('FileUploader');
+		Lib::loadClass('FoldersConfig');
+
+		// $dbID = $acl->getDB();
+		// $db = DB::getDB($dbID);
+		// if (!$db) throw new HttpException("No DB ({$dbID})", 406);
+
+		$record = $acl->buildQuery([])->getItem($primaryKey);
+		DBG::log($record, 'array', "\$record");
+		if (!$record) throw new HttpException("No item ID({$primaryKey})", 404);
+		if (!$acl->canReadRecord($record)) throw new Exception("Brak uprawnień do odczytu");
+		if (!$acl->canWriteRecord($record)) throw new Exception("Brak uprawnień do zapisu");
+
+
+		$rootTableName = $acl->getRootTableName();
+		$confTblName = "{$rootTableName}_COLUMN";
+		$folderConfAll = FoldersConfig::getRawData();
+		if (!FoldersConfig::hasConfig($confTblName)) throw new HttpException("Brak danych konfiguracyjnych ({$rootTableName})", 404);
+		$folderConf = FoldersConfig::getAll($confTblName);
+		DBG::log($folderConf, 'array', "\$folderConf");
+
+		$uploader = new FileUploader($confTblName, (object)$record);
+		if (!$uploader->setConfig($folderConf)) throw new HttpException("Błąd danych konfiguracyjnych ({$rootTableName})", 404);
+		$uploader->findFolder();
+		DBG::log($uploader, 'array', "\$uploader");
+		// $errorMsg = '';
+		// if (!empty($args['SCANS_COLUMN_ADD'])) {
+		// 	$uploaded = $uploader->tryMoveFromScanAjax($errorMsg);
+		// }
+		// else {
+		// 	$uploaded = $uploader->tryUploadAjax($errorMsg);
+		// }
+		$destPath = $uploader->getDestLocalPath($show_if_not_found = true);
+		DBG::log($destPath, 'array', "\$destPath");
+		if (!file_exists($destPath)) {
+			if (!$uploader->tryCreateDestFolder($destPath)) throw new Exception("Wystąpił błąd podczas tworzenie katalogu dla rekordu '{$primaryKey}'");
+		}
+
+		$generateSafeFileName = function($path) {
+			if (!file_exists($path)) return $path;
+			$infoPath = pathinfo($path);
+			//    pathinfo('/path/t1/t2/fileName.ext') = [
+			//        [dirname] => /path/t1/t2
+			//        [basename] => fileName.ext
+			//        [extension] => ext
+			//        [filename] => fileName
+			//    ]
+			return $infoPath['dirname'] . "/" . $infoPath['filename'] . "--" . date("Y-m-d_H-i-s") . "." . $infoPath['extension'];
+		};
+		$moveActions = array_map(function ($file) use ($destPath, $generateSafeFileName) {
+			return [
+				$file['tmp_name'],
+				$generateSafeFileName("{$destPath}/{$file['name']}"),
+				$file['name'],
+			];
+		}, $_FILES);
+		DBG::log($moveActions, 'array', "\$moveActions"); // [ [ srcPath, descPath ] ]
+		$errorMsgs = [];
+		$pkField = $acl->getSqlPrimaryKeyField();
+		foreach ($moveActions as $fileMoveAction) {
+			if (!move_uploaded_file($fileMoveAction[0], $fileMoveAction[1])) {
+				$errorMsgs[] = "Nie udało się wgrać pliku '{$fileMoveAction[2]}'";
+			} else {
+				try {
+					$affected = DB::getPDO($acl->getDB())->update($rootTableName, $pkField, $primaryKey, [
+						'M_DIST_FILES' => "Wrano plik '{$fileMoveAction[2]}'",
+						'A_RECORD_UPDATE_AUTHOR' => User::getLogin(),
+						'A_RECORD_UPDATE_DATE' => 'NOW()',
+					]);
+					if ($affected) {
+						DB::getPDO($acl->getDB())->insert("{$rootTableName}_HIST", [
+							'ID_USERS2' => $primaryKey,
+							'M_DIST_FILES' => "Wrano plik '{$fileMoveAction[2]}'",
+							'A_RECORD_UPDATE_AUTHOR' => User::getLogin(),
+							'A_RECORD_UPDATE_DATE' => 'NOW()',
+						]);
+					}
+				} catch (Exception $e) {
+					DBG::log($e);
+					$errorMsgs[] = $e->getMessage();
+				}
+			}
+		}
+
+		if (!empty($errorMsgs)) {
+			return [
+				'type' => "error",
+				'msg' => "Wystąpiły błędy podczas wgrywania plików dla '{$primaryKey}'",
+				'errors' => $errorMsgs,
+			];
+		}
+		return [
+			'type' => "success",
+			'msg' => "Wgrano nowe pliki dla '{$primaryKey}'",
+		];
+	}
 }

+ 181 - 39
SE/se-lib/TableAjax.php

@@ -409,6 +409,7 @@ class TableAjax extends ViewAjax {
 		UI::startContainer();
 		UI::showMessagesForTable($this->_tbl);
 		UI::endContainer();
+		$namespace = $acl->getNamespace();
 		?>
 		<div class="AjaxTableCont">
 			<ul class="breadcrumb">
@@ -580,7 +581,8 @@ var p5UI_TableAjax_generateFunctionNode = function(funObj, rowPK, props) {
 
 		priv.options = {};
 		var defaults = {
-			url: '',  //webservice url
+			namespace: '',
+			url: '', //webservice url
 			urlData: '', //webservice params
 			urlPost: false, //use POST instead of GET
 			debug: false, //prints debug info to console
@@ -1170,6 +1172,10 @@ var p5UI_TableAjax_generateFunctionNode = function(funObj, rowPK, props) {
 					columnName, columnProps, val, cellCnt, format, showTooltip, fldWidgetNode,
 					dbg = priv.options.debug
 			;
+			//  ondrop="drop_handler(event);" ondragover="dragover_handler(event);" ondragend="dragend_handler(event);"
+			rowNode.attr('ondrop', "p5TA_onDrop(event, '"+rowPK+"', '"+priv.options.namespace+"')")
+			rowNode.attr('ondragover', "p5TA_onDragOver(event, this, '"+rowPK+"', '"+priv.options.namespace+"')")
+			rowNode.attr('ondragend', "p5TA_onDragEnd(event, this, '"+rowPK+"', '"+priv.options.namespace+"')")
 
 			if (priv.options.rowFunctions || priv.options.filtersClean) {
 				cellNode = priv.renderCellRowFunctions(priv.options.rowFunctions, rowPK, props);
@@ -3681,6 +3687,7 @@ function TableAjax__HIST_Route(args) {
 		<script>
 jQuery(document).ready(function(){
 	jQuery('#<?php echo $this->_htmlID; ?>').TableAjax({
+		namespace: '<?= $acl->getNamespace(); ?>',
 		url: '<?= $this->syncUrl; ?>&_hash=<?= $this->_htmlID; ?>&_task=loadDataAjax',// priv.options.url
 		userTableFilterUrl: '<?= ($this->_useUserTableFilter) ? $this->_useUserTableFilter : ''; ?>',
 		columnPicker: true,
@@ -4112,6 +4119,137 @@ function <?php echo $jsToogleFiltrProcesuFunctionName; ?>(n) {
 }
 		</script>
 		<?php
+		echo UI::h('script', [], "
+			(function (global) {
+				var p5TA_dragOverChecker = function () {
+					var _node = null
+					var _pk = null
+					var _ns = null
+					var _overlayNode = null
+					var markNodeHoverOn = function (node, pk, ns) {
+						if (!_overlayNode) {
+							_overlayNode = document.createElement('div')
+							_overlayNode.style.backgroundColor = '#03a9f4'
+							_overlayNode.style.opacity = '0.2'
+							_overlayNode.style.position = 'absolute'
+							document.body.appendChild(_overlayNode)
+							_overlayNode.appendChild(document.createTextNode('drag file...'))
+						}
+						var bbox = node.getBoundingClientRect()
+						_overlayNode.style.top = ((window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0) + bbox.top) + 'px'
+						_overlayNode.style.left = '0px' // bbox.left + 'px'
+						_overlayNode.style.width = '100%' // bbox.width + 'px'
+						_overlayNode.style.height = bbox.height + 'px'
+						_overlayNode.setAttribute('ondrop', 'p5TA_onDrop(event, \''+pk+'\', \''+ns+'\')')
+						_overlayNode.setAttribute('ondragover', 'p5TA_overlay_onDragOver(event, this, \''+pk+'\', \''+ns+'\')')
+					}
+					var markNodeHoverOff = function () {
+						if (_overlayNode && _overlayNode.parentNode) _overlayNode.parentNode.removeChild(_overlayNode)
+						_overlayNode = null
+					}
+					var _removeOverlayTimeoutId = null
+					return {
+						update: function (node, pk, ns) {
+							_ns = ns
+							if (null !== _pk && _pk !== pk) {
+								markNodeHoverOff()
+							}
+							if (_pk !== pk) {
+								if (null !== node) markNodeHoverOn(node, pk, ns)
+							}
+							_pk = pk
+							if (null !== node) _node = node
+							if (_removeOverlayTimeoutId) clearTimeout(_removeOverlayTimeoutId)
+							_removeOverlayTimeoutId = setTimeout(markNodeHoverOff, 1000)
+						},
+						removeOverlay: function () {
+							markNodeHoverOff()
+						},
+					}
+				}
+				var this__dragOverChecker = p5TA_dragOverChecker()
+
+				function p5TA_uploadFiles(files, ns, pk) {
+					var formData = new FormData()
+					formData.append('namespace', ns)
+					formData.append('primaryKey', pk)
+					files.forEach(function (file, idx) {
+						formData.append('file' + idx, file)
+					})
+
+					window.fetch('index.php?_route=ViewTableAjax&_task=uploadFilesAjax', {
+						method: 'POST',
+						body: formData,
+						credentials: 'same-origin',
+					}).then(function checkStatus(response) {
+						if (response.status >= 200 && response.status < 300) {
+							return response
+						} else {
+							var error = new Error(response.statusText)
+							error.response = response
+							throw error
+						}
+					}).then(function (response) {
+						return response.json()
+					}).then(function (response) {
+						p5UI__notifyAjaxCallback(response)
+					}).catch(function(error) {
+						p5UI__notifyAjaxCallback({ type: 'error', msg: error })
+					})
+				}
+
+				function p5TA_onDrop(e, pk, ns) {
+					e.preventDefault();
+
+					// If dropped items aren't files, reject them
+					var dt = e.dataTransfer;
+					var files = []
+					if (dt.items) { // Use DataTransferItemList interface to access the file(s)
+						for (var i = 0; i < dt.items.length; i++) {
+							if (dt.items[i].kind == 'file') {
+								var file = dt.items[i].getAsFile();
+								files.push(file)
+							}
+						}
+					} else { // Use DataTransfer interface to access the file(s)
+						for (var i=0; i < dt.files.length; i++) {
+							files.push(dt.files[i])
+						}
+					}
+					if (!files) {
+						p5UI__notifyAjaxCallback({
+							type: 'info',
+							msg: 'brak plików',
+						})
+						return false
+					}
+					p5TA_uploadFiles(files, ns, pk);
+					this__dragOverChecker.removeOverlay()
+				}
+				function p5TA_onDragOver(e, n, pk, ns) {
+					e.preventDefault();
+					this__dragOverChecker.update(n, pk, ns)
+				}
+				function p5TA_overlay_onDragOver(e, n, pk, ns) {
+					e.preventDefault();
+					this__dragOverChecker.update(null, pk, ns)
+				}
+				function p5TA_onDragEnd(e, n, pk, ns) {
+					var dt = e.dataTransfer;
+					if (dt.items) { // Use DataTransferItemList interface to remove the drag data
+						for (var i = 0; i < dt.items.length; i++) {
+							dt.items.remove(i);
+						}
+					} else { // Use DataTransfer interface to remove the drag data
+						e.dataTransfer.clearData();
+					}
+				}
+				global.p5TA_onDrop = p5TA_onDrop
+				global.p5TA_onDragOver = p5TA_onDragOver
+				global.p5TA_onDragEnd = p5TA_onDragEnd
+				global.p5TA_overlay_onDragOver = p5TA_overlay_onDragOver
+			})(window);
+		");
 		UI::setTitle($this->_acl->getRawLabel(100) . " - " . UI::getTitle());
 		$out = ob_get_contents();
 		ob_end_clean();
@@ -4121,50 +4259,54 @@ function <?php echo $jsToogleFiltrProcesuFunctionName; ?>(n) {
 	public function _viewProcesInitListItem($vInitId, $gotoIds, $pInitList) {
 		$vLabel = $pInitList[$vInitId];
 		$kId = $vInitId;
-		?>
-		<a href="index.php?FUNCTION_INIT=MENU_SELECT_PROCES&_action=setPermsByProces&id_proces=<?php echo $kId; ?>&MENU_INIT=VIEWTABLE_AJAX&ZASOB_ID=<?php echo $this->_zasobID; ?>" title="<?php echo htmlspecialchars("{{$kId}} {$vLabel}"); ?>">
-			<i class="glyphicon glyphicon-info-sign"
-				 onclick="window.open('procesy5.php?task=PROCES_VIEW_LIST&id_proces=<?php echo $kId; ?>&HIDE_PANEL=0&show_big_img=1&group_stanowiska=1');return false;"
-				 style="color:#aaa;"
-				 onmouseover="this.style.color='#337AB7'"
-				 onmouseout="this.style.color='#aaa'"></i>
-			<?php echo "{{$kId}} {$vLabel}"; ?>
-		</a>
-<?php
+		echo UI::h('a', [
+			'href' => "index.php?FUNCTION_INIT=MENU_SELECT_PROCES&_action=setPermsByProces&id_proces={$kId}&MENU_INIT=VIEWTABLE_AJAX&ZASOB_ID={$this->_zasobID}",
+			'title' => htmlspecialchars("{{$kId}} {$vLabel}"),
+		], [
+			UI::h('i', [
+				'class' => "glyphicon glyphicon-info-sign",
+				 'onclick' => "window.open('procesy5.php?task=PROCES_VIEW_LIST&id_proces={$kId}&HIDE_PANEL=0&show_big_img=1&group_stanowiska=1');return false;",
+				 'style' => "color:#aaa",
+				 'onmouseover' => "this.style.color='#337AB7'",
+				 'onmouseout' => "this.style.color='#aaa'"]),
+			"{{$kId}} {$vLabel}"
+		]);
 	}
 	public function _viewProcesGotoAndRetListItem($vGotoId, $pInitList) {
 		$vLabel = $pInitList[$vGotoId];
 		$kId = $vGotoId;
 		// TODO:?: prevent to execute procedure
-		?>
-		<a href="index.php?FUNCTION_INIT=MENU_SELECT_PROCES&_action=setPermsByProces&id_proces=<?php echo $kId; ?>&MENU_INIT=VIEWTABLE_AJAX&ZASOB_ID=<?php echo $this->_zasobID; ?>" title="<?php echo htmlspecialchars("{{$kId}} {$vLabel}"); ?>">
-			<span style="padding:10px;"></span>
-			<i class="glyphicon glyphicon-arrow-right" style="color:#aaa"></i>
-			<i class="glyphicon glyphicon-info-sign"
-				 onclick="window.open('procesy5.php?task=PROCES_VIEW_LIST&id_proces=<?php echo $kId; ?>&HIDE_PANEL=0&show_big_img=1&group_stanowiska=1');return false;"
-				 style="color:#aaa;"
-				 onmouseover="this.style.color='#337AB7'"
-				 onmouseout="this.style.color='#aaa'"></i>
-			<?php echo "{{$kId}} {$vLabel}"; ?>
-		</a>
-<?php
+		echo UI::h('a', [
+			'href' => "index.php?FUNCTION_INIT=MENU_SELECT_PROCES&_action=setPermsByProces&id_proces={$kId}&MENU_INIT=VIEWTABLE_AJAX&ZASOB_ID={$this->_zasobID}",
+			'title' => htmlspecialchars("{{$kId}} {$vLabel}"),
+		], [
+			UI::h('span', [ 'style' => "padding:10px;"]),
+			UI::h('i', [ 'class' => "glyphicon glyphicon-arrow-right", 'style' => "color:#aaa"]),
+			UI::h('i', [ 'class' => "glyphicon glyphicon-info-sign",
+				 'onclick' => "window.open('procesy5.php?task=PROCES_VIEW_LIST&id_proces={$kId}&HIDE_PANEL=0&show_big_img=1&group_stanowiska=1');return false;",
+				 'style' => "color:#aaa",
+				 'onmouseover' => "this.style.color='#337AB7'",
+				 'onmouseout' => "this.style.color='#aaa'"]),
+			"{{$kId}} {$vLabel}",
+		]);
 	}
 	public function _viewProcesGotoAndRetLvl2ListItem($vGotoLvl2Id, $pInitList) {
 		$vLabel = $pInitList[$vGotoLvl2Id];
 		$kId = $vGotoLvl2Id;
 		// TODO:?: prevent to execute procedure
-		?>
-		<a href="index.php?FUNCTION_INIT=MENU_SELECT_PROCES&_action=setPermsByProces&id_proces=<?php echo $kId; ?>&MENU_INIT=VIEWTABLE_AJAX&ZASOB_ID=<?php echo $this->_zasobID; ?>" title="<?php echo htmlspecialchars("{{$kId}} {$vLabel}"); ?>">
-			<span style="padding:20px;"></span>
-			<i class="glyphicon glyphicon-arrow-right" style="color:#aaa"></i>
-			<i class="glyphicon glyphicon-info-sign"
-				 onclick="window.open('procesy5.php?task=PROCES_VIEW_LIST&id_proces=<?php echo $kId; ?>&HIDE_PANEL=0&show_big_img=1&group_stanowiska=1');return false;"
-				 style="color:#aaa;"
-				 onmouseover="this.style.color='#337AB7'"
-				 onmouseout="this.style.color='#aaa'"></i>
-			<?php echo "{{$kId}} {$vLabel}"; ?>
-		</a>
-<?php
+		echo UI::h('a', [
+			'href' => "index.php?FUNCTION_INIT=MENU_SELECT_PROCES&_action=setPermsByProces&id_proces={$kId}&MENU_INIT=VIEWTABLE_AJAX&ZASOB_ID={$this->_zasobID}",
+			'title' => htmlspecialchars("{{$kId}} {$vLabel}"),
+		], [
+			UI::h('span', [ 'style' => "padding:20px;" ]),
+			UI::h('i', [ 'class' => "glyphicon glyphicon-arrow-right", 'style' => "color:#aaa" ]),
+			UI::h('i', [ 'class' => "glyphicon glyphicon-info-sign",
+				 'onclick' => "window.open('procesy5.php?task=PROCES_VIEW_LIST&id_proces={$kId}&HIDE_PANEL=0&show_big_img=1&group_stanowiska=1');return false;",
+				 'style' => "color:#aaa",
+				 'onmouseover' => "this.style.color='#337AB7'",
+				 'onmouseout' => "this.style.color='#aaa'"]),
+			"{{$kId}} {$vLabel}",
+		]);
 	}
 
 	public function hasAdditionalLayers() {
@@ -5001,7 +5143,7 @@ jQuery(document).ready(function(){
 		$db = DB::getDB($dbID);
 		if (!$db) throw new HttpException("No DB ({$dbID})", 406);
 		$record = $this->_acl->buildQuery([])->getItem($id);
-		if (!$record) throw new HttpException("No item ID({$rowID})", 404);
+		if (!$record) throw new HttpException("No item ID({$id})", 404);
 		if (!$this->_acl->canReadRecord($record)) throw new Exception("Brak uprawnień do odczytu");
 		if (!$this->_acl->canWriteRecord($record)) throw new Exception("Brak uprawnień do zapisu");
 		$tblName = $this->_acl->getName();
@@ -5051,7 +5193,7 @@ jQuery(document).ready(function(){
 		$db = DB::getDB($dbID);
 		if (!$db) throw new HttpException("No DB ({$dbID})", 406);
 		$record = $this->_acl->buildQuery([])->getItem($id);
-		if (!$record) throw new HttpException("No item ID({$rowID})", 404);
+		if (!$record) throw new HttpException("No item ID({$id})", 404);
 		if (!$this->_acl->canReadRecord($record)) throw new Exception("Brak uprawnień do odczytu");
 		if (!$this->_acl->canWriteRecord($record)) throw new Exception("Brak uprawnień do zapisu");
 		$tblName = $this->_acl->getName();
@@ -5080,7 +5222,7 @@ jQuery(document).ready(function(){
 		$db = DB::getDB($dbID);
 		if (!$db) throw new HttpException("No DB ({$dbID})", 406);
 		$record = $this->_acl->buildQuery([])->getItem($id);
-		if (!$record) throw new HttpException("No item ID({$rowID})", 404);
+		if (!$record) throw new HttpException("No item ID({$id})", 404);
 		if (!$this->_acl->canReadRecord($record)) throw new Exception("Brak uprawnień do odczytu");
 		$tblName = $this->_acl->getName();
 		$confTblName = "{$tblName}_COLUMN";
@@ -5108,7 +5250,7 @@ jQuery(document).ready(function(){
 		if (!$db) throw new HttpException("No DB", 406);
 
 		$record = $this->_acl->buildQuery([])->getItem($id);
-		if (!$record) throw new Exception("No item ID({$rowID})", 404);
+		if (!$record) throw new Exception("No item ID({$id})", 404);
 
 		$tblName = $this->_acl->getName();