Lines
96.59 %
Functions
34.62 %
use crate::server::{
dataset::{Dataset, PredicateObject},
DatasetSummary, DatasetVersionSummary,
};
use askama::Template;
use sophia::api::{prefix::PrefixMapPair, term::IriRef, MownStr};
use std::collections::BTreeSet;
#[derive(Template)]
#[template(path = "index.html")]
pub(crate) struct IndexTemplate<'a> {
pub datasets: &'a [DatasetSummary<'a>],
}
#[template(path = "dataset.html")]
pub(crate) struct DatasetTemplate<'a> {
pub dataset: &'a Dataset,
pub versions: &'a [DatasetVersionSummary],
#[template(path = "version.html")]
pub(crate) struct VersionTemplate<'a> {
pub dataset: &'a DatasetSummary<'a>,
pub version: &'a DatasetVersionSummary,
pub subjects: BTreeSet<&'a IriRef<MownStr<'a>>>,
pub datasets: &'a Vec<Dataset>,
pub prefixes: &'a Vec<PrefixMapPair>,
#[template(path = "subject.html")]
pub(crate) struct SubjectTemplate<'a> {
pub subject: String,
pub pos: Vec<PredicateObject<'a>>,
mod filters {
use std::{collections::BTreeSet, fmt};
use askama::Error::Fmt;
use chrono::{DateTime, Utc};
use sophia::{
api::{
prefix::{PrefixMap, PrefixMapPair},
term::IriRef,
MownStr,
},
iri::Iri,
use crate::{
constants::LABEL_RDFS_IRI,
server::{dataset::Dataset, get_dataset_version},
/// Filter to replace the prefix in a resource IRI
pub(crate) fn replace_prefix<T: std::fmt::Display>(
s: T,
prefixes: &Vec<PrefixMapPair>,
) -> ::askama::Result<String> {
let prefix_found = prefixes.get_prefixed_pair(Iri::new_unchecked(s.to_string()));
let out = if let Some(ps) = prefix_found {
format!("{}:{}", ps.0.as_str(), ps.1)
} else {
s.to_string()
Ok(out)
/// Filter to find and display the rdfs:label resource for a subject
pub(crate) fn rdfslabel<T: std::fmt::Display>(
datasets: &[Dataset],
id: &&str,
version: &DateTime<Utc>,
let subject = Iri::new_unchecked(s.to_string());
let Ok((_, dataset_version)) = get_dataset_version(datasets, id, *version) else {
return Err(Fmt(fmt::Error));
let pos = dataset_version.pos(&subject);
let find_target_po = pos
.into_iter()
.find(|po| po.predicate.as_str() == LABEL_RDFS_IRI);
let Some(target_po) = find_target_po else {
return Ok("".to_string());
let Some(target_object) = target_po.object_literal else {
Ok(target_object.to_string())
/// Tuple with a prefix and subjects that match that prefix
type PrefixWithMatchingSubjects<'a> = (&'a str, Vec<&'a IriRef<MownStr<'a>>>);
/// Filter to sort subjects by prefix
pub(crate) fn categorize_subjects<'a>(
subjects: &BTreeSet<&'a IriRef<MownStr<'a>>>,
prefixes: &'a Vec<PrefixMapPair>,
) -> ::askama::Result<Vec<PrefixWithMatchingSubjects<'a>>> {
// Define the special categories to be shown first
let mut special_categories: Vec<&str> = vec!["proposal", "nlnet"];
// Find the non-special categories
let mut other_categories: Vec<&str> = prefixes
.iter()
.map(|(p, _)| p.as_str())
.filter(|cat| !special_categories.contains(cat))
.collect();
// Merge categories
let mut categories = vec![];
categories.append(&mut special_categories);
categories.append(&mut other_categories);
// Find prefix for each subject
let subs_with_prefix: Vec<(&IriRef<MownStr<'a>>, Option<String>)> = subjects
.map(|subject| {
(
*subject,
prefixes
.get_prefixed_pair(Iri::new_unchecked(subject.to_string()))
.map(|prefix| (prefix.0.to_string())),
)
})
// Loop over each category and find the subjects with the matching prefix
Ok(categories
.map(|cat| {
let subs: Vec<&IriRef<MownStr<'a>>> = subs_with_prefix
.filter_map(|(sub, prefix)| {
if let Some(prefix) = prefix {
match prefix == cat {
true => Some(*sub),
false => None,
None
(*cat, subs)
.collect())