Add support for an extension based filter
authorAlexander Ebert <ebert@woltlab.com>
Sun, 28 Jan 2024 19:09:15 +0000 (20:09 +0100)
committerAlexander Ebert <ebert@woltlab.com>
Sat, 8 Jun 2024 10:19:38 +0000 (12:19 +0200)
ts/WoltLabSuite/WebComponent/woltlab-core-file-upload.ts
wcfsetup/install/files/js/WoltLabSuite/WebComponent.min.js
wcfsetup/install/files/lib/system/file/processor/AttachmentFileProcessor.class.php
wcfsetup/install/files/lib/system/file/processor/FileProcessor.class.php
wcfsetup/install/files/lib/system/file/processor/IFileProcessor.class.php

index df0752c19e764339c900108b1a5f7774e873e0d8..413ce7dbf1b79c737f1a0013205c5f41365d697a 100644 (file)
     }
 
     connectedCallback() {
+      const allowedFileExtensions = this.dataset.fileExtensions || "";
+      if (allowedFileExtensions !== "") {
+        this.#element.accept = allowedFileExtensions;
+      }
+
       const shadow = this.attachShadow({ mode: "open" });
       shadow.append(this.#element);
 
index 5b4f135b95b24ce5101357305ce7f5828b1ed49d..f442038ca3181ee5654e70b8b3bc47dc80f085d8 100644 (file)
@@ -60,7 +60,7 @@ Expecting `+Z.join(", ")+", got '"+(this.terminals_[T]||T)+"'":ae="Parse error o
             time::after {
               content: " (" attr(title) ")";
             }
-          }`,x.append(D)}m&&(this.#a.dateTime=p.toISOString(),this.#a.title=g.DateAndTime.format(p));let k;if(this.static)k=this.#a.title;else if(E<w.OneMinute)k=window.WoltLabLanguage.getPhrase("wcf.date.relative.now");else if(E<w.OneHour){let x=Math.trunc(E/w.OneMinute);k=g.Minutes.format(x*-1,"minute")}else if(E<w.TwelveHours){let x=Math.trunc(E/w.OneHour);k=g.Hours.format(x*-1,"hour")}else if(E<w.SixDays){let x=g.DayOfWeekAndTime.formatToParts(p);x[0].type==="weekday"?p.getTime()>t?k=this.#t(x,0):p.getTime()>a?k=this.#t(x,-1):k=x.map(W=>W.value).join(""):k=g.DateAndTime.format(p)}else k=g.Date.format(p);k=k.charAt(0).toUpperCase()+k.slice(1),this.#a.textContent=k}#t(m,p){return m.map(k=>k.type==="weekday"?g.TodayOrYesterday.format(p,"day"):k.value).join("")}}window.customElements.define("woltlab-core-date-time",q);let S=()=>{document.querySelectorAll("woltlab-core-date-time").forEach(h=>h.refresh(!1))},z,P=()=>{z=window.setInterval(()=>{l(),S()},6e4)};document.addEventListener("DOMContentLoaded",()=>P(),{once:!0}),document.addEventListener("visibilitychange",()=>{document.hidden?window.clearInterval(z):(S(),P())})}{class e extends HTMLElement{#e;constructor(){super(),this.#e=document.createElement("input"),this.#e.type="file",this.#e.addEventListener("change",()=>{let{files:i}=this.#e;if(!(i===null||i.length===0))for(let c of i){let t=new CustomEvent("shouldUpload",{cancelable:!0,detail:c});if(this.dispatchEvent(t),t.defaultPrevented)continue;let a=new CustomEvent("upload",{detail:c});this.dispatchEvent(a)}})}connectedCallback(){this.attachShadow({mode:"open"}).append(this.#e);let c=document.createElement("style");c.textContent=`
+          }`,x.append(D)}m&&(this.#a.dateTime=p.toISOString(),this.#a.title=g.DateAndTime.format(p));let k;if(this.static)k=this.#a.title;else if(E<w.OneMinute)k=window.WoltLabLanguage.getPhrase("wcf.date.relative.now");else if(E<w.OneHour){let x=Math.trunc(E/w.OneMinute);k=g.Minutes.format(x*-1,"minute")}else if(E<w.TwelveHours){let x=Math.trunc(E/w.OneHour);k=g.Hours.format(x*-1,"hour")}else if(E<w.SixDays){let x=g.DayOfWeekAndTime.formatToParts(p);x[0].type==="weekday"?p.getTime()>t?k=this.#t(x,0):p.getTime()>a?k=this.#t(x,-1):k=x.map(W=>W.value).join(""):k=g.DateAndTime.format(p)}else k=g.Date.format(p);k=k.charAt(0).toUpperCase()+k.slice(1),this.#a.textContent=k}#t(m,p){return m.map(k=>k.type==="weekday"?g.TodayOrYesterday.format(p,"day"):k.value).join("")}}window.customElements.define("woltlab-core-date-time",q);let S=()=>{document.querySelectorAll("woltlab-core-date-time").forEach(h=>h.refresh(!1))},z,P=()=>{z=window.setInterval(()=>{l(),S()},6e4)};document.addEventListener("DOMContentLoaded",()=>P(),{once:!0}),document.addEventListener("visibilitychange",()=>{document.hidden?window.clearInterval(z):(S(),P())})}{class e extends HTMLElement{#e;constructor(){super(),this.#e=document.createElement("input"),this.#e.type="file",this.#e.addEventListener("change",()=>{let{files:i}=this.#e;if(!(i===null||i.length===0))for(let c of i){let t=new CustomEvent("shouldUpload",{cancelable:!0,detail:c});if(this.dispatchEvent(t),t.defaultPrevented)continue;let a=new CustomEvent("upload",{detail:c});this.dispatchEvent(a)}})}connectedCallback(){let i=this.dataset.fileExtensions||"";i!==""&&(this.#e.accept=i),this.attachShadow({mode:"open"}).append(this.#e);let t=document.createElement("style");t.textContent=`
         :host {
             position: relative;
         }
index b327e5c2fd4fff791304b86a89832d9fe33a09d8..2c10b31ee1567599d65d4c61bda6bb5132ee9563 100644 (file)
@@ -17,6 +17,19 @@ final class AttachmentFileProcessor implements IFileProcessor
         return 'com.woltlab.wcf.attachment';
     }
 
