Merge branch 'master' of github.com:discourse/discourse

This commit is contained in:
Joffrey JAFFEUX 2019-05-08 11:50:50 +02:00
commit 0edf012dd9
12 changed files with 143 additions and 50 deletions

View File

@ -52,6 +52,11 @@ export default {
return true;
}
let href = ($link.attr("href") || $link.data("href") || "").trim();
if (!href || href.indexOf("mailto:") === 0) {
return true;
}
if ($link.hasClass("attachment")) {
// Warn the user if they cannot download the file.
if (
@ -59,17 +64,16 @@ export default {
!Discourse.User.current()
) {
bootbox.alert(I18n.t("post.errors.attachment_download_requires_login"));
} else if (wantsNewWindow(e)) {
const newWindow = window.open(href, "_blank");
newWindow.opener = null;
newWindow.focus();
} else {
DiscourseURL.redirectTo(href);
}
return false;
}
return true;
}
let href = ($link.attr("href") || $link.data("href") || "").trim();
if (!href || href.indexOf("mailto:") === 0) {
return true;
}
const $article = $link.closest(
"article:not(.onebox-body), .excerpt, #revisions"
);

View File

@ -5,6 +5,7 @@ import { defaultHomepage } from "discourse/lib/utilities";
import TopicList from "discourse/models/topic-list";
import { ajax } from "discourse/lib/ajax";
import PreloadStore from "preload-store";
import { searchPriorities } from "discourse/components/concerns/category_search_priorities";
const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, {
renderTemplate() {
@ -109,7 +110,8 @@ const DiscoveryCategoriesRoute = Discourse.Route.extend(OpenComposer, {
available_groups: groups.map(g => g.name),
allow_badges: true,
topic_featured_link_allowed: true,
custom_fields: {}
custom_fields: {},
search_priority: searchPriorities.normal
});
showModal("edit-category", { model });

View File

@ -0,0 +1,23 @@
module Jobs
class NotifyPostRevision < Jobs::Base
def execute(args)
raise Discourse::InvalidParameters.new(:user_ids) unless args[:user_ids]
post_revision = PostRevision.find_by(id: args[:post_revision_id])
raise Discourse::InvalidParameters.new(:post_revision_id) unless post_revision
ActiveRecord::Base.transaction do
User.where(id: args[:user_ids]).find_each do |user|
PostActionNotifier.alerter.create_notification(
user,
Notification.types[:edited],
post_revision.post,
display_username: post_revision.user.username,
acting_user_id: post_revision&.user_id,
revision_number: post_revision.number
)
end
end
end
end
end

View File

@ -7,11 +7,19 @@ class TopicUser < ActiveRecord::Base
# used for serialization
attr_accessor :post_action_data
scope :tracking, lambda { |topic_id|
scope :level, lambda { |topic_id, level|
where(topic_id: topic_id)
.where("COALESCE(topic_users.notification_level, :regular) >= :tracking",
.where("COALESCE(topic_users.notification_level, :regular) >= :level",
regular: TopicUser.notification_levels[:regular],
tracking: TopicUser.notification_levels[:tracking])
level: TopicUser.notification_levels[level])
}
scope :tracking, lambda { |topic_id|
level(topic_id, :tracking)
}
scope :watching, lambda { |topic_id|
level(topic_id, :watching)
}
# Class methods

View File

@ -93,21 +93,33 @@ class PostActionNotifier
return unless post
return if post_revision.user.blank?
return if post_revision.user_id == post.user_id
return if post.topic.blank?
return if post.topic.private_message?
return if SiteSetting.disable_edit_notifications && post_revision.user_id == Discourse::SYSTEM_USER_ID
alerter.create_notification(
post.user,
Notification.types[:edited],
post,
display_username: post_revision.user.username,
acting_user_id: post_revision.try(:user_id),
revision_number: post_revision.number
user_ids = []
if post_revision.user_id != post.user_id
user_ids << post.user_id
end
if post.wiki && post.is_first_post?
user_ids.concat(
TopicUser.watching(post.topic_id)
.where.not(user_id: post_revision.user_id)
.where(topic: post.topic)
.pluck(:user_id)
)
end
if user_ids.present?
Jobs.enqueue(:notify_post_revision,
user_ids: user_ids,
post_revision_id: post_revision.id
)
end
end
def self.after_post_unhide(post, flaggers)
return if @disabled || post.last_editor.blank? || flaggers.blank?

View File

@ -12,8 +12,7 @@ Discourse::Application.configure do
# Disable Rails's static asset server (Apache or nginx will already do this)
config.public_file_server.enabled = GlobalSetting.serve_static_assets || false
require 'uglifier'
config.assets.js_compressor = Uglifier.new(harmony: true)
config.assets.js_compressor = :uglifier
# stuff should be pre-compiled
config.assets.compile = false

View File

@ -16,7 +16,7 @@ task 'assets:precompile:before' do
# is recompiled
Emoji.clear_cache
if !`which uglifyjs`.empty? && !ENV['SKIP_NODE_UGLIFY']
if Rails.configuration.assets.js_compressor == :uglifier && !`which uglifyjs`.empty? && !ENV['SKIP_NODE_UGLIFY']
$node_uglify = true
end
@ -79,7 +79,7 @@ def compress_node(from, to)
source_map_root = assets + ((d = File.dirname(from)) == "." ? "" : "/#{d}")
source_map_url = cdn_path "/assets/#{to}.map"
cmd = "uglifyjs '#{assets_path}/#{from}' -p relative -m -c -o '#{to_path}' --source-map-root '#{source_map_root}' --source-map '#{assets_path}/#{to}.map' --source-map-url '#{source_map_url}'"
cmd = "uglifyjs '#{assets_path}/#{from}' -p relative -c -m -o '#{to_path}' --source-map-root '#{source_map_root}' --source-map '#{assets_path}/#{to}.map' --source-map-url '#{source_map_url}'"
STDERR.puts cmd
result = `#{cmd} 2>&1`
@ -128,16 +128,6 @@ def brotli(path)
raise "chmod failed: exit code #{$?.exitstatus}" if $?.exitstatus != 0
end
def should_compress?(path, locales)
return false if Rails.configuration.assets.skip_minification.include? path
return true unless path.include? "locales/"
path_locale = path.delete_prefix("locales/").delete_suffix(".js")
return true if locales.include? path_locale
false
end
def compress(from, to)
if $node_uglify
compress_node(from, to)
@ -173,15 +163,10 @@ task 'assets:precompile' => 'assets:precompile:before' do
if $bypass_sprockets_uglify
puts "Compressing Javascript and Generating Source Maps"
startAll = Process.clock_gettime(Process::CLOCK_MONOTONIC)
manifest = Sprockets::Manifest.new(assets_path)
locales = Set.new(["en"])
RailsMultisite::ConnectionManagement.each_connection do |db|
locales.add(SiteSetting.default_locale)
end
concurrent? do |proc|
to_skip = Rails.configuration.assets.skip_minification || []
manifest.files
.select { |k, v| k =~ /\.js$/ }
.each do |file, info|
@ -197,7 +182,8 @@ task 'assets:precompile' => 'assets:precompile:before' do
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
STDERR.puts "#{start} Compressing: #{file}"
if should_compress?(info["logical_path"], locales)
# We can specify some files to never minify
unless (ENV["DONT_MINIFY"] == "1") || to_skip.include?(info['logical_path'])
FileUtils.mv(path, _path)
compress(_file, file)
end
@ -205,7 +191,7 @@ task 'assets:precompile' => 'assets:precompile:before' do
info["size"] = File.size(path)
info["mtime"] = File.mtime(path).iso8601
gzip(path)
brotli(path) if should_compress?(info["logical_path"], locales)
brotli(path)
STDERR.puts "Done compressing #{file} : #{(Process.clock_gettime(Process::CLOCK_MONOTONIC) - start).round(2)} secs"
STDERR.puts
@ -214,9 +200,6 @@ task 'assets:precompile' => 'assets:precompile:before' do
end
end
STDERR.puts "Done compressing all JS files : #{(Process.clock_gettime(Process::CLOCK_MONOTONIC) - startAll).round(2)} secs"
STDERR.puts
# protected
manifest.send :save

View File

@ -69,7 +69,7 @@ module DiscourseNarrativeBot
valid = false
doc.css(".mention").each do |mention|
if mention.text.downcase == "@#{self.discobot_user.username}".downcase
if User.normalize_username(mention.text) == "@#{self.discobot_user.username_lower}"
valid = true
break
end

View File

@ -53,6 +53,7 @@ describe UserAction do
end
it 'includes the events correctly' do
Jobs.run_immediately!
PostActionNotifier.enable
mystats = stats_for_user(user)

View File

@ -6,6 +6,7 @@ describe PostActionNotifier do
before do
PostActionNotifier.enable
Jobs.run_immediately!
end
fab!(:evil_trout) { Fabricate(:evil_trout) }
@ -15,7 +16,62 @@ describe PostActionNotifier do
it 'notifies a user of the revision' do
expect {
post.revise(evil_trout, raw: "world is the new body of the message")
}.to change(post.user.notifications, :count).by(1)
}.to change { post.reload.user.notifications.count }.by(1)
end
it 'notifies watching users of revision when post is wiki-ed and first post in topic' do
SiteSetting.editing_grace_period_max_diff = 1
post.update!(wiki: true)
user = post.user
user2 = Fabricate(:user)
user3 = Fabricate(:user)
TopicUser.change(user2.id, post.topic,
notification_level: TopicUser.notification_levels[:watching]
)
TopicUser.change(user3.id, post.topic,
notification_level: TopicUser.notification_levels[:tracking]
)
expect do
post.revise(Fabricate(:user), raw: "I made some changes to the wiki!")
end.to change { Notification.count }.by(2)
edited_notification_type = Notification.types[:edited]
expect(Notification.exists?(
user: user,
notification_type: edited_notification_type
)).to eq(true)
expect(Notification.exists?(
user: user2,
notification_type: edited_notification_type
)).to eq(true)
expect do
post.revise(user, raw: "I made some changes to the wiki again!")
end.to change {
Notification.where(notification_type: edited_notification_type).count
}.by(1)
expect(Notification.where(
user: user2,
notification_type: edited_notification_type
).count).to eq(2)
expect do
post.revise(user2, raw: "I changed the wiki totally")
end.to change {
Notification.where(notification_type: edited_notification_type).count
}.by(1)
expect(Notification.where(
user: user,
notification_type: edited_notification_type
).count).to eq(2)
end
it 'stores the revision number with the notification' do

View File

@ -102,6 +102,7 @@ describe PostAlerter do
context 'edits' do
it 'notifies correctly on edits' do
Jobs.run_immediately!
PostActionNotifier.enable
post = Fabricate(:post, raw: 'I love waffles')

View File

@ -70,13 +70,17 @@ QUnit.test("does not track elements with no href", async assert => {
});
QUnit.test("does not track attachments", async assert => {
assert.expect(1);
sandbox.stub(DiscourseURL, "origin").returns("http://discuss.domain.com");
/* global server */
server.post("/clicks/track", () => assert.ok(false));
assert.ok(track(generateClickEventOn(".attachment")));
assert.notOk(track(generateClickEventOn(".attachment")));
assert.ok(
DiscourseURL.redirectTo.calledWith(
"http://discuss.domain.com/uploads/default/1234/1532357280.txt"
)
);
});
QUnit.test("tracks external URLs", async assert => {