FEATURE: Add ability to claim topics on flagged topics page

This commit is contained in:
Robin Ward 2017-09-07 12:23:12 -04:00
parent aa885dcfac
commit 856c5a5435
10 changed files with 134 additions and 38 deletions

View File

@ -0,0 +1,12 @@
{{#unless canAct}}
{{#if flaggedPost.topic.assigned_to_user}}
<div class='cant-act-flagged-post'>
<div class='cant-act-message'>
{{i18n "discourse_assign.cant_act"}}
</div>
<div class='assigned-to'>
{{assigned-to user=flaggedPost.topic.assigned_to_user}}
</div>
</div>
{{/if}}
{{/unless}}

View File

@ -1,25 +1,50 @@
import { withPluginApi } from 'discourse/lib/plugin-api'; import { withPluginApi } from 'discourse/lib/plugin-api';
import { observes } from 'ember-addons/ember-computed-decorators'; import { default as computed, observes } from 'ember-addons/ember-computed-decorators';
// should this be in API ? // should this be in API ?
import Topic from 'discourse/models/topic';
import TopicFooterDropdown from 'discourse/components/topic-footer-mobile-dropdown';
import showModal from 'discourse/lib/show-modal'; import showModal from 'discourse/lib/show-modal';
import { iconNode } from 'discourse-common/lib/icon-library'; import { iconNode } from 'discourse-common/lib/icon-library';
import { h } from 'virtual-dom'; import { h } from 'virtual-dom';
function initialize(api, container) { function initialize(api) {
const siteSettings = container.lookup('site-settings:main'); // You can't act on flags claimed by another user
const currentUser = container.lookup('current-user:main'); api.modifyClass('component:flagged-post', {
@computed('flaggedPost.topic.assigned_to_user_id', 'filter')
canAct(assignedToUserId, filter) {
if (assignedToUserId && this.currentUser.id !== assignedToUserId) {
return false;
}
return this._super(filter);
},
didInsertElement() {
this._super();
this.messageBus.subscribe("/staff/topic-assignment", data => {
let flaggedPost = this.get('flaggedPost');
if (data.topic_id === flaggedPost.get('topic.id')) {
flaggedPost.set('topic.assigned_to_user_id',
data.type === 'assigned' ? data.assigned_to.id : null
);
flaggedPost.set('topic.assigned_to_user', data.assigned_to);
}
});
},
willDestroyElement() {
this._super();
this.messageBus.unsubscribe("/staff/topic-assignment");
}
}, { ignoreMissing: true });
// doing this mess while we come up with a better API // doing this mess while we come up with a better API
TopicFooterDropdown.reopen({ api.modifyClass('component:topic-footer-mobile-dropdown', {
_createContent() { _createContent() {
this._super(); this._super();
if (!this.get('currentUser.staff') || !siteSettings.assign_enabled) { if (!this.get('currentUser.staff') || !this.siteSettings.assign_enabled) {
return; return;
} }
const content = this.get('content'); const content = this.get('content');
@ -50,16 +75,20 @@ function initialize(api, container) {
} }
}); });
Topic.reopen({ api.modifyClass('model:topic', {
assignedToUserPath: function(){ @computed('assigned_to_user')
return siteSettings.assigns_user_url_path.replace("{username}", this.get("assigned_to_user.username")); assignedToUserPath(assignedToUser) {
}.property('assigned_to_user') return this.siteSettings.assigns_user_url_path.replace(
"{username}",
Ember.get(assignedToUser, 'username')
);
}
}); });
api.addPostSmallActionIcon('assigned','user-plus'); api.addPostSmallActionIcon('assigned','user-plus');
api.addPostSmallActionIcon('unassigned','user-times'); api.addPostSmallActionIcon('unassigned','user-times');
api.addPostTransformCallback((transformed) => { api.addPostTransformCallback(transformed => {
if (transformed.actionCode === "assigned" || transformed.actionCode === "unassigned") { if (transformed.actionCode === "assigned" || transformed.actionCode === "unassigned") {
transformed.isSmallAction = true; transformed.isSmallAction = true;
transformed.canEdit = false; transformed.canEdit = false;
@ -77,14 +106,45 @@ function initialize(api, container) {
}); });
if (currentUser && currentUser.get("staff") && siteSettings.assign_enabled) { api.addUserMenuGlyph(widget => {
api.addUserMenuGlyph({ return undefined;
if (widget.currentUser &&
widget.currentUser.get('staff') &&
widget.siteSettings.assign_enabled) {
return {
label: 'discourse_assign.assigned', label: 'discourse_assign.assigned',
className: 'assigned', className: 'assigned',
icon: 'user-plus', icon: 'user-plus',
href: `${currentUser.get("path")}/activity/assigned` href: `${widget.currentUser.get("path")}/activity/assigned`,
}); };
} }
});
api.createWidget('assigned-to', {
html(attrs) {
let { assignedToUser, href } = attrs;
return h('p.assigned-to', [
iconNode('user-plus'),
h('span.assign-text', I18n.t('discourse_assign.assigned_to')),
h('a', { attributes: { class: 'assigned-to-username', href } }, assignedToUser.username)
]);
}
});
api.createWidget('assigned-to', {
html(attrs) {
let { assignedToUser, href } = attrs;
return h('p.assigned-to', [
iconNode('user-plus'),
h('span.assign-text', I18n.t('discourse_assign.assigned_to')),
h('a', { attributes: { class: 'assigned-to-username', href } }, assignedToUser.username)
]);
}
});
api.createWidget('assigned-to', { api.createWidget('assigned-to', {
html(attrs) { html(attrs) {
@ -113,19 +173,12 @@ function initialize(api, container) {
} }
}); });
api.replaceIcon('notification.discourse_assign.assign_notification', 'user-plus');
}; };
export default { export default {
name: 'extend-for-assign', name: 'extend-for-assign',
initialize(container) { initialize(container) {
withPluginApi('0.8.5', api => { withPluginApi('0.8.11', api => initialize(api, container));
initialize(api, container);
});
// Fix icons in new versions of discourse
withPluginApi('0.8.10', api => {
api.replaceIcon('notification.discourse_assign.assign_notification', 'user-plus');
});
} }
}; };

View File

@ -0,0 +1,3 @@
export default Ember.Component.extend({
classNames: ['assigned-to-user']
});

View File

@ -22,4 +22,3 @@ export default Ember.Component.extend({
this.messageBus.unsubscribe("/staff/topic-assignment"); this.messageBus.unsubscribe("/staff/topic-assignment");
} }
}); });

View File

@ -0,0 +1,5 @@
{{avatar user imageSize="small"}}
<span class='assigned-username'>
{{user.username}}
</span>
{{yield}}

View File

@ -1,16 +1,12 @@
{{#if topic.assigned_to_user}} {{#if topic.assigned_to_user}}
<div class='assigned-to-user'> {{#assigned-to user=topic.assigned_to_user}}
{{avatar topic.assigned_to_user imageSize="small"}}
<span class='assigned-username'>
{{topic.assigned_to_user.username}}
</span>
{{d-button {{d-button
icon="times" icon="times"
class="btn-small unassign" class="btn-small unassign"
action=(action "unassign") action=(action "unassign")
disabled=unassigning disabled=unassigning
title="discourse_assign.unassign.help"}} title="discourse_assign.unassign.help"}}
</div> {{/assigned-to}}
{{else}} {{else}}
{{d-button class="btn-small assign" {{d-button class="btn-small assign"
icon="user-plus" icon="user-plus"

View File

@ -8,6 +8,16 @@
} }
} }
.cant-act-flagged-post {
padding: 0.5em;
border: 1px dashed $primary-medium;
color: $primary;
display: flex;
justify-content: space-between;
align-items: center;
}
.assigned-to-user { .assigned-to-user {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -4,6 +4,7 @@ en:
assigned: "assigned %{who} %{when}" assigned: "assigned %{who} %{when}"
unassigned: "unassigned %{who} %{when}" unassigned: "unassigned %{who} %{when}"
discourse_assign: discourse_assign:
cant_act: "You cannot act on flags that have been assigned to other users"
assigned: "Assigned" assigned: "Assigned"
assigned_to: "Assigned to" assigned_to: "Assigned to"
assign_notification: "<i title='assigned' class='fa fa-user-plus'></i><p><span>{{username}}</span> {{description}}</p>" assign_notification: "<i title='assigned' class='fa fa-user-plus'></i><p><span>{{username}}</span> {{description}}</p>"

View File

@ -13,3 +13,4 @@ en:
assigned_to: "Topic assigned to @%{username}" assigned_to: "Topic assigned to @%{username}"
unassigned: "Topic was unassigned" unassigned: "Topic was unassigned"
already_claimed: "That topic has already been claimed." already_claimed: "That topic has already been claimed."
flag_assigned: "Sorry, flag's topic is assigned to another user"

View File

@ -17,6 +17,22 @@ end
after_initialize do after_initialize do
require 'topic_assigner' require 'topic_assigner'
# Raise an invalid access error if a user tries to act on something
# not assigned to them
DiscourseEvent.on(:before_staff_flag_action) do |args|
if custom_fields = args[:post].topic.custom_fields
if assigned_to_id = custom_fields['assigned_to_id']
unless assigned_to_id.to_i == args[:user].id
raise Discourse::InvalidAccess.new(
"That flag has been assigned to another user",
nil,
custom_message: 'discourse_assign.flag_assigned'
)
end
end
end
end
# We can remove this check once this method is stable # We can remove this check once this method is stable
if respond_to?(:add_preloaded_topic_list_custom_field) if respond_to?(:add_preloaded_topic_list_custom_field)
add_preloaded_topic_list_custom_field('assigned_to_id') add_preloaded_topic_list_custom_field('assigned_to_id')