mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 22:43:33 +08:00
Adjust flagged posts to use the store
This commit is contained in:
36
app/assets/javascripts/admin/adapters/flagged-post.js.es6
Normal file
36
app/assets/javascripts/admin/adapters/flagged-post.js.es6
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import RestAdapter from 'discourse/adapters/rest';
|
||||||
|
|
||||||
|
export default RestAdapter.extend({
|
||||||
|
pathFor(store, type, findArgs) {
|
||||||
|
return `/admin/flags/${findArgs.filter}.json?rest_api=true`;
|
||||||
|
},
|
||||||
|
|
||||||
|
afterFindAll(results, helper) {
|
||||||
|
results.forEach(flag => {
|
||||||
|
let conversations = [];
|
||||||
|
flag.post_actions.forEach(pa => {
|
||||||
|
if (pa.conversation) {
|
||||||
|
let conversation = {
|
||||||
|
permalink: pa.permalink,
|
||||||
|
hasMore: pa.conversation.has_more,
|
||||||
|
response: {
|
||||||
|
excerpt: pa.conversation.response.excerpt,
|
||||||
|
user: helper.lookup('user', pa.conversation.response.user_id)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (pa.conversation.reply) {
|
||||||
|
conversation.reply = {
|
||||||
|
excerpt: pa.conversation.reply.excerpt,
|
||||||
|
user: helper.lookup('user', pa.conversation.reply.user_id)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
conversations.push(conversation);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
flag.set('conversations', conversations);
|
||||||
|
});
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
});
|
15
app/assets/javascripts/admin/helpers/disposition-icon.js.es6
Normal file
15
app/assets/javascripts/admin/helpers/disposition-icon.js.es6
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { iconHTML } from 'discourse-common/lib/icon-library';
|
||||||
|
|
||||||
|
export default Ember.Helper.extend({
|
||||||
|
compute([disposition]) {
|
||||||
|
if (!disposition) { return null; }
|
||||||
|
let icon;
|
||||||
|
let title = 'admin.flags.dispositions.' + disposition;
|
||||||
|
switch (disposition) {
|
||||||
|
case "deferred": { icon = "external-link"; break; }
|
||||||
|
case "agreed": { icon = "thumbs-o-up"; break; }
|
||||||
|
case "disagreed": { icon = "thumbs-o-down"; break; }
|
||||||
|
}
|
||||||
|
return iconHTML(icon, { title }).htmlSafe();
|
||||||
|
}
|
||||||
|
});
|
@ -1,11 +1,8 @@
|
|||||||
import { ajax } from 'discourse/lib/ajax';
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
import AdminUser from 'admin/models/admin-user';
|
|
||||||
import Topic from 'discourse/models/topic';
|
|
||||||
import Post from 'discourse/models/post';
|
import Post from 'discourse/models/post';
|
||||||
import { iconHTML } from 'discourse-common/lib/icon-library';
|
|
||||||
import computed from 'ember-addons/ember-computed-decorators';
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
const FlaggedPost = Post.extend({
|
export default Post.extend({
|
||||||
|
|
||||||
@computed
|
@computed
|
||||||
summary() {
|
summary() {
|
||||||
@ -15,34 +12,6 @@ const FlaggedPost = Post.extend({
|
|||||||
.join(',');
|
.join(',');
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed
|
|
||||||
flaggers() {
|
|
||||||
return this.post_actions.map(postAction => {
|
|
||||||
return {
|
|
||||||
user: this.userLookup[postAction.user_id],
|
|
||||||
topic: this.topicLookup[postAction.topic_id],
|
|
||||||
flagType: I18n.t('admin.flags.summary.action_type_' + postAction.post_action_type_id, { count: 1 }),
|
|
||||||
flaggedAt: postAction.created_at,
|
|
||||||
disposedBy: postAction.disposed_by_id ? this.userLookup[postAction.disposed_by_id] : null,
|
|
||||||
disposedAt: postAction.disposed_at,
|
|
||||||
dispositionIcon: this.dispositionIcon(postAction.disposition),
|
|
||||||
tookAction: postAction.staff_took_action
|
|
||||||
};
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
dispositionIcon(disposition) {
|
|
||||||
if (!disposition) { return null; }
|
|
||||||
let icon;
|
|
||||||
let title = 'admin.flags.dispositions.' + disposition;
|
|
||||||
switch (disposition) {
|
|
||||||
case "deferred": { icon = "external-link"; break; }
|
|
||||||
case "agreed": { icon = "thumbs-o-up"; break; }
|
|
||||||
case "disagreed": { icon = "thumbs-o-down"; break; }
|
|
||||||
}
|
|
||||||
return iconHTML(icon, { title });
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('last_revised_at', 'post_actions.@each.created_at')
|
@computed('last_revised_at', 'post_actions.@each.created_at')
|
||||||
wasEdited(lastRevisedAt) {
|
wasEdited(lastRevisedAt) {
|
||||||
if (Ember.isEmpty(this.get("last_revised_at"))) { return false; }
|
if (Ember.isEmpty(this.get("last_revised_at"))) { return false; }
|
||||||
@ -52,44 +21,6 @@ const FlaggedPost = Post.extend({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed
|
|
||||||
conversations() {
|
|
||||||
let conversations = [];
|
|
||||||
|
|
||||||
this.post_actions.forEach(postAction => {
|
|
||||||
if (postAction.conversation) {
|
|
||||||
let conversation = {
|
|
||||||
permalink: postAction.permalink,
|
|
||||||
hasMore: postAction.conversation.has_more,
|
|
||||||
response: {
|
|
||||||
excerpt: postAction.conversation.response.excerpt,
|
|
||||||
user: this.userLookup[postAction.conversation.response.user_id]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (postAction.conversation.reply) {
|
|
||||||
conversation.reply = {
|
|
||||||
excerpt: postAction.conversation.reply.excerpt,
|
|
||||||
user: this.userLookup[postAction.conversation.reply.user_id]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
conversations.push(conversation);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return conversations;
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed
|
|
||||||
user() {
|
|
||||||
return this.userLookup[this.user_id];
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed
|
|
||||||
topic() {
|
|
||||||
return this.topicLookup[this.topic_id];
|
|
||||||
},
|
|
||||||
|
|
||||||
@computed('post_actions.@each.name_key')
|
@computed('post_actions.@each.name_key')
|
||||||
flaggedForSpam() {
|
flaggedForSpam() {
|
||||||
return this.get('post_actions').every(action => action.name_key === 'spam');
|
return this.get('post_actions').every(action => action.name_key === 'spam');
|
||||||
@ -136,43 +67,3 @@ const FlaggedPost = Post.extend({
|
|||||||
|
|
||||||
deleted: Ember.computed.or('deleted_at', 'topic_deleted_at'),
|
deleted: Ember.computed.or('deleted_at', 'topic_deleted_at'),
|
||||||
});
|
});
|
||||||
|
|
||||||
FlaggedPost.reopenClass({
|
|
||||||
findAll(args) {
|
|
||||||
let { filter } = args;
|
|
||||||
|
|
||||||
let result = [];
|
|
||||||
result.set('loading', true);
|
|
||||||
|
|
||||||
let data = {};
|
|
||||||
if (args.topic_id) {
|
|
||||||
data.topic_id = args.topic_id;
|
|
||||||
}
|
|
||||||
if (args.offset) {
|
|
||||||
data.offset = args.offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ajax(`/admin/flags/${filter}.json`, { data }).then(response => {
|
|
||||||
// users
|
|
||||||
let userLookup = {};
|
|
||||||
response.users.forEach(user => userLookup[user.id] = AdminUser.create(user));
|
|
||||||
|
|
||||||
// topics
|
|
||||||
let topicLookup = {};
|
|
||||||
response.topics.forEach(topic => topicLookup[topic.id] = Topic.create(topic));
|
|
||||||
|
|
||||||
// posts
|
|
||||||
response.posts.forEach(post => {
|
|
||||||
let f = FlaggedPost.create(post);
|
|
||||||
f.userLookup = userLookup;
|
|
||||||
f.topicLookup = topicLookup;
|
|
||||||
result.pushObject(f);
|
|
||||||
});
|
|
||||||
|
|
||||||
result.set('loading', false);
|
|
||||||
return result;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
export default FlaggedPost;
|
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import FlaggedPost from 'admin/models/flagged-post';
|
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
export default Discourse.Route.extend({
|
||||||
model() {
|
model() {
|
||||||
return FlaggedPost.findAll({ filter: 'active' });
|
return this.store.findAll('flagged-post', { filter: 'active' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import FlaggedPost from 'admin/models/flagged-post';
|
|
||||||
|
|
||||||
export default Discourse.Route.extend({
|
export default Discourse.Route.extend({
|
||||||
model() {
|
model() {
|
||||||
return FlaggedPost.findAll({ filter: 'old' });
|
return this.store.findAll('flagged-post', { filter: 'old' });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
{{#link-to 'adminUser' response.user class="response-avatar"}}
|
{{#link-to 'adminUser' response.user.id response.user.username class="response-avatar"}}
|
||||||
{{avatar response.user imageSize="medium"}}
|
{{avatar response.user imageSize="medium"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
<div class='excerpt'>{{{response.excerpt}}}</div>
|
<div class='excerpt'>{{{response.excerpt}}}</div>
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
<div class="flagged-post-avatar">
|
<div class="flagged-post-avatar">
|
||||||
{{#if flaggedPost.postAuthorFlagged}}
|
{{#if flaggedPost.postAuthorFlagged}}
|
||||||
{{#if flaggedPost.user}}
|
{{#if flaggedPost.user}}
|
||||||
{{#link-to 'adminUser' flaggedPost.user}}{{avatar flaggedPost.user imageSize="large"}}{{/link-to}}
|
{{#link-to 'adminUser' flaggedPost.user.id flaggedPost.user.username}}
|
||||||
|
{{avatar flaggedPost.user imageSize="large"}}
|
||||||
|
{{/link-to}}
|
||||||
{{#if flaggedPost.wasEdited}}
|
{{#if flaggedPost.wasEdited}}
|
||||||
{{d-icon "pencil" title="admin.flags.was_edited"}}
|
{{d-icon "pencil" title="admin.flags.was_edited"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
@ -37,22 +39,22 @@
|
|||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#each flaggedPost.flaggers as |flagger|}}
|
{{#each flaggedPost.post_actions as |postAction|}}
|
||||||
<div class='flagger'>
|
<div class='flagger'>
|
||||||
{{#link-to 'adminUser' flagger.user class='flagger-avatar'}}
|
{{#link-to 'adminUser' postAction.user.id postAction.user.username class='flagger-avatar'}}
|
||||||
{{avatar flagger.user imageSize="medium"}}
|
{{avatar postAction.user imageSize="medium"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
<div class='flagger-details'>
|
<div class='flagger-details'>
|
||||||
<div class='flagger-username'>
|
<div class='flagger-username'>
|
||||||
{{#link-to 'adminUser' flagger.user}}
|
{{#link-to 'adminUser' postAction.user.id postAction.user.username}}
|
||||||
{{flagger.user.username}}
|
{{postAction.user.username}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
</div>
|
</div>
|
||||||
<div class='flagger-flagged-at'>
|
<div class='flagger-flagged-at'>
|
||||||
{{format-age flagger.flaggedAt}}
|
{{format-age postAction.created_at}}
|
||||||
</div>
|
</div>
|
||||||
<div class='flagger-flag-type'>
|
<div class='flagger-flag-type'>
|
||||||
{{flagger.flagType}}
|
{{i18n (concat "admin.flags.summary.action_type_" postAction.post_action_type_id) count=1}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -61,15 +63,19 @@
|
|||||||
|
|
||||||
{{#if showResolvedBy}}
|
{{#if showResolvedBy}}
|
||||||
<div class='flagged-post-resolved-by'>
|
<div class='flagged-post-resolved-by'>
|
||||||
{{#each flaggedPost.flaggers as |flagger|}}
|
{{#each flaggedPost.post_actions as |postAction|}}
|
||||||
<div class='disposer'>
|
<div class='disposer'>
|
||||||
{{#link-to 'adminUser' flagger.disposedBy class="disposer-avatar"}}
|
{{#link-to
|
||||||
{{avatar flagger.disposedBy imageSize="medium"}}
|
'adminUser'
|
||||||
|
postAction.disposed_by.id
|
||||||
|
postAction.disposed_by.username
|
||||||
|
class="disposer-avatar"}}
|
||||||
|
{{avatar postAction.disposed_by imageSize="medium"}}
|
||||||
{{/link-to}}
|
{{/link-to}}
|
||||||
<div class='disposer-details'>
|
<div class='disposer-details'>
|
||||||
{{format-age flagger.disposedAt}}
|
{{format-age postAction.disposed_at}}
|
||||||
{{{flagger.dispositionIcon}}}
|
{{disposition-icon postAction.disposition}}
|
||||||
{{#if flagger.tookAction}}
|
{{#if postAction.staff_took_action}}
|
||||||
{{d-icon "gavel" title="admin.flags.took_action"}}
|
{{d-icon "gavel" title="admin.flags.took_action"}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
|
@ -139,8 +139,9 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||||||
canDeleteSpammer: function() {
|
canDeleteSpammer: function() {
|
||||||
if (this.get("flagTopic")) return false;
|
if (this.get("flagTopic")) return false;
|
||||||
|
|
||||||
if (Discourse.User.currentProp('staff') && this.get('selected.name_key') === 'spam') {
|
if (this.currentUser.get('staff') && this.get('selected.name_key') === 'spam') {
|
||||||
return this.get('userDetails.can_be_deleted') && this.get('userDetails.can_delete_all_posts');
|
return this.get('userDetails.can_be_deleted') &&
|
||||||
|
this.get('userDetails.can_delete_all_posts');
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -57,10 +57,19 @@ export default Ember.Object.extend({
|
|||||||
|
|
||||||
findAll(type, findArgs) {
|
findAll(type, findArgs) {
|
||||||
const adapter = this.adapterFor(type);
|
const adapter = this.adapterFor(type);
|
||||||
return adapter.findAll(this, type, findArgs).then((result) => {
|
|
||||||
|
let store = this;
|
||||||
|
return adapter.findAll(this, type, findArgs).then(result => {
|
||||||
let results = this._resultSet(type, result);
|
let results = this._resultSet(type, result);
|
||||||
if (adapter.afterFindAll) {
|
if (adapter.afterFindAll) {
|
||||||
results = adapter.afterFindAll(results);
|
results = adapter.afterFindAll(
|
||||||
|
results,
|
||||||
|
{
|
||||||
|
lookup(subType, id) {
|
||||||
|
return store._lookupSubType(subType, type, id, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
});
|
});
|
||||||
@ -231,6 +240,10 @@ export default Ember.Object.extend({
|
|||||||
return Discourse.Category.findById(id);
|
return Discourse.Category.findById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (root.meta && root.meta.types) {
|
||||||
|
subType = root.meta.types[subType] || subType;
|
||||||
|
}
|
||||||
|
|
||||||
const pluralType = this.pluralize(subType);
|
const pluralType = this.pluralize(subType);
|
||||||
const collection = root[this.pluralize(subType)];
|
const collection = root[this.pluralize(subType)];
|
||||||
if (collection) {
|
if (collection) {
|
||||||
|
@ -40,14 +40,14 @@ const TopicRoute = Discourse.Route.extend({
|
|||||||
actions: {
|
actions: {
|
||||||
|
|
||||||
showFlags(model) {
|
showFlags(model) {
|
||||||
showModal('flag', { model });
|
let controller = showModal('flag', { model });
|
||||||
this.controllerFor('flag').setProperties({ selected: null, flagTopic: false });
|
controller.setProperties({ selected: null, flagTopic: false });
|
||||||
},
|
},
|
||||||
|
|
||||||
showFlagTopic() {
|
showFlagTopic() {
|
||||||
const model = this.modelFor('topic');
|
const model = this.modelFor('topic');
|
||||||
showModal('flag', { model });
|
let controller = showModal('flag', { model });
|
||||||
this.controllerFor('flag').setProperties({ selected: null, flagTopic: true });
|
controller.setProperties({ selected: null, flagTopic: true });
|
||||||
},
|
},
|
||||||
|
|
||||||
showTopicStatusUpdate() {
|
showTopicStatusUpdate() {
|
||||||
|
@ -10,22 +10,40 @@ class Admin::FlagsController < Admin::AdminController
|
|||||||
# we may get out of sync, fix it here
|
# we may get out of sync, fix it here
|
||||||
PostAction.update_flagged_posts_count
|
PostAction.update_flagged_posts_count
|
||||||
|
|
||||||
posts, topics, users = FlagQuery.flagged_posts_report(
|
posts, topics, users, post_actions = FlagQuery.flagged_posts_report(
|
||||||
current_user,
|
current_user,
|
||||||
filter: params[:filter],
|
filter: params[:filter],
|
||||||
offset: params[:offset].to_i,
|
offset: params[:offset].to_i,
|
||||||
topic_id: params[:topic_id],
|
topic_id: params[:topic_id],
|
||||||
per_page: Admin::FlagsController.flags_per_page
|
per_page: Admin::FlagsController.flags_per_page,
|
||||||
|
rest_api: params[:rest_api].present?
|
||||||
)
|
)
|
||||||
|
|
||||||
if posts.blank?
|
if posts.blank?
|
||||||
render json: { posts: [], topics: [], users: [] }
|
render json: { posts: [], topics: [], users: [] }
|
||||||
else
|
else
|
||||||
render json: MultiJson.dump(
|
if params[:rest_api]
|
||||||
posts: posts,
|
render_json_dump(
|
||||||
topics: serialize_data(topics, FlaggedTopicSerializer),
|
{
|
||||||
users: serialize_data(users, FlaggedUserSerializer)
|
flagged_posts: posts,
|
||||||
)
|
topics: serialize_data(topics, FlaggedTopicSerializer),
|
||||||
|
users: serialize_data(users, FlaggedUserSerializer),
|
||||||
|
post_actions: post_actions
|
||||||
|
},
|
||||||
|
rest_serializer: true,
|
||||||
|
meta: {
|
||||||
|
types: {
|
||||||
|
disposed_by: 'user'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else
|
||||||
|
render_json_dump(
|
||||||
|
posts: posts,
|
||||||
|
topics: serialize_data(topics, FlaggedTopicSerializer),
|
||||||
|
users: serialize_data(users, FlaggedUserSerializer)
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -327,6 +327,7 @@ class ApplicationController < ActionController::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
obj['extras'] = opts[:extras] if opts[:extras]
|
obj['extras'] = opts[:extras] if opts[:extras]
|
||||||
|
obj['meta'] = opts[:meta] if opts[:meta]
|
||||||
end
|
end
|
||||||
|
|
||||||
render json: MultiJson.dump(obj), status: opts[:status] || 200
|
render json: MultiJson.dump(obj), status: opts[:status] || 200
|
||||||
|
@ -60,9 +60,17 @@ module FlagQuery
|
|||||||
.includes(related_post: { topic: { ordered_posts: :user } })
|
.includes(related_post: { topic: { ordered_posts: :user } })
|
||||||
.where(post_id: post_ids)
|
.where(post_id: post_ids)
|
||||||
|
|
||||||
|
all_post_actions = []
|
||||||
|
|
||||||
post_actions.each do |pa|
|
post_actions.each do |pa|
|
||||||
post = post_lookup[pa.post_id]
|
post = post_lookup[pa.post_id]
|
||||||
post.post_actions ||= []
|
|
||||||
|
if opts[:rest_api]
|
||||||
|
post.post_action_ids ||= []
|
||||||
|
else
|
||||||
|
post.post_actions ||= []
|
||||||
|
end
|
||||||
|
|
||||||
# TODO: add serializer so we can skip this
|
# TODO: add serializer so we can skip this
|
||||||
action = {
|
action = {
|
||||||
id: pa.id,
|
id: pa.id,
|
||||||
@ -101,7 +109,12 @@ module FlagQuery
|
|||||||
action.merge!(permalink: related_topic.relative_url, conversation: conversation)
|
action.merge!(permalink: related_topic.relative_url, conversation: conversation)
|
||||||
end
|
end
|
||||||
|
|
||||||
post.post_actions << action
|
if opts[:rest_api]
|
||||||
|
post.post_action_ids << action[:id]
|
||||||
|
all_post_actions << action
|
||||||
|
else
|
||||||
|
post.post_actions << action
|
||||||
|
end
|
||||||
|
|
||||||
user_ids << pa.user_id
|
user_ids << pa.user_id
|
||||||
user_ids << pa.disposed_by_id if pa.disposed_by_id
|
user_ids << pa.disposed_by_id if pa.disposed_by_id
|
||||||
@ -115,7 +128,8 @@ module FlagQuery
|
|||||||
[
|
[
|
||||||
posts,
|
posts,
|
||||||
Topic.with_deleted.where(id: topic_ids.to_a).to_a,
|
Topic.with_deleted.where(id: topic_ids.to_a).to_a,
|
||||||
User.includes(:user_stat).where(id: user_ids.to_a).to_a
|
User.includes(:user_stat).where(id: user_ids.to_a).to_a,
|
||||||
|
all_post_actions
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -36,19 +36,22 @@ export default function(helpers) {
|
|||||||
|
|
||||||
this.get('/admin/flags/active.json', () => {
|
this.get('/admin/flags/active.json', () => {
|
||||||
return response(200, {
|
return response(200, {
|
||||||
posts: [
|
flagged_posts: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
user_id: sam.id,
|
user_id: sam.id,
|
||||||
post_actions: [{
|
post_action_ids: [1]
|
||||||
user_id: eviltrout.id,
|
|
||||||
post_action_type_id: 8,
|
|
||||||
name_key: 'spam'
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
users: [eviltrout, sam],
|
users: [eviltrout, sam],
|
||||||
topics: [],
|
topics: [],
|
||||||
|
post_actions: [{
|
||||||
|
id: 1,
|
||||||
|
user_id: eviltrout.id,
|
||||||
|
post_action_type_id: 8,
|
||||||
|
name_key: 'spam'
|
||||||
|
}],
|
||||||
|
"__rest_serializer": "1"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user