User interface for watching first post

This commit is contained in:
Robin Ward 2016-07-05 15:16:32 -04:00
parent 323efcab71
commit 1eb64151f6
9 changed files with 91 additions and 41 deletions

View file

@ -1,5 +1,5 @@
import DropdownButton from 'discourse/components/dropdown-button';
import { all, buttonDetails } from 'discourse/lib/notification-levels';
import { allLevels, buttonDetails } from 'discourse/lib/notification-levels';
import { iconHTML } from 'discourse/helpers/fa-icon';
import computed from 'ember-addons/ember-computed-decorators';
@ -16,7 +16,7 @@ export default DropdownButton.extend({
const prefix = this.get('i18nPrefix');
const postfix = this.get('i18nPostfix');
return all.map(l => {
return allLevels.map(l => {
const start = `${prefix}.${l.key}${postfix}`;
return {
id: l.id,

View file

@ -1,26 +1,26 @@
import NotificationLevels from 'discourse/lib/notification-levels';
import computed from 'ember-addons/ember-computed-decorators';
import { topicLevels } from 'discourse/lib/notification-levels';
// Support for changing the notification level of various topics
export default Em.Controller.extend({
export default Ember.Controller.extend({
needs: ['topic-bulk-actions'],
notificationLevelId: null,
notificationLevels: function() {
var result = [];
Object.keys(NotificationLevels).forEach(function(k) {
result.push({
id: NotificationLevels[k].toString(),
name: I18n.t('topic.notifications.' + k.toLowerCase() + ".title"),
description: I18n.t('topic.notifications.' + k.toLowerCase() + ".description")
@computed
notificationLevels() {
return topicLevels.map(level => {
return {
id: level.id.toString(),
name: I18n.t(`topic.notifications.${level.key}.title`),
description: I18n.t(`topic.notifications.${level.key}.description`)
};
});
});
return result;
}.property(),
},
disabled: Em.computed.empty("notificationLevelId"),
actions: {
changeNotificationLevel: function() {
changeNotificationLevel() {
this.get('controllers.topic-bulk-actions').performAndRefresh({
type: 'change_notification_level',
notification_level_id: this.get('notificationLevelId')

View file

@ -1,24 +1,25 @@
const NotificationLevels = {
WATCHING: 3,
TRACKING: 2,
REGULAR: 1,
MUTED: 0
};
export default NotificationLevels;
const MUTED = 0;
const REGULAR = 1;
const TRACKING = 2;
const WATCHING = 3;
const WATCHING_FIRST_POST = 4;
export const NotificationLevels = { WATCHING_FIRST_POST, WATCHING, TRACKING, REGULAR, MUTED };
export function buttonDetails(level) {
switch(level) {
case NotificationLevels.WATCHING:
return { id: NotificationLevels.WATCHING, key: 'watching', icon: 'exclamation-circle' };
case NotificationLevels.TRACKING:
return { id: NotificationLevels.TRACKING, key: 'tracking', icon: 'circle' };
case NotificationLevels.MUTED:
return { id: NotificationLevels.MUTED, key: 'muted', icon: 'times-circle' };
case WATCHING_FIRST_POST:
return { id: WATCHING_FIRST_POST, key: 'watching_first_post', icon: 'dot-circle-o' };
case WATCHING:
return { id: WATCHING, key: 'watching', icon: 'exclamation-circle' };
case TRACKING:
return { id: TRACKING, key: 'tracking', icon: 'circle' };
case MUTED:
return { id: MUTED, key: 'muted', icon: 'times-circle' };
default:
return { id: NotificationLevels.REGULAR, key: 'regular', icon: 'circle-o' };
return { id: REGULAR, key: 'regular', icon: 'circle-o' };
}
}
export const all = [ NotificationLevels.WATCHING,
NotificationLevels.TRACKING,
NotificationLevels.MUTED,
NotificationLevels.DEFAULT ].map(buttonDetails);
export const allLevels = [ WATCHING, TRACKING, WATCHING_FIRST_POST, MUTED, REGULAR ].map(buttonDetails);
export const topicLevels = allLevels.filter(l => l.id !== WATCHING_FIRST_POST);

View file

@ -1,5 +1,5 @@
import { createWidget } from 'discourse/widgets/widget';
import { all, buttonDetails } from 'discourse/lib/notification-levels';
import { topicLevels, buttonDetails } from 'discourse/lib/notification-levels';
import { h } from 'virtual-dom';
import RawHTML from 'discourse/widgets/raw-html';
@ -63,7 +63,7 @@ export default createWidget('topic-notifications-button', {
const result = [ this.buttonFor(details.get('notification_level')) ];
if (state.expanded) {
result.push(h('ul.dropdown-menu', all.map(l => this.attach('notification-option', l))));
result.push(h('ul.dropdown-menu', topicLevels.map(l => this.attach('notification-option', l))));
}
if (attrs.appendReason) {

View file

@ -29,7 +29,7 @@ class EmailController < ApplicationController
@watched_count = nil
if @topic && @topic.category_id
if CategoryUser.exists?(user_id: @user.id,
notification_level: CategoryUser.notification_levels[:watching],
notification_level: CategoryUser.watching_levels,
category_id: @topic.category_id)
@watched_count = TopicUser.joins(:topic)
.where(:user => @user,
@ -74,7 +74,7 @@ class EmailController < ApplicationController
CategoryUser.where(user_id: user.id,
category_id: topic.category_id,
notification_level: CategoryUser.notification_levels[:watching]
notification_level: CategoryUser.watching_levels
)
.destroy_all
updated = true

View file

@ -10,9 +10,16 @@ class CategoryUser < ActiveRecord::Base
self.where(user: user, category: category)
end
# same for now
def self.notification_levels
TopicUser.notification_levels
@notification_levels ||= Enum.new(muted: 0,
regular: 1,
tracking: 2,
watching: 3,
watching_first_post: 4)
end
def self.watching_levels
[notification_levels[:watching], notification_levels[:watching_first_post]]
end
%w{watch track}.each do |s|

View file

@ -408,6 +408,9 @@ en:
watching:
title: "Watching"
description: "You will be notified of every new post in every message, and a count of new replies will be shown."
watching_first_post:
title: "Watching First Post Only"
description: "You will only be notified of the first post in each new topic in this group."
tracking:
title: "Tracking"
description: "You will be notified if someone mentions your @name or replies to you, and a count of new replies will be shown."
@ -1811,6 +1814,9 @@ en:
watching:
title: "Watching"
description: "You will automatically watch all new topics in these categories. You will be notified of every new post in every topic, and a count of new replies will be shown."
watching_first_post:
title: "Watching First Post Only"
description: "You will only be notified of the first post in each new topic in these categories."
tracking:
title: "Tracking"
description: "You will automatically track all new topics in these categories. You will be notified if someone mentions your @name or replies to you, and a count of new replies will be shown."
@ -2132,6 +2138,9 @@ en:
watching:
title: "Watching"
description: "You will automatically watch all new topics in this tag. You will be notified of all new posts and topics, plus the count of unread and new posts will also appear next to the topic."
watching_first_post:
title: "Watching First Post Only"
description: "You will only be notified of the first post in each new topic in this tag."
tracking:
title: "Tracking"
description: "You will automatically track all new topics in this tag. A count of unread and new posts will appear next to the topic."

View file

@ -109,6 +109,20 @@ describe EmailController do
expect(CategoryUser.find_by(id: cu.id)).to eq(nil)
end
it 'can unwatch first post from category' do
p = Fabricate(:post)
key = UnsubscribeKey.create_key_for(p.user, p)
cu = CategoryUser.create!(user_id: p.user.id,
category_id: p.topic.category_id,
notification_level: CategoryUser.notification_levels[:watching_first_post])
post :perform_unsubscribe, key: key, unwatch_category: "1"
expect(response.status).to eq(302)
expect(CategoryUser.find_by(id: cu.id)).to eq(nil)
end
end
context '.unsubscribe' do
@ -197,6 +211,25 @@ describe EmailController do
expect(response.body).not_to include("unwatch_category")
end
it 'correctly handles watched first post categories' do
post = Fabricate(:post)
user = post.user
cu = CategoryUser.create!(user_id: user.id,
category_id: post.topic.category_id,
notification_level: CategoryUser.notification_levels[:watching_first_post])
key = UnsubscribeKey.create_key_for(user, post)
get :unsubscribe, key: key
expect(response.body).to include("unwatch_category")
cu.destroy!
get :unsubscribe, key: key
expect(response.body).not_to include("unwatch_category")
end
end