Merge remote-tracking branch 'discourse/master' into transform-native-emojis-to-names

This commit is contained in:
Joffrey JAFFEUX 2017-06-14 14:39:30 +02:00
commit baa332a83e
81 changed files with 107 additions and 34 deletions

View File

@ -240,7 +240,11 @@ export default Ember.Component.extend({
$element.on('fileuploadsubmit', (e, data) => { $element.on('fileuploadsubmit', (e, data) => {
const isPrivateMessage = this.get("composer.privateMessage"); const isPrivateMessage = this.get("composer.privateMessage");
const isUploading = validateUploadedFiles(data.files, { isPrivateMessage }); const opts = {
isPrivateMessage,
allowStaffToUploadAnyFileInPm: this.siteSettings.allow_staff_to_upload_any_file_in_pm,
}
const isUploading = validateUploadedFiles(data.files, opts);
data.formData = { type: "composer", for_private_message: isPrivateMessage }; data.formData = { type: "composer", for_private_message: isPrivateMessage };
this.setProperties({ uploadProgress: 0, isUploading }); this.setProperties({ uploadProgress: 0, isUploading });
return isUploading; return isUploading;

View File

@ -138,7 +138,7 @@ class Toolbar {
label: button.label, label: button.label,
icon: button.label ? null : button.icon || button.id, icon: button.label ? null : button.icon || button.id,
action: button.action || 'toolbarButton', action: button.action || 'toolbarButton',
perform: button.perform || Ember.K, perform: button.perform || function() { },
trimLeading: button.trimLeading trimLeading: button.trimLeading
}; };
@ -338,8 +338,7 @@ export default Ember.Component.extend({
}, },
onKeyUp(text, cp) { onKeyUp(text, cp) {
const subtext = text.substring(0, cp); return text.substring(0, cp).match(/(:(?!:).?[\w-]*:?(?!:)(?:t\d?)?:?) ?$/g);
return subtext.match(/(:(?!:).?[\w-]*:?(?!:)(?:t\d?)?:?) ?$/gm);
}, },
transformComplete(v) { transformComplete(v) {

View File

@ -4,6 +4,9 @@ const _buttons = [];
const alwaysTrue = () => true; const alwaysTrue = () => true;
function identity() {
}
function addBulkButton(action, key, opts) { function addBulkButton(action, key, opts) {
opts = opts || {}; opts = opts || {};
@ -72,7 +75,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
this.perform(operation).then(topics => { this.perform(operation).then(topics => {
if (topics) { if (topics) {
topics.forEach(cb); topics.forEach(cb);
(this.get('refreshClosure') || Ember.k)(); (this.get('refreshClosure') || identity)();
this.send('closeModal'); this.send('closeModal');
} }
}); });
@ -80,7 +83,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
performAndRefresh(operation) { performAndRefresh(operation) {
return this.perform(operation).then(() => { return this.perform(operation).then(() => {
(this.get('refreshClosure') || Ember.k)(); (this.get('refreshClosure') || identity)();
this.send('closeModal'); this.send('closeModal');
}); });
}, },
@ -145,7 +148,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
this.perform({type: 'change_category', category_id: categoryId}).then(topics => { this.perform({type: 'change_category', category_id: categoryId}).then(topics => {
topics.forEach(t => t.set('category', category)); topics.forEach(t => t.set('category', category));
(this.get('refreshClosure') || Ember.k)(); (this.get('refreshClosure') || identity)();
this.send('closeModal'); this.send('closeModal');
}); });
}, },

View File

@ -2,5 +2,5 @@
export default { export default {
name: "inject-objects", name: "inject-objects",
initialize: Ember.K initialize() { }
}; };

View File

@ -2,5 +2,5 @@
export default { export default {
name: "register-discourse-location", name: "register-discourse-location",
initialize: Ember.K initialize() { }
}; };

View File

@ -363,7 +363,7 @@ export default function(options) {
if (options.key) { if (options.key) {
if (options.onKeyUp && key !== options.key) { if (options.onKeyUp && key !== options.key) {
var match = options.onKeyUp(me.val(), cp); let match = options.onKeyUp(me.val(), cp);
if (match) { if (match) {
completeStart = cp - match[0].length; completeStart = cp - match[0].length;
completeEnd = completeStart + match[0].length - 1; completeEnd = completeStart + match[0].length - 1;

View File

@ -701,7 +701,6 @@ const groups = [
"rotating_light", "rotating_light",
"taxi", "taxi",
"oncoming_taxi", "oncoming_taxi",
"automobile",
"oncoming_automobile", "oncoming_automobile",
"blue_car", "blue_car",
"truck", "truck",

View File

@ -56,7 +56,7 @@ export default Ember.Object.extend(Ember.Array, {
}, },
finishedPrepending(postIds) { finishedPrepending(postIds) {
this._changeArray(Ember.K, 0, 0, postIds.length); this._changeArray(function() { }, 0, 0, postIds.length);
}, },
objectAt(index) { objectAt(index) {

View File

@ -185,8 +185,8 @@ export function validateUploadedFile(file, opts) {
if (!name) { return false; } if (!name) { return false; }
// check that the uploaded file is authorized // check that the uploaded file is authorized
if (Discourse.SiteSettings.allow_staff_to_upload_any_file_in_pm) { if (opts["allowStaffToUploadAnyFileInPm"] && opts["isPrivateMessage"]) {
if (opts["isPrivateMessage"] && Discourse.User.current("staff")) { if (Discourse.User.current("staff")) {
return true; return true;
} }
} }

View File

@ -3,7 +3,7 @@ const RestModel = Ember.Object.extend({
isCreated: Ember.computed.equal('__state', 'created'), isCreated: Ember.computed.equal('__state', 'created'),
isSaving: false, isSaving: false,
afterUpdate: Ember.K, afterUpdate() { },
update(props) { update(props) {
if (this.get('isSaving')) { return Ember.RSVP.reject(); } if (this.get('isSaving')) { return Ember.RSVP.reject(); }

View File

@ -220,7 +220,7 @@ module ApplicationHelper
def gsub_emoji_to_unicode(str) def gsub_emoji_to_unicode(str)
if str if str
str.gsub(/:([\w\-+]*):/) { |name| Emoji.lookup_unicode($1) || name } str.gsub(/:([\w\-+]*(?::t\d)?):/) { |name| Emoji.lookup_unicode($1) || name }
end end
end end

View File

@ -2,6 +2,8 @@ class Emoji
# update this to clear the cache # update this to clear the cache
EMOJI_VERSION = "v5" EMOJI_VERSION = "v5"
FITZPATRICK_SCALE ||= [ "1f3fb", "1f3fc", "1f3fd", "1f3fe", "1f3ff" ]
include ActiveModel::SerializerSupport include ActiveModel::SerializerSupport
attr_reader :path attr_reader :path
@ -147,8 +149,17 @@ class Emoji
db['emojis'].each do |e| db['emojis'].each do |e|
next if e['name'] == 'tm' next if e['name'] == 'tm'
code = replacement_code(e['code']) code = replacement_code(e['code'])
map[e['name']] = code if code next unless code
map[e['name']] = code
if Emoji.tonable_emojis.include?(e['name'])
FITZPATRICK_SCALE.each_with_index do |scale, index|
toned_code = (code.codepoints.insert(1, scale.to_i(16))).pack("U*")
map["#{e['name']}:t#{index+2}"] = toned_code
end
end
end end
Emoji.aliases.each do |key, alias_names| Emoji.aliases.each do |key, alias_names|

View File

@ -719,6 +719,21 @@ SQL
# ensure all the notifications are out # ensure all the notifications are out
PostAlerter.new.after_save_post(last_post) PostAlerter.new.after_save_post(last_post)
add_small_action(user, "invited_group", group.name) add_small_action(user, "invited_group", group.name)
group.users.where(
"group_users.notification_level > ?", NotificationLevels.all[:muted]
).find_each do |u|
u.notifications.create!(
notification_type: Notification.types[:invited_to_private_message],
topic_id: self.id,
post_number: 1,
data: {
topic_title: self.title,
display_username: user.username
}.to_json
)
end
end end
true true

View File

@ -55,11 +55,11 @@ module BackupRestore
begin begin
notify_user notify_user
remove_old remove_old
clean_up
rescue => ex rescue => ex
Rails.logger.error("#{ex}\n" + ex.backtrace.join("\n")) Rails.logger.error("#{ex}\n" + ex.backtrace.join("\n"))
end end
clean_up
@success ? log("[SUCCESS]") : log("[FAILED]") @success ? log("[SUCCESS]") : log("[FAILED]")
end end
@ -259,9 +259,15 @@ module BackupRestore
log "Notifying '#{@user.username}' of the end of the backup..." log "Notifying '#{@user.username}' of the end of the backup..."
status = @success ? :backup_succeeded : :backup_failed status = @success ? :backup_succeeded : :backup_failed
SystemMessage.create_from_system_user(@user, status, post = SystemMessage.create_from_system_user(@user, status,
logs: Discourse::Utils.pretty_logs(@logs) logs: Discourse::Utils.pretty_logs(@logs)
) )
if @user.id == Discourse::SYSTEM_USER_ID
post.topic.invite_group(@user, Group[:admins])
end
post
end end
def clean_up def clean_up

View File

@ -5782,6 +5782,8 @@
"male_detective", "male_detective",
"woman_health_worker", "woman_health_worker",
"man_health_worker", "man_health_worker",
"woman_cook",
"man_cook",
"woman_pilot", "woman_pilot",
"man_pilot", "man_pilot",
"woman_judge", "woman_judge",
@ -6450,8 +6452,9 @@
"new_moon": [ "new_moon": [
"moon" "moon"
], ],
"automobile": [ "oncoming_automobile": [
"car" "car",
"automobile"
], ],
"fleur_de_lis": [ "fleur_de_lis": [
"fleur-de-lis" "fleur-de-lis"

View File

@ -208,7 +208,7 @@ EMOJI_ALIASES ||= {
"tipping_hand_woman" => [ "information_desk_person" ], "tipping_hand_woman" => [ "information_desk_person" ],
"rowing_man" => [ "rowboat" ], "rowing_man" => [ "rowboat" ],
"new_moon" => [ "moon" ], "new_moon" => [ "moon" ],
"automobile" => [ "car" ], "oncoming_automobile" => [ "car", "automobile" ],
"fleur_de_lis" => [ "fleur-de-lis" ], "fleur_de_lis" => [ "fleur-de-lis" ],
} }
@ -912,7 +912,6 @@ EMOJI_GROUPS ||= [
"rotating_light", "rotating_light",
"taxi", "taxi",
"oncoming_taxi", "oncoming_taxi",
"automobile",
"oncoming_automobile", "oncoming_automobile",
"blue_car", "blue_car",
"truck", "truck",
@ -1727,6 +1726,8 @@ VARIATION_SELECTOR ||= "fe0f"
# Patch content of EMOJI_KEYWORDS_URL # Patch content of EMOJI_KEYWORDS_URL
EMOJI_KEYWORDS_PATCH ||= { EMOJI_KEYWORDS_PATCH ||= {
"woman_cook" => { "fitzpatrick_scale" => true },
"man_cook" => { "fitzpatrick_scale" => true },
"thumbsup" => { "char" => "👍", "fitzpatrick_scale" => true }, "thumbsup" => { "char" => "👍", "fitzpatrick_scale" => true },
"thumbsdown" => { "char" => "👎", "fitzpatrick_scale" => true }, "thumbsdown" => { "char" => "👎", "fitzpatrick_scale" => true },
"asterisk" => { "char" => "*️⃣" }, "asterisk" => { "char" => "*️⃣" },

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 791 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 858 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 712 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 815 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 700 B

View File

@ -28,4 +28,18 @@ describe Emoji do
end end
end end
describe '.lookup_unicode' do
it 'should return the emoji' do
expect(Emoji.lookup_unicode("blonde_man")).to eq("👱")
end
it 'should return an aliased emoji' do
expect(Emoji.lookup_unicode("anger_right")).to eq("🗯")
end
it 'should return a skin toned emoji' do
expect(Emoji.lookup_unicode("blonde_woman:t6")).to eq("👱🏿‍♀️")
end
end
end end

View File

@ -439,22 +439,42 @@ describe Topic do
let(:walter) { Fabricate(:walter_white) } let(:walter) { Fabricate(:walter_white) }
context 'by group name' do context 'by group name' do
let(:group) { Fabricate(:group) }
it 'can add admin to allowed groups' do it 'can add admin to allowed groups' do
admins = Group[:admins] admins = Group[:admins]
admins.alias_level = Group::ALIAS_LEVELS[:everyone] admins.update!(alias_level: Group::ALIAS_LEVELS[:everyone])
admins.save
expect(topic.invite_group(topic.user, admins)).to eq(true) expect(topic.invite_group(topic.user, admins)).to eq(true)
expect(topic.allowed_groups.include?(admins)).to eq(true) expect(topic.allowed_groups.include?(admins)).to eq(true)
expect(topic.remove_allowed_group(topic.user, 'admins')).to eq(true) expect(topic.remove_allowed_group(topic.user, 'admins')).to eq(true)
topic.reload
expect(topic.allowed_groups.include?(admins)).to eq(false) expect(topic.allowed_groups.include?(admins)).to eq(false)
end end
it 'creates a notification for each user in the group' do
user = Fabricate(:user)
user_2 = Fabricate(:user)
Fabricate(:post, topic: topic)
group.add(user)
group.add(user_2)
group.group_users.find_by(user: user_2).update!(
notification_level: NotificationLevels.all[:muted]
)
expect { topic.invite_group(topic.user, group) }
.to change { Notification.count }.by(1)
notification = Notification.last
expect(notification.user).to eq(user)
expect(notification.topic).to eq(topic)
expect(notification.notification_type)
.to eq(Notification.types[:invited_to_private_message])
end
end end
context 'by username' do context 'by username' do

View File

@ -45,7 +45,7 @@ function acceptance(name, options) {
resetMobile(); resetMobile();
// For now don't do scrolling stuff in Test Mode // For now don't do scrolling stuff in Test Mode
HeaderComponent.reopen({examineDockHeader: Ember.K}); HeaderComponent.reopen({examineDockHeader: function() { }});
resetExtraClasses(); resetExtraClasses();
const siteJson = siteFixtures['site.json'].site; const siteJson = siteFixtures['site.json'].site;

View File

@ -73,14 +73,12 @@ test("ensures an authorized upload", function() {
test("staff can upload anything in PM", function() { test("staff can upload anything in PM", function() {
const files = [{ name: "some.docx" }]; const files = [{ name: "some.docx" }];
Discourse.SiteSettings.authorized_extensions = "jpeg"; Discourse.SiteSettings.authorized_extensions = "jpeg";
Discourse.SiteSettings.allow_staff_to_upload_any_file_in_pm = true;
Discourse.User.resetCurrent(Discourse.User.create({ moderator: true })); Discourse.User.resetCurrent(Discourse.User.create({ moderator: true }));
sandbox.stub(bootbox, "alert"); sandbox.stub(bootbox, "alert");
not(validUpload(files)); not(validUpload(files));
ok(validUpload(files, { isPrivateMessage: true })); ok(validUpload(files, { isPrivateMessage: true, allowStaffToUploadAnyFileInPm: true }));
}); });
var imageSize = 10 * 1024; var imageSize = 10 * 1024;

View File

@ -108,7 +108,7 @@ QUnit.testStart(function(ctx) {
window.sandbox.stub(ScrollingDOMMethods, "unbindOnScroll"); window.sandbox.stub(ScrollingDOMMethods, "unbindOnScroll");
// Unless we ever need to test this, let's leave it off. // Unless we ever need to test this, let's leave it off.
$.fn.autocomplete = Ember.K; $.fn.autocomplete = function() { };
// Don't debounce in test unless we're testing debouncing // Don't debounce in test unless we're testing debouncing
if (ctx.module.indexOf('debounce') === -1) { if (ctx.module.indexOf('debounce') === -1) {