13 use Symfony\Component\HttpFoundation\RedirectResponse;
14 use Symfony\Component\HttpFoundation\Request;
15 use Symfony\Component\HttpFoundation\Response;
24 const NAME =
'picker';
31 public function __construct()
33 parent::__construct(self::NAME, [
34 self::TITLE => _(
"File Picker"),
35 self::DEPENDENCIES => [
"browse",
"view"],
37 self::REQUIRES_LOGIN =>
true,
40 $this->uploadDao = $this->
getObject(
'dao.upload');
43 public function preInstall():
void
46 menu_insert(
"Browse-Pfile::Compare", 4, self::NAME, _(
"Compare this file to another."));
51 private function createFilePicker():
void
53 if (!$this->
dbManager->existsTable(
'file_picker')) {
55 "CREATE TABLE file_picker (
56 file_picker_pk serial NOT NULL PRIMARY KEY,
57 user_fk integer NOT NULL,
58 uploadtree_fk1 integer NOT NULL,
59 uploadtree_fk2 integer NOT NULL,
60 last_access_date date NOT NULL
62 ALTER TABLE ONLY file_picker
63 ADD CONSTRAINT file_picker_user_fk_key
64 UNIQUE (user_fk, uploadtree_fk1, uploadtree_fk2)",
68 $this->createFilePickerMulti();
71 private function createFilePickerMulti():
void
73 if ($this->
dbManager->existsTable(
'file_picker_multi')) {
77 "CREATE TABLE file_picker_multi (
78 file_picker_multi_pk serial NOT NULL PRIMARY KEY,
79 user_fk integer NOT NULL,
81 last_access_date date NOT NULL
96 "SELECT u.uploadtree_tablename
98 JOIN uploadtree ut ON ut.upload_fk = u.upload_pk
99 WHERE ut.uploadtree_pk = \$1",
100 [$uploadtreePk], __METHOD__
102 return $row[
'uploadtree_tablename'] ??
'uploadtree';
111 $groupId = Auth::getGroupId();
114 "SELECT u.upload_pk, u.upload_filename AS name,
115 u.upload_desc, u.upload_ts, u.uploadtree_tablename,
117 FROM foldercontents fc
118 JOIN upload u ON u.upload_pk = fc.child_id
119 AND fc.foldercontents_mode = 2
120 AND (u.upload_mode & (1<<5)) != 0
121 JOIN uploadtree ut ON ut.upload_fk = u.upload_pk AND ut.parent IS NULL
122 WHERE fc.parent_fk = \$1
123 ORDER BY u.upload_filename, u.upload_pk"
125 $res = $this->
dbManager->execute($stmt, [$folder_pk]);
127 while ($row = $this->
dbManager->fetchArray($res)) {
128 if (!$this->uploadDao->isAccessible($row[
'upload_pk'], $groupId)) {
132 'upload_pk' => intval($row[
'upload_pk']),
133 'uploadtree_pk' => intval($row[
'uploadtree_pk']),
134 'name' => htmlspecialchars($row[
'name']),
135 'desc' => htmlspecialchars((
string)($row[
'upload_desc'] ??
'')),
136 'ts' => !empty($row[
'upload_ts'])
149 private function historyPick(
int $uploadtree_pk,
int &$rtncount): string
151 $user_pk = Auth::getUserId();
152 if (empty($user_pk)) {
157 "SELECT file_picker_pk, uploadtree_fk1, uploadtree_fk2 FROM file_picker
158 WHERE user_fk=\$1 AND (\$2=uploadtree_fk1 OR \$2=uploadtree_fk2)"
160 $result = $this->
dbManager->execute($stmt, [$user_pk, $uploadtree_pk]);
162 while ($row = $this->
dbManager->fetchArray($result)) {
163 $pickerRows[] = $row;
166 $rtncount = count($pickerRows);
172 $PickSelectArray = [];
173 foreach ($pickerRows as $PickRec) {
174 $item2 = ($PickRec[
'uploadtree_fk1'] == $uploadtree_pk)
175 ? $PickRec[
'uploadtree_fk2'] : $PickRec[
'uploadtree_fk1'];
177 $PathArray =
Dir2Path($item2, $tableName);
178 $PickSelectArray[$item2] = $this->uploadtree2PathStr($PathArray);
181 $Options =
"id=HistoryPick onchange='AppJump(this.value)'";
185 private function applicationPick(
string $SLName,
string $selectedVal,
string $label): string
188 "multicompare" => _(
"Upload Comparison"),
189 "nomosdiff" => _(
"License Difference (2-way)"),
190 "bucketsdiff" => _(
"Bucket Difference (2-way)"),
192 $Options =
"id=apick";
193 $SelectList =
Array2SingleSelect($AppList, $SLName, $selectedVal,
false,
true, $Options);
194 return $label ?
"$SelectList $label" : $SelectList;
197 private function uploadtree2PathStr(array $PathArray): string
200 foreach ($PathArray as $PathRow) {
201 $parts[] = $PathRow[
'ufile_name'];
203 return implode(
'/', $parts);
208 protected function handle(Request $request): Response
210 $this->createFilePicker();
212 $RtnMod = $request->get(
'rtnmod',
'multicompare');
213 $uploadtree_pk = (int)($request->get(
'item', 0));
214 $folder_pk = (int)($request->get(
'folder', 0));
215 $user_pk = Auth::getUserId();
219 $rawItems = $request->get(
'items',
'');
220 if (!empty($rawItems)) {
221 $multiItems = array_values(array_unique(array_filter(
222 array_map(
'intval', explode(
',', $rawItems)), fn($v) => $v > 0
227 if ($RtnMod ===
'multicompare') {
228 if (!empty($uploadtree_pk) && !in_array($uploadtree_pk, $multiItems)) {
229 array_unshift($multiItems, $uploadtree_pk);
232 if (empty($multiItems)) {
233 return $this->flushContent(
234 "<div class='alert alert-warning'>"
235 . _(
"No component selected. Please navigate to an upload and click Compare.")
236 .
" <a href='" .
Traceback_uri() .
"?mod=browse'>" . _(
"Go to Browse") .
"</a>"
241 foreach ($multiItems as $idx => $pk) {
243 "SELECT ut.upload_fk, u.uploadtree_tablename
245 JOIN upload u ON u.upload_pk = ut.upload_fk
246 WHERE ut.uploadtree_pk = \$1",
247 [$pk], __METHOD__ .
'.permcheck'
249 if (!$row || !$this->uploadDao->isAccessible($row[
'upload_fk'], Auth::getGroupId())) {
250 return $this->flushContent(
251 "<h2>" . _(
"Permission Denied") .
" (item " . ($idx + 1) .
")</h2>"
256 if (empty($folder_pk)) {
260 if (!empty($user_pk) && count($multiItems) >= 2) {
261 $stmt = __METHOD__ .
'.insertMulti';
263 "INSERT INTO file_picker_multi (user_fk, items, last_access_date)
264 VALUES(\$1, \$2, now()) ON CONFLICT DO NOTHING"
266 $res = $this->
dbManager->execute($stmt, [$user_pk, implode(
',', $multiItems)]);
270 return $this->
renderPicker($RtnMod, $multiItems[0], $folder_pk, $multiItems);
274 if (!$uploadtree_pk) {
275 return $this->flushContent(
"<h2>" . _(
"Unidentified item 1") .
"</h2>");
278 $uploadtree_pk2 = (int)($request->get(
'item2', 0));
280 $Item1Row = $this->
dbManager->getSingleRow(
281 "SELECT ut.upload_fk, u.uploadtree_tablename
283 JOIN upload u ON u.upload_pk = ut.upload_fk
284 WHERE ut.uploadtree_pk = \$1",
285 [$uploadtree_pk], __METHOD__ .
'.item1'
287 if (!$this->uploadDao->isAccessible($Item1Row[
'upload_fk'], Auth::getGroupId())) {
288 return $this->flushContent(
"<h2>" . _(
"Permission Denied") .
" item 1</h2>");
291 if (!empty($uploadtree_pk2)) {
292 $Item2Row = $this->
dbManager->getSingleRow(
293 "SELECT ut.upload_fk, u.uploadtree_tablename
295 JOIN upload u ON u.upload_pk = ut.upload_fk
296 WHERE ut.uploadtree_pk = \$1",
297 [$uploadtree_pk2], __METHOD__ .
'.item2'
299 if (!$this->uploadDao->isAccessible($Item2Row[
'upload_fk'], Auth::getGroupId())) {
300 return $this->flushContent(
"<h2>" . _(
"Permission Denied") .
" item 2</h2>");
305 if (!empty($user_pk) && !empty($RtnMod) && $uploadtree_pk && $uploadtree_pk2) {
306 $stmt = __METHOD__ .
'.insertPicker';
308 "INSERT INTO file_picker (user_fk, uploadtree_fk1, uploadtree_fk2, last_access_date)
309 VALUES(\$1, \$2, \$3, now())"
311 $res = $this->
dbManager->execute($stmt, [$user_pk, $uploadtree_pk, $uploadtree_pk2]);
313 $uri =
Traceback_uri() .
"?mod=$RtnMod&item1=$uploadtree_pk&item2=$uploadtree_pk2";
314 return new RedirectResponse($uri);
317 if (empty($folder_pk)) {
320 return $this->
renderPicker($RtnMod, $uploadtree_pk, $folder_pk, []);
327 int $folder_pk, array $currentItems): Response
329 $isMulti = ($RtnMod ===
'multicompare');
338 if ($isMulti && !empty($currentItems)) {
339 $selectedUploadPks = [];
340 foreach ($currentItems as $utPk) {
342 "SELECT upload_fk FROM uploadtree WHERE uploadtree_pk = \$1",
343 [$utPk], __METHOD__ .
'.uploadfk'
346 $selectedUploadPks[] = intval($row[
'upload_fk']);
349 $uploads = array_values(array_filter(
350 $uploads, fn($u) => !in_array($u[
'upload_pk'], $selectedUploadPks)
355 $appPicker = $this->applicationPick(
356 "PickRtnApp", $RtnMod,
357 $isMulti ?
"" : _(
"will run after choosing a file")
361 'isMulti' => $isMulti,
362 'currentItems' => $currentItems,
363 'folderOptions' => $folderOptions,
364 'uploads' => $uploads,
365 'appPicker' => $appPicker,
367 'currentItemsJson' =>
"[" . implode(
",", array_map(
'intval', $currentItems)) .
"]",
368 'folderPk' => $folder_pk,
369 'anchorPk' => $anchorPk,
375 $count = count($currentItems);
378 $vars[
'compareUri'] = $count >= 2
379 ? htmlspecialchars(
Traceback_uri() .
"?mod=multicompare&items="
380 . implode(
",", $currentItems))
386 foreach ($currentItems as $pk) {
388 $pathArr =
Dir2Path($pk, $tableName);
389 $selectedPaths[$pk] = $this->uploadtree2PathStr($pathArr);
390 $remaining = array_values(array_filter($currentItems, fn($p) => $p !== $pk));
391 $removeUri = $uri .
"&rtnmod=$RtnMod&folder=$folder_pk";
392 if (!empty($remaining)) {
393 $removeUri .=
"&items=" . implode(
',', $remaining);
395 $removeUris[$pk] = htmlspecialchars($removeUri);
397 $vars[
'selectedPaths'] = $selectedPaths;
398 $vars[
'removeUris'] = $removeUris;
399 $vars[
'hint'] = $count < 2
400 ? _(
"Select at least 2 components to compare.")
401 : _(
"Add more components below, or click Compare Now.");
402 $vars[
'browseHint'] = _(
"Choose a folder, then click Add next to an upload.");
405 $pathStr = $this->uploadtree2PathStr(
Dir2Path($anchorPk, $tableName));
406 $vars[
'pathStr'] = htmlspecialchars($pathStr);
407 $vars[
'browseHint'] = _(
"Choose a folder, then click Select to pick File 2.");
410 $historyPick = $this->
historyPick($anchorPk, $historyCount);
411 $vars[
'historyPick'] = $historyPick;
412 $vars[
'historyCount'] = $historyCount;
415 return $this->
render(
'picker.html.twig', $this->mergeWithDefault($vars));
Contains the constants and helpers for authentication of user.
render($templateName, $vars=null, $headers=null)
getFolderUploads(int $folder_pk)
getUploadtreeTableName(int $uploadtreePk)
renderPicker(string $RtnMod, int $anchorPk, int $folder_pk, array $currentItems)
historyPick(int $uploadtree_pk, int &$rtncount)
Dir2Path($uploadtree_pk, $uploadtree_tablename='uploadtree')
Return the path (without artifacts) of an uploadtree_pk.
FolderListOption($ParentFolder, $Depth, $IncludeTop=1, $SelectId=-1, $linkParent=false, $OldParent=0)
Create the folder tree, using OPTION tags.
GetFolderFromItem($upload_pk="", $uploadtree_pk="")
Find what folder an item is in.
FolderGetTop()
DEPRECATED! Find the top-of-tree folder_pk for the current user.
Traceback_uri()
Get the URI without query to this location.
Array2SingleSelect($KeyValArray, $SLName="unnamed", $SelectedVal="", $FirstEmpty=false, $SelElt=true, $Options="", $ReturnKey=true)
Build a single choice select pulldown.
Convert2BrowserTime($server_time)
Convert the server time to browser time.
#define PERM_READ
Read-only permission.
fo_dbManager * dbManager
fo_dbManager object