1
use crate::server::{
2
    dataset::{Dataset, PredicateObject},
3
    DatasetSummary, DatasetVersionSummary,
4
};
5
use askama::Template;
6
use sophia::api::{term::IriRef, MownStr};
7
use std::collections::BTreeSet;
8

            
9
2
#[derive(Template)]
10
2
#[template(path = "index.html")]
11
pub(crate) struct IndexTemplate<'a> {
12
    pub datasets: &'a [DatasetSummary<'a>],
13
}
14

            
15
1
#[derive(Template)]
16
1
#[template(path = "dataset.html")]
17
pub(crate) struct DatasetTemplate<'a> {
18
    pub dataset: &'a Dataset,
19
    pub versions: &'a [DatasetVersionSummary],
20
}
21

            
22
1063
#[derive(Template)]
23
1
#[template(path = "version.html")]
24
pub(crate) struct VersionTemplate<'a> {
25
    pub dataset: &'a DatasetSummary<'a>,
26
    pub version: &'a DatasetVersionSummary,
27
    pub subjects: BTreeSet<&'a IriRef<MownStr<'a>>>,
28
}
29

            
30
6
#[derive(Template)]
31
1
#[template(path = "subject.html")]
32
pub(crate) struct SubjectTemplate<'a> {
33
    pub dataset: &'a DatasetSummary<'a>,
34
    pub subject: String,
35
    pub version: &'a DatasetVersionSummary,
36
    pub pos: Vec<PredicateObject<'a>>,
37
}
38

            
39
mod filters {
40
    use std::{collections::BTreeSet, fmt};
41

            
42
    use askama::Error::Fmt;
43
    use chrono::{DateTime, Utc};
44
    use lazy_static::lazy_static;
45
    use sophia::{
46
        api::{
47
            prefix::{PrefixMap, PrefixMapPair},
48
            term::IriRef,
49
            MownStr,
50
        },
51
        iri::Iri,
52
    };
53

            
54
    use crate::server::{
55
        dataset::{load_datasets, load_prefixes, Dataset},
56
        get_dataset_version,
57
    };
58

            
59
    static LABEL_RESOURCE: &str = "http://www.w3.org/2000/01/rdf-schema#label";
60

            
61
    lazy_static! {
62
        static ref DATASETS: Vec<Dataset> = load_datasets("datasets").unwrap_or_default();
63
    }
64

            
65
    lazy_static! {
66
        static ref PREFIXES: Vec<PrefixMapPair> = load_prefixes("datasets").unwrap_or_default();
67
    }
68

            
69
124
    pub fn replace_prefix<T: std::fmt::Display>(s: T) -> ::askama::Result<String> {
70
124
        let prefix_found = PREFIXES.get_prefixed_pair(Iri::new_unchecked(s.to_string()));
71

            
72
124
        let out = if let Some(ps) = prefix_found {
73
122
            format!("{}:{}", ps.0.as_str(), ps.1)
74
        } else {
75
2
            s.to_string()
76
        };
77

            
78
124
        Ok(out)
79
124
    }
80

            
81
    // Would be nice if this filter returned the found prefix in the original URL format
82
    // pub fn prefix<T: std::fmt::Display>(s: T) -> ::askama::Result<String> {
83
    //     let prefix_found = PREFIXES.get_prefixed_pair(Iri::new_unchecked(s.to_string()));
84

            
85
    //     let out = if let Some(ps) = prefix_found {
86
    //         format!("{}", ps.0.)
87
    //     } else {
88
    //         s.to_string()
89
    //     };
90

            
91
    //     Ok(out)
92
    // }
93

            
94
123
    pub fn rdfslabel<T: std::fmt::Display>(
95
123
        s: T,
96
123
        id: &&str,
97
123
        version: &DateTime<Utc>,
98
123
    ) -> ::askama::Result<String> {
99
123
        let subject = Iri::new_unchecked(s.to_string());
100
123
        let Ok((_, dataset_version)) = get_dataset_version(&DATASETS, id, *version) else {
101
            return Err(Fmt(fmt::Error));
102
        };
103
123
        let pos = dataset_version.pos(&subject);
104
123

            
105
123
        let find_target_po = pos
106
123
            .into_iter()
107
379
            .find(|po| po.predicate.as_str() == LABEL_RESOURCE);
108
123
        let Some(target_po) = find_target_po else {
109
7
            return Ok("".to_string());
110
        };
111
116
        let Some(target_object) = target_po.object_literal else {
112
            return Ok("".to_string());
113
        };
114

            
115
116
        Ok(target_object.to_string())
116
123
    }
117

            
118
1
    pub fn categorize_subjects<'a>(
119
1
        subs: &BTreeSet<&'a IriRef<MownStr<'a>>>,
120
1
    ) -> ::askama::Result<(Vec<String>, Vec<usize>)> {
121
1
        let special_categories: Vec<&str> = vec!["proposal", "nlnet"];
122
1
        let mut categories: Vec<String> = PREFIXES
123
1
            .clone()
124
1
            .into_iter()
125
7
            .map(|(p, _)| p.to_string())
126
7
            .filter(|cat| !special_categories.contains(&cat.as_str()))
127
1
            .collect();
128
1

            
129
1
        let cat_assigns: Vec<usize> = subs
130
1
            .into_iter()
131
118
            .map(|s| {
132
118
                let prefix_found = PREFIXES.get_prefixed_pair(Iri::new_unchecked(s.to_string()));
133

            
134
118
                if let Some((prefix, _)) = prefix_found {
135
116
                    if let Some(idx) = special_categories
136
116
                        .iter()
137
232
                        .position(|cat| cat == &prefix.as_str())
138
                    {
139
                        return idx;
140
116
                    } else if let Some(idx) =
141
625
                        categories.iter().position(|cat| cat == &prefix.as_str())
142
                    {
143
116
                        return idx + special_categories.len();
144
                    }
145
2
                }
146

            
147
2
                categories.len()
148
118
            })
149
1
            .collect();
150
1

            
151
1
        let mut all_categories = vec!["Proposals".to_string(), "NLnet".to_string()];
152
1
        let mut others = vec!["Other".to_string()];
153
1
        all_categories.append(&mut categories);
154
1
        all_categories.append(&mut others);
155
1

            
156
1
        Ok((all_categories, cat_assigns))
157
1
    }
158
}