mirror of
https://github.com/discourse/discourse.git
synced 2025-03-10 00:35:44 +08:00
FEATURE: allow users to archive messages
Messages are now in 3 buckets - Inbox for all new messages - Sent for all sent messages - Archive for all messages you are done with You can select messages from your Inbox or Sent and move them to your Archive, you can move messages out of your Archive similarly Similar concept applied to group messages, except that archiving and unarchiving will apply to all group members
This commit is contained in:
parent
e03861da7e
commit
03ea0bfe22
@ -1,4 +1,5 @@
|
|||||||
export default Ember.Component.extend({
|
export default Ember.Component.extend({
|
||||||
|
loadingMore: Ember.computed.alias('topicList.loadingMore'),
|
||||||
loading: Ember.computed.not('loaded'),
|
loading: Ember.computed.not('loaded'),
|
||||||
|
|
||||||
loaded: function() {
|
loaded: function() {
|
||||||
|
@ -1,25 +1,62 @@
|
|||||||
import computed from 'ember-addons/ember-computed-decorators';
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
import Topic from 'discourse/models/topic';
|
||||||
|
|
||||||
export default Ember.Controller.extend({
|
export default Ember.Controller.extend({
|
||||||
|
|
||||||
|
needs: ["user-topics-list"],
|
||||||
pmView: false,
|
pmView: false,
|
||||||
|
|
||||||
privateMessagesActive: Em.computed.equal('pmView', 'index'),
|
|
||||||
privateMessagesMineActive: Em.computed.equal('pmView', 'mine'),
|
|
||||||
privateMessagesUnreadActive: Em.computed.equal('pmView', 'unread'),
|
|
||||||
isGroup: Em.computed.equal('pmView', 'groups'),
|
isGroup: Em.computed.equal('pmView', 'groups'),
|
||||||
|
|
||||||
|
selected: Em.computed.alias('controllers.user-topics-list.selected'),
|
||||||
|
bulkSelectEnabled: Em.computed.alias('controllers.user-topics-list.bulkSelectEnabled'),
|
||||||
|
|
||||||
@computed('model.groups', 'groupFilter', 'pmView')
|
@computed('selected.@each', 'bulkSelectEnabled')
|
||||||
groupPMStats(groups, filter, pmView) {
|
hasSelection(selected, bulkSelectEnabled){
|
||||||
if (groups) {
|
return bulkSelectEnabled && selected && selected.length > 0;
|
||||||
return groups.filter(group => group.has_messages)
|
},
|
||||||
.map(g => {
|
|
||||||
return {
|
@computed('hasSelection', 'pmView', 'archive')
|
||||||
name: g.name,
|
canMoveToInbox(hasSelection, pmView, archive){
|
||||||
active: (g.name === filter && pmView === "groups")
|
return hasSelection && (pmView === "archive" || archive);
|
||||||
};
|
},
|
||||||
});
|
|
||||||
|
@computed('hasSelection', 'pmView', 'archive')
|
||||||
|
canArchive(hasSelection, pmView, archive){
|
||||||
|
return hasSelection && pmView !== "archive" && !archive;
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
bulkOperation(operation) {
|
||||||
|
const selected = this.get('selected');
|
||||||
|
var params = {type: operation};
|
||||||
|
if (this.get('isGroup')) {
|
||||||
|
params.group = this.get('groupFilter');
|
||||||
|
}
|
||||||
|
|
||||||
|
Topic.bulkOperation(selected,params).then(() => {
|
||||||
|
const model = this.get('controllers.user-topics-list.model');
|
||||||
|
const topics = model.get('topics');
|
||||||
|
topics.removeObjects(selected);
|
||||||
|
selected.clear();
|
||||||
|
model.loadMore();
|
||||||
|
}, () => {
|
||||||
|
bootbox.alert(I18n.t("user.messages.failed_to_move"));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
archive() {
|
||||||
|
this.bulkOperation("archive_messages");
|
||||||
|
},
|
||||||
|
toInbox() {
|
||||||
|
this.bulkOperation("move_messages_to_inbox");
|
||||||
|
},
|
||||||
|
toggleBulkSelect(){
|
||||||
|
this.toggleProperty("bulkSelectEnabled");
|
||||||
|
},
|
||||||
|
selectAll() {
|
||||||
|
$('input.bulk-select:not(checked)').click();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -17,6 +17,6 @@ export default Ember.Controller.extend({
|
|||||||
showNewPM: function(){
|
showNewPM: function(){
|
||||||
return this.get('controllers.user.viewingSelf') &&
|
return this.get('controllers.user.viewingSelf') &&
|
||||||
Discourse.User.currentProp('can_send_private_messages');
|
Discourse.User.currentProp('can_send_private_messages');
|
||||||
}.property('controllers.user.viewingSelf'),
|
}.property('controllers.user.viewingSelf')
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
Ember.Handlebars.registerBoundHelper("capitalize", function(str) {
|
||||||
|
return str[0].toUpperCase() + str.slice(1);
|
||||||
|
});
|
@ -76,9 +76,10 @@ export default function() {
|
|||||||
this.route('deletedPosts', { path: '/deleted-posts' });
|
this.route('deletedPosts', { path: '/deleted-posts' });
|
||||||
|
|
||||||
this.resource('userPrivateMessages', { path: '/messages' }, function() {
|
this.resource('userPrivateMessages', { path: '/messages' }, function() {
|
||||||
this.route('mine');
|
this.route('sent');
|
||||||
this.route('unread');
|
this.route('archive');
|
||||||
this.route('group', { path: 'group/:name'});
|
this.route('group', { path: 'group/:name'});
|
||||||
|
this.route('groupArchive', { path: 'group/:name/archive'});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.resource('preferences', function() {
|
this.resource('preferences', function() {
|
||||||
|
@ -21,10 +21,13 @@ export default (viewName, path) => {
|
|||||||
|
|
||||||
this.controllerFor("user-topics-list").setProperties({
|
this.controllerFor("user-topics-list").setProperties({
|
||||||
hideCategory: true,
|
hideCategory: true,
|
||||||
showParticipants: true
|
showParticipants: true,
|
||||||
|
canBulkSelect: true,
|
||||||
|
selected: []
|
||||||
});
|
});
|
||||||
|
|
||||||
this.controllerFor("userPrivateMessages").set("pmView", viewName);
|
this.controllerFor("user-private-messages").set("archive", false);
|
||||||
|
this.controllerFor("user-private-messages").set("pmView", viewName);
|
||||||
this.searchService.set('contextType', 'private_messages');
|
this.searchService.set('contextType', 'private_messages');
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
import createPMRoute from "discourse/routes/build-private-messages-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute('unread', 'private-messages-unread');
|
export default createPMRoute('archive', 'private-messages-archive');
|
@ -0,0 +1,18 @@
|
|||||||
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
|
export default createPMRoute('groups', 'private-messages-groups').extend({
|
||||||
|
model(params) {
|
||||||
|
const username = this.modelFor("user").get("username_lower");
|
||||||
|
return this.store.findFiltered("topicList", {
|
||||||
|
filter: `topics/private-messages-group/${username}/${params.name}/archive`
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model) {
|
||||||
|
this._super.apply(this, arguments);
|
||||||
|
const split = model.get("filter").split('/');
|
||||||
|
const group = split[split.length-2];
|
||||||
|
this.controllerFor("user-private-messages").set("groupFilter", group);
|
||||||
|
this.controllerFor("user-private-messages").set("archive", true);
|
||||||
|
}
|
||||||
|
});
|
@ -1,4 +1,3 @@
|
|||||||
import Group from 'discourse/models/group';
|
|
||||||
import createPMRoute from "discourse/routes/build-private-messages-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute('groups', 'private-messages-groups').extend({
|
export default createPMRoute('groups', 'private-messages-groups').extend({
|
||||||
@ -9,17 +8,10 @@ export default createPMRoute('groups', 'private-messages-groups').extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
afterModel(model) {
|
|
||||||
const groupName = _.last(model.get("filter").split('/'));
|
|
||||||
Group.findAll().then(groups => {
|
|
||||||
const group = _.first(groups.filterBy("name", groupName));
|
|
||||||
this.controllerFor("user-private-messages").set("group", group);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setupController(controller, model) {
|
setupController(controller, model) {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
const group = _.last(model.get("filter").split('/'));
|
const group = _.last(model.get("filter").split('/'));
|
||||||
this.controllerFor("userPrivateMessages").set("groupFilter", group);
|
this.controllerFor("user-private-messages").set("groupFilter", group);
|
||||||
|
this.controllerFor("user-private-messages").set("archive", false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
import createPMRoute from "discourse/routes/build-private-messages-route";
|
import createPMRoute from "discourse/routes/build-private-messages-route";
|
||||||
|
|
||||||
export default createPMRoute('mine', 'private-messages-sent');
|
export default createPMRoute('sent', 'private-messages-sent');
|
@ -5,10 +5,15 @@
|
|||||||
hideCategory=hideCategory
|
hideCategory=hideCategory
|
||||||
topics=topics
|
topics=topics
|
||||||
expandExcerpts=expandExcerpts
|
expandExcerpts=expandExcerpts
|
||||||
|
bulkSelectEnabled=bulkSelectEnabled
|
||||||
|
canBulkSelect=canBulkSelect
|
||||||
|
selected=selected
|
||||||
}}
|
}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
{{#unless loadingMore}}
|
||||||
<div class='alert alert-info'>
|
<div class='alert alert-info'>
|
||||||
{{i18n 'choose_topic.none_found'}}
|
{{i18n 'choose_topic.none_found'}}
|
||||||
</div>
|
</div>
|
||||||
|
{{/unless}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/conditional-loading-spinner}}
|
{{/conditional-loading-spinner}}
|
||||||
|
@ -2,4 +2,7 @@
|
|||||||
{{basic-topic-list topicList=model
|
{{basic-topic-list topicList=model
|
||||||
hideCategory=hideCategory
|
hideCategory=hideCategory
|
||||||
showParticipants=showParticipants
|
showParticipants=showParticipants
|
||||||
|
canBulkSelect=canBulkSelect
|
||||||
|
bulkSelectEnabled=bulkSelectEnabled
|
||||||
|
selected=selected
|
||||||
postsAction="showTopicEntrance"}}
|
postsAction="showTopicEntrance"}}
|
||||||
|
@ -1,30 +1,34 @@
|
|||||||
<section class='user-navigation'>
|
<section class='user-navigation'>
|
||||||
<ul class='action-list nav-stacked'>
|
<ul class='action-list nav-stacked'>
|
||||||
<li {{bind-attr class=":noGlyph privateMessagesActive:active"}}>
|
<li class="noGlyph">
|
||||||
{{#link-to 'userPrivateMessages.index' model}}
|
{{#link-to 'userPrivateMessages.index' model}}
|
||||||
{{i18n 'user.messages.all'}}
|
{{i18n 'user.messages.inbox'}}
|
||||||
{{#if model.hasPMs}}<span class='count'>({{model.private_messages_stats.all}})</span>{{/if}}
|
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
<li {{bind-attr class=":noGlyph privateMessagesMineActive:active"}}>
|
<li class="noGlyph">
|
||||||
{{#link-to 'userPrivateMessages.mine' model}}
|
{{#link-to 'userPrivateMessages.sent' model}}
|
||||||
{{i18n 'user.messages.mine'}}
|
{{i18n 'user.messages.sent'}}
|
||||||
{{#if model.hasStartedPMs}}<span class='count'>({{model.private_messages_stats.mine}})</span>{{/if}}
|
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
<li {{bind-attr class=":noGlyph privateMessagesUnreadActive:active"}}>
|
<li class="noGlyph">
|
||||||
{{#link-to 'userPrivateMessages.unread' model}}
|
{{#link-to 'userPrivateMessages.archive' model}}
|
||||||
{{i18n 'user.messages.unread'}}
|
{{i18n 'user.messages.archive'}}
|
||||||
{{#if model.hasUnreadPMs}}<span class='badge-notification unread-private-messages'>{{model.private_messages_stats.unread}}</span>{{/if}}
|
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
{{#each groupPMStats as |group|}}
|
{{#each model.groups as |group|}}
|
||||||
<li class="{{if group.active "active"}}">
|
{{#if group.has_messages}}
|
||||||
|
<li>
|
||||||
{{#link-to 'userPrivateMessages.group' group.name}}
|
{{#link-to 'userPrivateMessages.group' group.name}}
|
||||||
<i class='glyph fa fa-group'></i>
|
<i class='glyph fa fa-group'></i>
|
||||||
{{group.name}}
|
{{capitalize group.name}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
{{#link-to 'userPrivateMessages.groupArchive' group.name}}
|
||||||
|
{{i18n 'user.messages.archive'}}
|
||||||
|
{{/link-to}}
|
||||||
|
</li>
|
||||||
|
{{/if}}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
@ -33,11 +37,34 @@
|
|||||||
|
|
||||||
<section class='user-right messages'>
|
<section class='user-right messages'>
|
||||||
|
|
||||||
{{#if isGroup}}
|
<div class="clearfix list-actions">
|
||||||
<div class="clearfix">
|
<button {{action "toggleBulkSelect"}} class="btn bulk-select" title="{{i18n "user.messages.bulk_select"}}">
|
||||||
{{group-notifications-button group=group}}
|
<i class="fa fa-list"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{{#if canArchive}}
|
||||||
|
<button {{action "archive"}} class="btn btn-archive">
|
||||||
|
{{i18n "user.messages.archive"}}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if canMoveToInbox}}
|
||||||
|
<button {{action "toInbox"}} class="btn btn-to-inbox">
|
||||||
|
{{i18n "user.messages.move_to_inbox"}}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
|
||||||
|
{{#if bulkSelectEnabled}}
|
||||||
|
<button {{action "selectAll"}} class="btn btn-select-all">
|
||||||
|
{{i18n "user.messages.select_all"}}
|
||||||
|
</button>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if isGroup}}
|
||||||
|
{{group-notifications-button group=group}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
</section>
|
</section>
|
||||||
|
@ -92,6 +92,7 @@
|
|||||||
//= require ./discourse/components/conditional-loading-spinner
|
//= require ./discourse/components/conditional-loading-spinner
|
||||||
//= require ./discourse/helpers/user-avatar
|
//= require ./discourse/helpers/user-avatar
|
||||||
//= require ./discourse/helpers/cold-age-class
|
//= require ./discourse/helpers/cold-age-class
|
||||||
|
//= require ./discourse/helpers/capitalize
|
||||||
//= require ./discourse/helpers/loading-spinner
|
//= require ./discourse/helpers/loading-spinner
|
||||||
//= require ./discourse/helpers/category-link
|
//= require ./discourse/helpers/category-link
|
||||||
//= require ./discourse/lib/export-result
|
//= require ./discourse/lib/export-result
|
||||||
|
@ -162,3 +162,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user-right .list-actions {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
.btn {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -102,7 +102,7 @@ class ListController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
[:topics_by, :private_messages, :private_messages_sent, :private_messages_unread, :private_messages_group].each do |action|
|
[:topics_by, :private_messages, :private_messages_sent, :private_messages_unread, :private_messages_archive, :private_messages_group, :private_messages_group_archive].each do |action|
|
||||||
define_method("#{action}") do
|
define_method("#{action}") do
|
||||||
list_opts = build_topic_list_options
|
list_opts = build_topic_list_options
|
||||||
target_user = fetch_user_from_params(include_inactive: current_user.try(:staff?))
|
target_user = fetch_user_from_params(include_inactive: current_user.try(:staff?))
|
||||||
|
@ -451,7 +451,7 @@ class TopicsController < ApplicationController
|
|||||||
|
|
||||||
operation = params.require(:operation).symbolize_keys
|
operation = params.require(:operation).symbolize_keys
|
||||||
raise ActionController::ParameterMissing.new(:operation_type) if operation[:type].blank?
|
raise ActionController::ParameterMissing.new(:operation_type) if operation[:type].blank?
|
||||||
operator = TopicsBulkAction.new(current_user, topic_ids, operation)
|
operator = TopicsBulkAction.new(current_user, topic_ids, operation, group: operation[:group])
|
||||||
changed_topic_ids = operator.perform!
|
changed_topic_ids = operator.perform!
|
||||||
render_json_dump topic_ids: changed_topic_ids
|
render_json_dump topic_ids: changed_topic_ids
|
||||||
end
|
end
|
||||||
|
@ -5,6 +5,8 @@ class Group < ActiveRecord::Base
|
|||||||
has_many :group_users, dependent: :destroy
|
has_many :group_users, dependent: :destroy
|
||||||
has_many :group_mentions, dependent: :destroy
|
has_many :group_mentions, dependent: :destroy
|
||||||
|
|
||||||
|
has_many :group_archived_messages, dependent: :destroy
|
||||||
|
|
||||||
has_many :categories, through: :category_groups
|
has_many :categories, through: :category_groups
|
||||||
has_many :users, through: :group_users
|
has_many :users, through: :group_users
|
||||||
|
|
||||||
|
4
app/models/group_archived_message.rb
Normal file
4
app/models/group_archived_message.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
class GroupArchivedMessage < ActiveRecord::Base
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :topic
|
||||||
|
end
|
@ -83,6 +83,9 @@ class Topic < ActiveRecord::Base
|
|||||||
has_many :topic_allowed_users
|
has_many :topic_allowed_users
|
||||||
has_many :topic_allowed_groups
|
has_many :topic_allowed_groups
|
||||||
|
|
||||||
|
has_many :group_archived_messages, dependent: :destroy
|
||||||
|
has_many :user_archived_messages, dependent: :destroy
|
||||||
|
|
||||||
has_many :allowed_group_users, through: :allowed_groups, source: :users
|
has_many :allowed_group_users, through: :allowed_groups, source: :users
|
||||||
has_many :allowed_groups, through: :topic_allowed_groups, source: :group
|
has_many :allowed_groups, through: :topic_allowed_groups, source: :group
|
||||||
has_many :allowed_users, through: :topic_allowed_users, source: :user
|
has_many :allowed_users, through: :topic_allowed_users, source: :user
|
||||||
|
@ -35,6 +35,8 @@ class User < ActiveRecord::Base
|
|||||||
has_many :topic_links, dependent: :destroy
|
has_many :topic_links, dependent: :destroy
|
||||||
has_many :uploads
|
has_many :uploads
|
||||||
has_many :warnings
|
has_many :warnings
|
||||||
|
has_many :user_archived_messages, dependent: :destroy
|
||||||
|
|
||||||
|
|
||||||
has_one :user_avatar, dependent: :destroy
|
has_one :user_avatar, dependent: :destroy
|
||||||
has_one :facebook_user_info, dependent: :destroy
|
has_one :facebook_user_info, dependent: :destroy
|
||||||
|
4
app/models/user_archived_message.rb
Normal file
4
app/models/user_archived_message.rb
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
class UserArchivedMessage < ActiveRecord::Base
|
||||||
|
belongs_to :user
|
||||||
|
belongs_to :topic
|
||||||
|
end
|
@ -504,9 +504,14 @@ en:
|
|||||||
|
|
||||||
messages:
|
messages:
|
||||||
all: "All"
|
all: "All"
|
||||||
mine: "Mine"
|
inbox: "Inbox"
|
||||||
unread: "Unread"
|
sent: "Sent"
|
||||||
|
archive: "Archive"
|
||||||
groups: "My Groups"
|
groups: "My Groups"
|
||||||
|
bulk_select: "Select messages"
|
||||||
|
move_to_inbox: "Move to Inbox"
|
||||||
|
failed_to_move: "Failed to move selected messages (perhaps your network is down)"
|
||||||
|
select_all: "Select All"
|
||||||
|
|
||||||
change_password:
|
change_password:
|
||||||
success: "(email sent)"
|
success: "(email sent)"
|
||||||
|
@ -279,6 +279,9 @@ Discourse::Application.routes.draw do
|
|||||||
get "users/:username/messages" => "user_actions#private_messages", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "users/:username/messages" => "user_actions#private_messages", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get "users/:username/messages/:filter" => "user_actions#private_messages", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "users/:username/messages/:filter" => "user_actions#private_messages", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get "users/:username/messages/group/:group_name" => "user_actions#private_messages", constraints: {username: USERNAME_ROUTE_FORMAT, group_name: USERNAME_ROUTE_FORMAT}
|
get "users/:username/messages/group/:group_name" => "user_actions#private_messages", constraints: {username: USERNAME_ROUTE_FORMAT, group_name: USERNAME_ROUTE_FORMAT}
|
||||||
|
|
||||||
|
get "users/:username/messages/group/:group_name/archive" => "user_actions#private_messages", constraints: {username: USERNAME_ROUTE_FORMAT, group_name: USERNAME_ROUTE_FORMAT}
|
||||||
|
|
||||||
get "users/:username.json" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}, defaults: {format: :json}
|
get "users/:username.json" => "users#show", constraints: {username: USERNAME_ROUTE_FORMAT}, defaults: {format: :json}
|
||||||
get "users/:username" => "users#show", as: 'user', constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "users/:username" => "users#show", as: 'user', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
put "users/:username" => "users#update", constraints: {username: USERNAME_ROUTE_FORMAT}
|
put "users/:username" => "users#update", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
@ -468,12 +471,18 @@ Discourse::Application.routes.draw do
|
|||||||
get "topics/created-by/:username" => "list#topics_by", as: "topics_by", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "topics/created-by/:username" => "list#topics_by", as: "topics_by", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get "topics/private-messages/:username" => "list#private_messages", as: "topics_private_messages", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "topics/private-messages/:username" => "list#private_messages", as: "topics_private_messages", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get "topics/private-messages-sent/:username" => "list#private_messages_sent", as: "topics_private_messages_sent", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "topics/private-messages-sent/:username" => "list#private_messages_sent", as: "topics_private_messages_sent", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
|
get "topics/private-messages-archive/:username" => "list#private_messages_archive", as: "topics_private_messages_archive", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get "topics/private-messages-unread/:username" => "list#private_messages_unread", as: "topics_private_messages_unread", constraints: {username: USERNAME_ROUTE_FORMAT}
|
get "topics/private-messages-unread/:username" => "list#private_messages_unread", as: "topics_private_messages_unread", constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get "topics/private-messages-group/:username/:group_name.json" => "list#private_messages_group", as: "topics_private_messages_group", constraints: {
|
get "topics/private-messages-group/:username/:group_name.json" => "list#private_messages_group", as: "topics_private_messages_group", constraints: {
|
||||||
username: USERNAME_ROUTE_FORMAT,
|
username: USERNAME_ROUTE_FORMAT,
|
||||||
group_name: USERNAME_ROUTE_FORMAT
|
group_name: USERNAME_ROUTE_FORMAT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get "topics/private-messages-group/:username/:group_name/archive.json" => "list#private_messages_group_archive", as: "topics_private_messages_group_archive", constraints: {
|
||||||
|
username: USERNAME_ROUTE_FORMAT,
|
||||||
|
group_name: USERNAME_ROUTE_FORMAT
|
||||||
|
}
|
||||||
|
|
||||||
get 'embed/comments' => 'embed#comments'
|
get 'embed/comments' => 'embed#comments'
|
||||||
get 'embed/count' => 'embed#count'
|
get 'embed/count' => 'embed#count'
|
||||||
get 'embed/info' => 'embed#info'
|
get 'embed/info' => 'embed#info'
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
class AddUserArchivedMessagesGroupArchivedMessages < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
create_table :user_archived_messages do |t|
|
||||||
|
t.integer :user_id, null: false
|
||||||
|
t.integer :topic_id, null: false
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :user_archived_messages, [:user_id, :topic_id], unique: true
|
||||||
|
|
||||||
|
create_table :group_archived_messages do |t|
|
||||||
|
t.integer :group_id, null: false
|
||||||
|
t.integer :topic_id, null: false
|
||||||
|
t.timestamps
|
||||||
|
end
|
||||||
|
|
||||||
|
add_index :group_archived_messages, [:group_id, :topic_id], unique: true
|
||||||
|
end
|
||||||
|
end
|
@ -134,6 +134,7 @@ class PostCreator
|
|||||||
create_embedded_topic
|
create_embedded_topic
|
||||||
|
|
||||||
ensure_in_allowed_users if guardian.is_staff?
|
ensure_in_allowed_users if guardian.is_staff?
|
||||||
|
unarchive_message
|
||||||
@post.advance_draft_sequence
|
@post.advance_draft_sequence
|
||||||
@post.save_reply_relationships
|
@post.save_reply_relationships
|
||||||
end
|
end
|
||||||
@ -268,6 +269,13 @@ class PostCreator
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unarchive_message
|
||||||
|
return unless @topic.private_message? && @topic.id
|
||||||
|
|
||||||
|
UserArchivedMessage.where(topic_id: @topic.id).destroy_all
|
||||||
|
GroupArchivedMessage.where(topic_id: @topic.id).destroy_all
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def create_topic
|
def create_topic
|
||||||
|
@ -117,14 +117,35 @@ class TopicQuery
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def not_archived(list, user)
|
||||||
|
list.joins("LEFT JOIN user_archived_messages um
|
||||||
|
ON um.user_id = #{user.id.to_i} AND um.topic_id = topics.id")
|
||||||
|
.where('um.user_id IS NULL')
|
||||||
|
end
|
||||||
|
|
||||||
def list_private_messages(user)
|
def list_private_messages(user)
|
||||||
list = private_messages_for(user, :user)
|
list = private_messages_for(user, :user)
|
||||||
|
|
||||||
|
list = not_archived(list, user)
|
||||||
|
.where('NOT (topics.participant_count = 1 AND topics.user_id = ?)', user.id)
|
||||||
|
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_archive(user)
|
||||||
|
list = private_messages_for(user, :user)
|
||||||
|
list = list.joins(:user_archived_messages).where('user_archived_messages.user_id = ?', user.id)
|
||||||
create_list(:private_messages, {}, list)
|
create_list(:private_messages, {}, list)
|
||||||
end
|
end
|
||||||
|
|
||||||
def list_private_messages_sent(user)
|
def list_private_messages_sent(user)
|
||||||
list = private_messages_for(user, :user)
|
list = private_messages_for(user, :user)
|
||||||
list = list.where(user_id: user.id)
|
list = list.where('EXISTS (
|
||||||
|
SELECT 1 FROM posts
|
||||||
|
WHERE posts.topic_id = topics.id AND
|
||||||
|
posts.user_id = ?
|
||||||
|
)', user.id)
|
||||||
|
list = not_archived(list, user)
|
||||||
create_list(:private_messages, {}, list)
|
create_list(:private_messages, {}, list)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -136,6 +157,18 @@ class TopicQuery
|
|||||||
|
|
||||||
def list_private_messages_group(user)
|
def list_private_messages_group(user)
|
||||||
list = private_messages_for(user, :group)
|
list = private_messages_for(user, :group)
|
||||||
|
group_id = Group.where('name ilike ?', @options[:group_name]).pluck(:id).first
|
||||||
|
list = list.joins("LEFT JOIN group_archived_messages gm ON gm.topic_id = topics.id AND
|
||||||
|
gm.group_id = #{group_id.to_i}")
|
||||||
|
list = list.where("gm.id IS NULL")
|
||||||
|
create_list(:private_messages, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_private_messages_group_archive(user)
|
||||||
|
list = private_messages_for(user, :group)
|
||||||
|
group_id = Group.where('name ilike ?', @options[:group_name]).pluck(:id).first
|
||||||
|
list = list.joins("JOIN group_archived_messages gm ON gm.topic_id = topics.id AND
|
||||||
|
gm.group_id = #{group_id.to_i}")
|
||||||
create_list(:private_messages, {}, list)
|
create_list(:private_messages, {}, list)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -195,7 +228,9 @@ class TopicQuery
|
|||||||
topics = yield(topics) if block_given?
|
topics = yield(topics) if block_given?
|
||||||
|
|
||||||
options = options.merge(@options)
|
options = options.merge(@options)
|
||||||
if ["activity","default"].include?(options[:order] || "activity") && !options[:unordered]
|
if ["activity","default"].include?(options[:order] || "activity") &&
|
||||||
|
!options[:unordered] &&
|
||||||
|
filter != :private_messages
|
||||||
topics = prioritize_pinned_topics(topics, options)
|
topics = prioritize_pinned_topics(topics, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
class TopicsBulkAction
|
class TopicsBulkAction
|
||||||
|
|
||||||
def initialize(user, topic_ids, operation)
|
def initialize(user, topic_ids, operation, options={})
|
||||||
@user = user
|
@user = user
|
||||||
@topic_ids = topic_ids
|
@topic_ids = topic_ids
|
||||||
@operation = operation
|
@operation = operation
|
||||||
@changed_ids = []
|
@changed_ids = []
|
||||||
|
@options = options
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.operations
|
def self.operations
|
||||||
@operations ||= %w(change_category close archive change_notification_level reset_read dismiss_posts delete unlist)
|
@operations ||= %w(change_category close archive change_notification_level
|
||||||
|
reset_read dismiss_posts delete unlist archive_messages
|
||||||
|
move_messages_to_inbox)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.register_operation(name, &block)
|
def self.register_operation(name, &block)
|
||||||
@ -24,6 +27,43 @@ class TopicsBulkAction
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
|
def find_group
|
||||||
|
return unless @options[:group]
|
||||||
|
|
||||||
|
group = Group.where('name ilike ?', @options[:group]).first
|
||||||
|
raise Discourse::InvalidParameters.new(:group) unless group
|
||||||
|
unless group.group_users.where(user_id: @user.id).exists?
|
||||||
|
raise Discourse::InvalidParameters.new(:group)
|
||||||
|
end
|
||||||
|
group
|
||||||
|
end
|
||||||
|
|
||||||
|
def move_messages_to_inbox
|
||||||
|
group = find_group
|
||||||
|
topics.each do |t|
|
||||||
|
if guardian.can_see?(t) && t.private_message?
|
||||||
|
if group
|
||||||
|
GroupArchivedMessage.where(group_id: group.id, topic_id: t.id).destroy_all
|
||||||
|
else
|
||||||
|
UserArchivedMessage.where(user_id: @user.id, topic_id: t.id).destroy_all
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def archive_messages
|
||||||
|
group = find_group
|
||||||
|
topics.each do |t|
|
||||||
|
if guardian.can_see?(t) && t.private_message?
|
||||||
|
if group
|
||||||
|
GroupArchivedMessage.create!(group_id: group.id, topic_id: t.id)
|
||||||
|
else
|
||||||
|
UserArchivedMessage.create!(user_id: @user.id, topic_id: t.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def dismiss_posts
|
def dismiss_posts
|
||||||
sql = "
|
sql = "
|
||||||
UPDATE topic_users tu
|
UPDATE topic_users tu
|
||||||
|
@ -478,6 +478,9 @@ describe PostCreator do
|
|||||||
expect(unrelated.notifications.count).to eq(0)
|
expect(unrelated.notifications.count).to eq(0)
|
||||||
expect(post.topic.subtype).to eq(TopicSubtype.user_to_user)
|
expect(post.topic.subtype).to eq(TopicSubtype.user_to_user)
|
||||||
|
|
||||||
|
# archive this message and ensure archive is cleared for all users on reply
|
||||||
|
UserArchivedMessage.create(user_id: target_user2.id, topic_id: post.topic_id)
|
||||||
|
|
||||||
# if an admin replies they should be added to the allowed user list
|
# if an admin replies they should be added to the allowed user list
|
||||||
admin = Fabricate(:admin)
|
admin = Fabricate(:admin)
|
||||||
PostCreator.create(admin, raw: 'hi there welcome topic, I am a mod',
|
PostCreator.create(admin, raw: 'hi there welcome topic, I am a mod',
|
||||||
@ -485,6 +488,8 @@ describe PostCreator do
|
|||||||
|
|
||||||
post.topic.reload
|
post.topic.reload
|
||||||
expect(post.topic.topic_allowed_users.where(user_id: admin.id).count).to eq(1)
|
expect(post.topic.topic_allowed_users.where(user_id: admin.id).count).to eq(1)
|
||||||
|
|
||||||
|
expect(UserArchivedMessage.where(user_id: target_user2.id, topic_id: post.topic_id).count).to eq(0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1148,7 +1148,7 @@ describe TopicsController do
|
|||||||
|
|
||||||
it "delegates work to `TopicsBulkAction`" do
|
it "delegates work to `TopicsBulkAction`" do
|
||||||
topics_bulk_action = mock
|
topics_bulk_action = mock
|
||||||
TopicsBulkAction.expects(:new).with(user, topic_ids, operation).returns(topics_bulk_action)
|
TopicsBulkAction.expects(:new).with(user, topic_ids, operation, group: nil).returns(topics_bulk_action)
|
||||||
topics_bulk_action.expects(:perform!)
|
topics_bulk_action.expects(:perform!)
|
||||||
xhr :put, :bulk, topic_ids: topic_ids, operation: operation
|
xhr :put, :bulk, topic_ids: topic_ids, operation: operation
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user