UX: ensure we only allow images when uploading an avatar, user card background, etc...
This commit is contained in:
parent
5db57abd7f
commit
d8be3e8bb1
|
@ -11,6 +11,10 @@ export default Em.Component.extend(UploadMixin, {
|
|||
return uploading ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture");
|
||||
},
|
||||
|
||||
validateUploadedFilesOptions() {
|
||||
return { imagesOnly: true };
|
||||
},
|
||||
|
||||
uploadDone(upload) {
|
||||
this.setProperties({
|
||||
imageIsNotASquare: upload.width !== upload.height,
|
||||
|
|
|
@ -11,6 +11,10 @@ export default Em.Component.extend(UploadMixin, {
|
|||
return Ember.isBlank(this.get("name")) ? {} : { name: this.get("name") };
|
||||
}.property("name"),
|
||||
|
||||
validateUploadedFilesOptions() {
|
||||
return { imagesOnly: true };
|
||||
},
|
||||
|
||||
uploadDone(upload) {
|
||||
this.set("name", null);
|
||||
this.sendAction("done", upload);
|
||||
|
|
|
@ -10,6 +10,10 @@ export default Em.Component.extend(UploadMixin, {
|
|||
return `background-image: url(${imageUrl})`.htmlSafe();
|
||||
},
|
||||
|
||||
validateUploadedFilesOptions() {
|
||||
return { imagesOnly: true };
|
||||
},
|
||||
|
||||
uploadDone(upload) {
|
||||
this.set("imageUrl", upload.url);
|
||||
this.set("imageId", upload.id);
|
||||
|
|
|
@ -158,7 +158,7 @@ export function setCaretPosition(ctrl, pos) {
|
|||
}
|
||||
}
|
||||
|
||||
export function validateUploadedFiles(files, bypassNewUserRestriction) {
|
||||
export function validateUploadedFiles(files, opts) {
|
||||
if (!files || files.length === 0) { return false; }
|
||||
|
||||
if (files.length > 1) {
|
||||
|
@ -166,29 +166,43 @@ export function validateUploadedFiles(files, bypassNewUserRestriction) {
|
|||
return false;
|
||||
}
|
||||
|
||||
var upload = files[0];
|
||||
const upload = files[0];
|
||||
|
||||
// CHROME ONLY: if the image was pasted, sets its name to a default one
|
||||
if (typeof Blob !== "undefined" && typeof File !== "undefined") {
|
||||
if (upload instanceof Blob && !(upload instanceof File) && upload.type === "image/png") { upload.name = "blob.png"; }
|
||||
}
|
||||
|
||||
var type = uploadTypeFromFileName(upload.name);
|
||||
opts = opts || {};
|
||||
opts["type"] = uploadTypeFromFileName(upload.name);
|
||||
|
||||
return validateUploadedFile(upload, type, bypassNewUserRestriction);
|
||||
return validateUploadedFile(upload, opts);
|
||||
}
|
||||
|
||||
export function validateUploadedFile(file, type, bypassNewUserRestriction) {
|
||||
export function validateUploadedFile(file, opts) {
|
||||
opts = opts || {};
|
||||
|
||||
const name = file && file.name;
|
||||
|
||||
if (!name) { return false; }
|
||||
|
||||
// check that the uploaded file is authorized
|
||||
if (!authorizesAllExtensions() && !isAuthorizedUpload(file)) {
|
||||
bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedExtensions() }));
|
||||
return false;
|
||||
if (opts["imagesOnly"]) {
|
||||
if (!isAnImage(name) && !isAuthorizedImage(name)) {
|
||||
bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedImagesExtensions() }));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!authorizesAllExtensions() && !isAuthorizedFile(name)) {
|
||||
bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedExtensions() }));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bypassNewUserRestriction) {
|
||||
if (!opts["bypassNewUserRestriction"]) {
|
||||
// ensures that new users can upload a file
|
||||
if (!Discourse.User.current().isAllowedToUploadAFile(type)) {
|
||||
bootbox.alert(I18n.t('post.errors.' + type + '_upload_not_allowed_for_new_user'));
|
||||
if (!Discourse.User.current().isAllowedToUploadAFile(opts["type"])) {
|
||||
bootbox.alert(I18n.t(`post.errors.${opts["type"]}_upload_not_allowed_for_new_user`));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -197,13 +211,7 @@ export function validateUploadedFile(file, type, bypassNewUserRestriction) {
|
|||
return true;
|
||||
}
|
||||
|
||||
export function uploadTypeFromFileName(fileName) {
|
||||
return isAnImage(fileName) ? 'image' : 'attachment';
|
||||
}
|
||||
|
||||
export function authorizesAllExtensions() {
|
||||
return Discourse.SiteSettings.authorized_extensions.indexOf("*") >= 0;
|
||||
}
|
||||
const IMAGES_EXTENSIONS_REGEX = /(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)/i;
|
||||
|
||||
function extensions() {
|
||||
return Discourse.SiteSettings.authorized_extensions
|
||||
|
@ -213,16 +221,52 @@ function extensions() {
|
|||
.filter(ext => ext.indexOf("*") === -1);
|
||||
}
|
||||
|
||||
function imagesExtensions() {
|
||||
return extensions().filter(ext => IMAGES_EXTENSIONS_REGEX.test(ext));
|
||||
}
|
||||
|
||||
function extensionsRegex() {
|
||||
return new RegExp("\\.(" + extensions().join("|") + ")$", "i");
|
||||
}
|
||||
|
||||
export function isAuthorizedUpload(file) {
|
||||
return file && file.name && extensionsRegex().test(file.name);
|
||||
function imagesExtensionsRegex() {
|
||||
return new RegExp("\\.(" + imagesExtensions().join("|") + ")$", "i");
|
||||
}
|
||||
|
||||
function isAuthorizedFile(fileName) {
|
||||
return extensionsRegex().test(fileName);
|
||||
}
|
||||
|
||||
function isAuthorizedImage(fileName){
|
||||
return imagesExtensionsRegex().test(fileName);
|
||||
}
|
||||
|
||||
export function authorizedExtensions() {
|
||||
return extensions().join(", ");
|
||||
return authorizesAllExtensions() ? "*" : extensions().join(", ");
|
||||
}
|
||||
|
||||
export function authorizedImagesExtensions() {
|
||||
return authorizesAllExtensions() ? "png, jpg, jpeg, gif, bmp, tiff, svg, webp, ico" : imagesExtensions().join(", ");
|
||||
}
|
||||
|
||||
export function authorizesAllExtensions() {
|
||||
return Discourse.SiteSettings.authorized_extensions.indexOf("*") >= 0;
|
||||
}
|
||||
|
||||
export function isAnImage(path) {
|
||||
return (/\.(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)$/i).test(path);
|
||||
}
|
||||
|
||||
function uploadTypeFromFileName(fileName) {
|
||||
return isAnImage(fileName) ? 'image' : 'attachment';
|
||||
}
|
||||
|
||||
export function allowsImages() {
|
||||
return authorizesAllExtensions() || IMAGES_EXTENSIONS_REGEX.test(authorizedExtensions());
|
||||
}
|
||||
|
||||
export function allowsAttachments() {
|
||||
return authorizesAllExtensions() || extensions().length > imagesExtensions().length;
|
||||
}
|
||||
|
||||
export function uploadLocation(url) {
|
||||
|
@ -243,27 +287,12 @@ export function getUploadMarkdown(upload) {
|
|||
if (isAnImage(upload.original_filename)) {
|
||||
return '<img src="' + upload.url + '" width="' + upload.width + '" height="' + upload.height + '">';
|
||||
} else if (!Discourse.SiteSettings.prevent_anons_from_downloading_files && (/\.(mov|mp4|webm|ogv|mp3|ogg|wav|m4a)$/i).test(upload.original_filename)) {
|
||||
// is Audio/Video
|
||||
return uploadLocation(upload.url);
|
||||
} else {
|
||||
return '<a class="attachment" href="' + upload.url + '">' + upload.original_filename + '</a> (' + I18n.toHumanSize(upload.filesize) + ')\n';
|
||||
}
|
||||
}
|
||||
|
||||
export function isAnImage(path) {
|
||||
return (/\.(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)$/i).test(path);
|
||||
}
|
||||
|
||||
export function allowsImages() {
|
||||
return authorizesAllExtensions() ||
|
||||
(/(png|jpe?g|gif|bmp|tiff?|svg|webp|ico)/i).test(authorizedExtensions());
|
||||
}
|
||||
|
||||
export function allowsAttachments() {
|
||||
return authorizesAllExtensions() ||
|
||||
!/^((png|jpe?g|gif|bmp|tiff?|svg|webp|ico)(,\s)?)+$/i.test(authorizedExtensions());
|
||||
}
|
||||
|
||||
export function displayErrorForUpload(data) {
|
||||
// deal with meaningful errors first
|
||||
if (data.jqXHR) {
|
||||
|
|
|
@ -8,6 +8,10 @@ export default Em.Mixin.create({
|
|||
Em.warn("You should implement `uploadDone`");
|
||||
},
|
||||
|
||||
validateUploadedFilesOptions() {
|
||||
return {};
|
||||
},
|
||||
|
||||
_initialize: function() {
|
||||
const $upload = this.$(),
|
||||
csrf = Discourse.Session.currentProp("csrfToken"),
|
||||
|
@ -40,7 +44,8 @@ export default Em.Mixin.create({
|
|||
});
|
||||
|
||||
$upload.on("fileuploadsubmit", (e, data) => {
|
||||
const isValid = validateUploadedFiles(data.files, true);
|
||||
const opts = _.merge({ bypassNewUserRestriction: true }, this.validateUploadedFilesOptions());
|
||||
const isValid = validateUploadedFiles(data.files, opts);
|
||||
let form = { type: this.get("type") };
|
||||
if (this.get("data")) { form = $.extend(form, this.get("data")); }
|
||||
data.formData = form;
|
||||
|
|
|
@ -1737,7 +1737,7 @@ en:
|
|||
file_too_large: "Sorry, that file is too big (maximum size is {{max_size_kb}}kb). Why not upload your large file to a cloud sharing service, then share the link?"
|
||||
too_many_uploads: "Sorry, you can only upload one file at a time."
|
||||
too_many_dragged_and_dropped_files: "Sorry, you can only upload 10 files at a time."
|
||||
upload_not_authorized: "Sorry, the file you are trying to upload is not authorized (authorized extension: {{authorized_extensions}})."
|
||||
upload_not_authorized: "Sorry, the file you are trying to upload is not authorized (authorized extensions: {{authorized_extensions}})."
|
||||
image_upload_not_allowed_for_new_user: "Sorry, new users can not upload images."
|
||||
attachment_upload_not_allowed_for_new_user: "Sorry, new users can not upload attachments."
|
||||
attachment_download_requires_login: "Sorry, you need to be logged in to download attachments."
|
||||
|
|
Loading…
Reference in New Issue