mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
FEATURE: improved tag and category watching and tracking
- present tags watched on the user prefs page - automatically watch or unwatch old topics based on watch status New watching and tracking logic takes care of handling old topics (either with or without read state) When you watch a topic you now watch historically Also removes confusing warnings from user.
This commit is contained in:
parent
58c2389a7b
commit
4161ee210a
19 changed files with 583 additions and 224 deletions
|
@ -36,8 +36,13 @@ export default Ember.TextField.extend({
|
|||
const site = this.site,
|
||||
self = this,
|
||||
filterRegexp = new RegExp(this.site.tags_filter_regexp, "g");
|
||||
|
||||
var limit = this.siteSettings.max_tags_per_topic;
|
||||
|
||||
if (this.get('allowCreate') !== false) {
|
||||
this.set('allowCreate', site.get('can_create_tag'));
|
||||
}
|
||||
|
||||
if (this.get('unlimitedTagCount')) {
|
||||
limit = null;
|
||||
} else if (this.get('limit')) {
|
||||
|
@ -46,7 +51,7 @@ export default Ember.TextField.extend({
|
|||
|
||||
this.$().select2({
|
||||
tags: true,
|
||||
placeholder: I18n.t(this.get('placeholderKey') || 'tagging.choose_for_topic'),
|
||||
placeholder: this.get('placeholder') === "" ? "" : I18n.t(this.get('placeholderKey') || 'tagging.choose_for_topic'),
|
||||
maximumInputLength: this.siteSettings.max_tag_length,
|
||||
maximumSelectionSize: limit,
|
||||
initSelection(element, callback) {
|
||||
|
@ -73,7 +78,7 @@ export default Ember.TextField.extend({
|
|||
term = term.replace(filterRegexp, '').trim();
|
||||
|
||||
// No empty terms, make sure the user has permission to create the tag
|
||||
if (!term.length || !site.get('can_create_tag')) { return; }
|
||||
if (!term.lenght || !this.get('allowCreate')) return;
|
||||
|
||||
if ($(data).filter(function() {
|
||||
return this.text.localeCompare(term) === 0;
|
||||
|
|
|
@ -2,7 +2,6 @@ import { setting } from 'discourse/lib/computed';
|
|||
import CanCheckEmails from 'discourse/mixins/can-check-emails';
|
||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||
import computed from "ember-addons/ember-computed-decorators";
|
||||
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
||||
|
||||
export default Ember.Controller.extend(CanCheckEmails, {
|
||||
|
||||
|
@ -136,24 +135,6 @@ export default Ember.Controller.extend(CanCheckEmails, {
|
|||
|
||||
const model = this.get('model');
|
||||
|
||||
|
||||
// watched status changes warn user
|
||||
const changedWatch = model.changedCategoryNotifications("watched");
|
||||
|
||||
if (changedWatch.remove.length > 0 && !this.get("warnedRemoveWatch")) {
|
||||
var categories = Discourse.Category.findByIds(changedWatch.remove).map((cat) => {
|
||||
return categoryBadgeHTML(cat);
|
||||
}).join(" ");
|
||||
bootbox.confirm(I18n.t('user.warn_unwatch.message', {categories: categories}),
|
||||
I18n.t('user.warn_unwatch.no_value', {count: changedWatch.remove.length}), I18n.t('user.warn_unwatch.yes_value'),
|
||||
(yes)=>{
|
||||
this.set('unwatchCategoryTopics', yes ? changedWatch.remove : false);
|
||||
this.send('save');
|
||||
});
|
||||
this.set("warnedRemoveWatch", true);
|
||||
return;
|
||||
}
|
||||
|
||||
const userFields = this.get('userFields');
|
||||
|
||||
// Update the user fields
|
||||
|
@ -169,9 +150,6 @@ export default Ember.Controller.extend(CanCheckEmails, {
|
|||
// Cook the bio for preview
|
||||
model.set('name', this.get('newNameInput'));
|
||||
var options = {};
|
||||
if (this.get('warnedRemoveWatch') && this.get('unwatchCategoryTopics')) {
|
||||
options["unwatchCategoryTopics"] = this.get("unwatchCategoryTopics");
|
||||
}
|
||||
|
||||
return model.save(options).then(() => {
|
||||
if (Discourse.User.currentProp('id') === model.get('id')) {
|
||||
|
@ -179,8 +157,6 @@ export default Ember.Controller.extend(CanCheckEmails, {
|
|||
}
|
||||
model.set('bio_cooked', Discourse.Markdown.cook(Discourse.Markdown.sanitize(model.get('bio_raw'))));
|
||||
this.set('saved', true);
|
||||
this.set("unwatchTopics", false);
|
||||
this.set('warnedRemoveWatch', false);
|
||||
}).catch(popupAjaxError);
|
||||
},
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ const User = RestModel.extend({
|
|||
return Discourse.User.create(this.getProperties(Object.keys(this)));
|
||||
},
|
||||
|
||||
save(options) {
|
||||
save() {
|
||||
const data = this.getProperties(
|
||||
'bio_raw',
|
||||
'website',
|
||||
|
@ -152,7 +152,10 @@ const User = RestModel.extend({
|
|||
'user_fields',
|
||||
'muted_usernames',
|
||||
'profile_background',
|
||||
'card_background'
|
||||
'card_background',
|
||||
'muted_tags',
|
||||
'tracked_tags',
|
||||
'watched_tags'
|
||||
);
|
||||
|
||||
[ 'email_always',
|
||||
|
@ -192,10 +195,6 @@ const User = RestModel.extend({
|
|||
data['edit_history_public'] = this.get('user_option.edit_history_public');
|
||||
}
|
||||
|
||||
if (options && options.unwatchCategoryTopics) {
|
||||
data.unwatch_category_topics = options.unwatchCategoryTopics;
|
||||
}
|
||||
|
||||
// TODO: We can remove this when migrated fully to rest model.
|
||||
this.set('isSaving', true);
|
||||
return Discourse.ajax(`/users/${this.get('username_lower')}`, {
|
||||
|
|
|
@ -274,6 +274,27 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{{#if siteSettings.tagging_enabled}}
|
||||
<div class="control-group tags">
|
||||
<label class="control-label">{{i18n 'user.tag_settings'}}</label>
|
||||
<div class="controls tag-controls">
|
||||
<label><span class="icon fa fa-exclamation-circle watching"></span> {{i18n 'user.watched_tags'}}</label>
|
||||
{{tag-chooser tags=model.watched_tags blacklist=selectedTags allowCreate=false placeholder=""}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.watched_tags_instructions'}}</div>
|
||||
<div class="controls tag-controls">
|
||||
<label><span class="icon fa fa-circle tracking"></span> {{i18n 'user.tracked_tags'}}</label>
|
||||
{{tag-chooser tags=model.tracked_tags blacklist=selectedTags allowCreate=false placeholder=""}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.tracked_tags_instructions'}}</div>
|
||||
<div class="controls tag-controls">
|
||||
<label><span class="icon fa fa-times-circle muted"></span> {{i18n 'user.muted_tags'}}</label>
|
||||
{{tag-chooser tags=model.muted_tags blacklist=selectedTags allowCreate=false placeholder=""}}
|
||||
</div>
|
||||
<div class="instructions">{{i18n 'user.muted_tags_instructions'}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="control-group muting">
|
||||
<label class="control-label">{{i18n 'user.users'}}</label>
|
||||
<div class="controls category-controls">
|
||||
|
|
|
@ -279,3 +279,12 @@ and (max-width : 600px) {
|
|||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.user-preferences .tags .select2-container-multi {
|
||||
border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
|
||||
width: 540px;
|
||||
border-radius: 0;
|
||||
.select2-choices {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,10 +89,6 @@ class UsersController < ApplicationController
|
|||
user = fetch_user_from_params
|
||||
guardian.ensure_can_edit!(user)
|
||||
|
||||
if params[:unwatch_category_topics]
|
||||
TopicUser.unwatch_categories!(user, params[:unwatch_category_topics])
|
||||
end
|
||||
|
||||
if params[:user_fields].present?
|
||||
params[:custom_fields] = {} unless params[:custom_fields].present?
|
||||
|
||||
|
|
|
@ -20,85 +20,141 @@ class CategoryUser < ActiveRecord::Base
|
|||
[notification_levels[:watching], notification_levels[:watching_first_post]]
|
||||
end
|
||||
|
||||
%w{watch track}.each do |s|
|
||||
define_singleton_method("auto_#{s}_new_topic") do |topic, new_category=nil|
|
||||
category_id = topic.category_id
|
||||
|
||||
if new_category && topic.created_at > 5.days.ago
|
||||
# we want to apply default of the new category
|
||||
category_id = new_category.id
|
||||
# remove defaults from previous category
|
||||
remove_default_from_topic(topic.id, category_id, TopicUser.notification_levels[:"#{s}ing"], TopicUser.notification_reasons[:"auto_#{s}_category"])
|
||||
end
|
||||
|
||||
apply_default_to_topic(topic.id, category_id, TopicUser.notification_levels[:"#{s}ing"], TopicUser.notification_reasons[:"auto_#{s}_category"])
|
||||
end
|
||||
end
|
||||
|
||||
def self.batch_set(user, level, category_ids)
|
||||
records = CategoryUser.where(user: user, notification_level: notification_levels[level])
|
||||
old_ids = records.pluck(:category_id)
|
||||
changed = false
|
||||
|
||||
category_ids = Category.where('id in (?)', category_ids).pluck(:id)
|
||||
|
||||
remove = (old_ids - category_ids)
|
||||
if remove.present?
|
||||
records.where('category_id in (?)', remove).destroy_all
|
||||
changed = true
|
||||
end
|
||||
|
||||
(category_ids - old_ids).each do |id|
|
||||
CategoryUser.create!(user: user, category_id: id, notification_level: notification_levels[level])
|
||||
changed = true
|
||||
end
|
||||
|
||||
if changed
|
||||
auto_watch(user_id: user.id)
|
||||
auto_track(user_id: user.id)
|
||||
end
|
||||
|
||||
changed
|
||||
end
|
||||
|
||||
def self.set_notification_level_for_category(user, level, category_id)
|
||||
record = CategoryUser.where(user: user, category_id: category_id).first
|
||||
|
||||
return if record && record.notification_level = level
|
||||
|
||||
if record.present?
|
||||
record.notification_level = level
|
||||
record.save!
|
||||
else
|
||||
CategoryUser.create!(user: user, category_id: category_id, notification_level: level)
|
||||
end
|
||||
|
||||
auto_watch(user_id: user.id)
|
||||
auto_track(user_id: user.id)
|
||||
end
|
||||
|
||||
def self.apply_default_to_topic(topic_id, category_id, level, reason)
|
||||
# Can not afford to slow down creation of topics when a pile of users are watching new topics, reverting to SQL for max perf here
|
||||
sql = <<-SQL
|
||||
INSERT INTO topic_users(user_id, topic_id, notification_level, notifications_reason_id)
|
||||
SELECT user_id, :topic_id, :level, :reason
|
||||
FROM category_users
|
||||
WHERE notification_level = :level
|
||||
AND category_id = :category_id
|
||||
AND NOT EXISTS(SELECT 1 FROM topic_users WHERE topic_id = :topic_id AND user_id = category_users.user_id)
|
||||
SQL
|
||||
def self.auto_track(opts={})
|
||||
|
||||
exec_sql(sql,
|
||||
topic_id: topic_id,
|
||||
category_id: category_id,
|
||||
level: level,
|
||||
reason: reason
|
||||
)
|
||||
builder = SqlBuilder.new <<SQL
|
||||
UPDATE topic_users tu
|
||||
SET notification_level = :tracking,
|
||||
notifications_reason_id = :auto_track_category
|
||||
FROM topics t, category_users cu
|
||||
/*where*/
|
||||
SQL
|
||||
|
||||
builder.where("tu.topic_id = t.id AND
|
||||
cu.category_id = t.category_id AND
|
||||
cu.user_id = tu.user_id AND
|
||||
cu.notification_level = :tracking AND
|
||||
tu.notification_level = :regular")
|
||||
|
||||
if category_id = opts[:category_id]
|
||||
builder.where("t.category_id = :category_id", category_id: category_id)
|
||||
end
|
||||
|
||||
if topic_id = opts[:topic_id]
|
||||
builder.where("tu.topic_id = :topic_id", topic_id: topic_id)
|
||||
end
|
||||
|
||||
if user_id = opts[:user_id]
|
||||
builder.where("tu.user_id = :user_id", user_id: user_id)
|
||||
end
|
||||
|
||||
builder.exec(tracking: notification_levels[:tracking],
|
||||
regular: notification_levels[:regular],
|
||||
auto_track_category: TopicUser.notification_reasons[:auto_track_category])
|
||||
end
|
||||
|
||||
def self.remove_default_from_topic(topic_id, category_id, level, reason)
|
||||
sql = <<-SQL
|
||||
DELETE FROM topic_users
|
||||
WHERE topic_id = :topic_id
|
||||
AND notifications_changed_at IS NULL
|
||||
AND notification_level = :level
|
||||
AND notifications_reason_id = :reason
|
||||
AND NOT EXISTS(SELECT 1 FROM category_users WHERE category_users.category_id = :category_id AND category_users.notification_level = :level AND category_users.user_id = topic_users.user_id)
|
||||
SQL
|
||||
def self.auto_watch(opts={})
|
||||
|
||||
builder = SqlBuilder.new <<SQL
|
||||
UPDATE topic_users tu
|
||||
SET notification_level =
|
||||
CASE WHEN should_track THEN :tracking
|
||||
WHEN should_watch THEN :watching
|
||||
ELSE notification_level
|
||||
END,
|
||||
notifications_reason_id =
|
||||
CASE WHEN should_track THEN null
|
||||
WHEN should_watch THEN :auto_watch_category
|
||||
ELSE notifications_reason_id
|
||||
END
|
||||
FROM (
|
||||
SELECT tu1.topic_id,
|
||||
tu1.user_id,
|
||||
CASE WHEN
|
||||
cu.user_id IS NULL AND tu1.notification_level = :watching AND tu1.notifications_reason_id = :auto_watch_category THEN true
|
||||
ELSE false
|
||||
END should_track,
|
||||
CASE WHEN
|
||||
cu.user_id IS NOT NULL AND tu1.notification_level in (:regular, :tracking) THEN true
|
||||
ELSE false
|
||||
END should_watch
|
||||
|
||||
FROM topic_users tu1
|
||||
JOIN topics t ON t.id = tu1.topic_id
|
||||
LEFT JOIN category_users cu ON cu.category_id = t.category_id AND cu.user_id = tu1.user_id AND cu.notification_level = :watching
|
||||
/*where2*/
|
||||
) as X
|
||||
|
||||
/*where*/
|
||||
SQL
|
||||
|
||||
builder.where("X.topic_id = tu.topic_id AND X.user_id = tu.user_id")
|
||||
builder.where("should_watch OR should_track")
|
||||
|
||||
if category_id = opts[:category_id]
|
||||
builder.where2("t.category_id = :category_id", category_id: category_id)
|
||||
end
|
||||
|
||||
if topic_id = opts[:topic_id]
|
||||
builder.where("tu.topic_id = :topic_id", topic_id: topic_id)
|
||||
builder.where2("tu1.topic_id = :topic_id", topic_id: topic_id)
|
||||
end
|
||||
|
||||
if user_id = opts[:user_id]
|
||||
builder.where("tu.user_id = :user_id", user_id: user_id)
|
||||
builder.where2("tu1.user_id = :user_id", user_id: user_id)
|
||||
end
|
||||
|
||||
builder.exec(watching: notification_levels[:watching],
|
||||
tracking: notification_levels[:tracking],
|
||||
regular: notification_levels[:regular],
|
||||
auto_watch_category: TopicUser.notification_reasons[:auto_watch_category])
|
||||
|
||||
exec_sql(sql,
|
||||
topic_id: topic_id,
|
||||
category_id: category_id,
|
||||
level: level,
|
||||
reason: reason
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
def self.ensure_consistency!
|
||||
exec_sql <<SQL
|
||||
DELETE FROM category_users
|
||||
|
@ -110,7 +166,6 @@ class CategoryUser < ActiveRecord::Base
|
|||
SQL
|
||||
end
|
||||
|
||||
private_class_method :apply_default_to_topic, :remove_default_from_topic
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
|
|
@ -8,6 +8,38 @@ class TagUser < ActiveRecord::Base
|
|||
NotificationLevels.all
|
||||
end
|
||||
|
||||
def self.lookup(user, level)
|
||||
where(user: user, notification_level: notification_levels[level])
|
||||
end
|
||||
|
||||
def self.batch_set(user, level, tags)
|
||||
tags ||= []
|
||||
changed = false
|
||||
|
||||
records = TagUser.where(user: user, notification_level: notification_levels[level])
|
||||
old_ids = records.pluck(:tag_id)
|
||||
|
||||
tag_ids = tags.empty? ? [] : Tag.where('name in (?)', tags).pluck(:id)
|
||||
|
||||
remove = (old_ids - tag_ids)
|
||||
if remove.present?
|
||||
records.where('tag_id in (?)', remove).destroy_all
|
||||
changed = true
|
||||
end
|
||||
|
||||
(tag_ids - old_ids).each do |id|
|
||||
TagUser.create!(user: user, tag_id: id, notification_level: notification_levels[level])
|
||||
changed = true
|
||||
end
|
||||
|
||||
if changed
|
||||
auto_watch(user_id: user.id)
|
||||
auto_track(user_id: user.id)
|
||||
end
|
||||
|
||||
changed
|
||||
end
|
||||
|
||||
def self.change(user_id, tag_id, level)
|
||||
tag_id = tag_id.id if tag_id.is_a?(::Tag)
|
||||
user_id = user_id.id if user_id.is_a?(::User)
|
||||
|
@ -25,75 +57,100 @@ class TagUser < ActiveRecord::Base
|
|||
tag_user = TagUser.create(user_id: user_id, tag_id: tag_id, notification_level: level)
|
||||
end
|
||||
|
||||
auto_watch(user_id: user_id)
|
||||
auto_track(user_id: user_id)
|
||||
|
||||
tag_user
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
# In case of a race condition to insert, do nothing
|
||||
end
|
||||
|
||||
%w{watch track}.each do |s|
|
||||
define_singleton_method("auto_#{s}_new_topic") do |topic, new_tags=nil|
|
||||
tag_ids = topic.tags.pluck(:id)
|
||||
if !new_tags.nil? && topic.created_at && topic.created_at > 5.days.ago
|
||||
tag_ids = new_tags.map(&:id)
|
||||
remove_default_from_topic( topic.id, tag_ids,
|
||||
TopicUser.notification_levels[:"#{s}ing"],
|
||||
TopicUser.notification_reasons[:"auto_#{s}_tag"] )
|
||||
end
|
||||
def self.auto_watch(opts)
|
||||
builder = SqlBuilder.new <<SQL
|
||||
|
||||
apply_default_to_topic( topic.id, tag_ids,
|
||||
TopicUser.notification_levels[:"#{s}ing"],
|
||||
TopicUser.notification_reasons[:"auto_#{s}_tag"])
|
||||
end
|
||||
end
|
||||
UPDATE topic_users
|
||||
SET notification_level = CASE WHEN should_watch THEN :watching ELSE :tracking END,
|
||||
notifications_reason_id = CASE WHEN should_watch THEN :auto_watch_tag ELSE NULL END
|
||||
FROM
|
||||
(
|
||||
SELECT tu.topic_id, tu.user_id, CASE
|
||||
WHEN MAX(tag_users.notification_level) = :watching THEN true
|
||||
ELSE false
|
||||
END
|
||||
should_watch,
|
||||
|
||||
def self.apply_default_to_topic(topic_id, tag_ids, level, reason)
|
||||
sql = <<-SQL
|
||||
INSERT INTO topic_users(user_id, topic_id, notification_level, notifications_reason_id)
|
||||
SELECT user_id, :topic_id, :level, :reason
|
||||
FROM tag_users
|
||||
WHERE notification_level = :level
|
||||
AND tag_id in (:tag_ids)
|
||||
AND NOT EXISTS(SELECT 1 FROM topic_users WHERE topic_id = :topic_id AND user_id = tag_users.user_id)
|
||||
LIMIT 1
|
||||
SQL
|
||||
CASE WHEN MAX(tag_users.notification_level) IS NULL AND
|
||||
tu.notification_level = :watching AND
|
||||
tu.notifications_reason_id = :auto_watch_tag
|
||||
THEN true
|
||||
ELSE false
|
||||
END
|
||||
should_track
|
||||
|
||||
exec_sql(sql,
|
||||
topic_id: topic_id,
|
||||
tag_ids: tag_ids,
|
||||
level: level,
|
||||
reason: reason
|
||||
)
|
||||
end
|
||||
FROM topic_users tu
|
||||
LEFT JOIN topic_tags ON tu.topic_id = topic_tags.topic_id
|
||||
LEFT JOIN tag_users ON tag_users.user_id = tu.user_id
|
||||
AND topic_tags.tag_id = tag_users.tag_id
|
||||
AND tag_users.notification_level = :watching
|
||||
/*where*/
|
||||
GROUP BY tu.topic_id, tu.user_id, tu.notification_level, tu.notifications_reason_id
|
||||
) AS X
|
||||
WHERE X.topic_id = topic_users.topic_id AND
|
||||
X.user_id = topic_users.user_id AND
|
||||
(should_track OR should_watch)
|
||||
|
||||
def self.remove_default_from_topic(topic_id, tag_ids, level, reason)
|
||||
sql = <<-SQL
|
||||
DELETE FROM topic_users
|
||||
WHERE topic_id = :topic_id
|
||||
AND notifications_changed_at IS NULL
|
||||
AND notification_level = :level
|
||||
AND notifications_reason_id = :reason
|
||||
SQL
|
||||
SQL
|
||||
|
||||
if !tag_ids.empty?
|
||||
sql << <<-SQL
|
||||
AND NOT EXISTS(
|
||||
SELECT 1
|
||||
FROM tag_users
|
||||
WHERE tag_users.tag_id in (:tag_ids)
|
||||
AND tag_users.notification_level = :level
|
||||
AND tag_users.user_id = topic_users.user_id)
|
||||
SQL
|
||||
builder.where("tu.notification_level in (:tracking, :regular, :watching)")
|
||||
|
||||
if topic_id = opts[:topic_id]
|
||||
builder.where("tu.topic_id = :topic_id", topic_id: topic_id)
|
||||
end
|
||||
|
||||
exec_sql(sql,
|
||||
topic_id: topic_id,
|
||||
level: level,
|
||||
reason: reason,
|
||||
tag_ids: tag_ids
|
||||
)
|
||||
if user_id = opts[:user_id]
|
||||
builder.where("tu.user_id = :user_id", user_id: user_id)
|
||||
end
|
||||
|
||||
builder.exec(watching: notification_levels[:watching],
|
||||
tracking: notification_levels[:tracking],
|
||||
regular: notification_levels[:regular],
|
||||
auto_watch_tag: TopicUser.notification_reasons[:auto_watch_tag])
|
||||
|
||||
end
|
||||
|
||||
def self.auto_track(opts)
|
||||
|
||||
builder = SqlBuilder.new <<SQL
|
||||
UPDATE topic_users
|
||||
SET notification_level = :tracking, notifications_reason_id = :auto_track_tag
|
||||
FROM (
|
||||
SELECT DISTINCT tu.topic_id, tu.user_id
|
||||
FROM topic_users tu
|
||||
JOIN topic_tags ON tu.topic_id = topic_tags.topic_id
|
||||
JOIN tag_users ON tag_users.user_id = tu.user_id
|
||||
AND topic_tags.tag_id = tag_users.tag_id
|
||||
AND tag_users.notification_level = :tracking
|
||||
/*where*/
|
||||
) as X
|
||||
WHERE
|
||||
topic_users.notification_level = :regular AND
|
||||
topic_users.topic_id = X.topic_id AND
|
||||
topic_users.user_id = X.user_id
|
||||
SQL
|
||||
|
||||
if topic_id = opts[:topic_id]
|
||||
builder.where("tu.topic_id = :topic_id", topic_id: topic_id)
|
||||
end
|
||||
|
||||
if user_id = opts[:user_id]
|
||||
builder.where("tu.user_id = :user_id", user_id: user_id)
|
||||
end
|
||||
|
||||
builder.exec(tracking: notification_levels[:tracking],
|
||||
regular: notification_levels[:regular],
|
||||
auto_track_tag: TopicUser.notification_reasons[:auto_track_tag])
|
||||
end
|
||||
|
||||
private_class_method :apply_default_to_topic, :remove_default_from_topic
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
|
|
@ -25,7 +25,7 @@ class Topic < ActiveRecord::Base
|
|||
def_delegator :notifier, :mute!, :notify_muted!
|
||||
def_delegator :notifier, :toggle_mute, :toggle_mute
|
||||
|
||||
attr_accessor :allowed_user_ids
|
||||
attr_accessor :allowed_user_ids, :tags_changed
|
||||
|
||||
def self.max_sort_order
|
||||
@max_sort_order ||= (2 ** 31) - 1
|
||||
|
@ -187,6 +187,12 @@ class Topic < ActiveRecord::Base
|
|||
if archetype_was == banner || archetype == banner
|
||||
ApplicationController.banner_json_cache.clear
|
||||
end
|
||||
|
||||
if tags_changed
|
||||
TagUser.auto_watch(topic_id: id)
|
||||
TagUser.auto_track(topic_id: id)
|
||||
self.tags_changed = false
|
||||
end
|
||||
end
|
||||
|
||||
def initialize_default_values
|
||||
|
@ -518,13 +524,16 @@ class Topic < ActiveRecord::Base
|
|||
self.category_id = new_category.id
|
||||
self.update_column(:category_id, new_category.id)
|
||||
Category.where(id: old_category.id).update_all("topic_count = topic_count - 1") if old_category
|
||||
|
||||
# when a topic changes category we may have to start watching it
|
||||
# if we happen to have read state for it
|
||||
CategoryUser.auto_watch(category_id: new_category.id, topic_id: self.id)
|
||||
CategoryUser.auto_track(category_id: new_category.id, topic_id: self.id)
|
||||
end
|
||||
|
||||
Category.where(id: new_category.id).update_all("topic_count = topic_count + 1")
|
||||
CategoryFeaturedTopic.feature_topics_for(old_category) unless @import_mode
|
||||
CategoryFeaturedTopic.feature_topics_for(new_category) unless @import_mode || old_category.id == new_category.id
|
||||
CategoryUser.auto_watch_new_topic(self, new_category)
|
||||
CategoryUser.auto_track_new_topic(self, new_category)
|
||||
end
|
||||
|
||||
true
|
||||
|
|
|
@ -131,15 +131,7 @@ SQL
|
|||
rows = TopicUser.where(topic_id: topic_id, user_id: user_id).update_all([attrs_sql, *vals])
|
||||
|
||||
if rows == 0
|
||||
now = DateTime.now
|
||||
auto_track_after = UserOption.where(user_id: user_id).pluck(:auto_track_topics_after_msecs).first
|
||||
auto_track_after ||= SiteSetting.default_other_auto_track_topics_after_msecs
|
||||
|
||||
if auto_track_after >= 0 && auto_track_after <= (attrs[:total_msecs_viewed].to_i || 0)
|
||||
attrs[:notification_level] ||= notification_levels[:tracking]
|
||||
end
|
||||
|
||||
TopicUser.create(attrs.merge!(user_id: user_id, topic_id: topic_id, first_visited_at: now ,last_visited_at: now))
|
||||
create_missing_record(user_id, topic_id, attrs)
|
||||
else
|
||||
observe_after_save_callbacks_for topic_id, user_id
|
||||
end
|
||||
|
@ -153,12 +145,64 @@ SQL
|
|||
# In case of a race condition to insert, do nothing
|
||||
end
|
||||
|
||||
def create_missing_record(user_id, topic_id, attrs)
|
||||
now = DateTime.now
|
||||
|
||||
unless attrs[:notification_level]
|
||||
category_notification_level = CategoryUser.where(user_id: user_id)
|
||||
.where("category_id IN (SELECT category_id FROM topics WHERE id = :id)", id: topic_id)
|
||||
.where("notification_level IN (:levels)", levels: [CategoryUser.notification_levels[:watching],
|
||||
CategoryUser.notification_levels[:tracking]])
|
||||
.order("notification_level DESC")
|
||||
.limit(1)
|
||||
.pluck(:notification_level)
|
||||
.first
|
||||
|
||||
tag_notification_level = TagUser.where(user_id: user_id)
|
||||
.where("tag_id IN (SELECT tag_id FROM topic_tags WHERE topic_id = :id)", id: topic_id)
|
||||
.where("notification_level IN (:levels)", levels: [CategoryUser.notification_levels[:watching],
|
||||
CategoryUser.notification_levels[:tracking]])
|
||||
.order("notification_level DESC")
|
||||
.limit(1)
|
||||
.pluck(:notification_level)
|
||||
.first
|
||||
|
||||
if category_notification_level && !(tag_notification_level && (tag_notification_level > category_notification_level))
|
||||
attrs[:notification_level] = category_notification_level
|
||||
attrs[:notifications_changed_at] = DateTime.now
|
||||
attrs[:notifications_reason_id] = category_notification_level == CategoryUser.notification_levels[:watching] ?
|
||||
TopicUser.notification_reasons[:auto_watch_category] :
|
||||
TopicUser.notification_reasons[:auto_track_category]
|
||||
|
||||
elsif tag_notification_level
|
||||
attrs[:notification_level] = tag_notification_level
|
||||
attrs[:notifications_changed_at] = DateTime.now
|
||||
attrs[:notifications_reason_id] = tag_notification_level == TagUser.notification_levels[:watching] ?
|
||||
TopicUser.notification_reasons[:auto_watch_tag] :
|
||||
TopicUser.notification_reasons[:auto_track_tag]
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
unless attrs[:notification_level]
|
||||
auto_track_after = UserOption.where(user_id: user_id).pluck(:auto_track_topics_after_msecs).first
|
||||
auto_track_after ||= SiteSetting.default_other_auto_track_topics_after_msecs
|
||||
|
||||
if auto_track_after >= 0 && auto_track_after <= (attrs[:total_msecs_viewed].to_i || 0)
|
||||
attrs[:notification_level] ||= notification_levels[:tracking]
|
||||
end
|
||||
end
|
||||
|
||||
TopicUser.create(attrs.merge!(user_id: user_id, topic_id: topic_id, first_visited_at: now ,last_visited_at: now))
|
||||
end
|
||||
|
||||
def track_visit!(topic_id, user_id)
|
||||
now = DateTime.now
|
||||
rows = TopicUser.where(topic_id: topic_id, user_id: user_id).update_all(last_visited_at: now)
|
||||
|
||||
if rows == 0
|
||||
TopicUser.create(topic_id: topic_id, user_id: user_id, last_visited_at: now, first_visited_at: now)
|
||||
change(user_id, topic_id, last_visited_at: now, first_visited_at: now)
|
||||
else
|
||||
observe_after_save_callbacks_for(topic_id, user_id)
|
||||
end
|
||||
|
|
|
@ -83,6 +83,9 @@ class UserSerializer < BasicUserSerializer
|
|||
|
||||
private_attributes :locale,
|
||||
:muted_category_ids,
|
||||
:watched_tags,
|
||||
:tracked_tags,
|
||||
:muted_tags,
|
||||
:tracked_category_ids,
|
||||
:watched_category_ids,
|
||||
:private_messages_stats,
|
||||
|
@ -246,6 +249,17 @@ class UserSerializer < BasicUserSerializer
|
|||
###
|
||||
### PRIVATE ATTRIBUTES
|
||||
###
|
||||
def muted_tags
|
||||
TagUser.lookup(object, :muted).joins(:tag).pluck('tags.name')
|
||||
end
|
||||
|
||||
def tracked_tags
|
||||
TagUser.lookup(object, :tracking).joins(:tag).pluck('tags.name')
|
||||
end
|
||||
|
||||
def watched_tags
|
||||
TagUser.lookup(object, :watching).joins(:tag).pluck('tags.name')
|
||||
end
|
||||
|
||||
def muted_category_ids
|
||||
CategoryUser.lookup(object, :muted).pluck(:category_id)
|
||||
|
|
|
@ -452,14 +452,47 @@ class PostAlerter
|
|||
end
|
||||
|
||||
def notify_post_users(post, notified)
|
||||
notify = TopicUser.where(topic_id: post.topic_id)
|
||||
.where(notification_level: TopicUser.notification_levels[:watching])
|
||||
return unless post.topic
|
||||
|
||||
condition = <<SQL
|
||||
|
||||
id IN (
|
||||
SELECT user_id FROM topic_users
|
||||
WHERE notification_level = :watching AND topic_id = :topic_id
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT cu.user_id FROM category_users cu
|
||||
LEFT JOIN topic_users tu ON tu.user_id = cu.user_id AND tu.topic_id = :topic_id
|
||||
WHERE cu.notification_level = :watching AND cu.category_id = :category_id AND tu.user_id IS NULL
|
||||
|
||||
/*tags*/
|
||||
)
|
||||
SQL
|
||||
|
||||
tag_ids = post.topic.topic_tags.pluck('topic_tags.tag_id')
|
||||
if tag_ids.present?
|
||||
condition.sub! "/*tags*/", <<SQL
|
||||
UNION ALL
|
||||
|
||||
SELECT tag_users.user_id FROM tag_users
|
||||
LEFT JOIN topic_users tu ON tu.user_id = tag_users.user_id AND tu.topic_id = :topic_id
|
||||
WHERE tag_users.notification_level = :watching AND tag_users.tag_id IN (:tag_ids) AND tu.user_id IS NULL
|
||||
SQL
|
||||
end
|
||||
|
||||
notify = User.where(condition,
|
||||
watching: TopicUser.notification_levels[:watching],
|
||||
topic_id: post.topic_id,
|
||||
category_id: post.topic.category_id,
|
||||
tag_ids: tag_ids
|
||||
)
|
||||
|
||||
exclude_user_ids = notified.map(&:id)
|
||||
notify = notify.where("user_id NOT IN (?)", exclude_user_ids) if exclude_user_ids.present?
|
||||
notify = notify.where("id NOT IN (?)", exclude_user_ids) if exclude_user_ids.present?
|
||||
|
||||
notify.includes(:user).each do |tu|
|
||||
create_notification(tu.user, Notification.types[:posted], post)
|
||||
notify.each do |user|
|
||||
create_notification(user, Notification.types[:posted], post)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -6,6 +6,12 @@ class UserUpdater
|
|||
muted_category_ids: :muted
|
||||
}
|
||||
|
||||
TAG_NAMES = {
|
||||
watched_tags: :watching,
|
||||
tracked_tags: :tracking,
|
||||
muted_tags: :muted
|
||||
}
|
||||
|
||||
OPTION_ATTR = [
|
||||
:email_always,
|
||||
:mailing_list_mode,
|
||||
|
@ -55,6 +61,10 @@ class UserUpdater
|
|||
end
|
||||
end
|
||||
|
||||
TAG_NAMES.each do |attribute, level|
|
||||
TagUser.batch_set(user, level, attributes[attribute])
|
||||
end
|
||||
|
||||
|
||||
save_options = false
|
||||
|
||||
|
|
|
@ -539,8 +539,15 @@ en:
|
|||
individual: "Send an email for every new post"
|
||||
many_per_day: "Send me an email for every new post (about {{dailyEmailEstimate}} per day)"
|
||||
few_per_day: "Send me an email for every new post (about 2 per day)"
|
||||
tag_settings: "Tags"
|
||||
watched_tags: "Watched"
|
||||
watched_tags_instructions: "You will automatically watch all topics with these tags. You will be notified of all new posts and topics, and a count of new posts will also appear next to the topic."
|
||||
tracked_tags: "Tracked"
|
||||
tracked_tags_instructions: "You will automatically track all new topics with these tags. A count of new posts will appear next to the topic."
|
||||
muted_tags: "Muted"
|
||||
muted_tags_instructions: "You will not be notified of anything about new topics with these tags, and they will not appear in latest."
|
||||
watched_categories: "Watched"
|
||||
watched_categories_instructions: "You will automatically watch all new topics in these categories. You will be notified of all new posts and topics, and a count of new posts will also appear next to the topic."
|
||||
watched_categories_instructions: "You will automatically watch all topics in these categories. You will be notified of all new posts and topics, and a count of new posts will also appear next to the topic."
|
||||
tracked_categories: "Tracked"
|
||||
tracked_categories_instructions: "You will automatically track all new topics in these categories. A count of new posts will appear next to the topic."
|
||||
muted_categories: "Muted"
|
||||
|
@ -577,13 +584,6 @@ en:
|
|||
failed_to_move: "Failed to move selected messages (perhaps your network is down)"
|
||||
select_all: "Select All"
|
||||
|
||||
warn_unwatch:
|
||||
message: "Also stop watching previously watched topics in {{categories}}?"
|
||||
yes_value: "Yes, stop watching topics"
|
||||
no_value:
|
||||
one: "No, only stop watching category"
|
||||
other: "No, only stop watching categories"
|
||||
|
||||
change_password:
|
||||
success: "(email sent)"
|
||||
in_progress: "(sending email)"
|
||||
|
@ -1349,6 +1349,7 @@ en:
|
|||
title: change how often you get notified about this topic
|
||||
reasons:
|
||||
mailing_list_mode: "You have mailing list mode enabled, so you will be notified of replies to this topic via email."
|
||||
"3_10": 'You will receive notifications because you are watching this a tag on this topic.'
|
||||
"3_6": 'You will receive notifications because you are watching this category.'
|
||||
"3_5": 'You will receive notifications because you started watching this topic automatically.'
|
||||
"3_2": 'You will receive notifications because you are watching this topic.'
|
||||
|
|
|
@ -3,10 +3,6 @@ module DiscourseTagging
|
|||
TAGS_FIELD_NAME = "tags"
|
||||
TAGS_FILTER_REGEXP = /[<\\\/\>\#\?\&\s]/
|
||||
|
||||
# class Engine < ::Rails::Engine
|
||||
# engine_name "discourse_tagging"
|
||||
# isolate_namespace DiscourseTagging
|
||||
# end
|
||||
|
||||
def self.tag_topic_by_names(topic, guardian, tag_names_arg)
|
||||
if SiteSetting.tagging_enabled
|
||||
|
@ -43,13 +39,11 @@ module DiscourseTagging
|
|||
end
|
||||
end
|
||||
|
||||
auto_notify_for(tags, topic)
|
||||
|
||||
topic.tags = tags
|
||||
else
|
||||
auto_notify_for([], topic)
|
||||
topic.tags = []
|
||||
end
|
||||
topic.tags_changed=true
|
||||
end
|
||||
true
|
||||
end
|
||||
|
@ -146,11 +140,6 @@ module DiscourseTagging
|
|||
query
|
||||
end
|
||||
|
||||
def self.auto_notify_for(tags, topic)
|
||||
TagUser.auto_watch_new_topic(topic, tags)
|
||||
TagUser.auto_track_new_topic(topic, tags)
|
||||
end
|
||||
|
||||
def self.clean_tag(tag)
|
||||
tag.downcase.strip[0...SiteSetting.max_tag_length].gsub(TAGS_FILTER_REGEXP, '')
|
||||
end
|
||||
|
|
|
@ -90,14 +90,6 @@ class TopicCreator
|
|||
topic.notifier.send(action, gu.user_id)
|
||||
end
|
||||
end
|
||||
|
||||
unless topic.private_message?
|
||||
# In order of importance:
|
||||
CategoryUser.auto_watch_new_topic(topic)
|
||||
CategoryUser.auto_track_new_topic(topic)
|
||||
TagUser.auto_watch_new_topic(topic)
|
||||
TagUser.auto_track_new_topic(topic)
|
||||
end
|
||||
end
|
||||
|
||||
def setup_topic_params
|
||||
|
|
|
@ -5,6 +5,14 @@ require_dependency 'post_creator'
|
|||
|
||||
describe CategoryUser do
|
||||
|
||||
def tracking
|
||||
CategoryUser.notification_levels[:tracking]
|
||||
end
|
||||
|
||||
def regular
|
||||
CategoryUser.notification_levels[:regular]
|
||||
end
|
||||
|
||||
it 'allows batch set' do
|
||||
user = Fabricate(:user)
|
||||
category1 = Fabricate(:category)
|
||||
|
@ -22,6 +30,21 @@ describe CategoryUser do
|
|||
expect(watching.count).to eq 1
|
||||
end
|
||||
|
||||
it 'should correctly auto_track' do
|
||||
tracking_user = Fabricate(:user)
|
||||
user = Fabricate(:user)
|
||||
topic = Fabricate(:post).topic
|
||||
|
||||
TopicUser.change(user.id, topic.id, total_msecs_viewed: 10)
|
||||
TopicUser.change(tracking_user.id, topic.id, total_msecs_viewed: 10)
|
||||
|
||||
CategoryUser.create!(user: tracking_user, category: topic.category, notification_level: tracking)
|
||||
CategoryUser.auto_track(user_id: tracking_user.id)
|
||||
|
||||
expect(TopicUser.get(topic, tracking_user).notification_level).to eq(tracking)
|
||||
expect(TopicUser.get(topic, user).notification_level).to eq(regular)
|
||||
end
|
||||
|
||||
|
||||
context 'integration' do
|
||||
before do
|
||||
|
@ -35,6 +58,8 @@ describe CategoryUser do
|
|||
|
||||
user = Fabricate(:user)
|
||||
|
||||
early_watched_post = create_post(category: watched_category)
|
||||
|
||||
CategoryUser.create!(user: user, category: watched_category, notification_level: CategoryUser.notification_levels[:watching])
|
||||
CategoryUser.create!(user: user, category: muted_category, notification_level: CategoryUser.notification_levels[:muted])
|
||||
CategoryUser.create!(user: user, category: tracked_category, notification_level: CategoryUser.notification_levels[:tracking])
|
||||
|
@ -43,28 +68,36 @@ describe CategoryUser do
|
|||
_muted_post = create_post(category: muted_category)
|
||||
tracked_post = create_post(category: tracked_category)
|
||||
|
||||
create_post(topic_id: early_watched_post.topic_id)
|
||||
|
||||
expect(Notification.where(user_id: user.id, topic_id: watched_post.topic_id).count).to eq 1
|
||||
expect(Notification.where(user_id: user.id, topic_id: early_watched_post.topic_id).count).to eq 1
|
||||
expect(Notification.where(user_id: user.id, topic_id: tracked_post.topic_id).count).to eq 0
|
||||
|
||||
# we must create a record so tracked flicks over
|
||||
TopicUser.change(user.id, tracked_post.topic_id, total_msecs_viewed: 10)
|
||||
tu = TopicUser.get(tracked_post.topic, user)
|
||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:tracking]
|
||||
expect(tu.notifications_reason_id).to eq TopicUser.notification_reasons[:auto_track_category]
|
||||
end
|
||||
|
||||
it "watches categories that have been changed" do
|
||||
it "topics that move to a tracked category should auto track" do
|
||||
user = Fabricate(:user)
|
||||
watched_category = Fabricate(:category)
|
||||
CategoryUser.create!(user: user, category: watched_category, notification_level: CategoryUser.notification_levels[:watching])
|
||||
|
||||
post = create_post
|
||||
expect(TopicUser.get(post.topic, user)).to be_blank
|
||||
first_post = create_post
|
||||
tracked_category = first_post.topic.category
|
||||
|
||||
# Now, change the topic's category
|
||||
post.topic.change_category_to_id(watched_category.id)
|
||||
tu = TopicUser.get(post.topic, user)
|
||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:watching]
|
||||
TopicUser.change(user.id, first_post.topic_id, total_msecs_viewed: 10)
|
||||
tu = TopicUser.get(first_post.topic, user)
|
||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:regular]
|
||||
|
||||
CategoryUser.set_notification_level_for_category(user, CategoryUser.notification_levels[:tracking], tracked_category.id)
|
||||
|
||||
tu = TopicUser.get(first_post.topic, user)
|
||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:tracking]
|
||||
end
|
||||
|
||||
|
||||
it "unwatches categories that have been changed" do
|
||||
user = Fabricate(:user)
|
||||
watched_category = Fabricate(:category)
|
||||
|
@ -72,12 +105,15 @@ describe CategoryUser do
|
|||
|
||||
post = create_post(category: watched_category)
|
||||
tu = TopicUser.get(post.topic, user)
|
||||
|
||||
# we start watching cause a notification is sent to the watching user
|
||||
# this position sent is tracking in topic users
|
||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:watching]
|
||||
|
||||
# Now, change the topic's category
|
||||
unwatched_category = Fabricate(:category)
|
||||
post.topic.change_category_to_id(unwatched_category.id)
|
||||
expect(TopicUser.get(post.topic, user)).to be_blank
|
||||
expect(TopicUser.get(post.topic, user).notification_level).to eq TopicUser.notification_levels[:tracking]
|
||||
end
|
||||
|
||||
it "does not delete TopicUser record when topic category is changed, and new category has same notification level" do
|
||||
|
@ -87,16 +123,26 @@ describe CategoryUser do
|
|||
user = Fabricate(:user)
|
||||
watched_category_1 = Fabricate(:category)
|
||||
watched_category_2 = Fabricate(:category)
|
||||
category_3 = Fabricate(:category)
|
||||
|
||||
post = create_post(category: watched_category_1)
|
||||
|
||||
CategoryUser.create!(user: user, category: watched_category_1, notification_level: CategoryUser.notification_levels[:watching])
|
||||
CategoryUser.create!(user: user, category: watched_category_2, notification_level: CategoryUser.notification_levels[:watching])
|
||||
|
||||
post = create_post(category: watched_category_1)
|
||||
tu = TopicUser.get(post.topic, user)
|
||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:watching]
|
||||
# we must have a topic user record otherwise it will be watched implicitly
|
||||
TopicUser.change(user.id, post.topic_id, total_msecs_viewed: 10)
|
||||
|
||||
expect(TopicUser.get(post.topic, user).notification_level).to eq TopicUser.notification_levels[:watching]
|
||||
|
||||
post.topic.change_category_to_id(category_3.id)
|
||||
expect(TopicUser.get(post.topic, user).notification_level).to eq TopicUser.notification_levels[:tracking]
|
||||
|
||||
# Now, change the topic's category
|
||||
post.topic.change_category_to_id(watched_category_2.id)
|
||||
expect(TopicUser.get(post.topic, user)).to eq tu
|
||||
expect(TopicUser.get(post.topic, user).notification_level).to eq TopicUser.notification_levels[:watching]
|
||||
|
||||
post.topic.change_category_to_id(watched_category_1.id)
|
||||
expect(TopicUser.get(post.topic, user).notification_level).to eq TopicUser.notification_levels[:watching]
|
||||
end
|
||||
|
||||
it "deletes TopicUser record when topic category is changed, and new category has different notification level" do
|
||||
|
|
|
@ -4,13 +4,72 @@ require 'rails_helper'
|
|||
require_dependency 'post_creator'
|
||||
|
||||
describe TagUser do
|
||||
before do
|
||||
SiteSetting.tagging_enabled = true
|
||||
SiteSetting.min_trust_to_create_tag = 0
|
||||
SiteSetting.min_trust_level_to_tag_topics = 0
|
||||
end
|
||||
|
||||
def regular
|
||||
TagUser.notification_levels[:regular]
|
||||
end
|
||||
|
||||
def tracking
|
||||
TagUser.notification_levels[:tracking]
|
||||
end
|
||||
|
||||
def watching
|
||||
TagUser.notification_levels[:watching]
|
||||
end
|
||||
|
||||
context "change" do
|
||||
it "watches or tracks on change" do
|
||||
user = Fabricate(:user)
|
||||
tag = Fabricate(:tag)
|
||||
post = create_post(tags: [tag.name])
|
||||
topic = post.topic
|
||||
|
||||
TopicUser.change(user.id, topic.id, total_msecs_viewed: 1)
|
||||
|
||||
TagUser.change(user.id, tag.id, tracking)
|
||||
expect(TopicUser.get(topic, user).notification_level).to eq tracking
|
||||
|
||||
TagUser.change(user.id, tag.id, watching)
|
||||
expect(TopicUser.get(topic, user).notification_level).to eq watching
|
||||
|
||||
TagUser.change(user.id, tag.id, regular)
|
||||
expect(TopicUser.get(topic, user).notification_level).to eq tracking
|
||||
end
|
||||
end
|
||||
|
||||
context "batch_set" do
|
||||
it "watches and unwatches tags correctly" do
|
||||
|
||||
user = Fabricate(:user)
|
||||
tag = Fabricate(:tag)
|
||||
post = create_post(tags: [tag.name])
|
||||
topic = post.topic
|
||||
|
||||
# we need topic user record to ensure watch picks up other wise it is implicit
|
||||
TopicUser.change(user.id, topic.id, total_msecs_viewed: 1)
|
||||
|
||||
TagUser.batch_set(user, :tracking, [tag.name])
|
||||
|
||||
expect(TopicUser.get(topic, user).notification_level).to eq tracking
|
||||
|
||||
TagUser.batch_set(user, :watching, [tag.name])
|
||||
|
||||
expect(TopicUser.get(topic, user).notification_level).to eq watching
|
||||
|
||||
TagUser.batch_set(user, :watching, [])
|
||||
|
||||
expect(TopicUser.get(topic, user).notification_level).to eq tracking
|
||||
end
|
||||
end
|
||||
|
||||
context "integration" do
|
||||
before do
|
||||
ActiveRecord::Base.observers.enable :all
|
||||
SiteSetting.tagging_enabled = true
|
||||
SiteSetting.min_trust_to_create_tag = 0
|
||||
SiteSetting.min_trust_level_to_tag_topics = 0
|
||||
end
|
||||
|
||||
let(:user) { Fabricate(:user) }
|
||||
|
@ -20,28 +79,43 @@ describe TagUser do
|
|||
let(:tracked_tag) { Fabricate(:tag) }
|
||||
|
||||
context "with some tag notification settings" do
|
||||
before do
|
||||
|
||||
let :watched_post do
|
||||
TagUser.create!(user: user, tag: watched_tag, notification_level: TagUser.notification_levels[:watching])
|
||||
create_post(tags: [watched_tag.name])
|
||||
end
|
||||
|
||||
let :muted_post do
|
||||
TagUser.create!(user: user, tag: muted_tag, notification_level: TagUser.notification_levels[:muted])
|
||||
create_post(tags: [muted_tag.name])
|
||||
end
|
||||
|
||||
let :tracked_post do
|
||||
TagUser.create!(user: user, tag: tracked_tag, notification_level: TagUser.notification_levels[:tracking])
|
||||
create_post(tags: [tracked_tag.name])
|
||||
end
|
||||
|
||||
it "sets notification levels correctly" do
|
||||
watched_post = create_post(tags: [watched_tag.name])
|
||||
muted_post = create_post(tags: [muted_tag.name])
|
||||
tracked_post = create_post(tags: [tracked_tag.name])
|
||||
|
||||
expect(Notification.where(user_id: user.id, topic_id: watched_post.topic_id).count).to eq 1
|
||||
expect(Notification.where(user_id: user.id, topic_id: tracked_post.topic_id).count).to eq 0
|
||||
|
||||
TopicUser.change(user.id, tracked_post.topic.id, total_msecs_viewed: 1)
|
||||
tu = TopicUser.get(tracked_post.topic, user)
|
||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:tracking]
|
||||
expect(tu.notifications_reason_id).to eq TopicUser.notification_reasons[:auto_track_tag]
|
||||
end
|
||||
|
||||
it "sets notification level to the highest one if there are multiple tags" do
|
||||
TagUser.create!(user: user, tag: tracked_tag, notification_level: TagUser.notification_levels[:tracking])
|
||||
TagUser.create!(user: user, tag: muted_tag, notification_level: TagUser.notification_levels[:muted])
|
||||
TagUser.create!(user: user, tag: watched_tag, notification_level: TagUser.notification_levels[:watching])
|
||||
|
||||
post = create_post(tags: [muted_tag.name, tracked_tag.name, watched_tag.name])
|
||||
|
||||
expect(Notification.where(user_id: user.id, topic_id: post.topic_id).count).to eq 1
|
||||
|
||||
TopicUser.change(user.id, post.topic.id, total_msecs_viewed: 1)
|
||||
tu = TopicUser.get(post.topic, user)
|
||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:watching]
|
||||
expect(tu.notifications_reason_id).to eq TopicUser.notification_reasons[:auto_watch_tag]
|
||||
|
@ -49,36 +123,43 @@ describe TagUser do
|
|||
|
||||
it "can start watching after tag has been added" do
|
||||
post = create_post
|
||||
expect(TopicUser.get(post.topic, user)).to be_blank
|
||||
DiscourseTagging.tag_topic_by_names(post.topic, Guardian.new(user), [watched_tag.name])
|
||||
tu = TopicUser.get(post.topic, user)
|
||||
expect(tu.notification_level).to eq(TopicUser.notification_levels[:watching])
|
||||
end
|
||||
|
||||
it "can start watching after tag has changed" do
|
||||
post = create_post(tags: [Fabricate(:tag).name])
|
||||
expect(TopicUser.get(post.topic, user)).to be_blank
|
||||
# this is assuming post was already visited in the past, but now cause tag
|
||||
# was added we should start watching it
|
||||
TopicUser.change(user.id, post.topic.id, total_msecs_viewed: 1)
|
||||
TagUser.create!(user: user, tag: watched_tag, notification_level: TagUser.notification_levels[:watching])
|
||||
|
||||
DiscourseTagging.tag_topic_by_names(post.topic, Guardian.new(user), [watched_tag.name])
|
||||
post.topic.save!
|
||||
|
||||
tu = TopicUser.get(post.topic, user)
|
||||
expect(tu.notification_level).to eq(TopicUser.notification_levels[:watching])
|
||||
end
|
||||
|
||||
it "can stop watching after tag has changed" do
|
||||
post = create_post(tags: [watched_tag.name])
|
||||
expect(TopicUser.get(post.topic, user)).to be_present
|
||||
DiscourseTagging.tag_topic_by_names(post.topic, Guardian.new(user), [Fabricate(:tag).name])
|
||||
expect(TopicUser.get(post.topic, user)).to be_blank
|
||||
end
|
||||
watched_tag2 = Fabricate(:tag)
|
||||
TagUser.create!(user: user, tag: watched_tag, notification_level: TagUser.notification_levels[:watching])
|
||||
TagUser.create!(user: user, tag: watched_tag2, notification_level: TagUser.notification_levels[:watching])
|
||||
|
||||
post = create_post(tags: [watched_tag.name, watched_tag2.name])
|
||||
|
||||
TopicUser.change(user.id, post.topic_id, total_msecs_viewed: 1)
|
||||
expect(TopicUser.get(post.topic, user).notification_level).to eq TopicUser.notification_levels[:watching]
|
||||
|
||||
|
||||
DiscourseTagging.tag_topic_by_names(post.topic, Guardian.new(user), [watched_tag.name])
|
||||
post.topic.save!
|
||||
expect(TopicUser.get(post.topic, user).notification_level).to eq TopicUser.notification_levels[:watching]
|
||||
|
||||
|
||||
it "can stop watching after tags have been removed" do
|
||||
post = create_post(tags: [muted_tag.name, tracked_tag.name, watched_tag.name])
|
||||
expect(TopicUser.get(post.topic, user)).to be_present
|
||||
DiscourseTagging.tag_topic_by_names(post.topic, Guardian.new(user), [])
|
||||
expect(TopicUser.get(post.topic, user)).to be_blank
|
||||
post.topic.save!
|
||||
expect(TopicUser.get(post.topic, user).notification_level).to eq TopicUser.notification_levels[:tracking]
|
||||
|
||||
end
|
||||
|
||||
it "is destroyed when a user is deleted" do
|
||||
expect(TagUser.where(user_id: user.id).count).to eq(3)
|
||||
TagUser.create!(user: user, tag: tracked_tag, notification_level: TagUser.notification_levels[:tracking])
|
||||
user.destroy!
|
||||
expect(TagUser.where(user_id: user.id).count).to eq(0)
|
||||
end
|
||||
|
|
|
@ -39,6 +39,28 @@ describe UserUpdater do
|
|||
expect(user.reload.name).to eq 'Jim Tom'
|
||||
end
|
||||
|
||||
it 'can update categories and tags' do
|
||||
category = Fabricate(:category)
|
||||
tag = Fabricate(:tag)
|
||||
|
||||
user = Fabricate(:user)
|
||||
updater = UserUpdater.new(acting_user, user)
|
||||
updater.update(watched_tags: [tag.name], muted_category_ids: [category.id])
|
||||
|
||||
expect(TagUser.where(
|
||||
user_id: user.id,
|
||||
tag_id: tag.id,
|
||||
notification_level: TagUser.notification_levels[:watching]
|
||||
).count).to eq(1)
|
||||
|
||||
expect(CategoryUser.where(
|
||||
user_id: user.id,
|
||||
category_id: category.id,
|
||||
notification_level: CategoryUser.notification_levels[:muted]
|
||||
).count).to eq(1)
|
||||
|
||||
end
|
||||
|
||||
it 'updates various fields' do
|
||||
user = Fabricate(:user)
|
||||
updater = UserUpdater.new(acting_user, user)
|
||||
|
|
Loading…
Reference in a new issue