mirror of
https://github.com/freedit-org/freedit.git
synced 2026-01-10 04:58:07 -05:00
atom.xml
This commit is contained in:
100
Cargo.lock
generated
100
Cargo.lock
generated
@@ -75,21 +75,6 @@ dependencies = [
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
@@ -134,9 +119,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a3a5ed3201df5658d1aa45060c5a57dc9dba8a8ada20d696d67cb0c479ee043"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"derive_builder",
|
||||
"diligent-date-parser",
|
||||
"never",
|
||||
"quick-xml",
|
||||
]
|
||||
|
||||
@@ -478,10 +461,7 @@ version = "0.4.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -503,12 +483,6 @@ dependencies = [
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.14"
|
||||
@@ -628,37 +602,6 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947"
|
||||
dependencies = [
|
||||
"derive_builder_macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_core"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "derive_builder_macro"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c"
|
||||
dependencies = [
|
||||
"derive_builder_core",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.7"
|
||||
@@ -807,7 +750,6 @@ dependencies = [
|
||||
"bincode 2.0.0-rc.3",
|
||||
"cached",
|
||||
"captcha",
|
||||
"chrono",
|
||||
"data-encoding",
|
||||
"fast2s",
|
||||
"garde",
|
||||
@@ -1203,29 +1145,6 @@ dependencies = [
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.61"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
@@ -1336,11 +1255,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
[[package]]
|
||||
name = "jieba-rs"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1e2b0210dc78b49337af9e49d7ae41a39dceac6e5985613f1cf7763e2f76a25"
|
||||
source = "git+https://github.com/messense/jieba-rs.git?rev=b39957e#b39957e9a6d738c4b00f3fa645da971ad426ec21"
|
||||
dependencies = [
|
||||
"cedarwood",
|
||||
"derive_builder",
|
||||
"fxhash",
|
||||
"lazy_static",
|
||||
"phf",
|
||||
@@ -1636,12 +1553,6 @@ dependencies = [
|
||||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "never"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91"
|
||||
|
||||
[[package]]
|
||||
name = "new_debug_unreachable"
|
||||
version = "1.0.6"
|
||||
@@ -3326,15 +3237,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-registry"
|
||||
version = "0.2.0"
|
||||
|
||||
@@ -6,7 +6,7 @@ license = "MIT License"
|
||||
|
||||
[dependencies]
|
||||
ammonia = "4.0.0"
|
||||
atom_syndication = "0.12"
|
||||
atom_syndication = { version = "0.12", default-features = false }
|
||||
axum = { version = "0.7.5", features = ["http1", "http2", "form", "query", "multipart", "tokio"], default-features = false }
|
||||
axum-extra = { version = "0.9", features = ["typed-header"] }
|
||||
axum_garde = { version = "0.20.0", default-features = false, features = ["form"] }
|
||||
@@ -14,7 +14,6 @@ basic-toml = "*"
|
||||
bincode = "2.0.0-rc.3"
|
||||
cached = { version = "0.53", default-features = false, features = ["proc_macro", "ahash"] }
|
||||
captcha = { version = "0.0", default-features = false }
|
||||
chrono = { version = "0.4", default-features = false, features = ["clock"] }
|
||||
data-encoding = "*"
|
||||
fast2s = "0.3"
|
||||
garde = { version = "0.20.0", features = ["derive"] }
|
||||
@@ -23,7 +22,7 @@ identicon = { git = "https://github.com/freedit-dev/identicon.git", default-feat
|
||||
image = { version = "0.25.2", default-features = false, features = ["jpeg", "png", "gif"] }
|
||||
img-parts = "0.3.0"
|
||||
indexmap = "2"
|
||||
jieba-rs = "0.7.0"
|
||||
jieba-rs = { git = "https://github.com/messense/jieba-rs.git", rev = "b39957e" }
|
||||
jiff = { version = "0.1.13", default-features = false, features = ["std"] }
|
||||
latex2mathml = "0.2.3"
|
||||
mozjpeg = "0.10.10"
|
||||
|
||||
@@ -26,10 +26,7 @@ use super::{
|
||||
Claim, Comment, Feed, FormPost, Inn, InnType, Post, PostContent, PostStatus, SiteConfig, User,
|
||||
};
|
||||
use crate::{error::AppError, DB};
|
||||
use atom_syndication::{
|
||||
CategoryBuilder, ContentBuilder, EntryBuilder, FeedBuilder, LinkBuilder, PersonBuilder, Text,
|
||||
WriteConfig,
|
||||
};
|
||||
|
||||
use axum::{
|
||||
extract::{Path, Query},
|
||||
response::{IntoResponse, Redirect},
|
||||
@@ -39,7 +36,6 @@ use axum_extra::{headers::Cookie, TypedHeader};
|
||||
use axum_garde::WithValidation;
|
||||
use bincode::config::standard;
|
||||
use cached::proc_macro::cached;
|
||||
use chrono::{DateTime, Utc};
|
||||
use garde::Validate;
|
||||
use jiff::Timestamp;
|
||||
use rinja::filters::{escape, Html};
|
||||
@@ -47,11 +43,7 @@ use rinja_axum::{into_response, Template};
|
||||
use serde::Deserialize;
|
||||
use sled::{transaction::ConflictableTransactionError, Transactional};
|
||||
use sled::{Batch, Db};
|
||||
use std::{
|
||||
collections::{BTreeSet, HashMap, HashSet},
|
||||
path::PathBuf,
|
||||
sync::LazyLock,
|
||||
};
|
||||
use std::collections::{BTreeSet, HashMap, HashSet};
|
||||
|
||||
/// Page data: `inn_create.html`
|
||||
#[derive(Template)]
|
||||
@@ -1155,10 +1147,27 @@ fn recommend_users() -> Result<Vec<(u32, String)>, AppError> {
|
||||
Ok(users)
|
||||
}
|
||||
|
||||
static FEED_CONFIG: LazyLock<WriteConfig> = LazyLock::new(|| WriteConfig {
|
||||
write_document_declaration: false,
|
||||
indent_size: Some(2),
|
||||
});
|
||||
/// Page data: `atom.xml`
|
||||
#[derive(Template)]
|
||||
#[template(path = "atom.xml")]
|
||||
struct PageAtom {
|
||||
domain: String,
|
||||
title: String,
|
||||
iid: u32,
|
||||
categories: Vec<String>,
|
||||
updated: String,
|
||||
subtitle: String,
|
||||
entries: Vec<Entry>,
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
title: String,
|
||||
iid: u32,
|
||||
pid: u32,
|
||||
updated: String,
|
||||
author: (String, u32),
|
||||
content: String,
|
||||
}
|
||||
|
||||
/// `GET /inn/:iid/atom.xml` inn page
|
||||
pub(crate) async fn inn_feed(Path(i): Path<String>) -> Result<impl IntoResponse, AppError> {
|
||||
@@ -1177,18 +1186,12 @@ pub(crate) async fn inn_feed(Path(i): Path<String>) -> Result<impl IntoResponse,
|
||||
let mut index = Vec::with_capacity(page_params.n);
|
||||
let title;
|
||||
let description;
|
||||
let alternate_link = PathBuf::from(&site_config.domain)
|
||||
.join("inn")
|
||||
.join(iid.to_string())
|
||||
.display()
|
||||
.to_string();
|
||||
let self_link = format!("{alternate_link}/atom.xml");
|
||||
let mut categories = Vec::new();
|
||||
|
||||
if iid == 0 {
|
||||
index = get_pids_all(&DB, &[], &page_params, false)?;
|
||||
title = site_config.site_name;
|
||||
description = site_config.description;
|
||||
description = md2html(&site_config.description);
|
||||
} else {
|
||||
let inn: Inn = get_one(&DB, "inns", iid)?;
|
||||
description = md2html(&inn.about);
|
||||
@@ -1196,8 +1199,8 @@ pub(crate) async fn inn_feed(Path(i): Path<String>) -> Result<impl IntoResponse,
|
||||
index = get_pids_by_iids(&DB, &[iid], &page_params)?;
|
||||
}
|
||||
title = inn.inn_name;
|
||||
for i in &inn.topics {
|
||||
categories.push(CategoryBuilder::default().term(i).build());
|
||||
for i in inn.topics {
|
||||
categories.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1206,58 +1209,34 @@ pub(crate) async fn inn_feed(Path(i): Path<String>) -> Result<impl IntoResponse,
|
||||
let post: Post = get_one(&DB, "posts", i)?;
|
||||
let user: User = get_one(&DB, "users", post.uid)?;
|
||||
let content = post.content.to_html(&DB)?;
|
||||
let post_link = format!("/post/{}/{}", post.iid, post.pid);
|
||||
let dt: DateTime<Utc> = DateTime::<Utc>::from_timestamp(post.created_at, 0).unwrap();
|
||||
let entry = EntryBuilder::default()
|
||||
.authors(vec![PersonBuilder::default()
|
||||
.name(user.username)
|
||||
.uri(Some(format!("{}/user/{}", &site_config.domain, user.uid)))
|
||||
.build()])
|
||||
.id(&post_link)
|
||||
.updated(dt)
|
||||
.links(vec![LinkBuilder::default()
|
||||
.rel("alternate".to_owned())
|
||||
.mime_type(Some("text/html".to_owned()))
|
||||
.href(post_link)
|
||||
.build()])
|
||||
.title(Text::plain(post.title))
|
||||
.content(Some(ContentBuilder::default().value(Some(content)).build()))
|
||||
.build();
|
||||
let updated = Timestamp::from_second(post.created_at)
|
||||
.unwrap()
|
||||
.strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
.to_string();
|
||||
let entry = Entry {
|
||||
title: post.title,
|
||||
iid: post.iid,
|
||||
pid: post.pid,
|
||||
updated,
|
||||
author: (user.username, user.uid),
|
||||
content,
|
||||
};
|
||||
|
||||
entries.push(entry);
|
||||
}
|
||||
|
||||
let mut feed = FeedBuilder::default()
|
||||
.title(title)
|
||||
.subtitle(Some(Text::plain(description)))
|
||||
.id(&self_link)
|
||||
.link(
|
||||
LinkBuilder::default()
|
||||
.rel("self".to_owned())
|
||||
.mime_type(Some("application/atom+xml".to_owned()))
|
||||
.href(self_link)
|
||||
.build(),
|
||||
)
|
||||
.link(
|
||||
LinkBuilder::default()
|
||||
.rel("alternate".to_owned())
|
||||
.mime_type(Some("text/html".to_owned()))
|
||||
.href(alternate_link)
|
||||
.build(),
|
||||
)
|
||||
.build();
|
||||
let updated = entries[0].updated.clone();
|
||||
let page_atom = PageAtom {
|
||||
domain: site_config.domain,
|
||||
title,
|
||||
iid,
|
||||
categories,
|
||||
updated,
|
||||
subtitle: description,
|
||||
entries,
|
||||
};
|
||||
|
||||
feed.set_categories(categories);
|
||||
feed.set_entries(entries);
|
||||
|
||||
let mut output = Vec::new();
|
||||
feed.write_with_config(&mut output, *FEED_CONFIG).unwrap();
|
||||
|
||||
let headers = [(
|
||||
http::header::CONTENT_TYPE,
|
||||
http::HeaderValue::from_static("application/xml"),
|
||||
)];
|
||||
|
||||
Ok((headers, output))
|
||||
Ok(into_response(&page_atom))
|
||||
}
|
||||
|
||||
/// get [OutPostList] from pids
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
#![warn(clippy::pedantic)]
|
||||
// #![warn(clippy::unwrap_used)]
|
||||
|
||||
use chrono::Utc;
|
||||
use freedit::{
|
||||
router, AppError, CONFIG, DB, VERSION, {clear_invalid, cron_feed, Tan},
|
||||
};
|
||||
use jiff::Timestamp;
|
||||
use std::{fs, net::SocketAddr, path::PathBuf};
|
||||
use tokio::net::TcpListener;
|
||||
use tracing::{error, info, warn};
|
||||
@@ -89,7 +89,7 @@ fn create_snapshot(db: &sled::Db) {
|
||||
let checksum = db.checksum().unwrap();
|
||||
info!(%checksum);
|
||||
|
||||
let ts = Utc::now().format("%Y-%m-%d-%H-%M-%S");
|
||||
let ts = Timestamp::now().strftime("%Y-%m-%d-%H-%M-%S");
|
||||
let mut snapshot_path = PathBuf::from("snapshots");
|
||||
if !snapshot_path.exists() {
|
||||
fs::create_dir_all(&snapshot_path).unwrap();
|
||||
|
||||
25
templates/atom.xml
Normal file
25
templates/atom.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<feed xmlns="http://www.w3.org/2005/Atom">
|
||||
<title>{{ title }}</title>
|
||||
<id>{{ domain }}/inn/{{ iid }}</id>
|
||||
<updated>{{ updated }}</updated>
|
||||
<link href="{{ domain }}/inn/{{ iid }}/atom.xml" rel="self" type="application/atom+xml"/>
|
||||
<link href="{{ domain }}/inn/{{ iid }}/" rel="alternate" type="text/html"/>
|
||||
<subtitle>{{ subtitle }}</subtitle>
|
||||
{% for category in categories %}
|
||||
<category term="{{ category }}" />
|
||||
{% endfor %}
|
||||
|
||||
{% for entry in entries %}
|
||||
<entry>
|
||||
<title>{{ entry.title }}</title>
|
||||
<id>{{ domain }}/inn/{{ entry.iid }}/{{ entry.pid }}</id>
|
||||
<updated>{{ entry.updated }}</updated>
|
||||
<author>
|
||||
<name>{{ entry.author.0 }}</name>
|
||||
<uri>{{ domain }}/user/{{ entry.author.1 }}</uri>
|
||||
</author>
|
||||
<link href="{{ domain }}/post/{{entry.iid}}/{{entry.pid}}" rel="alternate" type="text/html"/>
|
||||
<content>{{ entry.content|trim }}</content>
|
||||
</entry>
|
||||
{% endfor %}
|
||||
</feed>
|
||||
Reference in New Issue
Block a user