mirror of
https://github.com/discourse/discourse.git
synced 2025-06-04 10:54:50 +08:00
FEATURE: add period filter in top topics route for tags. (#13415)
And also move all the "top topics by period" routes to query string param. /top/monthly => /top?period=monthly /c/:slug/:id/l/top/monthly => /c/:slug/:id/l/top?period=monthly /tag/:slug/l/top/daily => /tag/:slug/l/top?period=daily (new)
This commit is contained in:
@ -13,6 +13,7 @@ export const queryParams = {
|
|||||||
before: { replace: true, refreshModel: true },
|
before: { replace: true, refreshModel: true },
|
||||||
bumped_before: { replace: true, refreshModel: true },
|
bumped_before: { replace: true, refreshModel: true },
|
||||||
f: { replace: true, refreshModel: true },
|
f: { replace: true, refreshModel: true },
|
||||||
|
period: { replace: true, refreshModel: true },
|
||||||
};
|
};
|
||||||
|
|
||||||
// Basic controller options
|
// Basic controller options
|
||||||
|
@ -37,9 +37,10 @@ export default Controller.extend({
|
|||||||
}/l`;
|
}/l`;
|
||||||
}
|
}
|
||||||
|
|
||||||
url += "/top/" + period;
|
url += "/top";
|
||||||
|
|
||||||
const queryParams = this.router.currentRoute.queryParams;
|
let queryParams = this.router.currentRoute.queryParams;
|
||||||
|
queryParams.period = period;
|
||||||
if (Object.keys(queryParams).length) {
|
if (Object.keys(queryParams).length) {
|
||||||
url =
|
url =
|
||||||
`${url}?` +
|
`${url}?` +
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
import {
|
import { alias, empty, equal, gt, not, readOnly } from "@ember/object/computed";
|
||||||
alias,
|
|
||||||
empty,
|
|
||||||
equal,
|
|
||||||
gt,
|
|
||||||
not,
|
|
||||||
notEmpty,
|
|
||||||
readOnly,
|
|
||||||
} from "@ember/object/computed";
|
|
||||||
import BulkTopicSelection from "discourse/mixins/bulk-topic-selection";
|
import BulkTopicSelection from "discourse/mixins/bulk-topic-selection";
|
||||||
import DiscoveryController from "discourse/controllers/discovery";
|
import DiscoveryController from "discourse/controllers/discovery";
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
@ -140,7 +132,7 @@ const controllerOpts = {
|
|||||||
allLoaded: empty("model.more_topics_url"),
|
allLoaded: empty("model.more_topics_url"),
|
||||||
latest: endWith("model.filter", "latest"),
|
latest: endWith("model.filter", "latest"),
|
||||||
new: endWith("model.filter", "new"),
|
new: endWith("model.filter", "new"),
|
||||||
top: notEmpty("period"),
|
top: endWith("model.filter", "top"),
|
||||||
yearly: equal("period", "yearly"),
|
yearly: equal("period", "yearly"),
|
||||||
quarterly: equal("period", "quarterly"),
|
quarterly: equal("period", "quarterly"),
|
||||||
monthly: equal("period", "monthly"),
|
monthly: equal("period", "monthly"),
|
||||||
|
@ -8,6 +8,7 @@ import Topic from "discourse/models/topic";
|
|||||||
import { alias } from "@ember/object/computed";
|
import { alias } from "@ember/object/computed";
|
||||||
import bootbox from "bootbox";
|
import bootbox from "bootbox";
|
||||||
import { queryParams } from "discourse/controllers/discovery-sortable";
|
import { queryParams } from "discourse/controllers/discovery-sortable";
|
||||||
|
import { endWith } from "discourse/lib/computed";
|
||||||
|
|
||||||
export default Controller.extend(BulkTopicSelection, FilterModeMixin, {
|
export default Controller.extend(BulkTopicSelection, FilterModeMixin, {
|
||||||
application: controller(),
|
application: controller(),
|
||||||
@ -27,6 +28,8 @@ export default Controller.extend(BulkTopicSelection, FilterModeMixin, {
|
|||||||
max_posts: null,
|
max_posts: null,
|
||||||
q: null,
|
q: null,
|
||||||
showInfo: false,
|
showInfo: false,
|
||||||
|
top: endWith("list.filter", "top"),
|
||||||
|
period: alias("list.for_period"),
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"canCreateTopic",
|
"canCreateTopic",
|
||||||
@ -131,8 +134,30 @@ export default Controller.extend(BulkTopicSelection, FilterModeMixin, {
|
|||||||
this.setProperties({ order, ascending: false });
|
this.setProperties({ order, ascending: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let params = { order, ascending: this.ascending };
|
||||||
|
if (this.period) {
|
||||||
|
params.period = this.period;
|
||||||
|
}
|
||||||
|
|
||||||
this.transitionToRoute({
|
this.transitionToRoute({
|
||||||
queryParams: { order, ascending: this.ascending },
|
queryParams: params,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
changePeriod(p) {
|
||||||
|
this.set("period", p);
|
||||||
|
|
||||||
|
let params = { period: this.period };
|
||||||
|
|
||||||
|
if (!(this.order === "default" && this.ascending === false)) {
|
||||||
|
params = Object.assign(params, {
|
||||||
|
order: this.order,
|
||||||
|
ascending: this.ascending,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.transitionToRoute({
|
||||||
|
queryParams: params,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -36,13 +36,7 @@ export default Mixin.create({
|
|||||||
|
|
||||||
set(key, value) {
|
set(key, value) {
|
||||||
this.set("rawFilterMode", value);
|
this.set("rawFilterMode", value);
|
||||||
const parts = value.split("/");
|
this.set("filterType", value.split("/").pop());
|
||||||
|
|
||||||
if (parts.length >= 2 && parts[parts.length - 2] === "top") {
|
|
||||||
this.set("filterType", "top");
|
|
||||||
} else {
|
|
||||||
this.set("filterType", parts.pop());
|
|
||||||
}
|
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
|
@ -34,7 +34,18 @@ export default {
|
|||||||
app[
|
app[
|
||||||
`Discovery${filterCapitalized}CategoryNoneController`
|
`Discovery${filterCapitalized}CategoryNoneController`
|
||||||
] = DiscoverySortableController.extend();
|
] = DiscoverySortableController.extend();
|
||||||
if (filter !== "top") {
|
|
||||||
|
if (filter === "top") {
|
||||||
|
app.DiscoveryTopRoute = buildTopicRoute("top", {
|
||||||
|
actions: {
|
||||||
|
willTransition() {
|
||||||
|
User.currentProp("should_be_redirected_to_top", false);
|
||||||
|
User.currentProp("redirected_to_top.reason", null);
|
||||||
|
return this._super(...arguments);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
app[`Discovery${filterCapitalized}Route`] = buildTopicRoute(filter);
|
app[`Discovery${filterCapitalized}Route`] = buildTopicRoute(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,38 +57,6 @@ export default {
|
|||||||
] = buildCategoryRoute(filter, { no_subcategories: true });
|
] = buildCategoryRoute(filter, { no_subcategories: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
app.DiscoveryTopRoute = buildTopicRoute("top", {
|
|
||||||
actions: {
|
|
||||||
willTransition() {
|
|
||||||
User.currentProp("should_be_redirected_to_top", false);
|
|
||||||
User.currentProp("redirected_to_top.reason", null);
|
|
||||||
return this._super(...arguments);
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
site.get("periods").forEach((period) => {
|
|
||||||
const periodCapitalized = period.capitalize();
|
|
||||||
app[
|
|
||||||
`DiscoveryTop${periodCapitalized}Controller`
|
|
||||||
] = DiscoverySortableController.extend();
|
|
||||||
app[
|
|
||||||
`DiscoveryTop${periodCapitalized}CategoryController`
|
|
||||||
] = DiscoverySortableController.extend();
|
|
||||||
app[
|
|
||||||
`DiscoveryTop${periodCapitalized}CategoryNoneController`
|
|
||||||
] = DiscoverySortableController.extend();
|
|
||||||
app[`DiscoveryTop${periodCapitalized}Route`] = buildTopicRoute(
|
|
||||||
"top/" + period
|
|
||||||
);
|
|
||||||
app[`DiscoveryTop${periodCapitalized}CategoryRoute`] = buildCategoryRoute(
|
|
||||||
"top/" + period
|
|
||||||
);
|
|
||||||
app[
|
|
||||||
`DiscoveryTop${periodCapitalized}CategoryNoneRoute`
|
|
||||||
] = buildCategoryRoute("top/" + period, { no_subcategories: true });
|
|
||||||
});
|
|
||||||
|
|
||||||
app["TagsShowCategoryRoute"] = TagShowRoute.extend();
|
app["TagsShowCategoryRoute"] = TagShowRoute.extend();
|
||||||
app["TagsShowCategoryNoneRoute"] = TagShowRoute.extend({
|
app["TagsShowCategoryNoneRoute"] = TagShowRoute.extend({
|
||||||
noSubcategories: true,
|
noSubcategories: true,
|
||||||
|
@ -27,14 +27,7 @@ export default function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.route("discovery", { path: "/", resetNamespace: true }, function () {
|
this.route("discovery", { path: "/", resetNamespace: true }, function () {
|
||||||
// top
|
// top by periods - legacy route
|
||||||
this.route("top");
|
|
||||||
this.route("topCategoryNone", {
|
|
||||||
path: "/c/*category_slug_path_with_id/none/l/top",
|
|
||||||
});
|
|
||||||
this.route("topCategory", { path: "/c/*category_slug_path_with_id/l/top" });
|
|
||||||
|
|
||||||
// top by periods
|
|
||||||
Site.currentProp("periods").forEach((period) => {
|
Site.currentProp("periods").forEach((period) => {
|
||||||
const top = "top" + period.capitalize();
|
const top = "top" + period.capitalize();
|
||||||
|
|
||||||
@ -47,7 +40,7 @@ export default function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// filters (e.g. bookmarks, posted, read, unread, latest)
|
// filters (e.g. bookmarks, posted, read, unread, latest, top)
|
||||||
Site.currentProp("filters").forEach((filter) => {
|
Site.currentProp("filters").forEach((filter) => {
|
||||||
this.route(filter, { path: "/" + filter });
|
this.route(filter, { path: "/" + filter });
|
||||||
this.route(filter + "CategoryNone", {
|
this.route(filter + "CategoryNone", {
|
||||||
|
@ -148,8 +148,7 @@ export default (filterArg, params) => {
|
|||||||
category = model.category,
|
category = model.category,
|
||||||
canCreateTopic = topics.get("can_create_topic"),
|
canCreateTopic = topics.get("can_create_topic"),
|
||||||
canCreateTopicOnCategory =
|
canCreateTopicOnCategory =
|
||||||
canCreateTopic && category.get("permission") === PermissionType.FULL,
|
canCreateTopic && category.get("permission") === PermissionType.FULL;
|
||||||
filter = this.filter(category);
|
|
||||||
|
|
||||||
this.controllerFor("navigation/category").setProperties({
|
this.controllerFor("navigation/category").setProperties({
|
||||||
canCreateTopicOnCategory: canCreateTopicOnCategory,
|
canCreateTopicOnCategory: canCreateTopicOnCategory,
|
||||||
@ -162,7 +161,7 @@ export default (filterArg, params) => {
|
|||||||
category,
|
category,
|
||||||
period:
|
period:
|
||||||
topics.get("for_period") ||
|
topics.get("for_period") ||
|
||||||
(filter.indexOf("/") > 0 ? filter.split("/")[1] : ""),
|
(model.modelParams && model.modelParams.period),
|
||||||
selected: [],
|
selected: [],
|
||||||
noSubcategories: params && !!params.no_subcategories,
|
noSubcategories: params && !!params.no_subcategories,
|
||||||
expandAllPinned: true,
|
expandAllPinned: true,
|
||||||
|
@ -130,9 +130,7 @@ export default function (filter, extras) {
|
|||||||
const topicOpts = {
|
const topicOpts = {
|
||||||
model,
|
model,
|
||||||
category: null,
|
category: null,
|
||||||
period:
|
period: model.get("for_period") || model.get("params.period"),
|
||||||
model.get("for_period") ||
|
|
||||||
(filter.indexOf("top/") >= 0 ? filter.split("/")[1] : ""),
|
|
||||||
selected: [],
|
selected: [],
|
||||||
expandAllPinned: false,
|
expandAllPinned: false,
|
||||||
expandGloballyPinned: true,
|
expandGloballyPinned: true,
|
||||||
|
@ -7,6 +7,7 @@ import OpenComposer from "discourse/mixins/open-composer";
|
|||||||
import User from "discourse/models/user";
|
import User from "discourse/models/user";
|
||||||
import { scrollTop } from "discourse/mixins/scroll-top";
|
import { scrollTop } from "discourse/mixins/scroll-top";
|
||||||
import { setTopicList } from "discourse/lib/topic-list-tracker";
|
import { setTopicList } from "discourse/lib/topic-list-tracker";
|
||||||
|
import Site from "discourse/models/site";
|
||||||
|
|
||||||
export default DiscourseRoute.extend(OpenComposer, {
|
export default DiscourseRoute.extend(OpenComposer, {
|
||||||
queryParams: {
|
queryParams: {
|
||||||
@ -19,6 +20,7 @@ export default DiscourseRoute.extend(OpenComposer, {
|
|||||||
|
|
||||||
beforeModel(transition) {
|
beforeModel(transition) {
|
||||||
const url = transition.intent.url;
|
const url = transition.intent.url;
|
||||||
|
let matches;
|
||||||
if (
|
if (
|
||||||
(url === "/" || url === "/latest" || url === "/categories") &&
|
(url === "/" || url === "/latest" || url === "/categories") &&
|
||||||
transition.targetName.indexOf("discovery.top") === -1 &&
|
transition.targetName.indexOf("discovery.top") === -1 &&
|
||||||
@ -26,7 +28,19 @@ export default DiscourseRoute.extend(OpenComposer, {
|
|||||||
) {
|
) {
|
||||||
User.currentProp("should_be_redirected_to_top", false);
|
User.currentProp("should_be_redirected_to_top", false);
|
||||||
const period = User.currentProp("redirected_to_top.period") || "all";
|
const period = User.currentProp("redirected_to_top.period") || "all";
|
||||||
this.replaceWith(`discovery.top${period.capitalize()}`);
|
this.replaceWith("discovery.top", {
|
||||||
|
queryParams: {
|
||||||
|
period: period,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else if (url && (matches = url.match(/top\/(.*)$/))) {
|
||||||
|
if (Site.currentProp("periods").includes(matches[1])) {
|
||||||
|
this.replaceWith("discovery.top", {
|
||||||
|
queryParams: {
|
||||||
|
period: matches[1],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -45,21 +45,26 @@
|
|||||||
<div class="full-width">
|
<div class="full-width">
|
||||||
<div id="list-area">
|
<div id="list-area">
|
||||||
{{#unless loading}}
|
{{#unless loading}}
|
||||||
{{#if list.topics}}
|
{{#discovery-topics-list
|
||||||
{{#discovery-topics-list
|
model=list
|
||||||
model=list
|
refresh=(action "refresh")
|
||||||
refresh=(action "refresh")
|
autoAddTopicsToBulkSelect=autoAddTopicsToBulkSelect
|
||||||
autoAddTopicsToBulkSelect=autoAddTopicsToBulkSelect
|
bulkSelectEnabled=bulkSelectEnabled
|
||||||
bulkSelectEnabled=bulkSelectEnabled
|
addTopicsToBulkSelect=(action "addTopicsToBulkSelect")
|
||||||
addTopicsToBulkSelect=(action "addTopicsToBulkSelect")
|
as |discoveryTopicList|
|
||||||
as |discoveryTopicList|
|
}}
|
||||||
|
{{#if top}}
|
||||||
|
<div class="top-lists">
|
||||||
|
{{period-chooser period=period action=(action "changePeriod") fullDay=false}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
{{bulk-select-button
|
||||||
|
selected=selected
|
||||||
|
action=(action "refresh")
|
||||||
|
category=category
|
||||||
}}
|
}}
|
||||||
{{bulk-select-button
|
|
||||||
selected=selected
|
|
||||||
action=(action "refresh")
|
|
||||||
category=category
|
|
||||||
}}
|
|
||||||
|
|
||||||
|
{{#if list.topics}}
|
||||||
{{topic-list
|
{{topic-list
|
||||||
topics=list.topics
|
topics=list.topics
|
||||||
canBulkSelect=canBulkSelect
|
canBulkSelect=canBulkSelect
|
||||||
@ -74,8 +79,8 @@
|
|||||||
onScroll=discoveryTopicList.saveScrollPosition
|
onScroll=discoveryTopicList.saveScrollPosition
|
||||||
scrollOnLoad=true
|
scrollOnLoad=true
|
||||||
}}
|
}}
|
||||||
{{/discovery-topics-list}}
|
{{/if}}
|
||||||
{{/if}}
|
{{/discovery-topics-list}}
|
||||||
|
|
||||||
<footer class="topic-list-bottom">
|
<footer class="topic-list-bottom">
|
||||||
{{topic-dismiss-buttons position="bottom" selectedTopics=selected
|
{{topic-dismiss-buttons position="bottom" selectedTopics=selected
|
||||||
|
@ -2,13 +2,13 @@ import {
|
|||||||
acceptance,
|
acceptance,
|
||||||
updateCurrentUser,
|
updateCurrentUser,
|
||||||
} from "discourse/tests/helpers/qunit-helpers";
|
} from "discourse/tests/helpers/qunit-helpers";
|
||||||
import { currentRouteName, visit } from "@ember/test-helpers";
|
import { currentURL, visit } from "@ember/test-helpers";
|
||||||
import DiscoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
|
import DiscoveryFixtures from "discourse/tests/fixtures/discovery-fixtures";
|
||||||
import { test } from "qunit";
|
import { test } from "qunit";
|
||||||
|
|
||||||
acceptance("Redirect to Top", function (needs) {
|
acceptance("Redirect to Top", function (needs) {
|
||||||
needs.pretender((server, helper) => {
|
needs.pretender((server, helper) => {
|
||||||
server.get("/top/weekly.json", () => {
|
server.get("/top.json?period=weekly", () => {
|
||||||
return helper.response(DiscoveryFixtures["/latest.json"]);
|
return helper.response(DiscoveryFixtures["/latest.json"]);
|
||||||
});
|
});
|
||||||
server.get("/top/monthly.json", () => {
|
server.get("/top/monthly.json", () => {
|
||||||
@ -30,11 +30,7 @@ acceptance("Redirect to Top", function (needs) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await visit("/categories");
|
await visit("/categories");
|
||||||
assert.equal(
|
assert.equal(currentURL(), "/top?period=weekly", "it works for categories");
|
||||||
currentRouteName(),
|
|
||||||
"discovery.topWeekly",
|
|
||||||
"it works for categories"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("redirects latest to monthly top", async function (assert) {
|
test("redirects latest to monthly top", async function (assert) {
|
||||||
@ -47,11 +43,7 @@ acceptance("Redirect to Top", function (needs) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await visit("/latest");
|
await visit("/latest");
|
||||||
assert.equal(
|
assert.equal(currentURL(), "/top?period=monthly", "it works for latest");
|
||||||
currentRouteName(),
|
|
||||||
"discovery.topMonthly",
|
|
||||||
"it works for latest"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("redirects root to All top", async function (assert) {
|
test("redirects root to All top", async function (assert) {
|
||||||
@ -64,6 +56,6 @@ acceptance("Redirect to Top", function (needs) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
await visit("/");
|
await visit("/");
|
||||||
assert.equal(currentRouteName(), "discovery.topAll", "it works for root");
|
assert.equal(currentURL(), "/top?period=all", "it works for root");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -124,7 +124,7 @@ acceptance("Topic Discovery", function (needs) {
|
|||||||
await periodChooser.selectRowByValue("yearly");
|
await periodChooser.selectRowByValue("yearly");
|
||||||
|
|
||||||
assert.ok(
|
assert.ok(
|
||||||
DiscourseURL.routeTo.calledWith("/top/yearly?f=foo&d=bar"),
|
DiscourseURL.routeTo.calledWith("/top?f=foo&d=bar&period=yearly"),
|
||||||
"it keeps the query params"
|
"it keeps the query params"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -35,6 +35,7 @@ export default {
|
|||||||
"latest",
|
"latest",
|
||||||
"unread",
|
"unread",
|
||||||
"new",
|
"new",
|
||||||
|
"top",
|
||||||
"starred",
|
"starred",
|
||||||
"read",
|
"read",
|
||||||
"posted",
|
"posted",
|
||||||
|
@ -40,6 +40,7 @@ PreloadStore.store("site", {
|
|||||||
"latest",
|
"latest",
|
||||||
"unread",
|
"unread",
|
||||||
"new",
|
"new",
|
||||||
|
"top",
|
||||||
"starred",
|
"starred",
|
||||||
"read",
|
"read",
|
||||||
"posted",
|
"posted",
|
||||||
|
@ -84,6 +84,7 @@ class ListController < ApplicationController
|
|||||||
if Discourse.anonymous_filters.include?(filter)
|
if Discourse.anonymous_filters.include?(filter)
|
||||||
@description = SiteSetting.site_description
|
@description = SiteSetting.site_description
|
||||||
@rss = filter
|
@rss = filter
|
||||||
|
@rss_description = filter
|
||||||
|
|
||||||
# Note the first is the default and we don't add a title
|
# Note the first is the default and we don't add a title
|
||||||
if (filter.to_s != current_homepage) && use_crawler_layout?
|
if (filter.to_s != current_homepage) && use_crawler_layout?
|
||||||
@ -216,7 +217,8 @@ class ListController < ApplicationController
|
|||||||
@link = "#{Discourse.base_url}/top"
|
@link = "#{Discourse.base_url}/top"
|
||||||
@atom_link = "#{Discourse.base_url}/top.rss"
|
@atom_link = "#{Discourse.base_url}/top.rss"
|
||||||
@description = I18n.t("rss_description.top")
|
@description = I18n.t("rss_description.top")
|
||||||
@topic_list = TopicQuery.new(nil).list_top_for(SiteSetting.top_page_default_timeframe.to_sym)
|
period = params[:period] || SiteSetting.top_page_default_timeframe.to_sym
|
||||||
|
@topic_list = TopicQuery.new(nil).list_top_for(period)
|
||||||
|
|
||||||
render 'list', formats: [:rss]
|
render 'list', formats: [:rss]
|
||||||
end
|
end
|
||||||
@ -253,7 +255,8 @@ class ListController < ApplicationController
|
|||||||
|
|
||||||
def top(options = nil)
|
def top(options = nil)
|
||||||
options ||= {}
|
options ||= {}
|
||||||
period = ListController.best_period_for(current_user.try(:previous_visit_at), options[:category])
|
period = params[:period]
|
||||||
|
period ||= ListController.best_period_for(current_user.try(:previous_visit_at), options[:category])
|
||||||
public_send("top_#{period}", options)
|
public_send("top_#{period}", options)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -276,7 +279,9 @@ class ListController < ApplicationController
|
|||||||
list.for_period = period
|
list.for_period = period
|
||||||
list.more_topics_url = construct_url_with(:next, top_options)
|
list.more_topics_url = construct_url_with(:next, top_options)
|
||||||
list.prev_topics_url = construct_url_with(:prev, top_options)
|
list.prev_topics_url = construct_url_with(:prev, top_options)
|
||||||
@rss = "top_#{period}"
|
@rss = "top"
|
||||||
|
@params = { period: period }
|
||||||
|
@rss_description = "top_#{period}"
|
||||||
|
|
||||||
if use_crawler_layout?
|
if use_crawler_layout?
|
||||||
@title = I18n.t("js.filters.top.#{period}.title") + " - #{SiteSetting.title}"
|
@title = I18n.t("js.filters.top.#{period}.title") + " - #{SiteSetting.title}"
|
||||||
@ -302,8 +307,8 @@ class ListController < ApplicationController
|
|||||||
|
|
||||||
@description = I18n.t("rss_description.top_#{period}")
|
@description = I18n.t("rss_description.top_#{period}")
|
||||||
@title = "#{SiteSetting.title} - #{@description}"
|
@title = "#{SiteSetting.title} - #{@description}"
|
||||||
@link = "#{Discourse.base_url}/top/#{period}"
|
@link = "#{Discourse.base_url}/top?period=#{period}"
|
||||||
@atom_link = "#{Discourse.base_url}/top/#{period}.rss"
|
@atom_link = "#{Discourse.base_url}/top.rss?period=#{period}"
|
||||||
@topic_list = TopicQuery.new(nil).list_top_for(period)
|
@topic_list = TopicQuery.new(nil).list_top_for(period)
|
||||||
|
|
||||||
render 'list', formats: [:rss]
|
render 'list', formats: [:rss]
|
||||||
@ -338,6 +343,7 @@ class ListController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
route_params[:username] = UrlHelper.encode_component(params[:username]) if params[:username].present?
|
route_params[:username] = UrlHelper.encode_component(params[:username]) if params[:username].present?
|
||||||
|
route_params[:period] = params[:period] if params[:period].present?
|
||||||
route_params
|
route_params
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -89,7 +89,9 @@ class TagsController < ::ApplicationController
|
|||||||
@list = nil
|
@list = nil
|
||||||
|
|
||||||
if filter == :top
|
if filter == :top
|
||||||
@list = TopicQuery.new(current_user, list_opts).public_send("list_top_for", SiteSetting.top_page_default_timeframe.to_sym)
|
period = params[:period] || SiteSetting.top_page_default_timeframe.to_sym
|
||||||
|
@list = TopicQuery.new(current_user, list_opts).public_send("list_top_for", period)
|
||||||
|
@list.for_period = period
|
||||||
else
|
else
|
||||||
@list = TopicQuery.new(current_user, list_opts).public_send("list_#{filter}")
|
@list = TopicQuery.new(current_user, list_opts).public_send("list_#{filter}")
|
||||||
end
|
end
|
||||||
|
@ -8,10 +8,6 @@ class ApiKeyScope < ActiveRecord::Base
|
|||||||
def list_actions
|
def list_actions
|
||||||
actions = %w[list#category_feed]
|
actions = %w[list#category_feed]
|
||||||
|
|
||||||
TopTopic.periods.each do |p|
|
|
||||||
actions.concat(["list#category_top_#{p}", "list#top_#{p}", "list#top_#{p}_feed"])
|
|
||||||
end
|
|
||||||
|
|
||||||
%i[latest unread new top].each { |f| actions.concat(["list#category_#{f}", "list##{f}"]) }
|
%i[latest unread new top].each { |f| actions.concat(["list#category_#{f}", "list##{f}"]) }
|
||||||
|
|
||||||
actions
|
actions
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class TopListSerializer < ApplicationSerializer
|
|
||||||
|
|
||||||
attributes :can_create_topic
|
|
||||||
|
|
||||||
def can_create_topic
|
|
||||||
scope.can_create?(Topic)
|
|
||||||
end
|
|
||||||
|
|
||||||
TopTopic.periods.each do |period|
|
|
||||||
attribute period
|
|
||||||
|
|
||||||
define_method(period) do
|
|
||||||
if resolved = object.public_send(period)
|
|
||||||
TopicListSerializer.new(resolved, scope: scope).as_json
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -136,7 +136,7 @@
|
|||||||
<% if @rss %>
|
<% if @rss %>
|
||||||
<% content_for :head do %>
|
<% content_for :head do %>
|
||||||
<%= auto_discovery_link_tag(:rss, "#{Discourse.base_url}/posts.rss", title: I18n.t("rss_description.posts")) %>
|
<%= auto_discovery_link_tag(:rss, "#{Discourse.base_url}/posts.rss", title: I18n.t("rss_description.posts")) %>
|
||||||
<%= auto_discovery_link_tag(:rss, { action: "#{@rss}_feed" }, title: I18n.t("rss_description.#{@rss}")) %>
|
<%= auto_discovery_link_tag(:rss, { action: "#{@rss}_feed", params: @params || {} }, title: I18n.t("rss_description.#{@rss_description}")) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
@ -705,8 +705,8 @@ Discourse::Application.routes.draw do
|
|||||||
get "/none" => "list#category_none_latest"
|
get "/none" => "list#category_none_latest"
|
||||||
|
|
||||||
TopTopic.periods.each do |period|
|
TopTopic.periods.each do |period|
|
||||||
get "/none/l/top/#{period}" => "list#category_none_top_#{period}", as: "category_none_top_#{period}"
|
get "/none/l/top/#{period}", to: redirect("/none/l/top?period=#{period}", status: 301)
|
||||||
get "/l/top/#{period}" => "list#category_top_#{period}", as: "category_top_#{period}"
|
get "/l/top/#{period}", to: redirect("/l/top?period=#{period}", status: 301)
|
||||||
end
|
end
|
||||||
|
|
||||||
Discourse.filters.each do |filter|
|
Discourse.filters.each do |filter|
|
||||||
@ -721,8 +721,9 @@ Discourse::Application.routes.draw do
|
|||||||
get "hashtags" => "hashtags#show"
|
get "hashtags" => "hashtags#show"
|
||||||
|
|
||||||
TopTopic.periods.each do |period|
|
TopTopic.periods.each do |period|
|
||||||
get "top/#{period}.rss" => "list#top_#{period}_feed", format: :rss
|
get "top/#{period}.rss", to: redirect("top.rss?period=#{period}", status: 301)
|
||||||
get "top/#{period}" => "list#top_#{period}"
|
get "top/#{period}.json", to: redirect("top.json?period=#{period}", status: 301)
|
||||||
|
get "top/#{period}", to: redirect("top?period=#{period}", status: 301)
|
||||||
end
|
end
|
||||||
|
|
||||||
Discourse.anonymous_filters.each do |filter|
|
Discourse.anonymous_filters.each do |filter|
|
||||||
|
@ -743,7 +743,7 @@ describe 'topics' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
path '/top/{flag}.json' do
|
path '/top.json?period={flag}' do
|
||||||
get 'Get the top topics filtered by a flag' do
|
get 'Get the top topics filtered by a flag' do
|
||||||
tags 'Topics'
|
tags 'Topics'
|
||||||
consumes 'application/json'
|
consumes 'application/json'
|
||||||
|
@ -412,7 +412,7 @@ RSpec.describe ListController do
|
|||||||
|
|
||||||
TopTopic.periods.each do |period|
|
TopTopic.periods.each do |period|
|
||||||
it "renders #{period} top RSS" do
|
it "renders #{period} top RSS" do
|
||||||
get "/top/#{period}.rss"
|
get "/top.rss?period=#{period}"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
expect(response.media_type).to eq('application/rss+xml')
|
expect(response.media_type).to eq('application/rss+xml')
|
||||||
end
|
end
|
||||||
|
@ -683,11 +683,13 @@ describe TagsController do
|
|||||||
fab!(:category) { Fabricate(:category) }
|
fab!(:category) { Fabricate(:category) }
|
||||||
fab!(:topic) { Fabricate(:topic, category: category) }
|
fab!(:topic) { Fabricate(:topic, category: category) }
|
||||||
fab!(:tag_topic) { Fabricate(:topic, category: category, tags: [tag]) }
|
fab!(:tag_topic) { Fabricate(:topic, category: category, tags: [tag]) }
|
||||||
|
fab!(:tag_topic2) { Fabricate(:topic, category: category, tags: [tag]) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
SiteSetting.top_page_default_timeframe = 'all'
|
SiteSetting.top_page_default_timeframe = 'all'
|
||||||
TopTopic.create!(topic: topic, all_score: 1)
|
TopTopic.create!(topic: topic, all_score: 1)
|
||||||
TopTopic.create!(topic: tag_topic, all_score: 1)
|
TopTopic.create!(topic: tag_topic, all_score: 1)
|
||||||
|
TopTopic.create!(topic: tag_topic2, daily_score: 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "can filter by tag" do
|
it "can filter by tag" do
|
||||||
@ -698,6 +700,16 @@ describe TagsController do
|
|||||||
expect(topic_ids).to eq([tag_topic.id])
|
expect(topic_ids).to eq([tag_topic.id])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "can filter by tag and period" do
|
||||||
|
get "/tag/#{tag.name}/l/top.json?period=daily"
|
||||||
|
expect(response.status).to eq(200)
|
||||||
|
|
||||||
|
list = response.parsed_body["topic_list"]
|
||||||
|
topic_ids = list["topics"].map { |topic| topic["id"] }
|
||||||
|
expect(topic_ids).to eq([tag_topic2.id])
|
||||||
|
expect(list["for_period"]).to eq("daily")
|
||||||
|
end
|
||||||
|
|
||||||
it "can filter by both category and tag" do
|
it "can filter by both category and tag" do
|
||||||
get "/tags/c/#{category.slug}/#{category.id}/#{tag.name}/l/top.json"
|
get "/tags/c/#{category.slug}/#{category.id}/#{tag.name}/l/top.json"
|
||||||
expect(response.status).to eq(200)
|
expect(response.status).to eq(200)
|
||||||
|
Reference in New Issue
Block a user