Merge branch 'master' of github.com:discourse/discourse into bbpress-missing-display-name
This commit is contained in:
commit
e307bbccf9
|
@ -15,7 +15,7 @@ To learn more about the philosophy and goals of the project, [visit **discourse.
|
|||
<a href="http://discuss.howtogeek.com"><img src="https://www.discourse.org/faq/17/how-to-geek-discourse.png" width="720px"></a>
|
||||
<a href="https://talk.turtlerockstudios.com/"><img src="https://www.discourse.org/faq/17/turtle-rock-discourse.png" width="720px"></a>
|
||||
|
||||
<a href="https://discuss.atom.io"><img src="https://www.discourse.org/faq/15/nexus-7-2013-mobile-discourse.png?v=2" alt="Atom" width="430px"></a>
|
||||
<a href="https://discuss.atom.io"><img src="https://www.discourse.org/faq/17/nexus-7-2013-mobile-discourse.png" alt="Atom" width="430px"></a>
|
||||
<a href="//discourse.soylent.com"><img src="https://www.discourse.org/faq/15/iphone-5s-mobile-discourse.png" alt="Soylent" width="270px"></a>
|
||||
|
||||
Browse [lots more notable Discourse instances](http://www.discourse.org/faq/customers/).
|
||||
|
|
|
@ -6,6 +6,10 @@ export default Em.Component.extend(UploadMixin, {
|
|||
tagName: "span",
|
||||
uploadUrl: "/invites/upload_csv",
|
||||
|
||||
validateUploadedFilesOptions() {
|
||||
return { csvOnly: true };
|
||||
},
|
||||
|
||||
@computed("uploading")
|
||||
uploadButtonText(uploading) {
|
||||
return uploading ? I18n.t("uploading") : I18n.t("user.invited.bulk_invite.text");
|
||||
|
|
|
@ -192,6 +192,11 @@ export function validateUploadedFile(file, opts) {
|
|||
bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedImagesExtensions() }));
|
||||
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() && !isAuthorizedFile(name)) {
|
||||
bootbox.alert(I18n.t('post.errors.upload_not_authorized', { authorized_extensions: authorizedExtensions() }));
|
||||
|
|
|
@ -1,9 +1,18 @@
|
|||
import { register } from 'pretty-text/engines/discourse-markdown/bbcode';
|
||||
import { registerOption } from 'pretty-text/pretty-text';
|
||||
import { performEmojiUnescape } from 'pretty-text/emoji';
|
||||
|
||||
registerOption((siteSettings, opts) => {
|
||||
opts.enableEmoji = siteSettings.enable_emoji;
|
||||
opts.emojiSet = siteSettings.emoji_set;
|
||||
});
|
||||
|
||||
|
||||
export function setup(helper) {
|
||||
register(helper, 'quote', {noWrap: true, singlePara: true}, (contents, bbParams, options) => {
|
||||
const params = {'class': 'quote'};
|
||||
let username = null;
|
||||
const opts = helper.getOptions();
|
||||
|
||||
if (bbParams) {
|
||||
const paramsSplit = bbParams.split(/\,\s*/);
|
||||
|
@ -52,7 +61,16 @@ export function setup(helper) {
|
|||
if (postNumber > 0) { href += "/" + postNumber; }
|
||||
// get rid of username said stuff
|
||||
header.pop();
|
||||
header.push(['a', {'href': href}, topicInfo.title]);
|
||||
|
||||
let title = topicInfo.title;
|
||||
|
||||
if (opts.enableEmoji) {
|
||||
title = performEmojiUnescape(topicInfo.title, {
|
||||
getURL: opts.getURL, emojiSet: opts.emojiSet
|
||||
});
|
||||
}
|
||||
|
||||
header.push(['a', {'href': href}, title]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,7 @@ fieldset {
|
|||
|
||||
pre code {
|
||||
overflow: auto;
|
||||
tab-size: 4;
|
||||
}
|
||||
|
||||
// TODO figure out a clean place to put stuff like this
|
||||
|
|
|
@ -95,7 +95,14 @@ class Admin::BackupsController < Admin::AdminController
|
|||
|
||||
def readonly
|
||||
enable = params.fetch(:enable).to_s == "true"
|
||||
enable ? Discourse.enable_readonly_mode(user_enabled: true) : Discourse.disable_readonly_mode(user_enabled: true)
|
||||
readonly_mode_key = Discourse::USER_READONLY_MODE_KEY
|
||||
|
||||
if enable
|
||||
Discourse.enable_readonly_mode(readonly_mode_key)
|
||||
else
|
||||
Discourse.disable_readonly_mode(readonly_mode_key)
|
||||
end
|
||||
|
||||
render nothing: true
|
||||
end
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ class Admin::UsersController < Admin::AdminController
|
|||
def delete_all_posts
|
||||
@user = User.find_by(id: params[:user_id])
|
||||
@user.delete_all_posts!(guardian)
|
||||
# staff action logs will have an entry for each post
|
||||
render nothing: true
|
||||
end
|
||||
|
||||
|
@ -182,6 +183,8 @@ class Admin::UsersController < Admin::AdminController
|
|||
@user.trust_level_locked = new_lock == "true"
|
||||
@user.save
|
||||
|
||||
StaffActionLogger.new(current_user).log_lock_trust_level(@user)
|
||||
|
||||
unless @user.trust_level_locked
|
||||
p = Promotion.new(@user)
|
||||
2.times{ p.review }
|
||||
|
@ -210,12 +213,14 @@ class Admin::UsersController < Admin::AdminController
|
|||
def activate
|
||||
guardian.ensure_can_activate!(@user)
|
||||
@user.activate
|
||||
StaffActionLogger.new(current_user).log_user_activate(@user, I18n.t('user.activated_by_staff'))
|
||||
render json: success_json
|
||||
end
|
||||
|
||||
def deactivate
|
||||
guardian.ensure_can_deactivate!(@user)
|
||||
@user.deactivate
|
||||
StaffActionLogger.new(current_user).log_user_deactivate(@user, I18n.t('user.deactivated_by_staff'))
|
||||
refresh_browser @user
|
||||
render nothing: true
|
||||
end
|
||||
|
|
|
@ -156,9 +156,9 @@ class InvitesController < ApplicationController
|
|||
|
||||
Scheduler::Defer.later("Upload CSV") do
|
||||
begin
|
||||
data = if extension == ".csv"
|
||||
data = if extension.downcase == ".csv"
|
||||
path = Invite.create_csv(file, name)
|
||||
Jobs.enqueue(:bulk_invite, filename: "#{name}.csv", current_user_id: current_user.id)
|
||||
Jobs.enqueue(:bulk_invite, filename: "#{name}#{extension}", current_user_id: current_user.id)
|
||||
{url: path}
|
||||
else
|
||||
failed_json.merge(errors: [I18n.t("bulk_invite.file_should_be_csv")])
|
||||
|
|
|
@ -17,7 +17,7 @@ class MetadataController < ApplicationController
|
|||
name: SiteSetting.title,
|
||||
short_name: SiteSetting.title,
|
||||
display: 'standalone',
|
||||
orientation: 'portrait',
|
||||
orientation: 'any',
|
||||
start_url: "#{Discourse.base_uri}/",
|
||||
background_color: "##{ColorScheme.hex_for_name('secondary')}",
|
||||
theme_color: "##{ColorScheme.hex_for_name('header_background')}",
|
||||
|
|
|
@ -3,6 +3,7 @@ require_dependency 'email/message_builder'
|
|||
require_dependency 'age_words'
|
||||
|
||||
class UserNotifications < ActionMailer::Base
|
||||
include UserNotificationsHelper
|
||||
helper :application
|
||||
default charset: 'UTF-8'
|
||||
|
||||
|
@ -106,20 +107,27 @@ class UserNotifications < ActionMailer::Base
|
|||
end
|
||||
|
||||
@popular_topics = topics_for_digest[0,SiteSetting.digest_topics]
|
||||
@other_new_for_you = topics_for_digest.size > SiteSetting.digest_topics ? topics_for_digest[SiteSetting.digest_topics..-1] : []
|
||||
|
||||
@popular_posts = if SiteSetting.digest_posts > 0
|
||||
Post.order("posts.score DESC")
|
||||
.for_mailing_list(user, min_date)
|
||||
.where('posts.post_type = ?', Post.types[:regular])
|
||||
.where('posts.deleted_at IS NULL AND posts.hidden = false AND posts.user_deleted = false')
|
||||
.where("posts.post_number > ? AND posts.score > ?", 1, ScoreCalculator.default_score_weights[:like_score] * 5.0)
|
||||
.limit(SiteSetting.digest_posts)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
if @popular_topics.present?
|
||||
@other_new_for_you = topics_for_digest.size > SiteSetting.digest_topics ? topics_for_digest[SiteSetting.digest_topics..-1] : []
|
||||
|
||||
@popular_posts = if SiteSetting.digest_posts > 0
|
||||
Post.order("posts.score DESC")
|
||||
.for_mailing_list(user, min_date)
|
||||
.where('posts.post_type = ?', Post.types[:regular])
|
||||
.where('posts.deleted_at IS NULL AND posts.hidden = false AND posts.user_deleted = false')
|
||||
.where("posts.post_number > ? AND posts.score > ?", 1, ScoreCalculator.default_score_weights[:like_score] * 5.0)
|
||||
.limit(SiteSetting.digest_posts)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
@excerpts = {}
|
||||
|
||||
@popular_topics.map do |t|
|
||||
@excerpts[t.first_post.id] = email_excerpt(t.first_post.cooked) if t.first_post.present?
|
||||
end
|
||||
|
||||
# Try to find 3 interesting stats for the top of the digest
|
||||
|
||||
new_topics_count = Topic.new_since_last_seen(user, min_date).count
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
require_dependency 'slug'
|
||||
|
||||
class Badge < ActiveRecord::Base
|
||||
# NOTE: These badge ids are not in order! They are grouped logically.
|
||||
# When picking an id, *search* for it.
|
||||
|
@ -119,6 +121,10 @@ class Badge < ActiveRecord::Base
|
|||
}
|
||||
end
|
||||
|
||||
def awarded_for_trust_level?
|
||||
id <= 4
|
||||
end
|
||||
|
||||
def reset_grant_count!
|
||||
self.grant_count = UserBadge.where(badge_id: id).count
|
||||
save!
|
||||
|
@ -208,6 +214,7 @@ SQL
|
|||
def i18n_name
|
||||
self.name.downcase.tr(' ', '_')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
|
|
@ -145,14 +145,14 @@ class GlobalSetting
|
|||
attr_accessor :provider
|
||||
end
|
||||
|
||||
|
||||
if Rails.env == "test"
|
||||
@provider = BlankProvider.new
|
||||
else
|
||||
@provider =
|
||||
FileProvider.from(File.expand_path('../../../config/discourse.conf', __FILE__)) ||
|
||||
EnvProvider.new
|
||||
def self.configure!
|
||||
if Rails.env == "test"
|
||||
@provider = BlankProvider.new
|
||||
else
|
||||
@provider =
|
||||
FileProvider.from(File.expand_path('../../../config/discourse.conf', __FILE__)) ||
|
||||
EnvProvider.new
|
||||
end
|
||||
end
|
||||
|
||||
load_defaults
|
||||
end
|
||||
|
|
|
@ -55,7 +55,10 @@ class UserHistory < ActiveRecord::Base
|
|||
rate_limited_like: 37, # not used anymore
|
||||
revoke_email: 38,
|
||||
deactivate_user: 39,
|
||||
wizard_step: 40
|
||||
wizard_step: 40,
|
||||
lock_trust_level: 41,
|
||||
unlock_trust_level: 42,
|
||||
activate_user: 43
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -91,7 +94,10 @@ class UserHistory < ActiveRecord::Base
|
|||
:revoke_moderation,
|
||||
:backup_operation,
|
||||
:revoke_email,
|
||||
:deactivate_user]
|
||||
:deactivate_user,
|
||||
:lock_trust_level,
|
||||
:unlock_trust_level,
|
||||
:activate_user]
|
||||
end
|
||||
|
||||
def self.staff_action_ids
|
||||
|
|
|
@ -274,7 +274,7 @@ class BadgeGranter
|
|||
/*where*/
|
||||
RETURNING id, user_id, granted_at
|
||||
)
|
||||
select w.*, username, locale FROM w
|
||||
select w.*, username, locale, (u.admin OR u.moderator) AS staff FROM w
|
||||
JOIN users u on u.id = w.user_id
|
||||
"
|
||||
|
||||
|
@ -315,6 +315,8 @@ class BadgeGranter
|
|||
# Make this variable in this scope
|
||||
notification = nil
|
||||
|
||||
next if (row.staff && badge.awarded_for_trust_level?)
|
||||
|
||||
I18n.with_locale(notification_locale) do
|
||||
notification = Notification.create!(
|
||||
user_id: row.user_id,
|
||||
|
|
|
@ -14,7 +14,6 @@ class StaffActionLogger
|
|||
raise Discourse::InvalidParameters.new(:deleted_user) unless deleted_user && deleted_user.is_a?(User)
|
||||
UserHistory.create( params(opts).merge({
|
||||
action: UserHistory.actions[:delete_user],
|
||||
email: deleted_user.email,
|
||||
ip_address: deleted_user.ip_address.to_s,
|
||||
details: [:id, :username, :name, :created_at, :trust_level, :last_seen_at, :last_emailed_at].map { |x| "#{x}: #{deleted_user.send(x)}" }.join("\n")
|
||||
}))
|
||||
|
@ -96,6 +95,14 @@ class StaffActionLogger
|
|||
}))
|
||||
end
|
||||
|
||||
def log_lock_trust_level(user, opts={})
|
||||
raise Discourse::InvalidParameters.new(:user) unless user && user.is_a?(User)
|
||||
UserHistory.create!( params(opts).merge({
|
||||
action: UserHistory.actions[user.trust_level_locked ? :lock_trust_level : :unlock_trust_level],
|
||||
target_user_id: user.id
|
||||
}))
|
||||
end
|
||||
|
||||
def log_site_setting_change(setting_name, previous_value, new_value, opts={})
|
||||
raise Discourse::InvalidParameters.new(:setting_name) unless setting_name.present? && SiteSetting.respond_to?(setting_name)
|
||||
UserHistory.create( params(opts).merge({
|
||||
|
@ -353,6 +360,15 @@ class StaffActionLogger
|
|||
}))
|
||||
end
|
||||
|
||||
def log_user_activate(user, reason, opts={})
|
||||
raise Discourse::InvalidParameters.new(:user) unless user
|
||||
UserHistory.create(params(opts).merge({
|
||||
action: UserHistory.actions[:activate_user],
|
||||
target_user_id: user.id,
|
||||
details: reason
|
||||
}))
|
||||
end
|
||||
|
||||
def log_wizard_step(step, opts={})
|
||||
raise Discourse::InvalidParameters.new(:step) unless step
|
||||
UserHistory.create(params(opts).merge({
|
||||
|
|
|
@ -17,8 +17,11 @@ class UserBlocker
|
|||
unless @user.blocked?
|
||||
@user.blocked = true
|
||||
if @user.save
|
||||
SystemMessage.create(@user, @opts[:message] || :blocked_by_staff)
|
||||
StaffActionLogger.new(@by_user).log_block_user(@user) if @by_user
|
||||
message_type = @opts[:message] || :blocked_by_staff
|
||||
post = SystemMessage.create(@user, message_type)
|
||||
if post && @by_user
|
||||
StaffActionLogger.new(@by_user).log_block_user(@user, {context: "#{message_type}: '#{post.topic&.title rescue ''}'"})
|
||||
end
|
||||
end
|
||||
else
|
||||
false
|
||||
|
|
|
@ -149,7 +149,7 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
|
|||
<p style="color:inherit;font-size:14px;font-weight:400;line-height:1.3;margin:0 0 8px 0;padding:0;word-wrap:normal;"><%= t.user.username -%></p>
|
||||
<% end %>
|
||||
</td>
|
||||
<%- if show_image_with_url(t.image_url) && t.featured_link.nil? -%>
|
||||
<%- if show_image_with_url(t.image_url) && t.featured_link.nil? && !(@excerpts[t.first_post&.id]||"").include?(t.image_url) -%>
|
||||
<td style="margin:0;padding:0 16px 0 8px;text-align:right;" align="right">
|
||||
<img src="<%= url_for_email(t.image_url) -%>" height="64" style="margin:auto;max-height:64px;max-width:100%;outline:0;text-align:right;text-decoration:none;">
|
||||
</td>
|
||||
|
@ -163,7 +163,7 @@ body, table, td, th, h1, h2, h3 {font-family: Helvetica, Arial, sans-serif !impo
|
|||
<tbody>
|
||||
<tr>
|
||||
<td class="post-excerpt" style="color:#0a0a0a;font-size:14px;padding:0 16px 0 16px;text-align:left;width:100%;font-weight:normal;">
|
||||
<%= email_excerpt(t.first_post.cooked) %>
|
||||
<%= @excerpts[t.first_post.id] %>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -6,8 +6,15 @@ require_relative '../lib/discourse_event'
|
|||
require_relative '../lib/discourse_plugin'
|
||||
require_relative '../lib/discourse_plugin_registry'
|
||||
|
||||
require_relative '../lib/plugin_gem'
|
||||
|
||||
# Global config
|
||||
require_relative '../app/models/global_setting'
|
||||
GlobalSetting.configure!
|
||||
unless Rails.env.test? && ENV['LOAD_PLUGINS'] != "1"
|
||||
require_relative '../lib/custom_setting_providers'
|
||||
end
|
||||
GlobalSetting.load_defaults
|
||||
|
||||
require 'pry-rails' if Rails.env.development?
|
||||
|
||||
|
@ -15,8 +22,10 @@ if defined?(Bundler)
|
|||
Bundler.require(*Rails.groups(assets: %w(development test profile)))
|
||||
end
|
||||
|
||||
|
||||
module Discourse
|
||||
class Application < Rails::Application
|
||||
|
||||
def config.database_configuration
|
||||
if Rails.env.production?
|
||||
GlobalSetting.database_config
|
||||
|
|
|
@ -833,6 +833,7 @@ en:
|
|||
none: "You haven't invited anyone here yet. You can send individual invites, or invite a bunch of people at once by <a href='https://meta.discourse.org/t/send-bulk-invites/16468'>uploading a CSV file</a>."
|
||||
text: "Bulk Invite from File"
|
||||
success: "File uploaded successfully, you will be notified via message when the process is complete."
|
||||
error: "Sorry, file should be of csv format."
|
||||
|
||||
password:
|
||||
title: "Password"
|
||||
|
@ -2409,8 +2410,8 @@ en:
|
|||
backups: "backups"
|
||||
traffic_short: "Traffic"
|
||||
traffic: "Application web requests"
|
||||
page_views: "API Requests"
|
||||
page_views_short: "API Requests"
|
||||
page_views: "Pageviews"
|
||||
page_views_short: "Pageviews"
|
||||
show_traffic_report: "Show Detailed Traffic Report"
|
||||
|
||||
reports:
|
||||
|
@ -2914,6 +2915,10 @@ en:
|
|||
deleted_tag: "deleted tag"
|
||||
renamed_tag: "renamed tag"
|
||||
revoke_email: "revoke email"
|
||||
lock_trust_level: "lock trust level"
|
||||
unlock_trust_level: "unlock trust level"
|
||||
activate_user: "activate user"
|
||||
deactivate_user: "deactivate user"
|
||||
screened_emails:
|
||||
title: "Screened Emails"
|
||||
description: "When someone tries to create a new account, the following email addresses will be checked and the registration will be blocked, or some other action performed."
|
||||
|
|
|
@ -53,6 +53,7 @@ en:
|
|||
purge_reason: "Automatically deleted as abandoned, deactivated account"
|
||||
disable_remote_images_download_reason: "Remote images download was disabled because there wasn't enough disk space available."
|
||||
anonymous: "Anonymous"
|
||||
remove_posts_deleted_by_author: "Deleted by author"
|
||||
|
||||
emails:
|
||||
incoming:
|
||||
|
@ -1615,6 +1616,8 @@ en:
|
|||
user:
|
||||
no_accounts_associated: "No accounts associated"
|
||||
deactivated: "Was deactivated due to too many bounced emails to '%{email}'."
|
||||
deactivated_by_staff: "Deactivated by staff"
|
||||
activated_by_staff: "Activated by staff"
|
||||
username:
|
||||
short: "must be at least %{min} characters"
|
||||
long: "must be no more than %{max} characters"
|
||||
|
|
|
@ -701,7 +701,7 @@ files:
|
|||
default: 3072
|
||||
authorized_extensions:
|
||||
client: true
|
||||
default: 'jpg|jpeg|png|gif|csv'
|
||||
default: 'jpg|jpeg|png|gif'
|
||||
refresh: true
|
||||
type: list
|
||||
crawl_images:
|
||||
|
|
|
@ -52,7 +52,7 @@ class PostgreSQLFallbackHandler
|
|||
logger.warn "#{log_prefix}: Master server is active. Reconnecting..."
|
||||
|
||||
self.master_up(key)
|
||||
Discourse.disable_readonly_mode
|
||||
Discourse.disable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
||||
end
|
||||
rescue => e
|
||||
logger.warn "#{log_prefix}: Connection to master PostgreSQL server failed with '#{e.message}'"
|
||||
|
@ -103,7 +103,7 @@ module ActiveRecord
|
|||
}))
|
||||
|
||||
verify_replica(connection)
|
||||
Discourse.enable_readonly_mode
|
||||
Discourse.enable_readonly_mode(Discourse::PG_READONLY_MODE_KEY)
|
||||
else
|
||||
begin
|
||||
connection = postgresql_connection(config)
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
# Support for plugins to register custom setting providers. They can do this
|
||||
# by having a file, `register_provider.rb` in their root that will be run
|
||||
# at this point.
|
||||
|
||||
Dir.glob(File.join(File.dirname(__FILE__), '../plugins', '*', "register_provider.rb")) do |p|
|
||||
require p
|
||||
end
|
|
@ -113,24 +113,6 @@ module Discourse
|
|||
end
|
||||
end
|
||||
|
||||
def self.last_read_only
|
||||
@last_read_only ||= {}
|
||||
end
|
||||
|
||||
def self.recently_readonly?
|
||||
read_only = last_read_only[$redis.namespace]
|
||||
return false unless read_only
|
||||
read_only > 15.seconds.ago
|
||||
end
|
||||
|
||||
def self.received_readonly!
|
||||
last_read_only[$redis.namespace] = Time.zone.now
|
||||
end
|
||||
|
||||
def self.clear_readonly!
|
||||
last_read_only[$redis.namespace] = nil
|
||||
end
|
||||
|
||||
def self.disabled_plugin_names
|
||||
plugins.select { |p| !p.enabled? }.map(&:name)
|
||||
end
|
||||
|
@ -210,43 +192,66 @@ module Discourse
|
|||
base_url_no_prefix + base_uri
|
||||
end
|
||||
|
||||
READONLY_MODE_KEY_TTL ||= 60
|
||||
READONLY_MODE_KEY ||= 'readonly_mode'.freeze
|
||||
READONLY_MODE_KEY_TTL ||= 60
|
||||
READONLY_MODE_KEY ||= 'readonly_mode'.freeze
|
||||
PG_READONLY_MODE_KEY ||= 'readonly_mode:postgres'.freeze
|
||||
USER_READONLY_MODE_KEY ||= 'readonly_mode:user'.freeze
|
||||
|
||||
def self.enable_readonly_mode(user_enabled: false)
|
||||
if user_enabled
|
||||
$redis.set(USER_READONLY_MODE_KEY, 1)
|
||||
READONLY_KEYS ||= [
|
||||
READONLY_MODE_KEY,
|
||||
PG_READONLY_MODE_KEY,
|
||||
USER_READONLY_MODE_KEY
|
||||
]
|
||||
|
||||
def self.enable_readonly_mode(key = READONLY_MODE_KEY)
|
||||
if key == USER_READONLY_MODE_KEY
|
||||
$redis.set(key, 1)
|
||||
else
|
||||
$redis.setex(READONLY_MODE_KEY, READONLY_MODE_KEY_TTL, 1)
|
||||
keep_readonly_mode
|
||||
$redis.setex(key, READONLY_MODE_KEY_TTL, 1)
|
||||
keep_readonly_mode(key)
|
||||
end
|
||||
|
||||
MessageBus.publish(readonly_channel, true)
|
||||
true
|
||||
end
|
||||
|
||||
def self.keep_readonly_mode
|
||||
def self.keep_readonly_mode(key)
|
||||
# extend the expiry by 1 minute every 30 seconds
|
||||
unless Rails.env.test?
|
||||
Thread.new do
|
||||
while readonly_mode?
|
||||
$redis.expire(READONLY_MODE_KEY, READONLY_MODE_KEY_TTL)
|
||||
$redis.expire(key, READONLY_MODE_KEY_TTL)
|
||||
sleep 30.seconds
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.disable_readonly_mode(user_enabled: false)
|
||||
key = user_enabled ? USER_READONLY_MODE_KEY : READONLY_MODE_KEY
|
||||
def self.disable_readonly_mode(key = READONLY_MODE_KEY)
|
||||
$redis.del(key)
|
||||
MessageBus.publish(readonly_channel, false)
|
||||
true
|
||||
end
|
||||
|
||||
def self.readonly_mode?
|
||||
recently_readonly? || !!$redis.get(READONLY_MODE_KEY) || !!$redis.get(USER_READONLY_MODE_KEY)
|
||||
recently_readonly? || READONLY_KEYS.any? { |key| !!$redis.get(key) }
|
||||
end
|
||||
|
||||
def self.last_read_only
|
||||
@last_read_only ||= {}
|
||||
end
|
||||
|
||||
def self.recently_readonly?
|
||||
return false unless read_only = last_read_only[$redis.namespace]
|
||||
read_only > 15.seconds.ago
|
||||
end
|
||||
|
||||
def self.received_readonly!
|
||||
last_read_only[$redis.namespace] = Time.zone.now
|
||||
end
|
||||
|
||||
def self.clear_readonly!
|
||||
last_read_only[$redis.namespace] = nil
|
||||
end
|
||||
|
||||
def self.request_refresh!
|
||||
|
|
|
@ -156,7 +156,7 @@ module Email
|
|||
elsif bounce_score >= SiteSetting.bounce_score_threshold
|
||||
# NOTE: we check bounce_score before sending emails, nothing to do
|
||||
# here other than log it happened.
|
||||
reason = I18n.t("user.email.revoked", email: user.email, date: user.user_stat.reset_bounce_score_after)
|
||||
reason = I18n.t("user.email.revoked", date: user.user_stat.reset_bounce_score_after)
|
||||
StaffActionLogger.new(Discourse.system_user).log_revoke_email(user, reason)
|
||||
end
|
||||
end
|
||||
|
@ -239,6 +239,8 @@ module Email
|
|||
end
|
||||
|
||||
def parse_from_field(mail)
|
||||
return unless mail[:from]
|
||||
|
||||
if mail[:from].errors.blank?
|
||||
mail[:from].address_list.addresses.each do |address_field|
|
||||
address_field.decoded
|
||||
|
|
|
@ -363,27 +363,7 @@ JS
|
|||
#
|
||||
# This is a very rough initial implementation
|
||||
def gem(name, version, opts = {})
|
||||
gems_path = File.dirname(path) + "/gems/#{RUBY_VERSION}"
|
||||
spec_path = gems_path + "/specifications"
|
||||
spec_file = spec_path + "/#{name}-#{version}.gemspec"
|
||||
unless File.exists? spec_file
|
||||
command = "gem install #{name} -v #{version} -i #{gems_path} --no-document --ignore-dependencies"
|
||||
if opts[:source]
|
||||
command << " --source #{opts[:source]}"
|
||||
end
|
||||
puts command
|
||||
puts `#{command}`
|
||||
end
|
||||
if File.exists? spec_file
|
||||
spec = Gem::Specification.load spec_file
|
||||
spec.activate
|
||||
unless opts[:require] == false
|
||||
require opts[:require_name] ? opts[:require_name] : name
|
||||
end
|
||||
else
|
||||
puts "You are specifying the gem #{name} in #{path}, however it does not exist!"
|
||||
exit(-1)
|
||||
end
|
||||
PluginGem.load(path, name, version, opts)
|
||||
end
|
||||
|
||||
def enabled_site_setting(setting=nil)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
module PluginGem
|
||||
def self.load(path, name, version, opts=nil)
|
||||
opts ||= {}
|
||||
|
||||
gems_path = File.dirname(path) + "/gems/#{RUBY_VERSION}"
|
||||
spec_path = gems_path + "/specifications"
|
||||
spec_file = spec_path + "/#{name}-#{version}.gemspec"
|
||||
unless File.exists? spec_file
|
||||
command = "gem install #{name} -v #{version} -i #{gems_path} --no-document --ignore-dependencies"
|
||||
if opts[:source]
|
||||
command << " --source #{opts[:source]}"
|
||||
end
|
||||
puts command
|
||||
puts `#{command}`
|
||||
end
|
||||
if File.exists? spec_file
|
||||
spec = Gem::Specification.load spec_file
|
||||
spec.activate
|
||||
unless opts[:require] == false
|
||||
require opts[:require_name] ? opts[:require_name] : name
|
||||
end
|
||||
else
|
||||
puts "You are specifying the gem #{name} in #{path}, however it does not exist!"
|
||||
exit(-1)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -29,7 +29,7 @@ class PostDestroyer
|
|||
pa.post_action_type_id IN (?)
|
||||
)", PostActionType.notify_flag_type_ids)
|
||||
.each do |post|
|
||||
PostDestroyer.new(Discourse.system_user, post).destroy
|
||||
PostDestroyer.new(Discourse.system_user, post, {context: I18n.t('remove_posts_deleted_by_author')}).destroy
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ module PrettyText
|
|||
topic = Topic.find_by(id: topic_id)
|
||||
if topic && Guardian.new.can_see?(topic)
|
||||
{
|
||||
title: topic.title,
|
||||
title: Rack::Utils.escape_html(topic.title),
|
||||
href: topic.url
|
||||
}
|
||||
end
|
||||
|
|
|
@ -16,6 +16,8 @@ class ImportScripts::Bbpress < ImportScripts::Base
|
|||
BATCH_SIZE ||= 1000
|
||||
BB_PRESS_PW ||= ENV['BBPRESS_PW'] || ""
|
||||
BB_PRESS_USER ||= ENV['BBPRESS_USER'] || "root"
|
||||
BB_PRESS_PREFIX ||= ENV['BBPRESS_PREFIX'] || "wp_"
|
||||
|
||||
def initialize
|
||||
super
|
||||
|
||||
|
@ -37,12 +39,12 @@ class ImportScripts::Bbpress < ImportScripts::Base
|
|||
puts "", "importing users..."
|
||||
|
||||
last_user_id = -1
|
||||
total_users = bbpress_query("SELECT COUNT(*) count FROM wp_users WHERE user_email LIKE '%@%'").first["count"]
|
||||
total_users = bbpress_query("SELECT COUNT(*) count FROM #{BB_PRESS_PREFIX}users WHERE user_email LIKE '%@%'").first["count"]
|
||||
|
||||
batches(BATCH_SIZE) do |offset|
|
||||
users = bbpress_query(<<-SQL
|
||||
SELECT id, user_nicename, display_name, user_email, user_registered, user_url
|
||||
FROM wp_users
|
||||
FROM #{BB_PRESS_PREFIX}users
|
||||
WHERE user_email LIKE '%@%'
|
||||
AND id > #{last_user_id}
|
||||
ORDER BY id
|
||||
|
@ -62,7 +64,7 @@ class ImportScripts::Bbpress < ImportScripts::Base
|
|||
users_description = {}
|
||||
bbpress_query(<<-SQL
|
||||
SELECT user_id, meta_value description
|
||||
FROM wp_usermeta
|
||||
FROM #{BB_PRESS_PREFIX}usermeta
|
||||
WHERE user_id IN (#{user_ids_sql})
|
||||
AND meta_key = 'description'
|
||||
SQL
|
||||
|
@ -71,7 +73,7 @@ class ImportScripts::Bbpress < ImportScripts::Base
|
|||
users_last_activity = {}
|
||||
bbpress_query(<<-SQL
|
||||
SELECT user_id, meta_value last_activity
|
||||
FROM wp_usermeta
|
||||
FROM #{BB_PRESS_PREFIX}usermeta
|
||||
WHERE user_id IN (#{user_ids_sql})
|
||||
AND meta_key = 'last_activity'
|
||||
SQL
|
||||
|
@ -97,7 +99,7 @@ class ImportScripts::Bbpress < ImportScripts::Base
|
|||
|
||||
categories = bbpress_query(<<-SQL
|
||||
SELECT id, post_name, post_parent
|
||||
FROM wp_posts
|
||||
FROM #{BB_PRESS_PREFIX}posts
|
||||
WHERE post_type = 'forum'
|
||||
AND LENGTH(COALESCE(post_name, '')) > 0
|
||||
ORDER BY post_parent, id
|
||||
|
@ -119,7 +121,7 @@ class ImportScripts::Bbpress < ImportScripts::Base
|
|||
last_post_id = -1
|
||||
total_posts = bbpress_query(<<-SQL
|
||||
SELECT COUNT(*) count
|
||||
FROM wp_posts
|
||||
FROM #{BB_PRESS_PREFIX}posts
|
||||
WHERE post_status <> 'spam'
|
||||
AND post_type IN ('topic', 'reply')
|
||||
SQL
|
||||
|
@ -134,7 +136,7 @@ class ImportScripts::Bbpress < ImportScripts::Base
|
|||
post_title,
|
||||
post_type,
|
||||
post_parent
|
||||
FROM wp_posts
|
||||
FROM #{BB_PRESS_PREFIX}posts
|
||||
WHERE post_status <> 'spam'
|
||||
AND post_type IN ('topic', 'reply')
|
||||
AND id > #{last_post_id}
|
||||
|
@ -155,7 +157,7 @@ class ImportScripts::Bbpress < ImportScripts::Base
|
|||
posts_likes = {}
|
||||
bbpress_query(<<-SQL
|
||||
SELECT post_id, meta_value likes
|
||||
FROM wp_postmeta
|
||||
FROM #{BB_PRESS_PREFIX}postmeta
|
||||
WHERE post_id IN (#{post_ids_sql})
|
||||
AND meta_key = 'Likes'
|
||||
SQL
|
||||
|
|
|
@ -0,0 +1,210 @@
|
|||
require "mysql2"
|
||||
require File.expand_path(File.dirname(__FILE__) + "/base.rb")
|
||||
|
||||
class ImportScripts::Drupal < ImportScripts::Base
|
||||
|
||||
DRUPAL_DB = ENV['DRUPAL_DB'] || "newsite3"
|
||||
VID = ENV['DRUPAL_VID'] || 1
|
||||
|
||||
def initialize
|
||||
super
|
||||
|
||||
@client = Mysql2::Client.new(
|
||||
host: "localhost",
|
||||
username: "root",
|
||||
#password: "password",
|
||||
database: DRUPAL_DB
|
||||
)
|
||||
end
|
||||
|
||||
def categories_query
|
||||
@client.query("SELECT tid, name, description FROM term_data WHERE vid = #{VID}")
|
||||
end
|
||||
|
||||
def execute
|
||||
create_users(@client.query("SELECT uid id, name, mail email, created FROM users;")) do |row|
|
||||
{id: row['id'], username: row['name'], email: row['email'], created_at: Time.zone.at(row['created'])}
|
||||
end
|
||||
|
||||
# You'll need to edit the following query for your Drupal install:
|
||||
#
|
||||
# * Drupal allows duplicate category names, so you may need to exclude some categories or rename them here.
|
||||
# * Table name may be term_data.
|
||||
# * May need to select a vid other than 1.
|
||||
create_categories(categories_query) do |c|
|
||||
{id: c['tid'], name: c['name'], description: c['description']}
|
||||
end
|
||||
|
||||
# "Nodes" in Drupal are divided into types. Here we import two types,
|
||||
# and will later import all the comments/replies for each node.
|
||||
# You will need to figure out what the type names are on your install and edit the queries to match.
|
||||
if ENV['DRUPAL_IMPORT_BLOG']
|
||||
create_blog_topics
|
||||
end
|
||||
|
||||
create_forum_topics
|
||||
|
||||
create_replies
|
||||
|
||||
begin
|
||||
create_admin(email: 'neil.lalonde@discourse.org', username: UserNameSuggester.suggest('neil'))
|
||||
rescue => e
|
||||
puts '', "Failed to create admin user"
|
||||
puts e.message
|
||||
end
|
||||
end
|
||||
|
||||
def create_blog_topics
|
||||
puts '', "creating blog topics"
|
||||
|
||||
create_category({
|
||||
name: 'Blog',
|
||||
user_id: -1,
|
||||
description: "Articles from the blog"
|
||||
}, nil) unless Category.find_by_name('Blog')
|
||||
|
||||
results = @client.query("
|
||||
SELECT n.nid nid,
|
||||
n.title title,
|
||||
n.uid uid,
|
||||
n.created created,
|
||||
n.sticky sticky,
|
||||
nr.body body
|
||||
FROM node n
|
||||
LEFT JOIN node_revisions nr ON nr.vid=n.vid
|
||||
WHERE n.type = 'blog'
|
||||
AND n.status = 1
|
||||
", cache_rows: false)
|
||||
|
||||
create_posts(results) do |row|
|
||||
{
|
||||
id: "nid:#{row['nid']}",
|
||||
user_id: user_id_from_imported_user_id(row['uid']) || -1,
|
||||
category: 'Blog',
|
||||
raw: row['body'],
|
||||
created_at: Time.zone.at(row['created']),
|
||||
pinned_at: row['sticky'].to_i == 1 ? Time.zone.at(row['created']) : nil,
|
||||
title: row['title'].try(:strip),
|
||||
custom_fields: {import_id: "nid:#{row['nid']}"}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def create_forum_topics
|
||||
puts '', "creating forum topics"
|
||||
|
||||
total_count = @client.query("
|
||||
SELECT COUNT(*) count
|
||||
FROM node n
|
||||
LEFT JOIN forum f ON f.vid=n.vid
|
||||
WHERE n.type = 'forum'
|
||||
AND n.status = 1
|
||||
").first['count']
|
||||
|
||||
batch_size = 1000
|
||||
|
||||
batches(batch_size) do |offset|
|
||||
results = @client.query("
|
||||
SELECT n.nid nid,
|
||||
n.title title,
|
||||
f.tid tid,
|
||||
n.uid uid,
|
||||
n.created created,
|
||||
n.sticky sticky,
|
||||
nr.body body
|
||||
FROM node n
|
||||
LEFT JOIN forum f ON f.vid=n.vid
|
||||
LEFT JOIN node_revisions nr ON nr.vid=n.vid
|
||||
WHERE node.type = 'forum'
|
||||
AND node.status = 1
|
||||
LIMIT #{batch_size}
|
||||
OFFSET #{offset};
|
||||
", cache_rows: false)
|
||||
|
||||
break if results.size < 1
|
||||
|
||||
next if all_records_exist? :posts, results.map {|p| "nid:#{p['nid']}"}
|
||||
|
||||
create_posts(results, total: total_count, offset: offset) do |row|
|
||||
{
|
||||
id: "nid:#{row['nid']}",
|
||||
user_id: user_id_from_imported_user_id(row['uid']) || -1,
|
||||
category: category_id_from_imported_category_id(row['tid']),
|
||||
raw: row['body'],
|
||||
created_at: Time.zone.at(row['created']),
|
||||
pinned_at: row['sticky'].to_i == 1 ? Time.zone.at(row['created']) : nil,
|
||||
title: row['title'].try(:strip)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_replies
|
||||
puts '', "creating replies in topics"
|
||||
|
||||
if ENV['DRUPAL_IMPORT_BLOG']
|
||||
node_types = "('forum','blog')"
|
||||
else
|
||||
node_types = "('forum')"
|
||||
end
|
||||
|
||||
total_count = @client.query("
|
||||
SELECT COUNT(*) count
|
||||
FROM comments c
|
||||
LEFT JOIN node n ON n.nid=c.nid
|
||||
WHERE node.type IN #{node_types}
|
||||
AND node.status = 1
|
||||
AND comments.status=0;
|
||||
").first['count']
|
||||
|
||||
batch_size = 1000
|
||||
|
||||
batches(batch_size) do |offset|
|
||||
results = @client.query("
|
||||
SELECT c.cid,
|
||||
c.pid,
|
||||
c.nid,
|
||||
c.uid,
|
||||
c.timestamp,
|
||||
c.comment body
|
||||
FROM comments c
|
||||
LEFT JOIN node n ON n.nid=c.nid
|
||||
WHERE n.type IN #{node_types}
|
||||
AND n.status = 1
|
||||
AND c.status=0
|
||||
LIMIT #{batch_size}
|
||||
OFFSET #{offset};
|
||||
", cache_rows: false)
|
||||
|
||||
break if results.size < 1
|
||||
|
||||
next if all_records_exist? :posts, results.map {|p| "cid:#{p['cid']}"}
|
||||
|
||||
create_posts(results, total: total_count, offset: offset) do |row|
|
||||
topic_mapping = topic_lookup_from_imported_post_id("nid:#{row['nid']}")
|
||||
if topic_mapping && topic_id = topic_mapping[:topic_id]
|
||||
h = {
|
||||
id: "cid:#{row['cid']}",
|
||||
topic_id: topic_id,
|
||||
user_id: user_id_from_imported_user_id(row['uid']) || -1,
|
||||
raw: row['body'],
|
||||
created_at: Time.zone.at(row['timestamp']),
|
||||
}
|
||||
if row['pid']
|
||||
parent = topic_lookup_from_imported_post_id("cid:#{row['pid']}")
|
||||
h[:reply_to_post_number] = parent[:post_number] if parent and parent[:post_number] > 1
|
||||
end
|
||||
h
|
||||
else
|
||||
puts "No topic found for comment #{row['cid']}"
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if __FILE__==$0
|
||||
ImportScripts::Drupal.new.perform
|
||||
end
|
|
@ -42,8 +42,13 @@ describe ActiveRecord::ConnectionHandling do
|
|||
end
|
||||
|
||||
after do
|
||||
with_multisite_db(multisite_db) { Discourse.disable_readonly_mode }
|
||||
Discourse.disable_readonly_mode
|
||||
pg_readonly_mode_key = Discourse::PG_READONLY_MODE_KEY
|
||||
|
||||
with_multisite_db(multisite_db) do
|
||||
Discourse.disable_readonly_mode(pg_readonly_mode_key)
|
||||
end
|
||||
|
||||
Discourse.disable_readonly_mode(pg_readonly_mode_key)
|
||||
ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[Rails.env])
|
||||
end
|
||||
|
||||
|
|
|
@ -118,7 +118,7 @@ describe Discourse do
|
|||
context 'user enabled readonly mode' do
|
||||
it "adds a key in redis and publish a message through the message bus" do
|
||||
expect($redis.get(user_readonly_mode_key)).to eq(nil)
|
||||
message = MessageBus.track_publish { Discourse.enable_readonly_mode(user_enabled: true) }.first
|
||||
message = MessageBus.track_publish { Discourse.enable_readonly_mode(user_readonly_mode_key) }.first
|
||||
assert_readonly_mode(message, user_readonly_mode_key)
|
||||
end
|
||||
end
|
||||
|
@ -160,10 +160,10 @@ describe Discourse do
|
|||
end
|
||||
|
||||
it "returns true when user enabled readonly mode key is present in redis" do
|
||||
Discourse.enable_readonly_mode(user_enabled: true)
|
||||
Discourse.enable_readonly_mode(user_readonly_mode_key)
|
||||
expect(Discourse.readonly_mode?).to eq(true)
|
||||
|
||||
Discourse.disable_readonly_mode(user_enabled: true)
|
||||
Discourse.disable_readonly_mode(user_readonly_mode_key)
|
||||
expect(Discourse.readonly_mode?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -383,37 +383,46 @@ describe Email::Receiver do
|
|||
expect(Post.last.raw).to match(/discourse\.rb/)
|
||||
end
|
||||
|
||||
it "handles forwarded emails" do
|
||||
SiteSetting.enable_forwarded_emails = true
|
||||
expect { process(:forwarded_email_1) }.to change(Topic, :count)
|
||||
context "with forwarded emails enabled" do
|
||||
before { SiteSetting.enable_forwarded_emails = true }
|
||||
|
||||
forwarded_post, last_post = *Post.last(2)
|
||||
it "handles forwarded emails" do
|
||||
expect { process(:forwarded_email_1) }.to change(Topic, :count)
|
||||
|
||||
expect(forwarded_post.user.email).to eq("some@one.com")
|
||||
expect(last_post.user.email).to eq("ba@bar.com")
|
||||
forwarded_post, last_post = *Post.last(2)
|
||||
|
||||
expect(forwarded_post.raw).to match(/XoXo/)
|
||||
expect(last_post.raw).to match(/can you have a look at this email below/)
|
||||
expect(forwarded_post.user.email).to eq("some@one.com")
|
||||
expect(last_post.user.email).to eq("ba@bar.com")
|
||||
|
||||
expect(last_post.post_type).to eq(Post.types[:regular])
|
||||
end
|
||||
expect(forwarded_post.raw).to match(/XoXo/)
|
||||
expect(last_post.raw).to match(/can you have a look at this email below/)
|
||||
|
||||
it "handles weirdly forwarded emails" do
|
||||
group.add(Fabricate(:user, email: "ba@bar.com"))
|
||||
group.save
|
||||
expect(last_post.post_type).to eq(Post.types[:regular])
|
||||
end
|
||||
|
||||
SiteSetting.enable_forwarded_emails = true
|
||||
expect { process(:forwarded_email_2) }.to change(Topic, :count)
|
||||
it "handles weirdly forwarded emails" do
|
||||
group.add(Fabricate(:user, email: "ba@bar.com"))
|
||||
group.save
|
||||
|
||||
forwarded_post, last_post = *Post.last(2)
|
||||
SiteSetting.enable_forwarded_emails = true
|
||||
expect { process(:forwarded_email_2) }.to change(Topic, :count)
|
||||
|
||||
expect(forwarded_post.user.email).to eq("some@one.com")
|
||||
expect(last_post.user.email).to eq("ba@bar.com")
|
||||
forwarded_post, last_post = *Post.last(2)
|
||||
|
||||
expect(forwarded_post.raw).to match(/XoXo/)
|
||||
expect(last_post.raw).to match(/can you have a look at this email below/)
|
||||
expect(forwarded_post.user.email).to eq("some@one.com")
|
||||
expect(last_post.user.email).to eq("ba@bar.com")
|
||||
|
||||
expect(forwarded_post.raw).to match(/XoXo/)
|
||||
expect(last_post.raw).to match(/can you have a look at this email below/)
|
||||
|
||||
expect(last_post.post_type).to eq(Post.types[:whisper])
|
||||
end
|
||||
|
||||
# Who thought this was a good idea?!
|
||||
it "doesn't blow up with localized email headers" do
|
||||
expect { process(:forwarded_email_3) }.to change(Topic, :count)
|
||||
end
|
||||
|
||||
expect(last_post.post_type).to eq(Post.types[:whisper])
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -10,10 +10,10 @@ describe PrettyText do
|
|||
|
||||
describe "off topic quoting" do
|
||||
it "can correctly populate topic title" do
|
||||
topic = Fabricate(:topic, title: "this is a test topic")
|
||||
topic = Fabricate(:topic, title: "this is a test topic :slight_smile:")
|
||||
expected = <<HTML
|
||||
<aside class="quote" data-post="2" data-topic="#{topic.id}"><div class="title">
|
||||
<div class="quote-controls"></div><a href="http://test.localhost/t/this-is-a-test-topic/#{topic.id}/2">This is a test topic</a>
|
||||
<div class="quote-controls"></div><a href="http://test.localhost/t/this-is-a-test-topic-slight-smile/#{topic.id}/2">This is a test topic <img src="/images/emoji/emoji_one/slight_smile.png?v=3" title="slight_smile" alt="slight_smile" class="emoji"></a>
|
||||
</div>
|
||||
<blockquote><p>ddd</p></blockquote></aside>
|
||||
HTML
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
Message-ID: <60@foo.bar.mail>
|
||||
From: Ba Bar <ba@bar.com>
|
||||
To: Team <team@bar.com>
|
||||
Date: Mon, 9 Dec 2016 13:37:42 +0100
|
||||
Subject: Fwd: Ça Discourse ?
|
||||
|
||||
@team, can you have a look at this email below?
|
||||
|
||||
Objet: Ça Discourse ?
|
||||
Date: 2017-01-04 11:27
|
||||
De: Un Français <un@francais.fr>
|
||||
À: ba@bar.com
|
||||
|
||||
Bonjour,
|
||||
|
||||
Ça Discourse bien aujourd'hui ?
|
||||
|
||||
Bises
|
|
@ -369,4 +369,42 @@ describe StaffActionLogger do
|
|||
expect(user_history.action).to eq(UserHistory.actions[:create_category])
|
||||
end
|
||||
end
|
||||
|
||||
describe 'log_lock_trust_level' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
it "raises an error when argument is missing" do
|
||||
expect { logger.log_lock_trust_level(nil) }.to raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
|
||||
it "creates a new UserHistory record" do
|
||||
user.trust_level_locked = true
|
||||
expect { logger.log_lock_trust_level(user) }.to change { UserHistory.count }.by(1)
|
||||
user_history = UserHistory.last
|
||||
expect(user_history.action).to eq(UserHistory.actions[:lock_trust_level])
|
||||
|
||||
user.trust_level_locked = false
|
||||
expect { logger.log_lock_trust_level(user) }.to change { UserHistory.count }.by(1)
|
||||
user_history = UserHistory.last
|
||||
expect(user_history.action).to eq(UserHistory.actions[:unlock_trust_level])
|
||||
end
|
||||
end
|
||||
|
||||
describe 'log_user_activate' do
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
||||
it "raises an error when argument is missing" do
|
||||
expect { logger.log_user_activate(nil, nil) }.to raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
|
||||
it "creates a new UserHistory record" do
|
||||
reason = "Staff activated from admin"
|
||||
expect {
|
||||
logger.log_user_activate(user, reason)
|
||||
}.to change { UserHistory.count }.by(1)
|
||||
user_history = UserHistory.last
|
||||
expect(user_history.action).to eq(UserHistory.actions[:activate_user])
|
||||
expect(user_history.details).to eq(reason)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,6 +58,14 @@ describe UserBlocker do
|
|||
SystemMessage.expects(:create).never
|
||||
expect(block_user).to eq(false)
|
||||
end
|
||||
|
||||
it "logs it with context" do
|
||||
SystemMessage.stubs(:create).returns(Fabricate.build(:post))
|
||||
expect {
|
||||
UserBlocker.block(user, Fabricate(:admin))
|
||||
}.to change { UserHistory.count }.by(1)
|
||||
expect(UserHistory.last.context).to be_present
|
||||
end
|
||||
end
|
||||
|
||||
describe 'unblock' do
|
||||
|
@ -81,6 +89,12 @@ describe UserBlocker do
|
|||
SystemMessage.expects(:create).never
|
||||
unblock_user
|
||||
end
|
||||
|
||||
it "logs it" do
|
||||
expect {
|
||||
unblock_user
|
||||
}.to change { UserHistory.count }.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'hide_posts' do
|
||||
|
|
Loading…
Reference in New Issue