This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.
osr-discourse-src/app/assets/javascripts/discourse/lib/uploads.js.es6
Martin Brennan dbfe9540fa FIX: be more tactical with replacing markdown chars
* instead of using encodeURIComponent in imageNameFromFileName,
  we just replace the bad characters that we wanted to get rid
  of in the first place where we introduced encodeURIComponent.
  as per review
2019-11-25 16:38:13 +10:00

287 lines
7.4 KiB
JavaScript

import { isAppleDevice } from "discourse/lib/utilities";
function isGUID(value) {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
value
);
}
function imageNameFromFileName(fileName) {
const split = fileName.split(".");
let name = split[split.length - 2];
if (isAppleDevice() && isGUID(name)) {
name = I18n.t("upload_selector.default_image_alt_text");
}
return name.replace(/\[|\]|\|/g, "");
// return encodeURIComponent(name).replace(/%20/g, " ");
}
export function validateUploadedFiles(files, opts) {
if (!files || files.length === 0) {
return false;
}
if (files.length > 1) {
bootbox.alert(I18n.t("post.errors.too_many_uploads"));
return false;
}
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 = "image.png";
}
}
opts = opts || {};
opts.type = uploadTypeFromFileName(upload.name);
return validateUploadedFile(upload, opts);
}
function validateUploadedFile(file, opts) {
if (opts.skipValidation) return true;
opts = opts || {};
let user = opts.user;
let staff = user && user.staff;
if (!authorizesOneOrMoreExtensions(staff)) return false;
const name = file && file.name;
if (!name) {
return false;
}
// check that the uploaded file is authorized
if (opts.allowStaffToUploadAnyFileInPm && opts.isPrivateMessage) {
if (staff) {
return true;
}
}
if (opts.imagesOnly) {
if (!isAnImage(name) && !isAuthorizedImage(name, staff)) {
bootbox.alert(
I18n.t("post.errors.upload_not_authorized", {
authorized_extensions: authorizedImagesExtensions(staff)
})
);
return false;
}
} else if (opts.csvOnly) {
if (!/\.csv$/i.test(name)) {
bootbox.alert(I18n.t("user.invited.bulk_invite.error"));
return false;
}
} else {
if (!authorizesAllExtensions(staff) && !isAuthorizedFile(name, staff)) {
bootbox.alert(
I18n.t("post.errors.upload_not_authorized", {
authorized_extensions: authorizedExtensions(staff)
})
);
return false;
}
}
if (!opts.bypassNewUserRestriction) {
// ensures that new users can upload a file
if (user && !user.isAllowedToUploadAFile(opts.type)) {
bootbox.alert(
I18n.t(`post.errors.${opts.type}_upload_not_allowed_for_new_user`)
);
return false;
}
}
// everything went fine
return true;
}
const IMAGES_EXTENSIONS_REGEX = /(png|jpe?g|gif|svg|ico)/i;
function extensionsToArray(exts) {
return exts
.toLowerCase()
.replace(/[\s\.]+/g, "")
.split("|")
.filter(ext => ext.indexOf("*") === -1);
}
function extensions() {
return extensionsToArray(Discourse.SiteSettings.authorized_extensions);
}
function staffExtensions() {
return extensionsToArray(
Discourse.SiteSettings.authorized_extensions_for_staff
);
}
function imagesExtensions(staff) {
let exts = extensions().filter(ext => IMAGES_EXTENSIONS_REGEX.test(ext));
if (staff) {
const staffExts = staffExtensions().filter(ext =>
IMAGES_EXTENSIONS_REGEX.test(ext)
);
exts = _.union(exts, staffExts);
}
return exts;
}
function extensionsRegex() {
return new RegExp("\\.(" + extensions().join("|") + ")$", "i");
}
function imagesExtensionsRegex(staff) {
return new RegExp("\\.(" + imagesExtensions(staff).join("|") + ")$", "i");
}
function staffExtensionsRegex() {
return new RegExp("\\.(" + staffExtensions().join("|") + ")$", "i");
}
function isAuthorizedFile(fileName, staff) {
if (staff && staffExtensionsRegex().test(fileName)) {
return true;
}
return extensionsRegex().test(fileName);
}
function isAuthorizedImage(fileName, staff) {
return imagesExtensionsRegex(staff).test(fileName);
}
export function authorizedExtensions(staff) {
const exts = staff ? [...extensions(), ...staffExtensions()] : extensions();
return exts.filter(ext => ext.length > 0).join(", ");
}
function authorizedImagesExtensions(staff) {
return authorizesAllExtensions(staff)
? "png, jpg, jpeg, gif, svg, ico"
: imagesExtensions(staff).join(", ");
}
export function authorizesAllExtensions(staff) {
return (
Discourse.SiteSettings.authorized_extensions.indexOf("*") >= 0 ||
(Discourse.SiteSettings.authorized_extensions_for_staff.indexOf("*") >= 0 &&
staff)
);
}
export function authorizesOneOrMoreExtensions(staff) {
if (authorizesAllExtensions(staff)) return true;
return (
Discourse.SiteSettings.authorized_extensions.split("|").filter(ext => ext)
.length > 0
);
}
export function authorizesOneOrMoreImageExtensions(staff) {
if (authorizesAllExtensions(staff)) return true;
return imagesExtensions(staff).length > 0;
}
export function isAnImage(path) {
return /\.(png|jpe?g|gif|svg|ico)$/i.test(path);
}
function uploadTypeFromFileName(fileName) {
return isAnImage(fileName) ? "image" : "attachment";
}
export function allowsImages(staff) {
return (
authorizesAllExtensions(staff) ||
IMAGES_EXTENSIONS_REGEX.test(authorizedExtensions(staff))
);
}
export function allowsAttachments(staff) {
return (
authorizesAllExtensions(staff) ||
authorizedExtensions(staff).split(", ").length >
imagesExtensions(staff).length
);
}
export function uploadIcon(staff) {
return allowsAttachments(staff) ? "upload" : "far-image";
}
function uploadLocation(url) {
if (Discourse.CDN) {
url = Discourse.getURLWithCDN(url);
return /^\/\//.test(url) ? "http:" + url : url;
} else if (Discourse.S3BaseUrl) {
return "https:" + url;
} else {
var protocol = window.location.protocol + "//",
hostname = window.location.hostname,
port = window.location.port ? ":" + window.location.port : "";
return protocol + hostname + port + url;
}
}
export function getUploadMarkdown(upload) {
if (isAnImage(upload.original_filename)) {
const name = imageNameFromFileName(upload.original_filename);
return `![${name}|${upload.thumbnail_width}x${
upload.thumbnail_height
}](${upload.short_url || upload.url})`;
} else if (
/\.(mov|mp4|webm|ogv|mp3|ogg|wav|m4a)$/i.test(upload.original_filename)
) {
return uploadLocation(upload.url);
} else {
return `[${upload.original_filename}|attachment](${
upload.short_url
}) (${I18n.toHumanSize(upload.filesize)})`;
}
}
export function displayErrorForUpload(data) {
if (data.jqXHR) {
switch (data.jqXHR.status) {
// cancelled by the user
case 0:
return;
// entity too large, usually returned from the web server
case 413:
const type = uploadTypeFromFileName(data.files[0].name);
const max_size_kb = Discourse.SiteSettings[`max_${type}_size_kb`];
bootbox.alert(I18n.t("post.errors.file_too_large", { max_size_kb }));
return;
// the error message is provided by the server
case 422:
if (data.jqXHR.responseJSON.message) {
bootbox.alert(data.jqXHR.responseJSON.message);
} else {
bootbox.alert(data.jqXHR.responseJSON.errors.join("\n"));
}
return;
}
} else if (data.errors && data.errors.length > 0) {
bootbox.alert(data.errors.join("\n"));
return;
}
// otherwise, display a generic error message
bootbox.alert(I18n.t("post.errors.upload"));
}