FEATURE: Add a site setting to allow emojis to come from an external URL (#12180)
This commit is contained in:
parent
7a53873568
commit
83f332b5a5
|
@ -23,6 +23,7 @@ import { notEmpty } from "@ember/object/computed";
|
|||
import { setting } from "discourse/lib/computed";
|
||||
import { userPath } from "discourse/lib/url";
|
||||
import { helperContext } from "discourse-common/lib/helpers";
|
||||
import { emojiBasePath } from "discourse/lib/settings";
|
||||
|
||||
export default Controller.extend(
|
||||
ModalFunctionality,
|
||||
|
@ -84,7 +85,7 @@ export default Controller.extend(
|
|||
|
||||
// random number between 2 -6 to render multiple skin tone waving hands
|
||||
const random = Math.floor(Math.random() * (7 - 2) + 2);
|
||||
return getURL(`/images/emoji/${emojiSet}/wave/${random}.png`);
|
||||
return getURL(`${emojiBasePath()}/${emojiSet}/wave/${random}.png`);
|
||||
},
|
||||
|
||||
@discourseComputed(
|
||||
|
|
|
@ -19,6 +19,7 @@ import { isEmpty } from "@ember/utils";
|
|||
import { setting } from "discourse/lib/computed";
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import { helperContext } from "discourse-common/lib/helpers";
|
||||
import { emojiBasePath } from "discourse/lib/settings";
|
||||
|
||||
// This is happening outside of the app via popup
|
||||
const AuthErrors = [
|
||||
|
@ -71,7 +72,7 @@ export default Controller.extend(ModalFunctionality, {
|
|||
|
||||
// random number between 2 -6 to render multiple skin tone waving hands
|
||||
const random = Math.floor(Math.random() * (7 - 2) + 2);
|
||||
return getURL(`/images/emoji/${emojiSet}/wave/${random}.png`);
|
||||
return getURL(`${emojiBasePath()}/${emojiSet}/wave/${random}.png`);
|
||||
},
|
||||
|
||||
@discourseComputed("showSecondFactor", "showSecurityKey")
|
||||
|
|
|
@ -7,3 +7,11 @@ export function prioritizeNameInUx(name) {
|
|||
!siteSettings.prioritize_username_in_ux && name && name.trim().length > 0
|
||||
);
|
||||
}
|
||||
|
||||
export function emojiBasePath() {
|
||||
let siteSettings = helperContext().siteSettings;
|
||||
|
||||
return siteSettings.external_emoji_url === ""
|
||||
? "/images/emojis"
|
||||
: siteSettings.external_emoji_url;
|
||||
}
|
||||
|
|
|
@ -90,6 +90,7 @@ function emojiOptions() {
|
|||
emojiSet: siteSettings.emoji_set,
|
||||
enableEmojiShortcuts: siteSettings.enable_emoji_shortcuts,
|
||||
inlineEmoji: siteSettings.enable_inline_emoji_translation,
|
||||
emojiCDNUrl: siteSettings.external_emoji_url,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -97,6 +97,7 @@ const ORIGINAL_SETTINGS = {
|
|||
enable_personal_messages: true,
|
||||
unicode_usernames: false,
|
||||
secure_media: false,
|
||||
external_emoji_url: "",
|
||||
};
|
||||
|
||||
let siteSettings = Object.assign({}, ORIGINAL_SETTINGS);
|
||||
|
|
|
@ -17,6 +17,7 @@ const rawOpts = {
|
|||
enable_emoji_shortcuts: true,
|
||||
enable_mentions: true,
|
||||
emoji_set: "google_classic",
|
||||
external_emoji_url: "",
|
||||
highlighted_languages: "json|ruby|javascript",
|
||||
default_code_lang: "auto",
|
||||
enable_markdown_linkify: true,
|
||||
|
@ -1519,6 +1520,19 @@ var bar = 'bar';
|
|||
);
|
||||
});
|
||||
|
||||
test("emoji - emojiCDN", function (assert) {
|
||||
assert.cookedOptions(
|
||||
":smile:",
|
||||
{
|
||||
siteSettings: {
|
||||
emoji_set: "twitter",
|
||||
external_emoji_url: "https://emoji.hosting.service",
|
||||
},
|
||||
},
|
||||
`<p><img src="https://emoji.hosting.service/twitter/smile.png?v=${v}" title=":smile:" class="emoji only-emoji" alt=":smile:"></p>`
|
||||
);
|
||||
});
|
||||
|
||||
test("emoji - registerEmoji", function (assert) {
|
||||
registerEmoji("foo", "/images/d-logo-sketch.png");
|
||||
|
||||
|
|
|
@ -180,6 +180,12 @@ export function buildEmojiUrl(code, opts) {
|
|||
}
|
||||
|
||||
const noToneMatch = code.match(/([^:]+):?/);
|
||||
|
||||
let emojiBasePath = "/images/emoji";
|
||||
if (opts.emojiCDNUrl) {
|
||||
emojiBasePath = opts.emojiCDNUrl;
|
||||
}
|
||||
|
||||
if (
|
||||
noToneMatch &&
|
||||
!url &&
|
||||
|
@ -187,7 +193,7 @@ export function buildEmojiUrl(code, opts) {
|
|||
aliasHash.hasOwnProperty(noToneMatch[1]))
|
||||
) {
|
||||
url = opts.getURL(
|
||||
`/images/emoji/${opts.emojiSet}/${code.replace(/:t/, "/")}.png`
|
||||
`${emojiBasePath}/${opts.emojiSet}/${code.replace(/:t/, "/")}.png`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -322,6 +322,7 @@ export function setup(helper) {
|
|||
opts.features.inlineEmoji = !!siteSettings.enable_inline_emoji_translation;
|
||||
opts.emojiSet = siteSettings.emoji_set || "";
|
||||
opts.customEmoji = state.customEmoji;
|
||||
opts.emojiCDNUrl = siteSettings.external_emoji_url;
|
||||
});
|
||||
|
||||
helper.registerPlugin((md) => {
|
||||
|
|
|
@ -124,6 +124,7 @@ const rule = {
|
|||
title = performEmojiUnescape(topicInfo.title, {
|
||||
getURL: options.getURL,
|
||||
emojiSet: options.emojiSet,
|
||||
emojiCDNUrl: options.emojiCDNUrl,
|
||||
enableEmojiShortcuts: options.enableEmojiShortcuts,
|
||||
inlineEmoji: options.inlineEmoji,
|
||||
});
|
||||
|
@ -160,6 +161,7 @@ export function setup(helper) {
|
|||
helper.registerOptions((opts, siteSettings) => {
|
||||
opts.enableEmoji = siteSettings.enable_emoji;
|
||||
opts.emojiSet = siteSettings.emoji_set;
|
||||
opts.emojiCDNUrl = siteSettings.external_emoji_url;
|
||||
opts.enableEmojiShortcuts = siteSettings.enable_emoji_shortcuts;
|
||||
opts.inlineEmoji = siteSettings.enable_inline_emoji_translation;
|
||||
});
|
||||
|
|
|
@ -194,6 +194,7 @@ module Jobs
|
|||
local_bases = [
|
||||
Discourse.base_url,
|
||||
Discourse.asset_host,
|
||||
SiteSetting.external_emoji_url.presence
|
||||
].compact.map { |s| normalize_src(s) }
|
||||
|
||||
if Discourse.store.has_been_uploaded?(src) || normalize_src(src).start_with?(*local_bases) || src =~ /\A\/[^\/]/i
|
||||
|
|
|
@ -73,7 +73,11 @@ class Emoji
|
|||
|
||||
def self.url_for(name)
|
||||
name = name.delete_prefix(':').delete_suffix(':').gsub(/(.+):t([1-6])/, '\1/\2')
|
||||
"#{Discourse.base_path}/images/emoji/#{SiteSetting.emoji_set}/#{name}.png?v=#{EMOJI_VERSION}"
|
||||
if SiteSetting.external_emoji_url.blank?
|
||||
"#{Discourse.base_path}/images/emoji/#{SiteSetting.emoji_set}/#{name}.png?v=#{EMOJI_VERSION}"
|
||||
else
|
||||
"#{SiteSetting.external_emoji_url}/#{SiteSetting.emoji_set}/#{name}.png?v=#{EMOJI_VERSION}"
|
||||
end
|
||||
end
|
||||
|
||||
def self.cache_key(name)
|
||||
|
|
|
@ -1782,6 +1782,7 @@ en:
|
|||
|
||||
external_system_avatars_enabled: "Use external system avatars service."
|
||||
external_system_avatars_url: "URL of the external system avatars service. Allowed substitutions are {username} {first_letter} {color} {size}"
|
||||
external_emoji_url: "URL of the external service for emoji images. Leave blank to disable."
|
||||
use_site_small_logo_as_system_avatar: "Use the site's small logo instead of the system user's avatar. Requires the logo to be present."
|
||||
restrict_letter_avatar_colors: "A list of 6-digit hexadecimal color values to be used for letter avatar background."
|
||||
|
||||
|
|
|
@ -1339,6 +1339,9 @@ files:
|
|||
default: "/letter_avatar_proxy/v4/letter/{first_letter}/{color}/{size}.png"
|
||||
client: true
|
||||
regex: '^((https?:)?\/)?\/.+[^\/]'
|
||||
external_emoji_url:
|
||||
default: ""
|
||||
client: true
|
||||
restrict_letter_avatar_colors:
|
||||
default: ""
|
||||
type: list
|
||||
|
|
|
@ -238,6 +238,7 @@ module PrettyText
|
|||
__performEmojiUnescape(#{title.inspect}, {
|
||||
getURL: __getURL,
|
||||
emojiSet: #{set},
|
||||
emojiCDNUrl: #{SiteSetting.external_emoji_url.blank? ? "''" : SiteSetting.external_emoji_url},
|
||||
customEmoji: #{custom},
|
||||
enableEmojiShortcuts: #{SiteSetting.enable_emoji_shortcuts},
|
||||
inlineEmoji: #{SiteSetting.enable_inline_emoji_translation}
|
||||
|
|
|
@ -151,6 +151,45 @@ describe PrettyText do
|
|||
|
||||
expect(cook(md)).to eq(html.strip)
|
||||
end
|
||||
|
||||
it "does use emoji CDN when enabled" do
|
||||
SiteSetting.external_emoji_url = "https://emoji.cdn.com"
|
||||
|
||||
html = <<~HTML
|
||||
<blockquote>
|
||||
<p>This is a quote with a regular emoji <img src="https://emoji.cdn.com/twitter/upside_down_face.png?v=9" title=":upside_down_face:" class="emoji" alt=":upside_down_face:"></p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>This is a quote with an emoji shortcut <img src="https://emoji.cdn.com/twitter/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>This is a quote with a Unicode emoji <img src="https://emoji.cdn.com/twitter/sunglasses.png?v=9" title=":sunglasses:" class="emoji" alt=":sunglasses:"></p>
|
||||
</blockquote>
|
||||
HTML
|
||||
|
||||
expect(cook(md)).to eq(html.strip)
|
||||
end
|
||||
|
||||
it "does use emoji CDN when others CDNs are also enabled" do
|
||||
set_cdn_url('https://cdn.com')
|
||||
setup_s3
|
||||
SiteSetting.s3_cdn_url = "https://s3.cdn.com"
|
||||
SiteSetting.external_emoji_url = "https://emoji.cdn.com"
|
||||
|
||||
html = <<~HTML
|
||||
<blockquote>
|
||||
<p>This is a quote with a regular emoji <img src="https://emoji.cdn.com/twitter/upside_down_face.png?v=9" title=":upside_down_face:" class="emoji" alt=":upside_down_face:"></p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>This is a quote with an emoji shortcut <img src="https://emoji.cdn.com/twitter/slight_smile.png?v=9" title=":slight_smile:" class="emoji" alt=":slight_smile:"></p>
|
||||
</blockquote>
|
||||
<blockquote>
|
||||
<p>This is a quote with a Unicode emoji <img src="https://emoji.cdn.com/twitter/sunglasses.png?v=9" title=":sunglasses:" class="emoji" alt=":sunglasses:"></p>
|
||||
</blockquote>
|
||||
HTML
|
||||
|
||||
expect(cook(md)).to eq(html.strip)
|
||||
end
|
||||
end
|
||||
|
||||
it "do off topic quoting of posts from secure categories" do
|
||||
|
|
|
@ -440,6 +440,23 @@ describe Jobs::PullHotlinkedImages do
|
|||
expect(subject.should_download_image?(src)).to eq(false)
|
||||
end
|
||||
|
||||
it "returns false for emoji when emoji CDN configured" do
|
||||
SiteSetting.external_emoji_url = "https://emoji.cdn.com"
|
||||
|
||||
src = UrlHelper.cook_url(Emoji.url_for("testemoji.png"))
|
||||
expect(subject.should_download_image?(src)).to eq(false)
|
||||
end
|
||||
|
||||
it "returns false for emoji when app, S3 *and* emoji CDNs configured" do
|
||||
setup_s3
|
||||
SiteSetting.s3_cdn_url = "https://s3.cdn.com"
|
||||
SiteSetting.external_emoji_url = "https://emoji.cdn.com"
|
||||
set_cdn_url "https://mydomain.cdn/test"
|
||||
|
||||
src = UrlHelper.cook_url(Emoji.url_for("testemoji.png"))
|
||||
expect(subject.should_download_image?(src)).to eq(false)
|
||||
end
|
||||
|
||||
it "returns false for plugin assets" do
|
||||
src = UrlHelper.cook_url("/plugins/discourse-amazing-plugin/myasset.png")
|
||||
expect(subject.should_download_image?(src)).to eq(false)
|
||||
|
|
Loading…
Reference in New Issue