A Fix for the permalinks in #1136 (#1142)

* add fix for (#1135) Taxonomies with identical slugs now get merged (#1136)

* update templates so they propperly render taxonomy names

* squash! add fix for (#1135) Taxonomies with identical slugs now get merged (#1136)

reimplement taxonomy deduping

* revert unwanted changes to templates

* add tests for unic in permalinks

* add tests for unic in permalinks
This commit is contained in:
Sam Vente 2020-08-26 19:36:02 +02:00 committed by GitHub
parent af0dd5ef32
commit 6e16dfdc29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 228 additions and 32 deletions

View file

@ -2,7 +2,7 @@ mod config;
pub mod highlighting;
mod theme;
pub use crate::config::{
languages::Language, link_checker::LinkChecker, taxonomies::Taxonomy, Config,
languages::Language, link_checker::LinkChecker, slugify::Slugify, taxonomies::Taxonomy, Config,
};
use std::path::Path;

View file

@ -1,3 +1,4 @@
use std::cmp::Ordering;
use std::collections::HashMap;
use serde_derive::Serialize;
@ -40,7 +41,7 @@ impl<'a> SerializedTaxonomyItem<'a> {
}
/// A taxonomy with all its pages
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone)]
pub struct TaxonomyItem {
pub name: String,
pub slug: String,
@ -70,22 +71,33 @@ impl TaxonomyItem {
})
.collect();
let (mut pages, ignored_pages) = sort_pages_by_date(data);
let slug = slugify_paths(name, config.slugify.taxonomies);
let item_slug = slugify_paths(name, config.slugify.taxonomies);
let taxo_slug = slugify_paths(&taxonomy.name, config.slugify.taxonomies);
let permalink = if taxonomy.lang != config.default_language {
config.make_permalink(&format!("/{}/{}/{}", taxonomy.lang, taxonomy.name, slug))
config.make_permalink(&format!("/{}/{}/{}", taxonomy.lang, taxo_slug, item_slug))
} else {
config.make_permalink(&format!("/{}/{}", taxonomy.name, slug))
config.make_permalink(&format!("/{}/{}", taxo_slug, item_slug))
};
// We still append pages without dates at the end
pages.extend(ignored_pages);
TaxonomyItem { name: name.to_string(), permalink, slug, pages }
TaxonomyItem { name: name.to_string(), permalink, slug: item_slug, pages }
}
pub fn serialize<'a>(&'a self, library: &'a Library) -> SerializedTaxonomyItem<'a> {
SerializedTaxonomyItem::from_item(self, library)
}
pub fn merge(&mut self, other: Self) {
self.pages.extend(other.pages);
}
}
impl PartialEq for TaxonomyItem {
fn eq(&self, other: &Self) -> bool {
self.permalink == other.permalink
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
@ -121,8 +133,23 @@ impl Taxonomy {
for (name, pages) in items {
sorted_items.push(TaxonomyItem::new(&name, &kind, config, pages, library));
}
sorted_items.sort_by(|a, b| a.name.cmp(&b.name));
//sorted_items.sort_by(|a, b| a.name.cmp(&b.name));
sorted_items.sort_by(|a, b| match a.slug.cmp(&b.slug) {
Ordering::Less => Ordering::Less,
Ordering::Greater => Ordering::Greater,
Ordering::Equal => a.name.cmp(&b.name),
});
sorted_items.dedup_by(|a, b| {
// custom Eq impl checks for equal permalinks
// here we make sure all pages from a get coppied to b
// before dedup gets rid of it
if a == b {
b.merge(a.to_owned());
true
} else {
false
}
});
Taxonomy { kind, items: sorted_items }
}
@ -189,27 +216,25 @@ pub fn find_taxonomies(config: &Config, library: &Library) -> Result<Vec<Taxonom
let taxonomies_def = {
let mut m = HashMap::new();
for t in &config.taxonomies {
m.insert(
format!("{}-{}", slugify_paths(&t.name, config.slugify.taxonomies), t.lang),
t,
);
let slug = slugify_paths(&t.name, config.slugify.taxonomies);
m.insert(format!("{}-{}", slug, t.lang), t);
}
m
};
let mut all_taxonomies = HashMap::new();
for (key, page) in library.pages() {
for (name, val) in &page.meta.taxonomies {
let taxo_key =
format!("{}-{}", slugify_paths(name, config.slugify.taxonomies), page.lang);
for (name, taxo_term) in &page.meta.taxonomies {
let taxo_slug = slugify_paths(&name, config.slugify.taxonomies);
let taxo_key = format!("{}-{}", &taxo_slug, page.lang);
if taxonomies_def.contains_key(&taxo_key) {
all_taxonomies.entry(taxo_key.clone()).or_insert_with(HashMap::new);
for v in val {
for term in taxo_term {
all_taxonomies
.get_mut(&taxo_key)
.unwrap()
.entry(v.to_string())
.entry(term.to_string())
.or_insert_with(|| vec![])
.push(key);
}
@ -239,7 +264,7 @@ mod tests {
use crate::content::Page;
use crate::library::Library;
use config::{Config, Language, Taxonomy as TaxonomyConfig};
use config::{Config, Language, Slugify, Taxonomy as TaxonomyConfig};
use utils::slugs::SlugifyStrategy;
#[test]
@ -714,8 +739,9 @@ mod tests {
);
assert_eq!(categories.items[1].pages.len(), 1);
}
#[test]
fn taxonomies_are_groupted_by_slug() {
fn taxonomies_are_groupted_by_permalink() {
let mut config = Config::default();
let mut library = Library::new(2, 0, false);
@ -744,40 +770,208 @@ mod tests {
let mut page1 = Page::default();
let mut taxo_page1 = HashMap::new();
taxo_page1
.insert("test-taxonomy".to_string(), vec!["term1".to_string(), "term2".to_string()]);
taxo_page1.insert(
"test-taxonomy".to_string(),
vec!["term one".to_string(), "term two".to_string()],
);
page1.meta.taxonomies = taxo_page1;
page1.lang = config.default_language.clone();
library.insert_page(page1);
let mut page2 = Page::default();
let mut taxo_page2 = HashMap::new();
taxo_page2
.insert("test taxonomy".to_string(), vec!["term2".to_string(), "term3".to_string()]);
taxo_page2.insert(
"test taxonomy".to_string(),
vec!["Term Two".to_string(), "term-one".to_string()],
);
page2.meta.taxonomies = taxo_page2;
page2.lang = config.default_language.clone();
library.insert_page(page2);
let mut page3 = Page::default();
let mut taxo_page3 = HashMap::new();
taxo_page3.insert("test-taxonomy ".to_string(), vec!["term4".to_string()]);
taxo_page3.insert("test-taxonomy ".to_string(), vec!["term one ".to_string()]);
page3.meta.taxonomies = taxo_page3;
page3.lang = config.default_language.clone();
library.insert_page(page3);
let mut page4 = Page::default();
let mut taxo_page4 = HashMap::new();
taxo_page4.insert("Test-Taxonomy ".to_string(), vec!["term8".to_string()]);
taxo_page4.insert("Test-Taxonomy ".to_string(), vec!["Term-Two ".to_string()]);
page4.meta.taxonomies = taxo_page4;
page4.lang = config.default_language.clone();
library.insert_page(page4);
// taxonomies get merged correctly
// taxonomies should all be the same
let taxonomies = find_taxonomies(&config, &library).unwrap();
assert_eq!(taxonomies.len(), 1);
// merged taxonomies contains all of the terms
let term = taxonomies.iter().next().unwrap();
assert_eq!(term.items.len(), 5);
let tax = &taxonomies[0];
// terms should be "term one", "term two"
assert_eq!(tax.items.len(), 2);
let term1 = &tax.items[0];
let term2 = &tax.items[1];
assert_eq!(term1.name, "term one");
assert_eq!(term1.slug, "term-one");
assert_eq!(term1.permalink, "http://a-website.com/test-taxonomy/term-one/");
assert_eq!(term1.pages.len(), 3);
assert_eq!(term2.name, "Term Two");
assert_eq!(term2.slug, "term-two");
assert_eq!(term2.permalink, "http://a-website.com/test-taxonomy/term-two/");
assert_eq!(term2.pages.len(), 3);
}
#[test]
fn taxonomies_with_unic_are_grouped_with_default_slugify_strategy() {
let mut config = Config::default();
let mut library = Library::new(2, 0, false);
config.taxonomies = vec![
TaxonomyConfig {
name: "test-taxonomy".to_string(),
lang: config.default_language.clone(),
..TaxonomyConfig::default()
},
TaxonomyConfig {
name: "test taxonomy".to_string(),
lang: config.default_language.clone(),
..TaxonomyConfig::default()
},
TaxonomyConfig {
name: "test-taxonomy ".to_string(),
lang: config.default_language.clone(),
..TaxonomyConfig::default()
},
TaxonomyConfig {
name: "Test-Taxonomy ".to_string(),
lang: config.default_language.clone(),
..TaxonomyConfig::default()
},
];
let mut page1 = Page::default();
let mut taxo_page1 = HashMap::new();
taxo_page1.insert("test-taxonomy".to_string(), vec!["Ecole".to_string()]);
page1.meta.taxonomies = taxo_page1;
page1.lang = config.default_language.clone();
library.insert_page(page1);
let mut page2 = Page::default();
let mut taxo_page2 = HashMap::new();
taxo_page2.insert("test taxonomy".to_string(), vec!["École".to_string()]);
page2.meta.taxonomies = taxo_page2;
page2.lang = config.default_language.clone();
library.insert_page(page2);
let mut page3 = Page::default();
let mut taxo_page3 = HashMap::new();
taxo_page3.insert("test-taxonomy ".to_string(), vec!["ecole".to_string()]);
page3.meta.taxonomies = taxo_page3;
page3.lang = config.default_language.clone();
library.insert_page(page3);
let mut page4 = Page::default();
let mut taxo_page4 = HashMap::new();
taxo_page4.insert("Test-Taxonomy ".to_string(), vec!["école".to_string()]);
page4.meta.taxonomies = taxo_page4;
page4.lang = config.default_language.clone();
library.insert_page(page4);
// taxonomies should all be the same
let taxonomies = find_taxonomies(&config, &library).unwrap();
assert_eq!(taxonomies.len(), 1);
let tax = &taxonomies[0];
// under the default slugify stratagy all of the provided terms should be the same
assert_eq!(tax.items.len(), 1);
let term1 = &tax.items[0];
assert_eq!(term1.name, "Ecole");
assert_eq!(term1.slug, "ecole");
assert_eq!(term1.permalink, "http://a-website.com/test-taxonomy/ecole/");
assert_eq!(term1.pages.len(), 4);
}
#[test]
fn taxonomies_with_unic_are_not_grouped_with_safe_slugify_strategy() {
let mut config = Config::default();
config.slugify = Slugify {
paths: SlugifyStrategy::Safe,
taxonomies: SlugifyStrategy::Safe,
anchors: SlugifyStrategy::Safe,
};
let mut library = Library::new(2, 0, false);
config.taxonomies = vec![
TaxonomyConfig {
name: "test-taxonomy".to_string(),
lang: config.default_language.clone(),
..TaxonomyConfig::default()
},
TaxonomyConfig {
name: "test taxonomy".to_string(),
lang: config.default_language.clone(),
..TaxonomyConfig::default()
},
TaxonomyConfig {
name: "test-taxonomy ".to_string(),
lang: config.default_language.clone(),
..TaxonomyConfig::default()
},
TaxonomyConfig {
name: "Test-Taxonomy ".to_string(),
lang: config.default_language.clone(),
..TaxonomyConfig::default()
},
];
let mut page1 = Page::default();
let mut taxo_page1 = HashMap::new();
taxo_page1.insert("test-taxonomy".to_string(), vec!["Ecole".to_string()]);
page1.meta.taxonomies = taxo_page1;
page1.lang = config.default_language.clone();
library.insert_page(page1);
let mut page2 = Page::default();
let mut taxo_page2 = HashMap::new();
taxo_page2.insert("test-taxonomy".to_string(), vec!["École".to_string()]);
page2.meta.taxonomies = taxo_page2;
page2.lang = config.default_language.clone();
library.insert_page(page2);
let mut page3 = Page::default();
let mut taxo_page3 = HashMap::new();
taxo_page3.insert("test-taxonomy".to_string(), vec!["ecole".to_string()]);
page3.meta.taxonomies = taxo_page3;
page3.lang = config.default_language.clone();
library.insert_page(page3);
let mut page4 = Page::default();
let mut taxo_page4 = HashMap::new();
taxo_page4.insert("test-taxonomy".to_string(), vec!["école".to_string()]);
page4.meta.taxonomies = taxo_page4;
page4.lang = config.default_language.clone();
library.insert_page(page4);
// taxonomies should all be the same
let taxonomies = find_taxonomies(&config, &library).unwrap();
let tax = &taxonomies[0];
// if names are different permalinks should also be different so
// the tems are still accessable
for term1 in tax.items.iter() {
for term2 in tax.items.iter() {
assert!(term1.name == term2.name || term1.permalink != term2.permalink);
}
}
// under the safe slugify strategy all terms should be distinct
assert_eq!(tax.items.len(), 4);
}
}

View file

@ -177,12 +177,14 @@ Currently, the only supported keys are `width` and `height`.
Gets the permalink for the taxonomy item found.
```jinja2
{% set url = get_taxonomy_url(kind="categories", name=page.taxonomies.category) %}
{% set url = get_taxonomy_url(kind="categories", name=page.taxonomies.category, lang=page.lang) %}
```
`name` will almost always come from a variable but in case you want to do it manually,
the value should be the same as the one in the front matter, not the slugified version.
`lang` (optional) default to `config.default_language` in config.toml
### `get_taxonomy`
Gets the whole taxonomy of a specific kind.