+    public function getAllowedFileExtensions(array $context): array
+    {
+        // TODO: Properly validate the shape of `$context`.
+        $objectType = $context['objectType'] ?? '';
+        $objectID = \intval($context['objectID'] ?? 0);
+        $parentObjectID = \intval($context['parentObjectID'] ?? 0);
+        $tmpHash = $context['tmpHash'] ?? '';
+
+        $attachmentHandler = new AttachmentHandler($objectType, $objectID, $tmpHash, $parentObjectID);
+
+        return $attachmentHandler->getAllowedExtensions();
+    }
+
     public function acceptUpload(string $filename, int $fileSize, array $context): FileProcessorPreflightResult
     {
         // TODO: Properly validate the shape of `$context`.
index 2ed15e41d1f77e62f2096a7743554218dea66d9b..311092be5bfa6bd25368c1cd8b1a50a6cba65b4b 100644 (file)
@@ -40,17 +40,32 @@ final class FileProcessor extends SingletonFactory
     {
         $endpoint = LinkHandler::getInstance()->getControllerLink(FileUploadPreflightAction::class);
 
+        $allowedFileExtensions = $fileProcessor->getAllowedFileExtensions($context);
+        if (\in_array('*', $allowedFileExtensions)) {
+            $allowedFileExtensions = '';
+        } else {
+            $allowedFileExtensions = \implode(
+                ',',
+                \array_map(
+                    static fn (string $fileExtension) => ".{$fileExtension}",
+                    $allowedFileExtensions
+                )
+            );
+        }
+
         return \sprintf(
             <<<'HTML'
                 <woltlab-core-file-upload
                     data-endpoint="%s"
                     data-type-name="%s"
                     data-context="%s"
+                    data-file-extensions="%s"
                 ></woltlab-core-file-upload>
                 HTML,
             StringUtil::encodeHTML($endpoint),
             StringUtil::encodeHTML($fileProcessor->getTypeName()),
             StringUtil::encodeHTML(JSON::encode($context)),
+            StringUtil::encodeHTML($allowedFileExtensions),
         );
     }
 }
index 52cb5da6124fbbf5433b4b3d39f8e14bf3d8c685..2184892f4918264aaa5376a43204b444191bc2af 100644 (file)
@@ -10,7 +10,9 @@ namespace wcf\system\file\processor;
  */
 interface IFileProcessor
 {
-    public function getTypeName(): string;
-
     public function acceptUpload(string $filename, int $fileSize, array $context): FileProcessorPreflightResult;
+
+    public function getAllowedFileExtensions(array $context): array;
+
+    public function getTypeName(): string;
 }