add: infinitely scrolling timelines
This commit is contained in:
parent
822aaed0c8
commit
2b253c811c
12 changed files with 316 additions and 9 deletions
|
@ -97,6 +97,7 @@ pub const TIMELINES_FOLLOWING_QUESTIONS: &str =
|
||||||
pub const TIMELINES_ALL_QUESTIONS: &str =
|
pub const TIMELINES_ALL_QUESTIONS: &str =
|
||||||
include_str!("./public/html/timelines/all_questions.lisp");
|
include_str!("./public/html/timelines/all_questions.lisp");
|
||||||
pub const TIMELINES_SEARCH: &str = include_str!("./public/html/timelines/search.lisp");
|
pub const TIMELINES_SEARCH: &str = include_str!("./public/html/timelines/search.lisp");
|
||||||
|
pub const TIMELINES_SWISS_ARMY: &str = include_str!("./public/html/timelines/swiss_army.lisp");
|
||||||
|
|
||||||
pub const MOD_AUDIT_LOG: &str = include_str!("./public/html/mod/audit_log.lisp");
|
pub const MOD_AUDIT_LOG: &str = include_str!("./public/html/mod/audit_log.lisp");
|
||||||
pub const MOD_REPORTS: &str = include_str!("./public/html/mod/reports.lisp");
|
pub const MOD_REPORTS: &str = include_str!("./public/html/mod/reports.lisp");
|
||||||
|
@ -385,6 +386,7 @@ pub(crate) async fn write_assets(config: &Config) -> PathBufD {
|
||||||
write_template!(html_path->"timelines/following_questions.html"(crate::assets::TIMELINES_FOLLOWING_QUESTIONS) --config=config --lisp plugins);
|
write_template!(html_path->"timelines/following_questions.html"(crate::assets::TIMELINES_FOLLOWING_QUESTIONS) --config=config --lisp plugins);
|
||||||
write_template!(html_path->"timelines/all_questions.html"(crate::assets::TIMELINES_ALL_QUESTIONS) --config=config --lisp plugins);
|
write_template!(html_path->"timelines/all_questions.html"(crate::assets::TIMELINES_ALL_QUESTIONS) --config=config --lisp plugins);
|
||||||
write_template!(html_path->"timelines/search.html"(crate::assets::TIMELINES_SEARCH) --config=config --lisp plugins);
|
write_template!(html_path->"timelines/search.html"(crate::assets::TIMELINES_SEARCH) --config=config --lisp plugins);
|
||||||
|
write_template!(html_path->"timelines/swiss_army.html"(crate::assets::TIMELINES_SWISS_ARMY) --config=config --lisp plugins);
|
||||||
|
|
||||||
write_template!(html_path->"mod/audit_log.html"(crate::assets::MOD_AUDIT_LOG) -d "mod" --config=config --lisp plugins);
|
write_template!(html_path->"mod/audit_log.html"(crate::assets::MOD_AUDIT_LOG) -d "mod" --config=config --lisp plugins);
|
||||||
write_template!(html_path->"mod/reports.html"(crate::assets::MOD_REPORTS) --config=config --lisp plugins);
|
write_template!(html_path->"mod/reports.html"(crate::assets::MOD_REPORTS) --config=config --lisp plugins);
|
||||||
|
|
|
@ -117,7 +117,7 @@
|
||||||
(text "{{ self::post(post=post, owner=owner, secondary=secondary, community=community, show_community=show_community, can_manage_post=can_manage_post, repost=repost, expect_repost=true) }}"))
|
(text "{{ self::post(post=post, owner=owner, secondary=secondary, community=community, show_community=show_community, can_manage_post=can_manage_post, repost=repost, expect_repost=true) }}"))
|
||||||
(text "{%- endmacro %} {% macro post(post, owner, question=false, secondary=false, community=false, show_community=true, can_manage_post=false, repost=false, expect_repost=false, poll=false, dont_show_title=false) -%} {% if community and show_community and community.id != config.town_square or question %}")
|
(text "{%- endmacro %} {% macro post(post, owner, question=false, secondary=false, community=false, show_community=true, can_manage_post=false, repost=false, expect_repost=false, poll=false, dont_show_title=false) -%} {% if community and show_community and community.id != config.town_square or question %}")
|
||||||
(div
|
(div
|
||||||
("class" "card-nest")
|
("class" "card-nest post_outer:{{ post.id }}")
|
||||||
(text "{% if question -%} {{ self::question(question=question[0], owner=question[1], profile=owner) }} {% else %}")
|
(text "{% if question -%} {{ self::question(question=question[0], owner=question[1], profile=owner) }} {% else %}")
|
||||||
(div
|
(div
|
||||||
("class" "card small")
|
("class" "card small")
|
||||||
|
@ -130,8 +130,7 @@
|
||||||
(text "{% if post.context.is_pinned or post.context.is_profile_pinned -%} {{ icon \"pin\" }} {%- endif %}")))
|
(text "{% if post.context.is_pinned or post.context.is_profile_pinned -%} {{ icon \"pin\" }} {%- endif %}")))
|
||||||
(text "{%- endif %} {%- endif %}")
|
(text "{%- endif %} {%- endif %}")
|
||||||
(div
|
(div
|
||||||
("class" "card flex flex-col gap-2 {% if secondary -%}secondary{%- endif %}")
|
("class" "card flex flex-col gap-2 post:{{ post.id }} {% if secondary -%}secondary{%- endif %}")
|
||||||
("id" "post:{{ post.id }}")
|
|
||||||
("data-community" "{{ post.community }}")
|
("data-community" "{{ post.community }}")
|
||||||
("data-ownsup" "{{ owner.permissions|has_supporter }}")
|
("data-ownsup" "{{ owner.permissions|has_supporter }}")
|
||||||
("hook" "verify_emojis")
|
("hook" "verify_emojis")
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
globalThis.no_policy = false;
|
globalThis.no_policy = false;
|
||||||
|
globalThis.BUILD_CODE = \"{{ random_cache_breaker }}\";
|
||||||
</script>")
|
</script>")
|
||||||
|
|
||||||
(script ("src" "/js/loader.js" ))
|
(script ("src" "/js/loader.js" ))
|
||||||
|
|
|
@ -30,6 +30,13 @@
|
||||||
(text "{%- endif %}")
|
(text "{%- endif %}")
|
||||||
(div
|
(div
|
||||||
("class" "card w-full flex flex-col gap-2")
|
("class" "card w-full flex flex-col gap-2")
|
||||||
(text "{% for post in list %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %} {{ components::pagination(page=page, items=list|length) }}")))
|
("ui_ident" "io_data_load")
|
||||||
|
(text "{% for post in list %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %}")
|
||||||
|
(div ("ui_ident" "io_data_marker"))))
|
||||||
|
|
||||||
|
(script
|
||||||
|
(text "setTimeout(() => {
|
||||||
|
trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=AllPosts&page=\", Number.parseInt(\"{{ page }}\")]);
|
||||||
|
});"))
|
||||||
|
|
||||||
(text "{% endblock %}")
|
(text "{% endblock %}")
|
||||||
|
|
|
@ -8,6 +8,13 @@
|
||||||
(text "{{ macros::timelines_nav(selected=\"following\", posts=\"/following\", questions=\"/following/questions\") }}")
|
(text "{{ macros::timelines_nav(selected=\"following\", posts=\"/following\", questions=\"/following/questions\") }}")
|
||||||
(div
|
(div
|
||||||
("class" "card w-full flex flex-col gap-2")
|
("class" "card w-full flex flex-col gap-2")
|
||||||
(text "{% for post in list %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %} {{ components::pagination(page=page, items=list|length) }}")))
|
("ui_ident" "io_data_load")
|
||||||
|
(text "{% for post in list %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %}")
|
||||||
|
(div ("ui_ident" "io_data_marker"))))
|
||||||
|
|
||||||
|
(script
|
||||||
|
(text "setTimeout(() => {
|
||||||
|
trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=FollowingPosts&page=\", Number.parseInt(\"{{ page }}\")]);
|
||||||
|
});"))
|
||||||
|
|
||||||
(text "{% endblock %}")
|
(text "{% endblock %}")
|
||||||
|
|
|
@ -27,7 +27,14 @@
|
||||||
(text "{% else %}")
|
(text "{% else %}")
|
||||||
(div
|
(div
|
||||||
("class" "card w-full flex flex-col gap-2")
|
("class" "card w-full flex flex-col gap-2")
|
||||||
(text "{% for post in list %} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], poll=post[5]) }} {%- endif %} {% endfor %} {{ components::pagination(page=page, items=list|length) }}"))
|
("ui_ident" "io_data_load")
|
||||||
|
(text "{% for post in list %} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], poll=post[5]) }} {%- endif %} {% endfor %}")
|
||||||
|
(div ("ui_ident" "io_data_marker")))
|
||||||
(text "{%- endif %}"))
|
(text "{%- endif %}"))
|
||||||
|
|
||||||
|
(script
|
||||||
|
(text "setTimeout(() => {
|
||||||
|
trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=MyCommunities&page=\", Number.parseInt(\"{{ page }}\")]);
|
||||||
|
});"))
|
||||||
|
|
||||||
(text "{% endblock %}")
|
(text "{% endblock %}")
|
||||||
|
|
|
@ -8,6 +8,13 @@
|
||||||
(text "{{ macros::timelines_nav(selected=\"popular\", posts=\"/popular\", questions=\"/popular/questions\") }}")
|
(text "{{ macros::timelines_nav(selected=\"popular\", posts=\"/popular\", questions=\"/popular/questions\") }}")
|
||||||
(div
|
(div
|
||||||
("class" "card w-full flex flex-col gap-2")
|
("class" "card w-full flex flex-col gap-2")
|
||||||
(text "{% for post in list %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %} {{ components::pagination(page=page, items=list|length) }}")))
|
("ui_ident" "io_data_load")
|
||||||
|
(text "{% for post in list %} {% if post[2].read_access == \"Everybody\" -%} {% if post[0].context.repost and post[0].context.repost.reposting -%} {{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true) }} {% else %} {{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], poll=post[5]) }} {%- endif %} {%- endif %} {% endfor %}")
|
||||||
|
(div ("ui_ident" "io_data_marker"))))
|
||||||
|
|
||||||
|
(script
|
||||||
|
(text "setTimeout(() => {
|
||||||
|
trigger(\"ui::io_data_load\", [\"/_swiss_army_timeline?tl=PopularPosts&page=\", Number.parseInt(\"{{ page }}\")]);
|
||||||
|
});"))
|
||||||
|
|
||||||
(text "{% endblock %}")
|
(text "{% endblock %}")
|
||||||
|
|
29
crates/app/src/public/html/timelines/swiss_army.lisp
Normal file
29
crates/app/src/public/html/timelines/swiss_army.lisp
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
(text "{%- import \"components.html\" as components -%} {%- import \"macros.html\" as macros -%}")
|
||||||
|
(text "{% for post in list %}
|
||||||
|
{% if post[2].read_access == \"Everybody\" -%}
|
||||||
|
{% if post[0].context.repost and post[0].context.repost.reposting -%}
|
||||||
|
{{ components::repost(repost=post[3], post=post[0], owner=post[1], secondary=true, community=post[2], show_community=true) }}
|
||||||
|
{% else %}
|
||||||
|
{{ components::post(post=post[0], owner=post[1], question=post[4], secondary=true, community=post[2], poll=post[5]) }}
|
||||||
|
{%- endif %}
|
||||||
|
{%- endif %}
|
||||||
|
{% endfor %}")
|
||||||
|
(datalist
|
||||||
|
("ui_ident" "list_posts_{{ page }}")
|
||||||
|
(text "{% for post in list -%}")
|
||||||
|
(option ("value" "{{ post[0].id }}"))
|
||||||
|
(text "{%- endfor %}"))
|
||||||
|
(text "{% if list|length == 0 -%}")
|
||||||
|
(div
|
||||||
|
("class" "card lowered green flex justify-between items-center gap-2")
|
||||||
|
(div
|
||||||
|
("class" "flex items-center gap-2")
|
||||||
|
(text "{{ icon \"shell\" }}")
|
||||||
|
(span
|
||||||
|
(text "That's a wrap!<!-- observer_disconnect_{{ random_cache_breaker }} -->")))
|
||||||
|
(a
|
||||||
|
("class" "button")
|
||||||
|
("href" "?page=0")
|
||||||
|
(icon (text "arrow-up"))
|
||||||
|
(str (text "chats:label.go_back"))))
|
||||||
|
(text "{%- endif %}")
|
|
@ -1119,6 +1119,127 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
|
||||||
document.getElementById("lightbox").classList.add("hidden");
|
document.getElementById("lightbox").classList.add("hidden");
|
||||||
}, 250);
|
}, 250);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// intersection observer infinite scrolling
|
||||||
|
self.IO_DATA_OBSERVER = new IntersectionObserver(
|
||||||
|
async (entries) => {
|
||||||
|
for (const entry of entries) {
|
||||||
|
if (!entry.isIntersecting) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
await self.io_load_data();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
root: document.body,
|
||||||
|
rootMargin: "0px",
|
||||||
|
threshold: 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
self.define("io_data_load", (_, tmpl, page) => {
|
||||||
|
self.IO_DATA_MARKER = document.querySelector(
|
||||||
|
"[ui_ident=io_data_marker]",
|
||||||
|
);
|
||||||
|
|
||||||
|
self.IO_DATA_ELEMENT = document.querySelector(
|
||||||
|
"[ui_ident=io_data_load]",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!self.IO_DATA_ELEMENT || !self.IO_DATA_MARKER) {
|
||||||
|
console.warn(
|
||||||
|
"ui::io_data_load called, but required elements don't exist",
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.IO_DATA_TMPL = tmpl;
|
||||||
|
self.IO_DATA_PAGE = page;
|
||||||
|
self.IO_DATA_SEEN_IDS = [];
|
||||||
|
|
||||||
|
self.IO_DATA_OBSERVER.observe(self.IO_DATA_MARKER);
|
||||||
|
});
|
||||||
|
|
||||||
|
self.define("io_load_data", async () => {
|
||||||
|
self.IO_DATA_PAGE += 1;
|
||||||
|
console.log("load page", self.IO_DATA_PAGE);
|
||||||
|
|
||||||
|
const text = await (
|
||||||
|
await fetch(`${self.IO_DATA_TMPL}${self.IO_DATA_PAGE}`)
|
||||||
|
).text();
|
||||||
|
|
||||||
|
if (
|
||||||
|
text.includes(
|
||||||
|
`That's a wrap!<!-- observer_disconnect_${window.BUILD_CODE} -->`,
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
console.log("io_data_end; disconnect");
|
||||||
|
self.IO_DATA_OBSERVER.disconnect();
|
||||||
|
self.IO_DATA_ELEMENT.innerHTML += text;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.IO_DATA_ELEMENT.innerHTML += text;
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// move marker to bottom of dom hierarchy
|
||||||
|
self.IO_DATA_ELEMENT.children[
|
||||||
|
self.IO_DATA_ELEMENT.children.length - 1
|
||||||
|
].after(self.IO_DATA_MARKER);
|
||||||
|
|
||||||
|
// remove posts we've already seen
|
||||||
|
function remove_elements(id, outer = false) {
|
||||||
|
let idx = 0;
|
||||||
|
for (const element of Array.from(
|
||||||
|
document.querySelectorAll(
|
||||||
|
`.post${outer ? "_outer" : ""}\\:${id}`,
|
||||||
|
),
|
||||||
|
)) {
|
||||||
|
if (idx === 0) {
|
||||||
|
idx += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// everything that isn't the first element should be removed
|
||||||
|
element.remove();
|
||||||
|
console.log("removed duplicate post");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const id of self.IO_DATA_SEEN_IDS) {
|
||||||
|
remove_elements(id, false);
|
||||||
|
remove_elements(id, true); // scoop up questions
|
||||||
|
}
|
||||||
|
|
||||||
|
// push ids
|
||||||
|
for (const opt of Array.from(
|
||||||
|
document.querySelectorAll(
|
||||||
|
`[ui_ident=list_posts_${self.IO_DATA_PAGE}] option`,
|
||||||
|
),
|
||||||
|
)) {
|
||||||
|
const v = opt.getAttribute("value");
|
||||||
|
|
||||||
|
if (!self.IO_DATA_SEEN_IDS[v]) {
|
||||||
|
self.IO_DATA_SEEN_IDS.push(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 150);
|
||||||
|
|
||||||
|
// run hooks
|
||||||
|
const atto = ns("atto");
|
||||||
|
|
||||||
|
atto.clean_date_codes();
|
||||||
|
atto.clean_poll_date_codes();
|
||||||
|
atto.link_filter();
|
||||||
|
|
||||||
|
atto["hooks::long_text.init"]();
|
||||||
|
atto["hooks::alt"]();
|
||||||
|
atto["hooks::online_indicator"]();
|
||||||
|
atto["hooks::verify_emoji"]();
|
||||||
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
|
|
|
@ -12,7 +12,20 @@ pub async fn get_request(
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
let data = &(data.read().await).0;
|
let data = &(data.read().await).0;
|
||||||
|
|
||||||
let upload = data.get_upload_by_id(id).await.unwrap();
|
let upload = match data.get_upload_by_id(id).await {
|
||||||
|
Ok(u) => u,
|
||||||
|
Err(_) => {
|
||||||
|
return Err((
|
||||||
|
[("Content-Type", "image/svg+xml")],
|
||||||
|
Body::from(read_image(PathBufD::current().extend(&[
|
||||||
|
data.0.0.dirs.media.as_str(),
|
||||||
|
"images",
|
||||||
|
"default-avatar.svg",
|
||||||
|
]))),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let path = upload.path(&data.0.0);
|
let path = upload.path(&data.0.0);
|
||||||
|
|
||||||
if !exists(&path).unwrap() {
|
if !exists(&path).unwrap() {
|
||||||
|
|
|
@ -9,7 +9,9 @@ use axum::{
|
||||||
};
|
};
|
||||||
use axum_extra::extract::CookieJar;
|
use axum_extra::extract::CookieJar;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tetratto_core::model::{permissions::FinePermission, requests::ActionType, Error};
|
use tetratto_core::model::{
|
||||||
|
auth::DefaultTimelineChoice, permissions::FinePermission, requests::ActionType, Error,
|
||||||
|
};
|
||||||
use std::fs::read_to_string;
|
use std::fs::read_to_string;
|
||||||
use pathbufd::PathBufD;
|
use pathbufd::PathBufD;
|
||||||
|
|
||||||
|
@ -649,3 +651,111 @@ pub async fn search_request(
|
||||||
data.1.render("timelines/search.html", &context).unwrap(),
|
data.1.render("timelines/search.html", &context).unwrap(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
pub struct TimelineQuery {
|
||||||
|
pub tl: DefaultTimelineChoice,
|
||||||
|
pub page: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `/_swiss_army_timeline`
|
||||||
|
pub async fn swiss_army_timeline_request(
|
||||||
|
jar: CookieJar,
|
||||||
|
Extension(data): Extension<State>,
|
||||||
|
Query(req): Query<TimelineQuery>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let data = data.read().await;
|
||||||
|
let user = get_user_from_token!(jar, data.0);
|
||||||
|
|
||||||
|
let ignore_users = crate::ignore_users_gen!(user, data);
|
||||||
|
|
||||||
|
let list = match match req.tl {
|
||||||
|
DefaultTimelineChoice::AllPosts => data.0.get_latest_posts(12, req.page).await,
|
||||||
|
DefaultTimelineChoice::PopularPosts => {
|
||||||
|
data.0.get_popular_posts(12, req.page, 604_800_000).await
|
||||||
|
}
|
||||||
|
DefaultTimelineChoice::FollowingPosts => {
|
||||||
|
if let Some(ref ua) = user {
|
||||||
|
data.0
|
||||||
|
.get_posts_from_user_following(ua.id, 12, req.page)
|
||||||
|
.await
|
||||||
|
} else {
|
||||||
|
return Err(Html(
|
||||||
|
render_error(Error::NotAllowed, &jar, &data, &user).await,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefaultTimelineChoice::MyCommunities => {
|
||||||
|
if let Some(ref ua) = user {
|
||||||
|
data.0
|
||||||
|
.get_posts_from_user_communities(ua.id, 12, req.page)
|
||||||
|
.await
|
||||||
|
} else {
|
||||||
|
return Err(Html(
|
||||||
|
render_error(Error::NotAllowed, &jar, &data, &user).await,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefaultTimelineChoice::Stack(ref s) => {
|
||||||
|
data.0
|
||||||
|
.get_posts_by_stack(
|
||||||
|
match s.parse::<usize>() {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => {
|
||||||
|
return Err(Html(
|
||||||
|
render_error(
|
||||||
|
Error::MiscError("ID deserialization error".to_string()),
|
||||||
|
&jar,
|
||||||
|
&data,
|
||||||
|
&user,
|
||||||
|
)
|
||||||
|
.await,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
12,
|
||||||
|
req.page,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
// questions bad
|
||||||
|
_ => {
|
||||||
|
return Err(Html(
|
||||||
|
render_error(Error::NotAllowed, &jar, &data, &user).await,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} {
|
||||||
|
Ok(l) => match data
|
||||||
|
.0
|
||||||
|
.fill_posts_with_community(
|
||||||
|
l,
|
||||||
|
if let Some(ref ua) = user { ua.id } else { 0 },
|
||||||
|
&ignore_users,
|
||||||
|
&user,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(l) => data.0.posts_muted_phrase_filter(
|
||||||
|
&l,
|
||||||
|
if let Some(ref ua) = user {
|
||||||
|
Some(&ua.settings.muted)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Err(e) => return Ok(Html(render_error(e, &jar, &data, &user).await)),
|
||||||
|
},
|
||||||
|
Err(e) => return Ok(Html(render_error(e, &jar, &data, &user).await)),
|
||||||
|
};
|
||||||
|
|
||||||
|
let lang = get_lang!(jar, data.0);
|
||||||
|
let mut context = initial_context(&data.0.0.0, lang, &user).await;
|
||||||
|
|
||||||
|
context.insert("list", &list);
|
||||||
|
context.insert("page", &req.page);
|
||||||
|
Ok(Html(
|
||||||
|
data.1
|
||||||
|
.render("timelines/swiss_army.html", &context)
|
||||||
|
.unwrap(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
@ -29,6 +29,10 @@ pub fn routes() -> Router {
|
||||||
.route("/following", get(misc::following_request))
|
.route("/following", get(misc::following_request))
|
||||||
.route("/all", get(misc::all_request))
|
.route("/all", get(misc::all_request))
|
||||||
.route("/search", get(misc::search_request))
|
.route("/search", get(misc::search_request))
|
||||||
|
.route(
|
||||||
|
"/_swiss_army_timeline",
|
||||||
|
get(misc::swiss_army_timeline_request),
|
||||||
|
)
|
||||||
// question timelines
|
// question timelines
|
||||||
.route("/questions", get(misc::index_questions_request))
|
.route("/questions", get(misc::index_questions_request))
|
||||||
.route("/popular/questions", get(misc::popular_questions_request))
|
.route("/popular/questions", get(misc::popular_questions_request))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue