Version bump

This commit is contained in:
Neil Lalonde 2017-08-17 15:59:39 -04:00
commit b124ada186
24 changed files with 201 additions and 50 deletions

View File

@ -150,7 +150,7 @@ GEM
mail (2.6.6)
mime-types (>= 1.16, < 4)
memory_profiler (0.9.8)
message_bus (2.0.3)
message_bus (2.0.5)
rack (>= 1.1.3)
metaclass (0.0.4)
method_source (0.8.2)
@ -214,7 +214,7 @@ GEM
omniauth-twitter (1.3.0)
omniauth-oauth (~> 1.1)
rack
onebox (1.8.17)
onebox (1.8.18)
fast_blank (>= 1.0.0)
htmlentities (~> 4.3)
moneta (~> 1.0)

View File

@ -236,7 +236,7 @@ export default Ember.Component.extend({
const shortcuts = this.get('toolbar.shortcuts');
// for some reason I am having trouble bubbling this so hack it in
mouseTrap.bind(['ctrl+/','command+/'], (event) =>{
mouseTrap.bind(['ctrl+shift+s','command+shift+s'], (event) =>{
this.appEvents.trigger('header:keyboard-trigger', {type: 'search', event});
return true;
});
@ -259,7 +259,7 @@ export default Ember.Component.extend({
if (this.get('composerEvents')) {
this.appEvents.on('composer:insert-block', text => this._addBlock(this._getSelected(), text));
this.appEvents.on('composer:insert-text', text => this._addText(this._getSelected(), text));
this.appEvents.on('composer:insert-text', (text, options) => this._addText(this._getSelected(), text, options));
this.appEvents.on('composer:replace-text', (oldVal, newVal) => this._replaceText(oldVal, newVal));
}
this._mouseTrap = mouseTrap;
@ -613,8 +613,22 @@ export default Ember.Component.extend({
Ember.run.scheduleOnce("afterRender", () => $textarea.focus());
},
_addText(sel, text) {
_addText(sel, text, options) {
const $textarea = this.$('textarea.d-editor-input');
if (options && options.ensureSpace) {
if ((sel.pre + '').length > 0) {
if (!sel.pre.match(/\s$/)) {
text = ' ' + text;
}
}
if ((sel.post + '').length > 0) {
if (!sel.post.match(/^\s/)) {
text = text + ' ';
}
}
}
const insert = `${sel.pre}${text}`;
const value = `${insert}${sel.post}`;
this.set('value', value);

View File

@ -0,0 +1,3 @@
export default Ember.Component.extend({
classNames: ['footer-message']
});

View File

@ -19,13 +19,14 @@ function updateState(state, opts) {
export default Ember.Component.extend(bufferedProperty('editables'), {
editing: propertyEqual('post', 'currentlyEditing'),
editables: {},
editables: null,
_confirmDelete: updateState('rejected', {deleteUser: true}),
_initEditables: function() {
const post = this.get('post');
const postOptions = post.get('post_options');
this.set('editables', {});
this.set('editables.raw', post.get('raw'));
this.set('editables.category', post.get('category'));
this.set('editables.category_id', post.get('category.id'));

View File

@ -6,8 +6,8 @@ const bindings = {
'!': {postAction: 'showFlags'},
'#': {handler: 'goToPost', anonymous: true},
'/': {handler: 'toggleSearch', anonymous: true},
'ctrl+/': {handler: 'toggleSearch', anonymous: true},
'command+/': {handler: 'toggleSearch', anonymous: true},
'ctrl+shift+s': {handler: 'toggleSearch', anonymous: true},
'command+shift+s': {handler: 'toggleSearch', anonymous: true},
'=': {handler: 'toggleHamburgerMenu', anonymous: true},
'?': {handler: 'showHelpModal', anonymous: true},
'.': {click: '.alert.alert-info.clickable', anonymous: true}, // show incoming/updated topics

View File

@ -64,7 +64,7 @@
{{d-icon "check"}} {{i18n 'topics.bulk.dismiss_new'}}</button>
{{/if}}
{{#footer-message education=footerEducation message=footerMessage tagName=""}}
{{#footer-message education=footerEducation message=footerMessage}}
{{#if latest}}
{{#if canCreateTopicOnCategory}}<a href {{action "createTopic"}}>{{i18n 'topic.suggest_create_topic'}}</a>{{/if}}
{{else if top}}

View File

@ -40,29 +40,15 @@
{{i18n 'topics.bulk.dismiss_new'}}</button>
{{/if}}
{{#if latest}}
<div class="education">
{{{footerEducation}}}
</div>
<h3>
{{footerMessage}}
{{#if model.can_create_topic}}<a href {{action "createTopic"}}>{{i18n 'topic.suggest_create_topic'}}</a>{{/if}}
</h3>
{{else}}
{{#if top}}
<h3>
{{#link-to "discovery.categories"}}{{i18n 'topic.browse_all_categories'}}{{/link-to}}, {{#link-to 'discovery.latest'}}{{i18n 'topic.view_latest_topics'}}{{/link-to}} {{i18n 'or'}} {{i18n 'filters.top.other_periods'}}
<br/>
{{top-period-buttons period=period action="changePeriod"}}
</h3>
{{#footer-message education=footerEducation message=footerMessage}}
{{#if latest}}
{{#if canCreateTopicOnCategory}}<a href {{action "createTopic"}}>{{i18n 'topic.suggest_create_topic'}}</a>{{/if}}
{{else if top}}
{{#link-to "discovery.categories"}}{{i18n 'topic.browse_all_categories'}}{{/link-to}}, {{#link-to 'discovery.latest'}}{{i18n 'topic.view_latest_topics'}}{{/link-to}} {{i18n 'or'}} {{i18n 'filters.top.other_periods'}}
{{top-period-buttons period=period action="changePeriod"}}
{{else}}
<div class="education">
{{{footerEducation}}}
</div>
<h3>
{{footerMessage}}{{#link-to "discovery.categories"}} {{i18n 'topic.browse_all_categories'}}{{/link-to}} {{i18n 'or'}} {{#link-to 'discovery.latest'}}{{i18n 'topic.view_latest_topics'}}{{/link-to}}
</h3>
{{#link-to "discovery.categories"}} {{i18n 'topic.browse_all_categories'}}{{/link-to}} {{i18n 'or'}} {{#link-to 'discovery.latest'}}{{i18n 'topic.view_latest_topics'}}{{/link-to}}
{{/if}}
{{/if}}
{{/footer-message}}
{{/if}}
</footer>

View File

@ -20,8 +20,8 @@ class Highlighted extends RawHtml {
function createSearchResult({ type, linkField, builder }) {
return createWidget(`search-result-${type}`, {
html(attrs) {
return attrs.results.map(r => {
return attrs.results.map(r => {
let searchResultId;
if (type === "topic") {
searchResultId = r.get('topic_id');

View File

@ -132,7 +132,7 @@ export default createWidget('search-menu', {
noResults: searchData.noResults,
results: searchData.results,
invalidTerm: searchData.invalidTerm,
searchContextEnabled: searchData.contextEnabled
searchContextEnabled: searchData.contextEnabled,
}));
}
}
@ -169,6 +169,75 @@ export default createWidget('search-menu', {
this.sendWidgetAction('toggleSearchMenu');
},
keyDown(e) {
if (searchData.loading || searchData.noResults) {
return;
}
if (e.which === 65 /* a */) {
let focused = $('header .results .search-link:focus');
if (focused.length === 1) {
if ($('#reply-control.open').length === 1) {
// add a link and focus composer
this.appEvents.trigger('composer:insert-text', focused[0].href, {ensureSpace: true});
this.appEvents.trigger('header:keyboard-trigger', {type: 'search'});
e.preventDefault();
$('#reply-control.open textarea').focus();
return false;
}
}
}
const up = e.which === 38;
const down = e.which === 40;
if (up || down) {
let focused = $('header .panel-body *:focus')[0];
if (!focused) {
return;
}
let links = $('header .panel-body .results a');
let results = $('header .panel-body .results .search-link');
let prevResult;
let result;
links.each((idx,item) => {
if ($(item).hasClass('search-link')) {
prevResult = item;
}
if (item === focused) {
result = prevResult;
}
});
let index = -1;
if (result) {
index = results.index(result);
}
if (index === -1 && down) {
$('header .panel-body .search-link:first').focus();
} else if (index === 0 && up) {
$('header .panel-body input:first').focus();
} else if (index > -1) {
index += (down ? 1 : -1);
if (index >= 0 && index < results.length) {
$(results[index]).focus();
}
}
e.preventDefault();
return false;
}
},
triggerSearch() {
searchData.noResults = false;
this.searchService().set('highlightTerm', searchData.term);

View File

@ -18,7 +18,7 @@
}
.menu-panel {
border: 1px solid $primary-low;
border: 1px solid $primary-low;
box-shadow: 0 2px 2px rgba(0,0,0, .25);
background-color: $secondary;
z-index: 1100;
@ -148,6 +148,7 @@
padding: 5px;
text-align: center;
}
.filter {
padding: 0;
&:hover {background: transparent;}

View File

@ -92,6 +92,11 @@
.user-table {
margin-top: 30px;
width: 100%;
display: table;
table-layout: fixed;
.wrapper {
display: table-row;
}
}
.user-navigation .nav-stacked .glyph {

View File

@ -574,6 +574,9 @@ class PostsController < ApplicationController
params[:skip_validations] = params[:skip_validations].to_s == "true"
permitted << :skip_validations
params[:import_mode] = params[:import_mode].to_s == "true"
permitted << :import_mode
# We allow `embed_url` via the API
permitted << :embed_url

View File

@ -31,6 +31,7 @@ class Backup
def after_create_hook
upload_to_s3 if SiteSetting.enable_s3_backups?
DiscourseEvent.trigger(:backup_created)
end
def after_remove_hook

View File

@ -23,7 +23,13 @@ class CategoryFeaturedTopic < ActiveRecord::Base
no_definitions: true
}
# Add topics, even if they're in secured categories:
# It may seem a bit odd that we are running 2 queries here, when admin
# can clearly pull out all the topics needed.
# We do so, so anonymous will ALWAYS get some topics
# If we only fetched as admin we may have a situation where anon can see
# no featured topics (all the previous 2x topics are only visible to admins)
# Add topics, even if they're in secured categories or invisible
query = TopicQuery.new(CategoryFeaturedTopic.fake_admin, query_opts)
results = query.list_category_topic_ids(c).uniq

View File

@ -139,7 +139,6 @@ module HasCustomFields
end
def custom_fields
if @preloaded_custom_fields
return @preloaded_proxy ||= PreloadedProxy.new(@preloaded_custom_fields)
end
@ -177,7 +176,10 @@ module HasCustomFields
dup.delete(f.name)
end
else
if dup[f.name] != f.value
t = {}
self.class.append_custom_field(t, f.name, f.value)
if dup[f.name] != t[f.name]
f.destroy
else
dup.delete(f.name)

View File

@ -2376,7 +2376,7 @@ en:
hamburger_menu: '<b>=</b> Open hamburger menu'
user_profile_menu: '<b>p</b> Open user menu'
show_incoming_updated_topics: '<b>.</b> Show updated topics'
search: '<b>/</b> or <b>ctrl</b>+<b>/</b> Search'
search: '<b>/</b> or <b>ctrl</b>+<b>shift</b>+<b>s</b> Search'
help: '<b>?</b> Open keyboard help'
dismiss_new_posts: '<b>x</b>, <b>r</b> Dismiss New/Posts'
dismiss_topics: '<b>x</b>, <b>t</b> Dismiss Topics'

View File

@ -2424,7 +2424,7 @@ en:
invited_group_to_private_message_body: |
%{username} invited @%{group_name} to a message
> #### %{topic_title}
> **%{topic_title}**
>
> %{topic_excerpt}

View File

@ -447,7 +447,7 @@ module Discourse
def self.reset_active_record_cache
ActiveRecord::Base.connection.query_cache.clear
(ActiveRecord::Base.connection.tables - %w[schema_migrations]).each do |table|
(ActiveRecord::Base.connection.tables - %w[schema_migrations versions]).each do |table|
table.classify.constantize.reset_column_information rescue nil
end
nil

View File

@ -92,7 +92,7 @@ class Plugin::Instance
def whitelist_staff_user_custom_field(field)
reloadable_patch do |plugin|
User.register_plugin_staff_custom_field(field, plugin) if plugin.enabled?
::User.register_plugin_staff_custom_field(field, plugin) if plugin.enabled?
end
end
@ -248,21 +248,27 @@ class Plugin::Instance
end
end
def register_category_custom_field_type(name, type)
reloadable_patch do |plugin|
Category.register_custom_field_type(name, type) if plugin.enabled?
end
end
def register_topic_custom_field_type(name, type)
reloadable_patch do |plugin|
Topic.register_custom_field_type(name, type) if plugin.enabled?
::Topic.register_custom_field_type(name, type) if plugin.enabled?
end
end
def register_post_custom_field_type(name, type)
reloadable_patch do |plugin|
Post.register_custom_field_type(name, type) if plugin.enabled?
::Post.register_custom_field_type(name, type) if plugin.enabled?
end
end
def register_group_custom_field_type(name, type)
reloadable_patch do |plugin|
Group.register_custom_field_type(name, type) if plugin.enabled?
::Group.register_custom_field_type(name, type) if plugin.enabled?
end
end

View File

@ -37,10 +37,14 @@ module Stylesheet
end
root = Rails.root.to_s
listener_opts = { ignore: /xxxx/ }
listener_opts[:force_polling] = true if ENV['FORCE_POLLING']
@paths.each do |watch|
Thread.new do
begin
listener = Listen.to("#{root}/#{watch}", ignore: /xxxx/) do |modified, added, _|
listener = Listen.to("#{root}/#{watch}", listener_opts) do |modified, added, _|
paths = [modified, added].flatten
paths.compact!
paths.map! { |long| long[(root.length + 1)..-1] }

View File

@ -5,7 +5,7 @@ module Discourse
MAJOR = 1
MINOR = 9
TINY = 0
PRE = 'beta6'
PRE = 'beta7'
STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
end

View File

@ -142,6 +142,16 @@ describe HasCustomFields do
test_item.reload
expect(test_item.custom_fields).to eq("bool" => true, "int" => 1, "json" => { "foo" => "bar" })
before_ids = CustomFieldsTestItemCustomField.where(custom_fields_test_item_id: test_item.id).pluck(:id)
test_item.custom_fields["bool"] = false
test_item.save
after_ids = CustomFieldsTestItemCustomField.where(custom_fields_test_item_id: test_item.id).pluck(:id)
# we updated only 1 custom field, so there should be only 1 different id
expect((before_ids - after_ids).size).to eq(1)
end
it "simple modifications don't interfere" do

View File

@ -510,7 +510,7 @@ describe PostsController do
end
it "toggle wiki status should create a new version" do
admin = log_in(:admin)
_admin = log_in(:admin)
another_user = Fabricate(:user)
another_post = Fabricate(:post, user: another_user)
@ -520,7 +520,7 @@ describe PostsController do
expect { xhr :put, :wiki, post_id: another_post.id, wiki: 'false' }
.to change { another_post.reload.version }.by(-1)
another_admin = log_in(:admin)
_another_admin = log_in(:admin)
expect { xhr :put, :wiki, post_id: another_post.id, wiki: 'true' }
.to change { another_post.reload.version }.by(1)
@ -631,6 +631,46 @@ describe PostsController do
expect(response.body).to eq(original)
end
it 'allows to create posts in import_mode' do
NotificationEmailer.enable
post = Fabricate(:post)
user = Fabricate(:user)
master_key = ApiKey.create_master_key.key
xhr :post, :create,
api_username: user.username,
api_key: master_key,
raw: 'this is test reply 1',
topic_id: post.topic.id,
reply_to_post_number: 1
expect(response).to be_success
expect(post.topic.user.notifications.count).to eq(1)
post.topic.user.notifications.destroy_all
xhr :post, :create,
api_username: user.username,
api_key: master_key,
raw: 'this is test reply 2',
topic_id: post.topic.id,
reply_to_post_number: 1,
import_mode: true
expect(response).to be_success
expect(post.topic.user.notifications.count).to eq(0)
xhr :post, :create,
api_username: user.username,
api_key: master_key,
raw: 'this is test reply 3',
topic_id: post.topic.id,
reply_to_post_number: 1,
import_mode: false
expect(response).to be_success
expect(post.topic.user.notifications.count).to eq(1)
end
end
describe 'when logged in' do

View File

@ -34,7 +34,7 @@ describe CategoryFeaturedTopic do
it 'should feature stuff in the correct order' do
category = Fabricate(:category, num_featured_topics: 2)
t5 = Fabricate(:topic, category_id: category.id, bumped_at: 12.minutes.ago)
_t5 = Fabricate(:topic, category_id: category.id, bumped_at: 12.minutes.ago)
t4 = Fabricate(:topic, category_id: category.id, bumped_at: 10.minutes.ago)
t3 = Fabricate(:topic, category_id: category.id, bumped_at: 7.minutes.ago)
t2 = Fabricate(:topic, category_id: category.id, bumped_at: 4.minutes.ago)
@ -45,7 +45,7 @@ describe CategoryFeaturedTopic do
# Should find more than we need: pinned topics first, then num_featured_topics * 2
expect(
CategoryFeaturedTopic.where(category_id: category.id).pluck(:topic_id)
CategoryFeaturedTopic.where(category_id: category.id).order('rank asc').pluck(:topic_id)
).to eq([pinned.id, t2.id, t1.id, t3.id, t4.id])
end