UX: Display group topics in a topic list.
This commit is contained in:
parent
d3f5b4e4b0
commit
a35227918f
|
@ -0,0 +1,7 @@
|
||||||
|
export default Ember.Controller.extend({
|
||||||
|
actions: {
|
||||||
|
loadMore() {
|
||||||
|
this.get('model').loadMore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -1,3 +1,11 @@
|
||||||
import { buildGroupPage } from 'discourse/routes/group-activity-posts';
|
export default Discourse.Route.extend({
|
||||||
|
titleToken() {
|
||||||
|
return I18n.t(`groups.topics`);
|
||||||
|
},
|
||||||
|
|
||||||
export default buildGroupPage('topics');
|
model() {
|
||||||
|
return this.store.findFiltered("topicList", {
|
||||||
|
filter: `topics/groups/${this.modelFor('group').get('name')}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
{{#load-more class="paginated-topics-list" selector=".paginated-topics-list .topic-list tr" action="loadMore"}}
|
||||||
|
{{basic-topic-list topicList=model
|
||||||
|
showPosters=true}}
|
||||||
|
{{conditional-loading-spinner condition=model.loadingMore}}
|
||||||
|
{{/load-more}}
|
|
@ -101,15 +101,6 @@ class GroupsController < ApplicationController
|
||||||
render 'posts/latest', formats: [:rss]
|
render 'posts/latest', formats: [:rss]
|
||||||
end
|
end
|
||||||
|
|
||||||
def topics
|
|
||||||
group = find_group(:group_id)
|
|
||||||
posts = group.posts_for(
|
|
||||||
guardian,
|
|
||||||
params.permit(:before_post_id, :category_id)
|
|
||||||
).where(post_number: 1).limit(20)
|
|
||||||
render_serialized posts.to_a, GroupPostSerializer
|
|
||||||
end
|
|
||||||
|
|
||||||
def mentions
|
def mentions
|
||||||
raise Discourse::NotFound unless SiteSetting.enable_mentions?
|
raise Discourse::NotFound unless SiteSetting.enable_mentions?
|
||||||
group = find_group(:group_id)
|
group = find_group(:group_id)
|
||||||
|
|
|
@ -50,6 +50,7 @@ class ListController < ApplicationController
|
||||||
TopTopic.periods.map { |p| :"category_top_#{p}" },
|
TopTopic.periods.map { |p| :"category_top_#{p}" },
|
||||||
TopTopic.periods.map { |p| :"category_none_top_#{p}" },
|
TopTopic.periods.map { |p| :"category_none_top_#{p}" },
|
||||||
TopTopic.periods.map { |p| :"parent_category_category_top_#{p}" },
|
TopTopic.periods.map { |p| :"parent_category_category_top_#{p}" },
|
||||||
|
:group_topics
|
||||||
].flatten
|
].flatten
|
||||||
|
|
||||||
# Create our filters
|
# Create our filters
|
||||||
|
@ -131,6 +132,18 @@ class ListController < ApplicationController
|
||||||
respond_with_list(list)
|
respond_with_list(list)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def group_topics
|
||||||
|
group = Group.find_by(name: params[:group_name])
|
||||||
|
raise Discourse::NotFound unless group
|
||||||
|
guardian.ensure_can_see_group!(group)
|
||||||
|
|
||||||
|
list_opts = build_topic_list_options
|
||||||
|
list = generate_list_for("group_topics", group, list_opts)
|
||||||
|
list.more_topics_url = url_for(construct_url_with(:next, list_opts))
|
||||||
|
list.prev_topics_url = url_for(construct_url_with(:prev, list_opts))
|
||||||
|
respond_with_list(list)
|
||||||
|
end
|
||||||
|
|
||||||
def self.generate_message_route(action)
|
def self.generate_message_route(action)
|
||||||
define_method("#{action}") do
|
define_method("#{action}") do
|
||||||
list_opts = build_topic_list_options
|
list_opts = build_topic_list_options
|
||||||
|
|
|
@ -455,7 +455,6 @@ Discourse::Application.routes.draw do
|
||||||
|
|
||||||
get 'members'
|
get 'members'
|
||||||
get 'posts'
|
get 'posts'
|
||||||
get 'topics'
|
|
||||||
get 'mentions'
|
get 'mentions'
|
||||||
get 'messages'
|
get 'messages'
|
||||||
get 'counts'
|
get 'counts'
|
||||||
|
@ -608,6 +607,7 @@ Discourse::Application.routes.draw do
|
||||||
get "private-messages-archive/:username" => "list#private_messages_archive", as: "topics_private_messages_archive"
|
get "private-messages-archive/:username" => "list#private_messages_archive", as: "topics_private_messages_archive"
|
||||||
get "private-messages-unread/:username" => "list#private_messages_unread", as: "topics_private_messages_unread"
|
get "private-messages-unread/:username" => "list#private_messages_unread", as: "topics_private_messages_unread"
|
||||||
get "private-messages-tags/:username/:tag_id.json" => "list#private_messages_tag", as: "topics_private_messages_tag", constraints: StaffConstraint.new
|
get "private-messages-tags/:username/:tag_id.json" => "list#private_messages_tag", as: "topics_private_messages_tag", constraints: StaffConstraint.new
|
||||||
|
get "groups/:group_name.json" => "list#group_topics", as: "group_topics"
|
||||||
|
|
||||||
scope "/private-messages-group/:username", group_name: RouteFormat.username do
|
scope "/private-messages-group/:username", group_name: RouteFormat.username do
|
||||||
get ":group_name.json" => "list#private_messages_group", as: "topics_private_messages_group"
|
get ":group_name.json" => "list#private_messages_group", as: "topics_private_messages_group"
|
||||||
|
|
|
@ -220,6 +220,16 @@ class TopicQuery
|
||||||
.where('um.user_id IS NULL')
|
.where('um.user_id IS NULL')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def list_group_topics(group)
|
||||||
|
list = default_results.where("
|
||||||
|
topics.user_id IN (
|
||||||
|
SELECT user_id FROM group_users gu WHERE gu.group_id = #{group.id.to_i}
|
||||||
|
)
|
||||||
|
")
|
||||||
|
|
||||||
|
create_list(:group_topics, {}, list)
|
||||||
|
end
|
||||||
|
|
||||||
def list_private_messages(user)
|
def list_private_messages(user)
|
||||||
list = private_messages_for(user, :user)
|
list = private_messages_for(user, :user)
|
||||||
|
|
||||||
|
|
|
@ -885,10 +885,49 @@ describe TopicQuery do
|
||||||
expect(suggested_topics[1, 3]).to include(closed_topic.id)
|
expect(suggested_topics[1, 3]).to include(closed_topic.id)
|
||||||
expect(suggested_topics[1, 3]).to include(archived_topic.id)
|
expect(suggested_topics[1, 3]).to include(archived_topic.id)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#list_group_topics' do
|
||||||
|
let(:group) { Fabricate(:group) }
|
||||||
|
|
||||||
|
let(:user) do
|
||||||
|
user = Fabricate(:user)
|
||||||
|
group.add(user)
|
||||||
|
user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
let(:user2) do
|
||||||
|
user = Fabricate(:user)
|
||||||
|
group.add(user)
|
||||||
|
user
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:private_category) do
|
||||||
|
Fabricate(:private_category, group: group)
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:private_message_topic) { Fabricate(:private_message_post, user: user).topic }
|
||||||
|
let!(:topic1) { Fabricate(:topic, user: user) }
|
||||||
|
let!(:topic2) { Fabricate(:topic, user: user, category: Fabricate(:category)) }
|
||||||
|
let!(:topic3) { Fabricate(:topic, user: user, category: private_category) }
|
||||||
|
let!(:topic4) { Fabricate(:topic) }
|
||||||
|
let!(:topic5) { Fabricate(:topic, user: user, visible: false) }
|
||||||
|
let!(:topic6) { Fabricate(:topic, user: user2) }
|
||||||
|
|
||||||
|
it 'should return the right list' do
|
||||||
|
topics = TopicQuery.new.list_group_topics(group).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(topic1, topic2, topic6)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(user).list_group_topics(group).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(topic1, topic2, topic3, topic6)
|
||||||
|
|
||||||
|
topics = TopicQuery.new(user2).list_group_topics(group).topics
|
||||||
|
|
||||||
|
expect(topics).to contain_exactly(topic1, topic2, topic3, topic6)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,7 +104,84 @@ RSpec.describe ListController do
|
||||||
[moderator, admin].each do |user|
|
[moderator, admin].each do |user|
|
||||||
sign_in(user)
|
sign_in(user)
|
||||||
get "/topics/private-messages-tags/#{user.username}/#{tag.name}.json"
|
get "/topics/private-messages-tags/#{user.username}/#{tag.name}.json"
|
||||||
expect(response).to be_success
|
expect(response.status).to eq(200)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#group_topics' do
|
||||||
|
let(:group) { Fabricate(:group) }
|
||||||
|
|
||||||
|
%i{user user2}.each do |user|
|
||||||
|
let(user) do
|
||||||
|
user = Fabricate(:user)
|
||||||
|
group.add(user)
|
||||||
|
user
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:topic) { Fabricate(:topic, user: user) }
|
||||||
|
let!(:topic2) { Fabricate(:topic, user: user2) }
|
||||||
|
let!(:another_topic) { Fabricate(:topic) }
|
||||||
|
|
||||||
|
describe 'when an invalid group name is given' do
|
||||||
|
it 'should return the right response' do
|
||||||
|
get "/topics/groups/something.json"
|
||||||
|
|
||||||
|
expect(response.status).to eq(404)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'for an anon user' do
|
||||||
|
describe 'public visible group' do
|
||||||
|
it 'should return the right response' do
|
||||||
|
get "/topics/groups/#{group.name}.json"
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
expect(JSON.parse(response.body)["topic_list"]).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'restricted group' do
|
||||||
|
before { group.update!(visibility_level: Group.visibility_levels[:staff]) }
|
||||||
|
|
||||||
|
it 'should return the right response' do
|
||||||
|
get "/topics/groups/#{group.name}.json"
|
||||||
|
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'for a normal user' do
|
||||||
|
before { sign_in(Fabricate(:user)) }
|
||||||
|
|
||||||
|
describe 'restricted group' do
|
||||||
|
before { group.update!(visibility_level: Group.visibility_levels[:staff]) }
|
||||||
|
|
||||||
|
it 'should return the right response' do
|
||||||
|
get "/topics/groups/#{group.name}.json"
|
||||||
|
|
||||||
|
expect(response.status).to eq(403)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'for a group user' do
|
||||||
|
before do
|
||||||
|
sign_in(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should be able to view the topics started by group users' do
|
||||||
|
get "/topics/groups/#{group.name}.json"
|
||||||
|
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
topics = JSON.parse(response.body)["topic_list"]["topics"]
|
||||||
|
|
||||||
|
expect(topics.map { |topic| topic["id"] }).to contain_exactly(
|
||||||
|
topic.id, topic2.id
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -60,7 +60,8 @@ QUnit.test("Anonymous Viewing Group", assert => {
|
||||||
click(".group-activity-nav li a[href='/groups/discourse/activity/topics']");
|
click(".group-activity-nav li a[href='/groups/discourse/activity/topics']");
|
||||||
|
|
||||||
andThen(() => {
|
andThen(() => {
|
||||||
assert.ok(count('.group-post') > 0, "it lists stream items");
|
assert.ok(find('.topic-list'), "it shows the topic list");
|
||||||
|
assert.equal(count('.topic-list-item'), 2, "it lists stream items");
|
||||||
});
|
});
|
||||||
|
|
||||||
click(".group-activity-nav li a[href='/groups/discourse/activity/mentions']");
|
click(".group-activity-nav li a[href='/groups/discourse/activity/mentions']");
|
||||||
|
|
|
@ -16,6 +16,106 @@ export default {
|
||||||
"messageable":true
|
"messageable":true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/topics/groups/discourse.json":{
|
||||||
|
"users":[
|
||||||
|
{
|
||||||
|
"id":2,
|
||||||
|
"username":"bruce1",
|
||||||
|
"avatar_template":"/letter_avatar_proxy/v2/letter/b/9de053/{size}.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":1,
|
||||||
|
"username":"bruce0",
|
||||||
|
"avatar_template":"/letter_avatar_proxy/v2/letter/b/90ced4/{size}.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"primary_groups":[],
|
||||||
|
"topic_list":{
|
||||||
|
"can_create_topic":true,
|
||||||
|
"draft":null,
|
||||||
|
"draft_key":"new_topic",
|
||||||
|
"draft_sequence":1,
|
||||||
|
"per_page":30,
|
||||||
|
"topics":[
|
||||||
|
{
|
||||||
|
"id":12074,
|
||||||
|
"title":"This is a test topic 1",
|
||||||
|
"fancy_title":"This is a test topic 1",
|
||||||
|
"slug":"this-is-a-test-topic-1",
|
||||||
|
"posts_count":0,
|
||||||
|
"reply_count":0,
|
||||||
|
"highest_post_number":0,
|
||||||
|
"image_url":null,
|
||||||
|
"created_at":"2018-03-15T03:12:48.955Z",
|
||||||
|
"last_posted_at":null,
|
||||||
|
"bumped":true,
|
||||||
|
"bumped_at":"2018-03-15T03:12:48.955Z",
|
||||||
|
"unseen":true,
|
||||||
|
"pinned":false,
|
||||||
|
"unpinned":null,
|
||||||
|
"visible":true,
|
||||||
|
"closed":false,
|
||||||
|
"archived":false,
|
||||||
|
"bookmarked":null,
|
||||||
|
"liked":null,
|
||||||
|
"views":0,
|
||||||
|
"like_count":0,
|
||||||
|
"has_summary":false,
|
||||||
|
"archetype":"regular",
|
||||||
|
"last_poster_username":"bruce1",
|
||||||
|
"category_id":1,
|
||||||
|
"pinned_globally":false,
|
||||||
|
"featured_link":null,
|
||||||
|
"posters":[
|
||||||
|
{
|
||||||
|
"extras":"latest single",
|
||||||
|
"description":"Original Poster, Most Recent Poster",
|
||||||
|
"user_id":2,
|
||||||
|
"primary_group_id":null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id":12073,
|
||||||
|
"title":"This is a test topic 0",
|
||||||
|
"fancy_title":"This is a test topic 0",
|
||||||
|
"slug":"this-is-a-test-topic-0",
|
||||||
|
"posts_count":0,
|
||||||
|
"reply_count":0,
|
||||||
|
"highest_post_number":0,
|
||||||
|
"image_url":null,
|
||||||
|
"created_at":"2018-03-15T03:12:48.899Z",
|
||||||
|
"last_posted_at":null,
|
||||||
|
"bumped":true,
|
||||||
|
"bumped_at":"2018-03-15T03:12:48.900Z",
|
||||||
|
"unseen":true,
|
||||||
|
"pinned":false,
|
||||||
|
"unpinned":null,
|
||||||
|
"visible":true,
|
||||||
|
"closed":false,
|
||||||
|
"archived":false,
|
||||||
|
"bookmarked":null,
|
||||||
|
"liked":null,
|
||||||
|
"views":0,
|
||||||
|
"like_count":0,
|
||||||
|
"has_summary":false,
|
||||||
|
"archetype":"regular",
|
||||||
|
"last_poster_username":"bruce0",
|
||||||
|
"category_id":1,
|
||||||
|
"pinned_globally":false,
|
||||||
|
"featured_link":null,
|
||||||
|
"posters":[
|
||||||
|
{
|
||||||
|
"extras":"latest single",
|
||||||
|
"description":"Original Poster, Most Recent Poster",
|
||||||
|
"user_id":1,
|
||||||
|
"primary_group_id":null
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
"/groups/discourse/counts.json":{
|
"/groups/discourse/counts.json":{
|
||||||
"counts":{
|
"counts":{
|
||||||
"posts":17829,
|
"posts":17829,
|
||||||
|
|
|
@ -295,8 +295,8 @@ export default function() {
|
||||||
return response(200, []);
|
return response(200, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.get("/groups/discourse/topics.json", () => {
|
this.get("/topics/groups/discourse.json", () => {
|
||||||
return response(200, fixturesByUrl['/groups/discourse/posts.json']);
|
return response(200, fixturesByUrl['/topics/groups/discourse.json']);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.get("/groups/discourse/mentions.json", () => {
|
this.get("/groups/discourse/mentions.json", () => {
|
||||||
|
|
Loading…
Reference in New Issue