FEATURE: pass supported file extensions to the system file picker (#13583)

FEATURE: pass supported file extensions to the system file picker (#13583)

diff --git a/app/assets/javascripts/discourse/app/components/composer-editor.js b/app/assets/javascripts/discourse/app/components/composer-editor.js
index 7ce199c..ae3addd 100644
--- a/app/assets/javascripts/discourse/app/components/composer-editor.js
+++ b/app/assets/javascripts/discourse/app/components/composer-editor.js
@@ -1,4 +1,6 @@
 import {
+  authorizedExtensions,
+  authorizesAllExtensions,
   authorizesOneOrMoreImageExtensions,
   displayErrorForUpload,
   getUploadMarkdown,
@@ -200,6 +202,21 @@ export default Component.extend({
     });
   },
 
+  @discourseComputed()
+  acceptsAllFormats() {
+    return authorizesAllExtensions(this.currentUser.staff, this.siteSettings);
+  },
+
+  @discourseComputed()
+  acceptedFormats() {
+    const extensions = authorizedExtensions(
+      this.currentUser.staff,
+      this.siteSettings
+    );
+
+    return extensions.map((ext) => `.${ext}`).join();
+  },
+
   @on("didInsertElement")
   _composerEditorInit() {
     const $input = $(this.element.querySelector(".d-editor-input"));
diff --git a/app/assets/javascripts/discourse/app/lib/uploads.js b/app/assets/javascripts/discourse/app/lib/uploads.js
index 9470354..99d1127 100644
--- a/app/assets/javascripts/discourse/app/lib/uploads.js
+++ b/app/assets/javascripts/discourse/app/lib/uploads.js
@@ -97,7 +97,10 @@ function validateUploadedFile(file, opts) {
     ) {
       bootbox.alert(
         I18n.t("post.errors.upload_not_authorized", {
-          authorized_extensions: authorizedExtensions(staff, opts.siteSettings),
+          authorized_extensions: authorizedExtensions(
+            staff,
+            opts.siteSettings
+          ).join(", "),
         })
       );
       return false;
@@ -177,7 +180,7 @@ export function authorizedExtensions(staff, siteSettings) {
   const exts = staff
     ? [...extensions(siteSettings), ...staffExtensions(siteSettings)]
     : extensions(siteSettings);
-  return exts.filter((ext) => ext.length > 0).join(", ");
+  return exts.filter((ext) => ext.length > 0);
 }
 
 function authorizedImagesExtensions(staff, siteSettings) {
@@ -230,14 +233,16 @@ function uploadTypeFromFileName(fileName) {
 export function allowsImages(staff, siteSettings) {
   return (
     authorizesAllExtensions(staff, siteSettings) ||
-    IMAGES_EXTENSIONS_REGEX.test(authorizedExtensions(staff, siteSettings))
+    IMAGES_EXTENSIONS_REGEX.test(
+      authorizedExtensions(staff, siteSettings).join()
+    )
   );
 }
 
 export function allowsAttachments(staff, siteSettings) {
   return (
     authorizesAllExtensions(staff, siteSettings) ||
-    authorizedExtensions(staff, siteSettings).split(", ").length >
+    authorizedExtensions(staff, siteSettings).length >
       imagesExtensions(staff, siteSettings).length
   );
 }
diff --git a/app/assets/javascripts/discourse/app/templates/components/composer-editor.hbs b/app/assets/javascripts/discourse/app/templates/components/composer-editor.hbs
index 7375710..1d2aeb7 100644
--- a/app/assets/javascripts/discourse/app/templates/components/composer-editor.hbs
+++ b/app/assets/javascripts/discourse/app/templates/components/composer-editor.hbs
@@ -19,4 +19,10 @@
   disabled=disableTextarea
   outletArgs=(hash composer=composer editorType="composer")}}
 
-<input type="file" id="file-uploader" multiple>
+{{#if allowUpload}}
+  {{#if acceptsAllFormats}}
+    <input type="file" id="file-uploader" multiple>
+  {{else}}
+    <input type="file" id="file-uploader" accept={{acceptedFormats}} multiple>
+  {{/if}}
+{{/if}}
diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js
index 1413cd5..4bd4eec 100644
--- a/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js
+++ b/app/assets/javascripts/discourse/tests/acceptance/composer-attachment-test.js
@@ -1,5 +1,6 @@
 import {
   acceptance,
+  exists,
   query,
   queryAll,
 } from "discourse/tests/helpers/qunit-helpers";
@@ -253,3 +254,40 @@ acceptance("Composer Attachment - Upload Placeholder", function (needs) {
     };
   }
 });
+
+acceptance("Composer Attachment - File input", function (needs) {
+  needs.user();
+
+  test("shouldn't add to DOM the hidden file input if uploads aren't allowed", async function (assert) {
+    this.siteSettings.authorized_extensions = "";
+    await visit("/");
+    await click("#create-topic");
+
+    assert.notOk(exists("input#file-uploader"));
+  });
+
+  test("should fill the accept attribute with allowed file extensions", async function (assert) {
+    this.siteSettings.authorized_extensions = "jpg|jpeg|png";
+    await visit("/");
+    await click("#create-topic");
+
+    assert.ok(exists("input#file-uploader"), "An input is rendered");
+    assert.equal(
+      query("input#file-uploader").accept,
+      ".jpg,.jpeg,.png",
+      "Accepted values are correct"
+    );
+  });
+
+  test("the hidden file input shouldn't have the accept attribute if any file extension is allowed", async function (assert) {
+    this.siteSettings.authorized_extensions = "jpg|jpeg|png|*";
+    await visit("/");
+    await click("#create-topic");
+
+    assert.ok(exists("input#file-uploader"), "An input is rendered");
+    assert.notOk(
+      query("input#file-uploader").hasAttribute("accept"),
+      "The input doesn't contain the accept attribute"
+    );
+  });
+});
diff --git a/app/assets/javascripts/discourse/tests/unit/lib/uploads-test.js b/app/assets/javascripts/discourse/tests/unit/lib/uploads-test.js
index 02be685..8e316cf 100644
--- a/app/assets/javascripts/discourse/tests/unit/lib/uploads-test.js
+++ b/app/assets/javascripts/discourse/tests/unit/lib/uploads-test.js
@@ -110,7 +110,10 @@ discourseModule("Unit | Utility | uploads", function () {
     assert.ok(
       bootbox.alert.calledWith(
         I18n.t("post.errors.upload_not_authorized", {
-          authorized_extensions: authorizedExtensions(false, this.siteSettings),
+          authorized_extensions: authorizedExtensions(
+            false,
+            this.siteSettings
+          ).join(", "),
         })
       )
     );

GitHub sha: 1c38b4abf1fab8d67aaaa4b9f2810add64b709c4

This commit appears in #13583 which was approved by eviltrout, pmusaraj, and martin. It was merged by AndrewPrigorshnev.