mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-30 10:58:31 -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,
|
const site = this.site,
|
||||||
self = this,
|
self = this,
|
||||||
filterRegexp = new RegExp(this.site.tags_filter_regexp, "g");
|
filterRegexp = new RegExp(this.site.tags_filter_regexp, "g");
|
||||||
|
|
||||||
var limit = this.siteSettings.max_tags_per_topic;
|
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')) {
|
if (this.get('unlimitedTagCount')) {
|
||||||
limit = null;
|
limit = null;
|
||||||
} else if (this.get('limit')) {
|
} else if (this.get('limit')) {
|
||||||
|
@ -46,7 +51,7 @@ export default Ember.TextField.extend({
|
||||||
|
|
||||||
this.$().select2({
|
this.$().select2({
|
||||||
tags: true,
|
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,
|
maximumInputLength: this.siteSettings.max_tag_length,
|
||||||
maximumSelectionSize: limit,
|
maximumSelectionSize: limit,
|
||||||
initSelection(element, callback) {
|
initSelection(element, callback) {
|
||||||
|
@ -73,7 +78,7 @@ export default Ember.TextField.extend({
|
||||||
term = term.replace(filterRegexp, '').trim();
|
term = term.replace(filterRegexp, '').trim();
|
||||||
|
|
||||||
// No empty terms, make sure the user has permission to create the tag
|
// 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() {
|
if ($(data).filter(function() {
|
||||||
return this.text.localeCompare(term) === 0;
|
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 CanCheckEmails from 'discourse/mixins/can-check-emails';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import computed from "ember-addons/ember-computed-decorators";
|
import computed from "ember-addons/ember-computed-decorators";
|
||||||
import { categoryBadgeHTML } from "discourse/helpers/category-link";
|
|
||||||
|
|
||||||
export default Ember.Controller.extend(CanCheckEmails, {
|
export default Ember.Controller.extend(CanCheckEmails, {
|
||||||
|
|
||||||
|
@ -136,24 +135,6 @@ export default Ember.Controller.extend(CanCheckEmails, {
|
||||||
|
|
||||||
const model = this.get('model');
|
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');
|
const userFields = this.get('userFields');
|
||||||
|
|
||||||
// Update the user fields
|
// Update the user fields
|
||||||
|
@ -169,9 +150,6 @@ export default Ember.Controller.extend(CanCheckEmails, {
|
||||||
// Cook the bio for preview
|
// Cook the bio for preview
|
||||||
model.set('name', this.get('newNameInput'));
|
model.set('name', this.get('newNameInput'));
|
||||||
var options = {};
|
var options = {};
|
||||||
if (this.get('warnedRemoveWatch') && this.get('unwatchCategoryTopics')) {
|
|
||||||
options["unwatchCategoryTopics"] = this.get("unwatchCategoryTopics");
|
|
||||||
}
|
|
||||||
|
|
||||||
return model.save(options).then(() => {
|
return model.save(options).then(() => {
|
||||||
if (Discourse.User.currentProp('id') === model.get('id')) {
|
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'))));
|
model.set('bio_cooked', Discourse.Markdown.cook(Discourse.Markdown.sanitize(model.get('bio_raw'))));
|
||||||
this.set('saved', true);
|
this.set('saved', true);
|
||||||
this.set("unwatchTopics", false);
|
|
||||||
this.set('warnedRemoveWatch', false);
|
|
||||||
}).catch(popupAjaxError);
|
}).catch(popupAjaxError);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -141,7 +141,7 @@ const User = RestModel.extend({
|
||||||
return Discourse.User.create(this.getProperties(Object.keys(this)));
|
return Discourse.User.create(this.getProperties(Object.keys(this)));
|
||||||
},
|
},
|
||||||
|
|
||||||
save(options) {
|
save() {
|
||||||
const data = this.getProperties(
|
const data = this.getProperties(
|
||||||
'bio_raw',
|
'bio_raw',
|
||||||
'website',
|
'website',
|
||||||
|
@ -152,7 +152,10 @@ const User = RestModel.extend({
|
||||||
'user_fields',
|
'user_fields',
|
||||||
'muted_usernames',
|
'muted_usernames',
|
||||||
'profile_background',
|
'profile_background',
|
||||||
'card_background'
|
'card_background',
|
||||||
|
'muted_tags',
|
||||||
|
'tracked_tags',
|
||||||
|
'watched_tags'
|
||||||
);
|
);
|
||||||
|
|
||||||
[ 'email_always',
|
[ 'email_always',
|
||||||
|
@ -192,10 +195,6 @@ const User = RestModel.extend({
|
||||||
data['edit_history_public'] = this.get('user_option.edit_history_public');
|
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.
|
// TODO: We can remove this when migrated fully to rest model.
|
||||||
this.set('isSaving', true);
|
this.set('isSaving', true);
|
||||||
return Discourse.ajax(`/users/${this.get('username_lower')}`, {
|
return Discourse.ajax(`/users/${this.get('username_lower')}`, {
|
||||||
|
|
|
@ -274,6 +274,27 @@
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="control-group muting">
|
||||||
<label class="control-label">{{i18n 'user.users'}}</label>
|
<label class="control-label">{{i18n 'user.users'}}</label>
|
||||||
<div class="controls category-controls">
|
<div class="controls category-controls">
|
||||||
|
|
|
@ -279,3 +279,12 @@ and (max-width : 600px) {
|
||||||
width: 100%;
|
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
|
user = fetch_user_from_params
|
||||||
guardian.ensure_can_edit!(user)
|
guardian.ensure_can_edit!(user)
|
||||||
|
|
||||||
if params[:unwatch_category_topics]
|
|
||||||
TopicUser.unwatch_categories!(user, params[:unwatch_category_topics])
|
|
||||||
end
|
|
||||||
|
|
||||||
if params[:user_fields].present?
|
if params[:user_fields].present?
|
||||||
params[:custom_fields] = {} unless params[:custom_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]]
|
[notification_levels[:watching], notification_levels[:watching_first_post]]
|
||||||
end
|
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)
|
def self.batch_set(user, level, category_ids)
|
||||||
records = CategoryUser.where(user: user, notification_level: notification_levels[level])
|
records = CategoryUser.where(user: user, notification_level: notification_levels[level])
|
||||||
old_ids = records.pluck(:category_id)
|
old_ids = records.pluck(:category_id)
|
||||||
|
changed = false
|
||||||
|
|
||||||
category_ids = Category.where('id in (?)', category_ids).pluck(:id)
|
category_ids = Category.where('id in (?)', category_ids).pluck(:id)
|
||||||
|
|
||||||
remove = (old_ids - category_ids)
|
remove = (old_ids - category_ids)
|
||||||
if remove.present?
|
if remove.present?
|
||||||
records.where('category_id in (?)', remove).destroy_all
|
records.where('category_id in (?)', remove).destroy_all
|
||||||
|
changed = true
|
||||||
end
|
end
|
||||||
|
|
||||||
(category_ids - old_ids).each do |id|
|
(category_ids - old_ids).each do |id|
|
||||||
CategoryUser.create!(user: user, category_id: id, notification_level: notification_levels[level])
|
CategoryUser.create!(user: user, category_id: id, notification_level: notification_levels[level])
|
||||||
|
changed = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if changed
|
||||||
|
auto_watch(user_id: user.id)
|
||||||
|
auto_track(user_id: user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
changed
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.set_notification_level_for_category(user, level, category_id)
|
def self.set_notification_level_for_category(user, level, category_id)
|
||||||
record = CategoryUser.where(user: user, category_id: category_id).first
|
record = CategoryUser.where(user: user, category_id: category_id).first
|
||||||
|
|
||||||
|
return if record && record.notification_level = level
|
||||||
|
|
||||||
if record.present?
|
if record.present?
|
||||||
record.notification_level = level
|
record.notification_level = level
|
||||||
record.save!
|
record.save!
|
||||||
else
|
else
|
||||||
CategoryUser.create!(user: user, category_id: category_id, notification_level: level)
|
CategoryUser.create!(user: user, category_id: category_id, notification_level: level)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
auto_watch(user_id: user.id)
|
||||||
|
auto_track(user_id: user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.apply_default_to_topic(topic_id, category_id, level, reason)
|
def self.auto_track(opts={})
|
||||||
# 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
|
|
||||||
|
|
||||||
exec_sql(sql,
|
builder = SqlBuilder.new <<SQL
|
||||||
topic_id: topic_id,
|
UPDATE topic_users tu
|
||||||
category_id: category_id,
|
SET notification_level = :tracking,
|
||||||
level: level,
|
notifications_reason_id = :auto_track_category
|
||||||
reason: reason
|
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
|
end
|
||||||
|
|
||||||
def self.remove_default_from_topic(topic_id, category_id, level, reason)
|
def self.auto_watch(opts={})
|
||||||
sql = <<-SQL
|
|
||||||
DELETE FROM topic_users
|
builder = SqlBuilder.new <<SQL
|
||||||
WHERE topic_id = :topic_id
|
UPDATE topic_users tu
|
||||||
AND notifications_changed_at IS NULL
|
SET notification_level =
|
||||||
AND notification_level = :level
|
CASE WHEN should_track THEN :tracking
|
||||||
AND notifications_reason_id = :reason
|
WHEN should_watch THEN :watching
|
||||||
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)
|
ELSE notification_level
|
||||||
SQL
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
def self.ensure_consistency!
|
def self.ensure_consistency!
|
||||||
exec_sql <<SQL
|
exec_sql <<SQL
|
||||||
DELETE FROM category_users
|
DELETE FROM category_users
|
||||||
|
@ -110,7 +166,6 @@ class CategoryUser < ActiveRecord::Base
|
||||||
SQL
|
SQL
|
||||||
end
|
end
|
||||||
|
|
||||||
private_class_method :apply_default_to_topic, :remove_default_from_topic
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
|
|
|
@ -8,6 +8,38 @@ class TagUser < ActiveRecord::Base
|
||||||
NotificationLevels.all
|
NotificationLevels.all
|
||||||
end
|
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)
|
def self.change(user_id, tag_id, level)
|
||||||
tag_id = tag_id.id if tag_id.is_a?(::Tag)
|
tag_id = tag_id.id if tag_id.is_a?(::Tag)
|
||||||
user_id = user_id.id if user_id.is_a?(::User)
|
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)
|
tag_user = TagUser.create(user_id: user_id, tag_id: tag_id, notification_level: level)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
auto_watch(user_id: user_id)
|
||||||
|
auto_track(user_id: user_id)
|
||||||
|
|
||||||
tag_user
|
tag_user
|
||||||
rescue ActiveRecord::RecordNotUnique
|
rescue ActiveRecord::RecordNotUnique
|
||||||
# In case of a race condition to insert, do nothing
|
# In case of a race condition to insert, do nothing
|
||||||
end
|
end
|
||||||
|
|
||||||
%w{watch track}.each do |s|
|
def self.auto_watch(opts)
|
||||||
define_singleton_method("auto_#{s}_new_topic") do |topic, new_tags=nil|
|
builder = SqlBuilder.new <<SQL
|
||||||
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
|
|
||||||
|
|
||||||
apply_default_to_topic( topic.id, tag_ids,
|
UPDATE topic_users
|
||||||
TopicUser.notification_levels[:"#{s}ing"],
|
SET notification_level = CASE WHEN should_watch THEN :watching ELSE :tracking END,
|
||||||
TopicUser.notification_reasons[:"auto_#{s}_tag"])
|
notifications_reason_id = CASE WHEN should_watch THEN :auto_watch_tag ELSE NULL END
|
||||||
end
|
FROM
|
||||||
end
|
(
|
||||||
|
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)
|
CASE WHEN MAX(tag_users.notification_level) IS NULL AND
|
||||||
sql = <<-SQL
|
tu.notification_level = :watching AND
|
||||||
INSERT INTO topic_users(user_id, topic_id, notification_level, notifications_reason_id)
|
tu.notifications_reason_id = :auto_watch_tag
|
||||||
SELECT user_id, :topic_id, :level, :reason
|
THEN true
|
||||||
FROM tag_users
|
ELSE false
|
||||||
WHERE notification_level = :level
|
END
|
||||||
AND tag_id in (:tag_ids)
|
should_track
|
||||||
AND NOT EXISTS(SELECT 1 FROM topic_users WHERE topic_id = :topic_id AND user_id = tag_users.user_id)
|
|
||||||
LIMIT 1
|
|
||||||
SQL
|
|
||||||
|
|
||||||
exec_sql(sql,
|
FROM topic_users tu
|
||||||
topic_id: topic_id,
|
LEFT JOIN topic_tags ON tu.topic_id = topic_tags.topic_id
|
||||||
tag_ids: tag_ids,
|
LEFT JOIN tag_users ON tag_users.user_id = tu.user_id
|
||||||
level: level,
|
AND topic_tags.tag_id = tag_users.tag_id
|
||||||
reason: reason
|
AND tag_users.notification_level = :watching
|
||||||
)
|
/*where*/
|
||||||
end
|
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 = <<-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
|
|
||||||
|
|
||||||
if !tag_ids.empty?
|
builder.where("tu.notification_level in (:tracking, :regular, :watching)")
|
||||||
sql << <<-SQL
|
|
||||||
AND NOT EXISTS(
|
if topic_id = opts[:topic_id]
|
||||||
SELECT 1
|
builder.where("tu.topic_id = :topic_id", topic_id: topic_id)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
exec_sql(sql,
|
if user_id = opts[:user_id]
|
||||||
topic_id: topic_id,
|
builder.where("tu.user_id = :user_id", user_id: user_id)
|
||||||
level: level,
|
end
|
||||||
reason: reason,
|
|
||||||
tag_ids: tag_ids
|
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
|
end
|
||||||
|
|
||||||
private_class_method :apply_default_to_topic, :remove_default_from_topic
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
|
|
|
@ -25,7 +25,7 @@ class Topic < ActiveRecord::Base
|
||||||
def_delegator :notifier, :mute!, :notify_muted!
|
def_delegator :notifier, :mute!, :notify_muted!
|
||||||
def_delegator :notifier, :toggle_mute, :toggle_mute
|
def_delegator :notifier, :toggle_mute, :toggle_mute
|
||||||
|
|
||||||
attr_accessor :allowed_user_ids
|
attr_accessor :allowed_user_ids, :tags_changed
|
||||||
|
|
||||||
def self.max_sort_order
|
def self.max_sort_order
|
||||||
@max_sort_order ||= (2 ** 31) - 1
|
@max_sort_order ||= (2 ** 31) - 1
|
||||||
|
@ -187,6 +187,12 @@ class Topic < ActiveRecord::Base
|
||||||
if archetype_was == banner || archetype == banner
|
if archetype_was == banner || archetype == banner
|
||||||
ApplicationController.banner_json_cache.clear
|
ApplicationController.banner_json_cache.clear
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if tags_changed
|
||||||
|
TagUser.auto_watch(topic_id: id)
|
||||||
|
TagUser.auto_track(topic_id: id)
|
||||||
|
self.tags_changed = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize_default_values
|
def initialize_default_values
|
||||||
|
@ -518,13 +524,16 @@ class Topic < ActiveRecord::Base
|
||||||
self.category_id = new_category.id
|
self.category_id = new_category.id
|
||||||
self.update_column(: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
|
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
|
end
|
||||||
|
|
||||||
Category.where(id: new_category.id).update_all("topic_count = topic_count + 1")
|
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(old_category) unless @import_mode
|
||||||
CategoryFeaturedTopic.feature_topics_for(new_category) unless @import_mode || old_category.id == new_category.id
|
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
|
end
|
||||||
|
|
||||||
true
|
true
|
||||||
|
|
|
@ -131,15 +131,7 @@ SQL
|
||||||
rows = TopicUser.where(topic_id: topic_id, user_id: user_id).update_all([attrs_sql, *vals])
|
rows = TopicUser.where(topic_id: topic_id, user_id: user_id).update_all([attrs_sql, *vals])
|
||||||
|
|
||||||
if rows == 0
|
if rows == 0
|
||||||
now = DateTime.now
|
create_missing_record(user_id, topic_id, attrs)
|
||||||
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))
|
|
||||||
else
|
else
|
||||||
observe_after_save_callbacks_for topic_id, user_id
|
observe_after_save_callbacks_for topic_id, user_id
|
||||||
end
|
end
|
||||||
|
@ -153,12 +145,64 @@ SQL
|
||||||
# In case of a race condition to insert, do nothing
|
# In case of a race condition to insert, do nothing
|
||||||
end
|
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)
|
def track_visit!(topic_id, user_id)
|
||||||
now = DateTime.now
|
now = DateTime.now
|
||||||
rows = TopicUser.where(topic_id: topic_id, user_id: user_id).update_all(last_visited_at: now)
|
rows = TopicUser.where(topic_id: topic_id, user_id: user_id).update_all(last_visited_at: now)
|
||||||
|
|
||||||
if rows == 0
|
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
|
else
|
||||||
observe_after_save_callbacks_for(topic_id, user_id)
|
observe_after_save_callbacks_for(topic_id, user_id)
|
||||||
end
|
end
|
||||||
|
|
|
@ -83,6 +83,9 @@ class UserSerializer < BasicUserSerializer
|
||||||
|
|
||||||
private_attributes :locale,
|
private_attributes :locale,
|
||||||
:muted_category_ids,
|
:muted_category_ids,
|
||||||
|
:watched_tags,
|
||||||
|
:tracked_tags,
|
||||||
|
:muted_tags,
|
||||||
:tracked_category_ids,
|
:tracked_category_ids,
|
||||||
:watched_category_ids,
|
:watched_category_ids,
|
||||||
:private_messages_stats,
|
:private_messages_stats,
|
||||||
|
@ -246,6 +249,17 @@ class UserSerializer < BasicUserSerializer
|
||||||
###
|
###
|
||||||
### PRIVATE ATTRIBUTES
|
### 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
|
def muted_category_ids
|
||||||
CategoryUser.lookup(object, :muted).pluck(:category_id)
|
CategoryUser.lookup(object, :muted).pluck(:category_id)
|
||||||
|
|
|
@ -452,14 +452,47 @@ class PostAlerter
|
||||||
end
|
end
|
||||||
|
|
||||||
def notify_post_users(post, notified)
|
def notify_post_users(post, notified)
|
||||||
notify = TopicUser.where(topic_id: post.topic_id)
|
return unless post.topic
|
||||||
.where(notification_level: TopicUser.notification_levels[:watching])
|
|
||||||
|
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)
|
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|
|
notify.each do |user|
|
||||||
create_notification(tu.user, Notification.types[:posted], post)
|
create_notification(user, Notification.types[:posted], post)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,12 @@ class UserUpdater
|
||||||
muted_category_ids: :muted
|
muted_category_ids: :muted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TAG_NAMES = {
|
||||||
|
watched_tags: :watching,
|
||||||
|
tracked_tags: :tracking,
|
||||||
|
muted_tags: :muted
|
||||||
|
}
|
||||||
|
|
||||||
OPTION_ATTR = [
|
OPTION_ATTR = [
|
||||||
:email_always,
|
:email_always,
|
||||||
:mailing_list_mode,
|
:mailing_list_mode,
|
||||||
|
@ -55,6 +61,10 @@ class UserUpdater
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
TAG_NAMES.each do |attribute, level|
|
||||||
|
TagUser.batch_set(user, level, attributes[attribute])
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
save_options = false
|
save_options = false
|
||||||
|
|
||||||
|
|
|
@ -539,8 +539,15 @@ en:
|
||||||
individual: "Send an email for every new post"
|
individual: "Send an email for every new post"
|
||||||
many_per_day: "Send me an email for every new post (about {{dailyEmailEstimate}} per day)"
|
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)"
|
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: "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: "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."
|
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"
|
muted_categories: "Muted"
|
||||||
|
@ -577,13 +584,6 @@ en:
|
||||||
failed_to_move: "Failed to move selected messages (perhaps your network is down)"
|
failed_to_move: "Failed to move selected messages (perhaps your network is down)"
|
||||||
select_all: "Select All"
|
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:
|
change_password:
|
||||||
success: "(email sent)"
|
success: "(email sent)"
|
||||||
in_progress: "(sending email)"
|
in_progress: "(sending email)"
|
||||||
|
@ -1349,6 +1349,7 @@ en:
|
||||||
title: change how often you get notified about this topic
|
title: change how often you get notified about this topic
|
||||||
reasons:
|
reasons:
|
||||||
mailing_list_mode: "You have mailing list mode enabled, so you will be notified of replies to this topic via email."
|
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_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_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_2": 'You will receive notifications because you are watching this topic.'
|
||||||
|
|
|
@ -3,10 +3,6 @@ module DiscourseTagging
|
||||||
TAGS_FIELD_NAME = "tags"
|
TAGS_FIELD_NAME = "tags"
|
||||||
TAGS_FILTER_REGEXP = /[<\\\/\>\#\?\&\s]/
|
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)
|
def self.tag_topic_by_names(topic, guardian, tag_names_arg)
|
||||||
if SiteSetting.tagging_enabled
|
if SiteSetting.tagging_enabled
|
||||||
|
@ -43,13 +39,11 @@ module DiscourseTagging
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
auto_notify_for(tags, topic)
|
|
||||||
|
|
||||||
topic.tags = tags
|
topic.tags = tags
|
||||||
else
|
else
|
||||||
auto_notify_for([], topic)
|
|
||||||
topic.tags = []
|
topic.tags = []
|
||||||
end
|
end
|
||||||
|
topic.tags_changed=true
|
||||||
end
|
end
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
@ -146,11 +140,6 @@ module DiscourseTagging
|
||||||
query
|
query
|
||||||
end
|
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)
|
def self.clean_tag(tag)
|
||||||
tag.downcase.strip[0...SiteSetting.max_tag_length].gsub(TAGS_FILTER_REGEXP, '')
|
tag.downcase.strip[0...SiteSetting.max_tag_length].gsub(TAGS_FILTER_REGEXP, '')
|
||||||
end
|
end
|
||||||
|
|
|
@ -90,14 +90,6 @@ class TopicCreator
|
||||||
topic.notifier.send(action, gu.user_id)
|
topic.notifier.send(action, gu.user_id)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
|
|
||||||
def setup_topic_params
|
def setup_topic_params
|
||||||
|
|
|
@ -5,6 +5,14 @@ require_dependency 'post_creator'
|
||||||
|
|
||||||
describe CategoryUser do
|
describe CategoryUser do
|
||||||
|
|
||||||
|
def tracking
|
||||||
|
CategoryUser.notification_levels[:tracking]
|
||||||
|
end
|
||||||
|
|
||||||
|
def regular
|
||||||
|
CategoryUser.notification_levels[:regular]
|
||||||
|
end
|
||||||
|
|
||||||
it 'allows batch set' do
|
it 'allows batch set' do
|
||||||
user = Fabricate(:user)
|
user = Fabricate(:user)
|
||||||
category1 = Fabricate(:category)
|
category1 = Fabricate(:category)
|
||||||
|
@ -22,6 +30,21 @@ describe CategoryUser do
|
||||||
expect(watching.count).to eq 1
|
expect(watching.count).to eq 1
|
||||||
end
|
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
|
context 'integration' do
|
||||||
before do
|
before do
|
||||||
|
@ -35,6 +58,8 @@ describe CategoryUser do
|
||||||
|
|
||||||
user = Fabricate(:user)
|
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: 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: muted_category, notification_level: CategoryUser.notification_levels[:muted])
|
||||||
CategoryUser.create!(user: user, category: tracked_category, notification_level: CategoryUser.notification_levels[:tracking])
|
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)
|
_muted_post = create_post(category: muted_category)
|
||||||
tracked_post = create_post(category: tracked_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: 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
|
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)
|
tu = TopicUser.get(tracked_post.topic, user)
|
||||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:tracking]
|
expect(tu.notification_level).to eq TopicUser.notification_levels[:tracking]
|
||||||
expect(tu.notifications_reason_id).to eq TopicUser.notification_reasons[:auto_track_category]
|
expect(tu.notifications_reason_id).to eq TopicUser.notification_reasons[:auto_track_category]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "watches categories that have been changed" do
|
it "topics that move to a tracked category should auto track" do
|
||||||
user = Fabricate(:user)
|
user = Fabricate(:user)
|
||||||
watched_category = Fabricate(:category)
|
|
||||||
CategoryUser.create!(user: user, category: watched_category, notification_level: CategoryUser.notification_levels[:watching])
|
|
||||||
|
|
||||||
post = create_post
|
first_post = create_post
|
||||||
expect(TopicUser.get(post.topic, user)).to be_blank
|
tracked_category = first_post.topic.category
|
||||||
|
|
||||||
# Now, change the topic's category
|
TopicUser.change(user.id, first_post.topic_id, total_msecs_viewed: 10)
|
||||||
post.topic.change_category_to_id(watched_category.id)
|
tu = TopicUser.get(first_post.topic, user)
|
||||||
tu = TopicUser.get(post.topic, user)
|
expect(tu.notification_level).to eq TopicUser.notification_levels[:regular]
|
||||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:watching]
|
|
||||||
|
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
|
end
|
||||||
|
|
||||||
|
|
||||||
it "unwatches categories that have been changed" do
|
it "unwatches categories that have been changed" do
|
||||||
user = Fabricate(:user)
|
user = Fabricate(:user)
|
||||||
watched_category = Fabricate(:category)
|
watched_category = Fabricate(:category)
|
||||||
|
@ -72,12 +105,15 @@ describe CategoryUser do
|
||||||
|
|
||||||
post = create_post(category: watched_category)
|
post = create_post(category: watched_category)
|
||||||
tu = TopicUser.get(post.topic, user)
|
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]
|
expect(tu.notification_level).to eq TopicUser.notification_levels[:watching]
|
||||||
|
|
||||||
# Now, change the topic's category
|
# Now, change the topic's category
|
||||||
unwatched_category = Fabricate(:category)
|
unwatched_category = Fabricate(:category)
|
||||||
post.topic.change_category_to_id(unwatched_category.id)
|
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
|
end
|
||||||
|
|
||||||
it "does not delete TopicUser record when topic category is changed, and new category has same notification level" do
|
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)
|
user = Fabricate(:user)
|
||||||
watched_category_1 = Fabricate(:category)
|
watched_category_1 = Fabricate(:category)
|
||||||
watched_category_2 = 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_1, notification_level: CategoryUser.notification_levels[:watching])
|
||||||
CategoryUser.create!(user: user, category: watched_category_2, 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)
|
# we must have a topic user record otherwise it will be watched implicitly
|
||||||
tu = TopicUser.get(post.topic, user)
|
TopicUser.change(user.id, post.topic_id, total_msecs_viewed: 10)
|
||||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:watching]
|
|
||||||
|
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)
|
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
|
end
|
||||||
|
|
||||||
it "deletes TopicUser record when topic category is changed, and new category has different notification level" do
|
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'
|
require_dependency 'post_creator'
|
||||||
|
|
||||||
describe TagUser do
|
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
|
context "integration" do
|
||||||
before do
|
before do
|
||||||
ActiveRecord::Base.observers.enable :all
|
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
|
end
|
||||||
|
|
||||||
let(:user) { Fabricate(:user) }
|
let(:user) { Fabricate(:user) }
|
||||||
|
@ -20,28 +79,43 @@ describe TagUser do
|
||||||
let(:tracked_tag) { Fabricate(:tag) }
|
let(:tracked_tag) { Fabricate(:tag) }
|
||||||
|
|
||||||
context "with some tag notification settings" do
|
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])
|
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])
|
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])
|
TagUser.create!(user: user, tag: tracked_tag, notification_level: TagUser.notification_levels[:tracking])
|
||||||
|
create_post(tags: [tracked_tag.name])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets notification levels correctly" do
|
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: 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
|
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)
|
tu = TopicUser.get(tracked_post.topic, user)
|
||||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:tracking]
|
expect(tu.notification_level).to eq TopicUser.notification_levels[:tracking]
|
||||||
expect(tu.notifications_reason_id).to eq TopicUser.notification_reasons[:auto_track_tag]
|
expect(tu.notifications_reason_id).to eq TopicUser.notification_reasons[:auto_track_tag]
|
||||||
end
|
end
|
||||||
|
|
||||||
it "sets notification level to the highest one if there are multiple tags" do
|
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])
|
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
|
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)
|
tu = TopicUser.get(post.topic, user)
|
||||||
expect(tu.notification_level).to eq TopicUser.notification_levels[:watching]
|
expect(tu.notification_level).to eq TopicUser.notification_levels[:watching]
|
||||||
expect(tu.notifications_reason_id).to eq TopicUser.notification_reasons[:auto_watch_tag]
|
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
|
it "can start watching after tag has been added" do
|
||||||
post = create_post
|
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
|
# this is assuming post was already visited in the past, but now cause tag
|
||||||
post = create_post(tags: [Fabricate(:tag).name])
|
# was added we should start watching it
|
||||||
expect(TopicUser.get(post.topic, user)).to be_blank
|
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])
|
DiscourseTagging.tag_topic_by_names(post.topic, Guardian.new(user), [watched_tag.name])
|
||||||
|
post.topic.save!
|
||||||
|
|
||||||
tu = TopicUser.get(post.topic, user)
|
tu = TopicUser.get(post.topic, user)
|
||||||
expect(tu.notification_level).to eq(TopicUser.notification_levels[:watching])
|
expect(tu.notification_level).to eq(TopicUser.notification_levels[:watching])
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can stop watching after tag has changed" do
|
it "can stop watching after tag has changed" do
|
||||||
post = create_post(tags: [watched_tag.name])
|
watched_tag2 = Fabricate(:tag)
|
||||||
expect(TopicUser.get(post.topic, user)).to be_present
|
TagUser.create!(user: user, tag: watched_tag, notification_level: TagUser.notification_levels[:watching])
|
||||||
DiscourseTagging.tag_topic_by_names(post.topic, Guardian.new(user), [Fabricate(:tag).name])
|
TagUser.create!(user: user, tag: watched_tag2, notification_level: TagUser.notification_levels[:watching])
|
||||||
expect(TopicUser.get(post.topic, user)).to be_blank
|
|
||||||
end
|
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), [])
|
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
|
end
|
||||||
|
|
||||||
it "is destroyed when a user is deleted" do
|
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!
|
user.destroy!
|
||||||
expect(TagUser.where(user_id: user.id).count).to eq(0)
|
expect(TagUser.where(user_id: user.id).count).to eq(0)
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,6 +39,28 @@ describe UserUpdater do
|
||||||
expect(user.reload.name).to eq 'Jim Tom'
|
expect(user.reload.name).to eq 'Jim Tom'
|
||||||
end
|
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
|
it 'updates various fields' do
|
||||||
user = Fabricate(:user)
|
user = Fabricate(:user)
|
||||||
updater = UserUpdater.new(acting_user, user)
|
updater = UserUpdater.new(acting_user, user)
|
||||||
|
|
Loading…
Reference in a new issue