Automatically generate slugs for articles based on title
This commit is contained in:
parent
ea28f4f4f7
commit
debf44623c
4 changed files with 53 additions and 2 deletions
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -589,6 +589,7 @@ dependencies = [
|
|||
"serde_derive 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"static_resource_derive 0.1.0",
|
||||
"tokio-io 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -677,6 +678,14 @@ name = "slab"
|
|||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "slug"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.2.1"
|
||||
|
@ -844,6 +853,11 @@ name = "unicode-xid"
|
|||
version = "0.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unidecode"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
|
@ -994,6 +1008,7 @@ dependencies = [
|
|||
"checksum serde_urlencoded 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce0fd303af908732989354c6f02e05e2e6d597152870f2c6990efb0577137480"
|
||||
"checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a"
|
||||
"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23"
|
||||
"checksum slug 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f5ff4b43cb07b86c5f9236c92714a22cdf9e5a27a7d85e398e2c9403328cb8"
|
||||
"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013"
|
||||
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
|
||||
"checksum syn 0.10.8 (registry+https://github.com/rust-lang/crates.io-index)" = "58fd09df59565db3399efbba34ba8a2fec1307511ebd245d0061ff9d42691673"
|
||||
|
@ -1014,6 +1029,7 @@ dependencies = [
|
|||
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
|
||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||
"checksum unidecode 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d2adb95ee07cd579ed18131f2d9e7a17c25a4b76022935c7f2460d2bfae89fd2"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum url 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb819346883532a271eb626deb43c4a1bb4c4dd47c519bd78137c3e72a4fe27"
|
||||
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||
|
|
|
@ -14,6 +14,7 @@ serde_derive = "1.0.0"
|
|||
serde = "1.0.0"
|
||||
serde_urlencoded = "0.5.0"
|
||||
serde_json = "1.0"
|
||||
slug = "0.1"
|
||||
r2d2 = "0.7"
|
||||
r2d2-diesel = "0.16"
|
||||
regex = "0.2"
|
||||
|
|
|
@ -17,6 +17,7 @@ extern crate r2d2;
|
|||
extern crate r2d2_diesel;
|
||||
extern crate serde_json;
|
||||
extern crate serde_urlencoded;
|
||||
extern crate slug;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
|
|
37
src/state.rs
37
src/state.rs
|
@ -26,6 +26,38 @@ pub enum SlugLookup {
|
|||
Redirect(String),
|
||||
}
|
||||
|
||||
fn decide_slug(conn: &SqliteConnection, prev_title: &str, title: &str, prev_slug: &str) -> Result<String, Error> {
|
||||
if title == prev_title {
|
||||
return Ok(prev_slug.to_owned());
|
||||
}
|
||||
|
||||
let base_slug = ::slug::slugify(title);
|
||||
|
||||
if base_slug == prev_slug {
|
||||
return Ok(base_slug);
|
||||
}
|
||||
|
||||
use schema::article_revisions;
|
||||
|
||||
let mut slug = base_slug.clone();
|
||||
let mut disambiguator = 1;
|
||||
|
||||
loop {
|
||||
let slug_in_use = article_revisions::table
|
||||
.filter(article_revisions::slug.eq(&slug))
|
||||
.filter(article_revisions::latest.eq(true))
|
||||
.count()
|
||||
.first::<i64>(conn)? != 0;
|
||||
|
||||
if !slug_in_use {
|
||||
break Ok(slug);
|
||||
}
|
||||
|
||||
disambiguator += 1;
|
||||
slug = format!("{}-{}", base_slug, disambiguator);
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn new(connection_pool: Pool<ConnectionManager<SqliteConnection>>, cpu_pool: futures_cpupool::CpuPool) -> State {
|
||||
State {
|
||||
|
@ -106,8 +138,7 @@ impl State {
|
|||
conn.transaction(|| {
|
||||
use schema::article_revisions;
|
||||
|
||||
// TODO: Get title and slug as parameters to update_article, so we can... update those
|
||||
let (latest_revision, title, slug) = article_revisions::table
|
||||
let (latest_revision, prev_title, prev_slug) = article_revisions::table
|
||||
.filter(article_revisions::article_id.eq(article_id))
|
||||
.order(article_revisions::revision.desc())
|
||||
.limit(1)
|
||||
|
@ -127,6 +158,8 @@ impl State {
|
|||
}
|
||||
let new_revision = base_revision + 1;
|
||||
|
||||
let title = prev_title.clone(); // TODO Have title be a parameter to this function
|
||||
let slug = decide_slug(&*conn, &prev_title, &title, &prev_slug)?;
|
||||
|
||||
#[derive(Insertable)]
|
||||
#[table_name="article_revisions"]
|
||||
|
|
Loading…
Reference in a new issue