FEATURE: notification_level on a per-group basis

This commit is contained in:
Régis Hanol 2015-12-14 23:17:09 +01:00
parent d0bbf5c9a6
commit 15c229195f
17 changed files with 137 additions and 30 deletions

View File

@ -0,0 +1,11 @@
import NotificationsButton from 'discourse/components/notifications-button';
export default NotificationsButton.extend({
classNames: ['notification-options', 'group-notification-menu'],
notificationLevel: Em.computed.alias('group.notification_level'),
i18nPrefix: 'groups.notifications',
clicked(id) {
this.get('group').setNotification(id);
}
});

View File

@ -133,7 +133,15 @@ const Group = Discourse.Model.extend({
return Em.Object.create(p); return Em.Object.create(p);
}); });
}); });
} },
setNotification(notification_level) {
this.set("notification_level", notification_level);
return Discourse.ajax(`/groups/${this.get("name")}/notifications`, {
data: { notification_level },
type: "POST"
});
},
}); });
Group.reopenClass({ Group.reopenClass({

View File

@ -1,13 +1,25 @@
import Group from 'discourse/models/group';
import createPMRoute from "discourse/routes/build-user-topic-list-route"; import createPMRoute from "discourse/routes/build-user-topic-list-route";
export default createPMRoute('groups', 'private-messages-groups').extend({ export default createPMRoute('groups', 'private-messages-groups').extend({
model(params) { model(params) {
return this.store.findFiltered("topicList", { filter: "topics/private-messages-group/" + this.modelFor("user").get("username_lower") + "/" + params.name }); const username = this.modelFor("user").get("username_lower");
return this.store.findFiltered("topicList", {
filter: `topics/private-messages-group/${username}/${params.name}`
});
}, },
setupController(controller,model) { afterModel(model) {
const groupName = _.last(model.get("filter").split('/'));
Group.findAll().then(groups => {
const group = _.first(groups.filterBy("name", groupName));
this.controllerFor("user-topics-list").set("group", group)
});
},
setupController(controller, model) {
this._super.apply(this, arguments); this._super.apply(this, arguments);
const filter = _.last(model.get("filter").split('/')); const group = _.last(model.get("filter").split('/'));
this.controllerFor("user").set("groupFilter", filter); this.controllerFor("user").set("groupFilter", group);
} }
}); });

View File

@ -1,8 +1,11 @@
{{#if showNewPM}} <div class="clearfix">
<div class="clearfix"> {{#if group}}
<a class='btn btn-primary pull-right new-private-message' {{action "composePrivateMessage"}}>{{fa-icon "envelope"}}{{i18n 'user.new_private_message'}}</a> {{group-notifications-button group=group}}
</div> {{/if}}
{{/if}} {{#if showNewPM}}
{{d-button class="btn-primary pull-right new-private-message" action="composePrivateMessage" icon="envelope" label="user.new_private_message"}}
{{/if}}
</div>
{{basic-topic-list topicList=model {{basic-topic-list topicList=model
hideCategory=hideCategory hideCategory=hideCategory

View File

@ -630,6 +630,10 @@
clear: both; clear: both;
margin-bottom: 10px; margin-bottom: 10px;
} }
.group-notification-menu .dropdown-menu {
top: 30px;
bottom: auto;
}
} }
.paginated-topics-list { .paginated-topics-list {

View File

@ -1,5 +1,7 @@
class GroupsController < ApplicationController class GroupsController < ApplicationController
before_filter :ensure_logged_in, only: [:set_notifications]
def show def show
render_serialized(find_group(:id), BasicGroupSerializer) render_serialized(find_group(:id), BasicGroupSerializer)
end end
@ -123,6 +125,17 @@ class GroupsController < ApplicationController
end end
def set_notifications
group = find_group(:id)
notification_level = params.require(:notification_level)
GroupUser.where(group_id: group.id)
.where(user_id: current_user.id)
.update_all(notification_level: notification_level)
render json: success_json
end
private private
def find_group(param_name) def find_group(param_name)

View File

@ -19,9 +19,9 @@ class Topic < ActiveRecord::Base
def_delegator :featured_users, :choose, :feature_topic_users def_delegator :featured_users, :choose, :feature_topic_users
def_delegator :notifier, :watch!, :notify_watch! def_delegator :notifier, :watch!, :notify_watch!
def_delegator :notifier, :tracking!, :notify_tracking! def_delegator :notifier, :track!, :notify_tracking!
def_delegator :notifier, :regular!, :notify_regular! def_delegator :notifier, :regular!, :notify_regular!
def_delegator :notifier, :muted!, :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

View File

@ -3,10 +3,10 @@ class TopicNotifier
@topic = topic @topic = topic
end end
{ :watch! => :watching, { :watch! => :watching,
:tracking! => :tracking, :track! => :tracking,
:regular! => :regular, :regular! => :regular,
:muted! => :muted }.each_pair do |method_name, level| :mute! => :muted }.each_pair do |method_name, level|
define_method method_name do |user_id| define_method method_name do |user_id|
change_level user_id, level change_level user_id, level

View File

@ -103,7 +103,7 @@ class TopicUser < ActiveRecord::Base
if rows == 0 if rows == 0
now = DateTime.now now = DateTime.now
auto_track_after = User.select(:auto_track_topics_after_msecs).find_by(id: user_id).auto_track_topics_after_msecs auto_track_after = User.select(:auto_track_topics_after_msecs).find_by(id: user_id).try(:auto_track_topics_after_msecs)
auto_track_after ||= SiteSetting.default_other_auto_track_topics_after_msecs 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) if auto_track_after >= 0 && auto_track_after <= (attrs[:total_msecs_viewed].to_i || 0)

View File

@ -10,9 +10,20 @@ class BasicGroupSerializer < ApplicationSerializer
:primary_group, :primary_group,
:title, :title,
:grant_trust_level, :grant_trust_level,
:incoming_email :incoming_email,
:notification_level
def include_incoming_email? def include_incoming_email?
scope.is_staff? scope.is_staff?
end end
def notification_level
# TODO: fix this N+1
GroupUser.where(group_id: object.id, user_id: scope.user.id).first.try(:notification_level)
end
def include_notification_level?
scope.authenticated?
end
end end

View File

@ -64,6 +64,7 @@ class ListableTopicSerializer < BasicTopicSerializer
def notification_level def notification_level
object.user_data.notification_level object.user_data.notification_level
end end
def include_notification_level? def include_notification_level?
object.user_data.present? object.user_data.present?
end end

View File

@ -15,22 +15,27 @@ class PostAlerter
end end
def after_save_post(post, new_record = false) def after_save_post(post, new_record = false)
reply_to_user = post.reply_notification_target
notified = [post.user].compact notified = [post.user].compact
if new_record && post.topic.private_message? if new_record && post.topic.private_message?
# If it's a private message, notify the topic_allowed_users # If it's a private message, notify the topic_allowed_users
allowed_users(post).each do |user| allowed_users(post).each do |user|
if TopicUser.get(post.topic, user).try(:notification_level) == TopicUser.notification_levels[:tracking] case TopicUser.get(post.topic, user).try(:notification_level)
when TopicUser.notification_levels[:tracking]
next unless post.reply_to_post_number || post.reply_to_post.try(:user_id) == user.id next unless post.reply_to_post_number || post.reply_to_post.try(:user_id) == user.id
when TopicUser.notification_levels[:regular]
next unless post.reply_to_post.try(:user_id) == user.id
when TopicUser.notification_levels[:muted]
notified += [user]
next
end end
create_notification(user, Notification.types[:private_message], post) create_notification(user, Notification.types[:private_message], post)
notified += [user] notified += [user]
end end
end end
reply_to_user = post.reply_notification_target
if new_record && reply_to_user && post.post_type == Post.types[:regular] if new_record && reply_to_user && post.post_type == Post.types[:regular]
notify_users(reply_to_user, :replied, post) notify_users(reply_to_user, :replied, post)
end end
@ -133,6 +138,11 @@ class PostAlerter
# skip if muted on the topic # skip if muted on the topic
return if TopicUser.get(post.topic, user).try(:notification_level) == TopicUser.notification_levels[:muted] return if TopicUser.get(post.topic, user).try(:notification_level) == TopicUser.notification_levels[:muted]
# skip if muted on the group
if group = opts[:group]
return if GroupUser.find_by(group_id: opts[:group_id], user_id: user.id).try(:notification_level) == TopicUser.notification_levels[:muted]
end
# Don't notify the same user about the same notification on the same post # Don't notify the same user about the same notification on the same post
existing_notification = user.notifications existing_notification = user.notifications
.order("notifications.id desc") .order("notifications.id desc")

View File

@ -355,6 +355,19 @@ en:
trust_levels: trust_levels:
title: "Trust level automatically granted to members when they're added:" title: "Trust level automatically granted to members when they're added:"
none: "None" none: "None"
notifications:
watching:
title: "Watching"
description: "You will be notified of every new post in every message, and a count of new replies will be shown."
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."
regular:
title: "Normal"
description: "You will be notified if someone mentions your @name or replies to you."
muted:
title: "Muted"
description: "You will never be notified of anything about new topics in this group."
user_action_groups: user_action_groups:
"1": "Likes Given" "1": "Likes Given"

View File

@ -351,6 +351,7 @@ Discourse::Application.routes.draw do
member do member do
put "members" => "groups#add_members" put "members" => "groups#add_members"
delete "members" => "groups#remove_member" delete "members" => "groups#remove_member"
post "notifications" => "groups#set_notifications"
end end
end end

View File

@ -0,0 +1,6 @@
class AddNotificationLevelToGroupUsers < ActiveRecord::Migration
def change
# defaults to TopicUser.notification_levels[:watching]
add_column :group_users, :notification_level, :integer, default: 3, null: false
end
end

View File

@ -64,15 +64,28 @@ class TopicCreator
topic.notifier.watch_topic!(topic.user_id) topic.notifier.watch_topic!(topic.user_id)
end end
user_ids = topic.topic_allowed_users(true).pluck(:user_id) topic.topic_allowed_users(true).each do |tau|
user_ids += topic.topic_allowed_groups(true).map { |t| t.group.users.pluck(:id) }.flatten next if tau.user_id == -1 || tau.user_id == topic.user_id
topic.notifier.watch!(tau.user_id)
user_ids.uniq.reject{ |id| id == topic.user_id }.each do |user_id|
topic.notifier.watch_topic!(user_id, nil) unless user_id == -1
end end
CategoryUser.auto_watch_new_topic(topic) topic.topic_allowed_groups(true).each do |tag|
CategoryUser.auto_track_new_topic(topic) tag.group.group_users.each do |gu|
next if gu.user_id == -1 || gu.user_id == topic.user_id
action = case gu.notification_level
when TopicUser.notification_levels[:tracking] then "track!"
when TopicUser.notification_levels[:regular] then "regular!"
when TopicUser.notification_levels[:muted] then "mute!"
else "watch!"
end
topic.notifier.send(action, gu.user_id)
end
end
unless topic.private_message?
CategoryUser.auto_watch_new_topic(topic)
CategoryUser.auto_track_new_topic(topic)
end
end end
def setup_topic_params def setup_topic_params

View File

@ -31,7 +31,8 @@ describe Admin::GroupsController do
"title"=>nil, "title"=>nil,
"primary_group"=>false, "primary_group"=>false,
"grant_trust_level"=>nil, "grant_trust_level"=>nil,
"incoming_email"=>nil "incoming_email"=>nil,
"notification_level"=>3,
}]) }])
end end