First pass
This commit is contained in:
parent
823a699d41
commit
7e73b933c7
|
@ -132,6 +132,7 @@ export default function() {
|
||||||
this.route('showCategory' + filter.capitalize(), {path: '/c/:category/:tag_id/l/' + filter});
|
this.route('showCategory' + filter.capitalize(), {path: '/c/:category/:tag_id/l/' + filter});
|
||||||
this.route('showParentCategory' + filter.capitalize(), {path: '/c/:parent_category/:category/:tag_id/l/' + filter});
|
this.route('showParentCategory' + filter.capitalize(), {path: '/c/:parent_category/:category/:tag_id/l/' + filter});
|
||||||
});
|
});
|
||||||
|
this.route('show', {path: 'intersection/:tag_id/:secondary_tag_id'});
|
||||||
});
|
});
|
||||||
|
|
||||||
this.resource('tagGroups', {path: '/tag_groups'}, function() {
|
this.resource('tagGroups', {path: '/tag_groups'}, function() {
|
||||||
|
|
|
@ -14,6 +14,8 @@ export default Discourse.Route.extend({
|
||||||
var tag = this.store.createRecord("tag", { id: Handlebars.Utils.escapeExpression(params.tag_id) }),
|
var tag = this.store.createRecord("tag", { id: Handlebars.Utils.escapeExpression(params.tag_id) }),
|
||||||
f = '';
|
f = '';
|
||||||
|
|
||||||
|
this.set("secondaryTagId", params.secondary_tag_id)
|
||||||
|
|
||||||
if (params.category) {
|
if (params.category) {
|
||||||
f = 'c/';
|
f = 'c/';
|
||||||
if (params.parent_category) { f += params.parent_category + '/'; }
|
if (params.parent_category) { f += params.parent_category + '/'; }
|
||||||
|
@ -43,6 +45,7 @@ export default Discourse.Route.extend({
|
||||||
const params = controller.getProperties('order', 'ascending');
|
const params = controller.getProperties('order', 'ascending');
|
||||||
|
|
||||||
const categorySlug = this.get('categorySlug');
|
const categorySlug = this.get('categorySlug');
|
||||||
|
const secondaryTagId = this.get('secondaryTagId')
|
||||||
const parentCategorySlug = this.get('parentCategorySlug');
|
const parentCategorySlug = this.get('parentCategorySlug');
|
||||||
const filter = this.get('navMode');
|
const filter = this.get('navMode');
|
||||||
const tag_id = (tag ? tag.id : 'none');
|
const tag_id = (tag ? tag.id : 'none');
|
||||||
|
@ -56,6 +59,9 @@ export default Discourse.Route.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
this.set('category', category);
|
this.set('category', category);
|
||||||
|
} else if (secondaryTagId) {
|
||||||
|
params.filter = `tags/intersection/${tag_id}/${secondaryTagId}`;
|
||||||
|
this.set('category', null);
|
||||||
} else {
|
} else {
|
||||||
params.filter = `tags/${tag_id}/l/${filter}`;
|
params.filter = `tags/${tag_id}/l/${filter}`;
|
||||||
this.set('category', null);
|
this.set('category', null);
|
||||||
|
|
|
@ -44,6 +44,7 @@ class TagsController < ::ApplicationController
|
||||||
Discourse.filters.each do |filter|
|
Discourse.filters.each do |filter|
|
||||||
define_method("show_#{filter}") do
|
define_method("show_#{filter}") do
|
||||||
@tag_id = DiscourseTagging.clean_tag(params[:tag_id])
|
@tag_id = DiscourseTagging.clean_tag(params[:tag_id])
|
||||||
|
@secondary_tag_id = DiscourseTagging.clean_tag(params[:secondary_tag_id]) if params[:secondary_tag_id]
|
||||||
|
|
||||||
page = params[:page].to_i
|
page = params[:page].to_i
|
||||||
list_opts = build_topic_list_options
|
list_opts = build_topic_list_options
|
||||||
|
@ -71,7 +72,7 @@ class TagsController < ::ApplicationController
|
||||||
@list.more_topics_url = construct_url_with(:next, list_opts)
|
@list.more_topics_url = construct_url_with(:next, list_opts)
|
||||||
@list.prev_topics_url = construct_url_with(:prev, list_opts)
|
@list.prev_topics_url = construct_url_with(:prev, list_opts)
|
||||||
@rss = "tag"
|
@rss = "tag"
|
||||||
@description_meta = I18n.t("rss_by_tag", tag: @tag_id)
|
@description_meta = I18n.t("rss_by_tag", tag: [@tag_id, @secondary_tag_id].compact.join(' & '))
|
||||||
@title = @description_meta
|
@title = @description_meta
|
||||||
|
|
||||||
canonical_url "#{Discourse.base_url_no_prefix}#{public_send(url_method(params.slice(:category, :parent_category)))}"
|
canonical_url "#{Discourse.base_url_no_prefix}#{public_send(url_method(params.slice(:category, :parent_category)))}"
|
||||||
|
@ -297,7 +298,8 @@ class TagsController < ::ApplicationController
|
||||||
if params[:tag_id] == 'none'
|
if params[:tag_id] == 'none'
|
||||||
options[:no_tags] = true
|
options[:no_tags] = true
|
||||||
else
|
else
|
||||||
options[:tags] = [params[:tag_id]]
|
options[:tags] = [params[:tag_id], params[:secondary_tag_id]].compact
|
||||||
|
options[:match_all_tags] = true
|
||||||
end
|
end
|
||||||
|
|
||||||
options
|
options
|
||||||
|
|
|
@ -630,6 +630,7 @@ Discourse::Application.routes.draw do
|
||||||
get '/:tag_id' => 'tags#show', as: 'tag_show'
|
get '/:tag_id' => 'tags#show', as: 'tag_show'
|
||||||
get '/c/:category/:tag_id' => 'tags#show', as: 'tag_category_show'
|
get '/c/:category/:tag_id' => 'tags#show', as: 'tag_category_show'
|
||||||
get '/c/:parent_category/:category/:tag_id' => 'tags#show', as: 'tag_parent_category_category_show'
|
get '/c/:parent_category/:category/:tag_id' => 'tags#show', as: 'tag_parent_category_category_show'
|
||||||
|
get '/intersection/:tag_id/:secondary_tag_id' => 'tags#show', as: 'tag_intersection'
|
||||||
get '/:tag_id/notifications' => 'tags#notifications'
|
get '/:tag_id/notifications' => 'tags#notifications'
|
||||||
put '/:tag_id/notifications' => 'tags#update_notifications'
|
put '/:tag_id/notifications' => 'tags#update_notifications'
|
||||||
put '/:tag_id' => 'tags#update'
|
put '/:tag_id' => 'tags#update'
|
||||||
|
|
|
@ -20,6 +20,7 @@ class TopicQuery
|
||||||
visible
|
visible
|
||||||
category
|
category
|
||||||
tags
|
tags
|
||||||
|
match_all_tags
|
||||||
no_tags
|
no_tags
|
||||||
order
|
order
|
||||||
ascending
|
ascending
|
||||||
|
@ -460,11 +461,21 @@ class TopicQuery
|
||||||
|
|
||||||
if @options[:tags] && @options[:tags].size > 0
|
if @options[:tags] && @options[:tags].size > 0
|
||||||
result = result.joins(:tags)
|
result = result.joins(:tags)
|
||||||
# ANY of the given tags:
|
|
||||||
if @options[:tags][0].is_a?(Integer)
|
# ALL of the given tags:
|
||||||
result = result.where("tags.id in (?)", @options[:tags])
|
if @options[:match_all_tags]
|
||||||
|
@options[:tags] = Tag.where(name: @options[:tags]).pluck(:id) unless @options[:tags][0].is_a?(Integer)
|
||||||
|
@options[:tags].each_with_index do |tag, index|
|
||||||
|
sql_alias = ['t', index].join
|
||||||
|
result = result.joins("INNER JOIN topic_tags #{sql_alias} ON #{sql_alias}.topic_id = topics.id AND #{sql_alias}.tag_id = #{tag}")
|
||||||
|
end
|
||||||
else
|
else
|
||||||
result = result.where("tags.name in (?)", @options[:tags])
|
# ANY of the given tags:
|
||||||
|
if @options[:tags][0].is_a?(Integer)
|
||||||
|
result = result.where("tags.id in (?)", @options[:tags])
|
||||||
|
else
|
||||||
|
result = result.where("tags.name in (?)", @options[:tags])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
elsif @options[:no_tags]
|
elsif @options[:no_tags]
|
||||||
# the following will do: ("topics"."id" NOT IN (SELECT DISTINCT "topic_tags"."topic_id" FROM "topic_tags"))
|
# the following will do: ("topics"."id" NOT IN (SELECT DISTINCT "topic_tags"."topic_id" FROM "topic_tags"))
|
||||||
|
|
|
@ -145,6 +145,10 @@ describe TopicQuery do
|
||||||
# expect(TopicQuery.new(moderator, tags: [tag.id, other_tag.id]).list_latest.topics.map(&:id)).to eq([tagged_topic3.id].sort)
|
# expect(TopicQuery.new(moderator, tags: [tag.id, other_tag.id]).list_latest.topics.map(&:id)).to eq([tagged_topic3.id].sort)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can return topics with all specified tags" do
|
||||||
|
expect(TopicQuery.new(moderator, tags: [tag.name, other_tag.name], match_all_tags: true).list_latest.topics.map(&:id)).to eq([tagged_topic3.id])
|
||||||
|
end
|
||||||
|
|
||||||
it "can return topics with no tags" do
|
it "can return topics with no tags" do
|
||||||
expect(TopicQuery.new(moderator, no_tags: true).list_latest.topics.map(&:id)).to eq([no_tags_topic.id])
|
expect(TopicQuery.new(moderator, no_tags: true).list_latest.topics.map(&:id)).to eq([no_tags_topic.id])
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,9 +3,13 @@ require 'rails_helper'
|
||||||
describe TagsController do
|
describe TagsController do
|
||||||
describe 'show_latest' do
|
describe 'show_latest' do
|
||||||
let(:tag) { Fabricate(:tag) }
|
let(:tag) { Fabricate(:tag) }
|
||||||
|
let(:other_tag) { Fabricate(:tag) }
|
||||||
let(:category) { Fabricate(:category) }
|
let(:category) { Fabricate(:category) }
|
||||||
let(:subcategory) { Fabricate(:category, parent_category_id: category.id) }
|
let(:subcategory) { Fabricate(:category, parent_category_id: category.id) }
|
||||||
|
|
||||||
|
let(:single_tag_topic) { Fabricate(:topic, tags: [tag]) }
|
||||||
|
let(:multi_tag_topic) { Fabricate(:topic, tags: [tag, other_tag]) }
|
||||||
|
|
||||||
context 'tagging disabled' do
|
context 'tagging disabled' do
|
||||||
it "returns 404" do
|
it "returns 404" do
|
||||||
xhr :get, :show_latest, tag_id: tag.name
|
xhr :get, :show_latest, tag_id: tag.name
|
||||||
|
@ -23,6 +27,14 @@ describe TagsController do
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can filter by multiple tags" do
|
||||||
|
single_tag_topic; multi_tag_topic
|
||||||
|
xhr :get, :show_latest, tag_id: tag.name, secondary_tag_id: other_tag.name
|
||||||
|
expect(response).to be_success
|
||||||
|
expect(assigns(:list).topics).to include multi_tag_topic
|
||||||
|
expect(assigns(:list).topics).to_not include single_tag_topic
|
||||||
|
end
|
||||||
|
|
||||||
it "can filter by category and tag" do
|
it "can filter by category and tag" do
|
||||||
xhr :get, :show_latest, tag_id: tag.name, category: category.slug
|
xhr :get, :show_latest, tag_id: tag.name, category: category.slug
|
||||||
expect(response).to be_success
|
expect(response).to be_success
|
||||||
|
|
Loading…
Reference in New Issue