mirror of
https://github.com/discourse/discourse.git
synced 2025-02-23 15:57:41 +08:00
FEATURE: Change all core to use uppy-image-uploader (#14428)
Instead of using image-uploader, which relies on the old UploadMixin, we can now use the uppy-image-uploader which uses the new UppyUploadMixin which is stable enough and supports both regular XHR uploads and direct S3 uploads, controlled by a site setting (default to XHR). At some point it may make sense to rename uppy-image-uploader back to image-uploader, once we have gone through plugins etc. and given a bit of deprecation time period. This commit also fixes `for_private_message`, `for_site_setting`, and `pasted` flags not being sent via uppy uploads onto the UploadCreator, both via regular XHR uploads and also through external/multipart uploads. The uploaders changed are: * site setting images * badge images * category logo * category background * group flair * profile background * profile card background
This commit is contained in:
parent
92afa74d92
commit
2364626ded
@ -1,6 +0,0 @@
|
|||||||
import ImageUploader from "discourse/components/image-uploader";
|
|
||||||
|
|
||||||
export default ImageUploader.extend({
|
|
||||||
layoutName: "components/image-uploader",
|
|
||||||
uploadUrlParams: "&for_site_setting=true",
|
|
||||||
});
|
|
@ -40,12 +40,14 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
{{#if imageUploaderSelected}}
|
{{#if imageUploaderSelected}}
|
||||||
{{image-uploader
|
{{uppy-image-uploader
|
||||||
|
id="badge-image-uploader"
|
||||||
imageUrl=buffered.image_url
|
imageUrl=buffered.image_url
|
||||||
|
type="badge_image"
|
||||||
onUploadDone=(action "setImage")
|
onUploadDone=(action "setImage")
|
||||||
onUploadDeleted=(action "removeImage")
|
onUploadDeleted=(action "removeImage")
|
||||||
type="badge_image"
|
class="no-repeat contain-image"
|
||||||
class="no-repeat contain-image"}}
|
}}
|
||||||
<div class="control-instructions">
|
<div class="control-instructions">
|
||||||
<p class="help">{{i18n "admin.badges.image_help"}}</p>
|
<p class="help">{{i18n "admin.badges.image_help"}}</p>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,2 +1,8 @@
|
|||||||
{{site-settings-image-uploader imageUrl=value placeholderUrl=setting.placeholder type="site_setting"}}
|
{{uppy-image-uploader
|
||||||
|
imageUrl=value
|
||||||
|
placeholderUrl=setting.placeholder
|
||||||
|
additionalParams=(hash for_site_setting=true)
|
||||||
|
type="site_setting"
|
||||||
|
id=(concat "site-setting-image-uploader-" setting.setting)
|
||||||
|
}}
|
||||||
<div class="desc">{{html-safe setting.description}}</div>
|
<div class="desc">{{html-safe setting.description}}</div>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import Component from "@ember/component";
|
import Component from "@ember/component";
|
||||||
|
import deprecated from "discourse-common/lib/deprecated";
|
||||||
import UploadMixin from "discourse/mixins/upload";
|
import UploadMixin from "discourse/mixins/upload";
|
||||||
import { ajax } from "discourse/lib/ajax";
|
import { ajax } from "discourse/lib/ajax";
|
||||||
import discourseComputed from "discourse-common/utils/decorators";
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
@ -14,6 +15,10 @@ export default Component.extend(UploadMixin, {
|
|||||||
|
|
||||||
init() {
|
init() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
|
// TODO (martin) (2022-01-22) Remove this component.
|
||||||
|
deprecated(
|
||||||
|
"image-uploader will be removed in a future version, use uppy-image-uploader instead (the API is the same)"
|
||||||
|
);
|
||||||
this._applyLightbox();
|
this._applyLightbox();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -69,8 +69,6 @@ export default Component.extend(UppyUploadMixin, {
|
|||||||
|
|
||||||
uploadDone(upload) {
|
uploadDone(upload) {
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
imageUrl: upload.url,
|
|
||||||
imageId: upload.id,
|
|
||||||
imageFilesize: upload.human_filesize,
|
imageFilesize: upload.human_filesize,
|
||||||
imageFilename: upload.original_filename,
|
imageFilename: upload.original_filename,
|
||||||
imageWidth: upload.width,
|
imageWidth: upload.width,
|
||||||
@ -79,8 +77,13 @@ export default Component.extend(UppyUploadMixin, {
|
|||||||
|
|
||||||
this._applyLightbox();
|
this._applyLightbox();
|
||||||
|
|
||||||
|
// the value of the property used for imageUrl should be set
|
||||||
|
// in this callback. this should be done in cases where imageUrl
|
||||||
|
// is bound to a computed property of the parent component.
|
||||||
if (this.onUploadDone) {
|
if (this.onUploadDone) {
|
||||||
this.onUploadDone(upload);
|
this.onUploadDone(upload);
|
||||||
|
} else {
|
||||||
|
this.set("imageUrl", upload.url);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -123,13 +126,16 @@ export default Component.extend(UppyUploadMixin, {
|
|||||||
},
|
},
|
||||||
|
|
||||||
trash() {
|
trash() {
|
||||||
this.setProperties({ imageUrl: null, imageId: null });
|
|
||||||
|
|
||||||
// uppy needs to be reset to allow for more uploads
|
// uppy needs to be reset to allow for more uploads
|
||||||
this._reset();
|
this._reset();
|
||||||
|
|
||||||
|
// the value of the property used for imageUrl should be cleared
|
||||||
|
// in this callback. this should be done in cases where imageUrl
|
||||||
|
// is bound to a computed property of the parent component.
|
||||||
if (this.onUploadDeleted) {
|
if (this.onUploadDeleted) {
|
||||||
this.onUploadDeleted();
|
this.onUploadDeleted();
|
||||||
|
} else {
|
||||||
|
this.setProperties({ imageUrl: null });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -68,10 +68,6 @@ export default Controller.extend({
|
|||||||
"model.can_upload_user_card_background"
|
"model.can_upload_user_card_background"
|
||||||
),
|
),
|
||||||
|
|
||||||
experimentalUserCardImageUpload: readOnly(
|
|
||||||
"siteSettings.enable_experimental_image_uploader"
|
|
||||||
),
|
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
showFeaturedTopicModal() {
|
showFeaturedTopicModal() {
|
||||||
showModal("feature-topic-on-profile", {
|
showModal("feature-topic-on-profile", {
|
||||||
|
@ -136,7 +136,6 @@ export default Mixin.create(ExtendableUploader, {
|
|||||||
this._instrumentUploadTimings();
|
this._instrumentUploadTimings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// hidden setting like enable_experimental_image_uploader
|
|
||||||
if (this.siteSettings.enable_direct_s3_uploads) {
|
if (this.siteSettings.enable_direct_s3_uploads) {
|
||||||
this._useS3MultipartUploads();
|
this._useS3MultipartUploads();
|
||||||
} else {
|
} else {
|
||||||
@ -482,6 +481,8 @@ export default Mixin.create(ExtendableUploader, {
|
|||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
parts,
|
parts,
|
||||||
unique_identifier: file.meta.unique_identifier,
|
unique_identifier: file.meta.unique_identifier,
|
||||||
|
pasted: file.meta.pasted,
|
||||||
|
for_private_message: file.meta.for_private_message,
|
||||||
}),
|
}),
|
||||||
// uppy is inconsistent, an error here fires the upload-error event
|
// uppy is inconsistent, an error here fires the upload-error event
|
||||||
}).then((responseData) => {
|
}).then((responseData) => {
|
||||||
@ -570,14 +571,14 @@ export default Mixin.create(ExtendableUploader, {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event && event.clipboardData && event.clipboardData.files) {
|
if (event && event.clipboardData && event.clipboardData.files) {
|
||||||
this._addFiles([...event.clipboardData.files]);
|
this._addFiles([...event.clipboardData.files], { pasted: true });
|
||||||
}
|
}
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
this.element.addEventListener("paste", this.pasteEventListener);
|
this.element.addEventListener("paste", this.pasteEventListener);
|
||||||
},
|
},
|
||||||
|
|
||||||
_addFiles(files) {
|
_addFiles(files, opts = {}) {
|
||||||
files = Array.isArray(files) ? files : [files];
|
files = Array.isArray(files) ? files : [files];
|
||||||
try {
|
try {
|
||||||
this._uppyInstance.addFiles(
|
this._uppyInstance.addFiles(
|
||||||
@ -587,6 +588,7 @@ export default Mixin.create(ExtendableUploader, {
|
|||||||
name: file.name,
|
name: file.name,
|
||||||
type: file.type,
|
type: file.type,
|
||||||
data: file,
|
data: file,
|
||||||
|
meta: { pasted: opts.pasted },
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -25,10 +25,6 @@ export default Mixin.create({
|
|||||||
autoStartUploads: true,
|
autoStartUploads: true,
|
||||||
id: null,
|
id: null,
|
||||||
|
|
||||||
// TODO (martin): this is only used in one place, consider just using
|
|
||||||
// form data/meta instead uploadUrlParams: "&for_site_setting=true",
|
|
||||||
uploadUrlParams: "",
|
|
||||||
|
|
||||||
// TODO (martin): currently used for backups to turn on auto upload and PUT/XML requests
|
// TODO (martin): currently used for backups to turn on auto upload and PUT/XML requests
|
||||||
// and for emojis to do sequential uploads, when we get to replacing those
|
// and for emojis to do sequential uploads, when we get to replacing those
|
||||||
// with uppy make sure this is used when initializing uppy
|
// with uppy make sure this is used when initializing uppy
|
||||||
@ -83,7 +79,11 @@ export default Mixin.create({
|
|||||||
|
|
||||||
// need to use upload_type because uppy overrides type with the
|
// need to use upload_type because uppy overrides type with the
|
||||||
// actual file type
|
// actual file type
|
||||||
meta: deepMerge({ upload_type: this.type }, this.data || {}),
|
meta: deepMerge(
|
||||||
|
{ upload_type: this.type },
|
||||||
|
this.additionalParams || {},
|
||||||
|
this.data || {}
|
||||||
|
),
|
||||||
|
|
||||||
onBeforeFileAdded: (currentFile) => {
|
onBeforeFileAdded: (currentFile) => {
|
||||||
const validationOpts = deepMerge(
|
const validationOpts = deepMerge(
|
||||||
@ -160,7 +160,6 @@ export default Mixin.create({
|
|||||||
this._reset();
|
this._reset();
|
||||||
});
|
});
|
||||||
|
|
||||||
// hidden setting like enable_experimental_image_uploader
|
|
||||||
if (this.siteSettings.enable_direct_s3_uploads) {
|
if (this.siteSettings.enable_direct_s3_uploads) {
|
||||||
this._useS3Uploads();
|
this._useS3Uploads();
|
||||||
} else {
|
} else {
|
||||||
@ -224,8 +223,7 @@ export default Mixin.create({
|
|||||||
return (
|
return (
|
||||||
getUrl(this.getWithDefault("uploadUrl", "/uploads")) +
|
getUrl(this.getWithDefault("uploadUrl", "/uploads")) +
|
||||||
".json?client_id=" +
|
".json?client_id=" +
|
||||||
(this.messageBus && this.messageBus.clientId) +
|
this.messageBus?.clientId
|
||||||
this.uploadUrlParams
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -252,9 +250,10 @@ export default Mixin.create({
|
|||||||
_completeExternalUpload(file) {
|
_completeExternalUpload(file) {
|
||||||
return ajax(getUrl("/uploads/complete-external-upload"), {
|
return ajax(getUrl("/uploads/complete-external-upload"), {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: {
|
data: deepMerge(
|
||||||
unique_identifier: file.meta.uniqueUploadIdentifier,
|
{ unique_identifier: file.meta.uniqueUploadIdentifier },
|
||||||
},
|
this.additionalParams || {}
|
||||||
|
),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,18 +1,22 @@
|
|||||||
<section class="field category-logo">
|
<section class="field category-logo">
|
||||||
<label>{{i18n "category.logo"}}</label>
|
<label>{{i18n "category.logo"}}</label>
|
||||||
{{image-uploader
|
{{uppy-image-uploader
|
||||||
imageUrl=logoImageUrl
|
imageUrl=logoImageUrl
|
||||||
onUploadDone=(action "logoUploadDone")
|
onUploadDone=(action "logoUploadDone")
|
||||||
onUploadDeleted=(action "logoUploadDeleted")
|
onUploadDeleted=(action "logoUploadDeleted")
|
||||||
type="category_logo"
|
type="category_logo"
|
||||||
class="no-repeat contain-image"}}
|
class="no-repeat contain-image"
|
||||||
|
id="category-logo-uploader"
|
||||||
|
}}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="field category-background-image">
|
<section class="field category-background-image">
|
||||||
<label>{{i18n "category.background_image"}}</label>
|
<label>{{i18n "category.background_image"}}</label>
|
||||||
{{image-uploader
|
{{uppy-image-uploader
|
||||||
imageUrl=backgroundImageUrl
|
imageUrl=backgroundImageUrl
|
||||||
onUploadDone=(action "backgroundUploadDone")
|
onUploadDone=(action "backgroundUploadDone")
|
||||||
onUploadDeleted=(action "backgroundUploadDeleted")
|
onUploadDeleted=(action "backgroundUploadDeleted")
|
||||||
type="category_background"}}
|
type="category_background"
|
||||||
|
id="category-background-uploader"
|
||||||
|
}}
|
||||||
</section>
|
</section>
|
||||||
|
@ -21,11 +21,12 @@
|
|||||||
onChange=(action (mut model.flair_icon))
|
onChange=(action (mut model.flair_icon))
|
||||||
}}
|
}}
|
||||||
{{else if flairPreviewImage}}
|
{{else if flairPreviewImage}}
|
||||||
{{image-uploader
|
{{uppy-image-uploader
|
||||||
imageUrl=flairImageUrl
|
imageUrl=flairImageUrl
|
||||||
onUploadDone=(action "setFlairImage")
|
onUploadDone=(action "setFlairImage")
|
||||||
onUploadDeleted=(action "removeFlairImage")
|
onUploadDeleted=(action "removeFlairImage")
|
||||||
type="group_flair"
|
type="group_flair"
|
||||||
|
id="group-flair-uploader"
|
||||||
class="no-repeat contain-image"}}
|
class="no-repeat contain-image"}}
|
||||||
<div class="control-instructions">
|
<div class="control-instructions">
|
||||||
{{i18n "groups.flair_upload_description"}}
|
{{i18n "groups.flair_upload_description"}}
|
||||||
|
@ -47,8 +47,11 @@
|
|||||||
<div class="control-group pref-profile-bg">
|
<div class="control-group pref-profile-bg">
|
||||||
<label class="control-label">{{i18n "user.change_profile_background.title"}}</label>
|
<label class="control-label">{{i18n "user.change_profile_background.title"}}</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{image-uploader imageUrl=model.profile_background_upload_url
|
{{uppy-image-uploader
|
||||||
type="profile_background"}}
|
imageUrl=model.profile_background_upload_url
|
||||||
|
type="profile_background"
|
||||||
|
id="profile-background-uploader"
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
<div class="instructions">
|
<div class="instructions">
|
||||||
{{i18n "user.change_profile_background.instructions"}}
|
{{i18n "user.change_profile_background.instructions"}}
|
||||||
@ -59,15 +62,11 @@
|
|||||||
<div class="control-group pref-profile-bg">
|
<div class="control-group pref-profile-bg">
|
||||||
<label class="control-label">{{i18n "user.change_card_background.title"}}</label>
|
<label class="control-label">{{i18n "user.change_card_background.title"}}</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{#if experimentalUserCardImageUpload}}
|
|
||||||
{{uppy-image-uploader
|
{{uppy-image-uploader
|
||||||
imageUrl=model.card_background_upload_url
|
imageUrl=model.card_background_upload_url
|
||||||
type="card_background"
|
type="card_background"
|
||||||
id="profile-card-background"
|
id="profile-card-background-uploader"
|
||||||
}}
|
}}
|
||||||
{{else}}
|
|
||||||
{{image-uploader imageUrl=model.card_background_upload_url type="card_background"}}
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="instructions">
|
<div class="instructions">
|
||||||
{{i18n "user.change_card_background.instructions"}}
|
{{i18n "user.change_card_background.instructions"}}
|
||||||
|
@ -253,7 +253,13 @@ class UploadsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def complete_external_upload_via_manager(external_upload_stub)
|
def complete_external_upload_via_manager(external_upload_stub)
|
||||||
external_upload_manager = ExternalUploadManager.new(external_upload_stub)
|
opts = {
|
||||||
|
for_private_message: params[:for_private_message]&.to_s == "true",
|
||||||
|
for_site_setting: params[:for_site_setting]&.to_s == "true",
|
||||||
|
pasted: params[:pasted]&.to_s == "true",
|
||||||
|
}
|
||||||
|
|
||||||
|
external_upload_manager = ExternalUploadManager.new(external_upload_stub, opts)
|
||||||
hijack do
|
hijack do
|
||||||
begin
|
begin
|
||||||
upload = external_upload_manager.promote_to_upload!
|
upload = external_upload_manager.promote_to_upload!
|
||||||
|
@ -20,8 +20,9 @@ class ExternalUploadManager
|
|||||||
Discourse.redis.get("#{BAN_USER_REDIS_PREFIX}#{user.id}") == "1"
|
Discourse.redis.get("#{BAN_USER_REDIS_PREFIX}#{user.id}") == "1"
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(external_upload_stub)
|
def initialize(external_upload_stub, upload_create_opts = {})
|
||||||
@external_upload_stub = external_upload_stub
|
@external_upload_stub = external_upload_stub
|
||||||
|
@upload_create_opts = upload_create_opts
|
||||||
end
|
end
|
||||||
|
|
||||||
def can_promote?
|
def can_promote?
|
||||||
@ -67,18 +68,13 @@ class ExternalUploadManager
|
|||||||
end
|
end
|
||||||
|
|
||||||
# TODO (martin): See if these additional opts will be needed
|
# TODO (martin): See if these additional opts will be needed
|
||||||
#
|
# - check if retain_hours is needed
|
||||||
# for_private_message: for_private_message,
|
|
||||||
# for_site_setting: for_site_setting,
|
|
||||||
# pasted: pasted,
|
|
||||||
#
|
|
||||||
# also check if retain_hours is needed
|
|
||||||
opts = {
|
opts = {
|
||||||
type: external_upload_stub.upload_type,
|
type: external_upload_stub.upload_type,
|
||||||
existing_external_upload_key: external_upload_stub.key,
|
existing_external_upload_key: external_upload_stub.key,
|
||||||
external_upload_too_big: external_size > DOWNLOAD_LIMIT,
|
external_upload_too_big: external_size > DOWNLOAD_LIMIT,
|
||||||
filesize: external_size
|
filesize: external_size
|
||||||
}
|
}.merge(@upload_create_opts)
|
||||||
|
|
||||||
UploadCreator.new(tempfile, external_upload_stub.original_filename, opts).create_for(
|
UploadCreator.new(tempfile, external_upload_stub.original_filename, opts).create_for(
|
||||||
external_upload_stub.created_by_id
|
external_upload_stub.created_by_id
|
||||||
|
@ -0,0 +1,14 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class RemoveEnableExperimentalImageUploaderSiteSetting < ActiveRecord::Migration[6.1]
|
||||||
|
def up
|
||||||
|
execute <<~SQL
|
||||||
|
DELETE FROM site_settings
|
||||||
|
WHERE name = 'enable_experimental_image_uploader'
|
||||||
|
SQL
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
raise ActiveRecord::IrreversibleMigration
|
||||||
|
end
|
||||||
|
end
|
Loading…
x
Reference in New Issue
Block a user