mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 09:36:19 -05:00
FEATURE: offer to unwatch categories when unwatching category
This commit is contained in:
parent
3e07658fb2
commit
1411eedad3
6 changed files with 113 additions and 2 deletions
|
@ -2,6 +2,7 @@ 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, {
|
||||||
|
|
||||||
|
@ -134,6 +135,25 @@ export default Ember.Controller.extend(CanCheckEmails, {
|
||||||
this.set('saved', false);
|
this.set('saved', false);
|
||||||
|
|
||||||
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
|
||||||
|
@ -148,12 +168,19 @@ 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'));
|
||||||
return model.save().then(() => {
|
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')) {
|
if (Discourse.User.currentProp('id') === model.get('id')) {
|
||||||
Discourse.User.currentProp('name', model.get('name'));
|
Discourse.User.currentProp('name', model.get('name'));
|
||||||
}
|
}
|
||||||
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() {
|
save(options) {
|
||||||
const data = this.getProperties(
|
const data = this.getProperties(
|
||||||
'bio_raw',
|
'bio_raw',
|
||||||
'website',
|
'website',
|
||||||
|
@ -177,8 +177,12 @@ const User = RestModel.extend({
|
||||||
data[s] = this.get(`user_option.${s}`);
|
data[s] = this.get(`user_option.${s}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var updatedState = {};
|
||||||
|
|
||||||
['muted','watched','tracked'].forEach(s => {
|
['muted','watched','tracked'].forEach(s => {
|
||||||
let cats = this.get(s + 'Categories').map(c => c.get('id'));
|
let cats = this.get(s + 'Categories').map(c => c.get('id'));
|
||||||
|
updatedState[s + '_category_ids'] = cats;
|
||||||
|
|
||||||
// HACK: denote lack of categories
|
// HACK: denote lack of categories
|
||||||
if (cats.length === 0) { cats = [-1]; }
|
if (cats.length === 0) { cats = [-1]; }
|
||||||
data[s + '_category_ids'] = cats;
|
data[s + '_category_ids'] = cats;
|
||||||
|
@ -188,6 +192,10 @@ 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')}`, {
|
||||||
|
@ -197,6 +205,7 @@ const User = RestModel.extend({
|
||||||
this.set('bio_excerpt', result.user.bio_excerpt);
|
this.set('bio_excerpt', result.user.bio_excerpt);
|
||||||
const userProps = Em.getProperties(this.get('user_option'),'enable_quoting', 'external_links_in_new_tab', 'dynamic_favicon');
|
const userProps = Em.getProperties(this.get('user_option'),'enable_quoting', 'external_links_in_new_tab', 'dynamic_favicon');
|
||||||
Discourse.User.current().setProperties(userProps);
|
Discourse.User.current().setProperties(userProps);
|
||||||
|
this.setProperties(updatedState);
|
||||||
}).finally(() => {
|
}).finally(() => {
|
||||||
this.set('isSaving', false);
|
this.set('isSaving', false);
|
||||||
});
|
});
|
||||||
|
@ -352,6 +361,16 @@ const User = RestModel.extend({
|
||||||
this.set("watchedCategories", Discourse.Category.findByIds(this.watched_category_ids));
|
this.set("watchedCategories", Discourse.Category.findByIds(this.watched_category_ids));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
changedCategoryNotifications: function(type) {
|
||||||
|
const ids = this.get(type + "Categories").map(c => c.id);
|
||||||
|
const oldIds = this.get(type + "_category_ids");
|
||||||
|
|
||||||
|
return {
|
||||||
|
add: _.difference(ids, oldIds),
|
||||||
|
remove: _.difference(oldIds, ids),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
@computed("can_delete_account", "reply_count", "topic_count")
|
@computed("can_delete_account", "reply_count", "topic_count")
|
||||||
canDeleteAccount(canDeleteAccount, replyCount, topicCount) {
|
canDeleteAccount(canDeleteAccount, replyCount, topicCount) {
|
||||||
return !Discourse.SiteSettings.enable_sso && canDeleteAccount && ((replyCount || 0) + (topicCount || 0)) <= 1;
|
return !Discourse.SiteSettings.enable_sso && canDeleteAccount && ((replyCount || 0) + (topicCount || 0)) <= 1;
|
||||||
|
|
|
@ -89,6 +89,10 @@ 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?
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,32 @@ class TopicUser < ActiveRecord::Base
|
||||||
topic_user.save
|
topic_user.save
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unwatch_categories!(user, category_ids)
|
||||||
|
|
||||||
|
track_threshold = user.user_option.auto_track_topics_after_msecs
|
||||||
|
|
||||||
|
sql = <<SQL
|
||||||
|
UPDATE topic_users tu
|
||||||
|
SET notification_level = CASE
|
||||||
|
WHEN t.user_id = :user_id THEN :watching
|
||||||
|
WHEN total_msecs_viewed > :track_threshold AND :track_threshold >= 0 THEN :tracking
|
||||||
|
ELSE :regular
|
||||||
|
end
|
||||||
|
FROM topics t
|
||||||
|
WHERE t.id = tu.topic_id AND tu.notification_level <> :muted AND category_id IN (:category_ids) AND tu.user_id = :user_id
|
||||||
|
SQL
|
||||||
|
|
||||||
|
exec_sql(sql,
|
||||||
|
watching: notification_levels[:watching],
|
||||||
|
tracking: notification_levels[:tracking],
|
||||||
|
regular: notification_levels[:regular],
|
||||||
|
muted: notification_levels[:muted],
|
||||||
|
category_ids: category_ids,
|
||||||
|
user_id: user.id,
|
||||||
|
track_threshold: track_threshold
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
# Find the information specific to a user in a forum topic
|
# Find the information specific to a user in a forum topic
|
||||||
def lookup_for(user, topics)
|
def lookup_for(user, topics)
|
||||||
# If the user isn't logged in, there's no last read posts
|
# If the user isn't logged in, there's no last read posts
|
||||||
|
|
|
@ -574,6 +574,13 @@ 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, unwatch topics"
|
||||||
|
no_value:
|
||||||
|
one: "No, only unwatch category"
|
||||||
|
other: "No, only unwatch categories"
|
||||||
|
|
||||||
change_password:
|
change_password:
|
||||||
success: "(email sent)"
|
success: "(email sent)"
|
||||||
in_progress: "(sending email)"
|
in_progress: "(sending email)"
|
||||||
|
|
|
@ -2,6 +2,34 @@ require 'rails_helper'
|
||||||
|
|
||||||
describe TopicUser do
|
describe TopicUser do
|
||||||
|
|
||||||
|
describe "#unwatch_categories!" do
|
||||||
|
it "correctly unwatches categories" do
|
||||||
|
|
||||||
|
op_topic = Fabricate(:topic)
|
||||||
|
another_topic = Fabricate(:topic)
|
||||||
|
tracked_topic = Fabricate(:topic)
|
||||||
|
|
||||||
|
user = op_topic.user
|
||||||
|
watching = TopicUser.notification_levels[:watching]
|
||||||
|
regular = TopicUser.notification_levels[:regular]
|
||||||
|
tracking = TopicUser.notification_levels[:tracking]
|
||||||
|
|
||||||
|
TopicUser.change(user.id, op_topic, notification_level: watching)
|
||||||
|
TopicUser.change(user.id, another_topic, notification_level: watching)
|
||||||
|
TopicUser.change(user.id, tracked_topic, notification_level: watching, total_msecs_viewed: SiteSetting.default_other_auto_track_topics_after_msecs + 1)
|
||||||
|
|
||||||
|
TopicUser.unwatch_categories!(user, [Fabricate(:category).id, Fabricate(:category).id])
|
||||||
|
expect(TopicUser.get(another_topic, user).notification_level).to eq(watching)
|
||||||
|
|
||||||
|
TopicUser.unwatch_categories!(user, [op_topic.category_id])
|
||||||
|
|
||||||
|
expect(TopicUser.get(op_topic, user).notification_level).to eq(watching)
|
||||||
|
expect(TopicUser.get(another_topic, user).notification_level).to eq(regular)
|
||||||
|
expect(TopicUser.get(tracked_topic, user).notification_level).to eq(tracking)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
describe '#notification_levels' do
|
describe '#notification_levels' do
|
||||||
context "verify enum sequence" do
|
context "verify enum sequence" do
|
||||||
before do
|
before do
|
||||||
|
|
Loading…
Reference in a new issue