1use std::{collections::HashMap, fs, path::Path};
2
3use chrono::NaiveDate;
4use markdown::{mdast::Node, to_html_with_options, Options};
5use serde::{Deserialize, Serialize};
6
7use crate::{
8 common::{get_json_data, preview::get_preview, toc, BlogError, BlogJson},
9 medium::MediumBlogEntry,
10 types::Blog,
11};
12
13#[derive(Debug, Serialize, Deserialize)]
25pub struct HighBlog {
26 pub hash: HashMap<String, HighBlogEntry>,
30 pub entries: Vec<HighBlogEntry>,
34 pub tags: Vec<String>,
38 pub sitemap: String,
40}
41
42#[derive(Debug, Serialize, Deserialize, Clone)]
45pub struct HighBlogEntry {
46 title: String,
48 date: NaiveDate,
50 desc: Option<String>,
52 html: String,
54 slug: String,
56 tags: Vec<String>,
58 toc: Option<String>,
60 keywords: Option<Vec<String>>,
62 canonical_link: Option<String>,
64 author_name: Option<String>,
66 author_webpage: Option<String>,
68 preview: String,
70 last_modified: Option<NaiveDate>,
73 priority: Option<f64>,
75}
76
77impl Blog for HighBlogEntry {
78 fn create<T: AsRef<Path>>(
79 blog: T,
80 toc_generation_func: Option<&dyn Fn(&Node) -> String>,
81 preview_chars: Option<usize>,
82 ) -> Result<Self, BlogError> {
83 let json = get_json_data(&blog)?;
84
85 let markdown = match fs::read_to_string(blog) {
86 Ok(x) => x,
87 Err(y) => return Err(BlogError::File(y)),
88 };
89
90 let html = match to_html_with_options(
91 &markdown,
92 &Options {
93 compile: markdown::CompileOptions {
94 allow_dangerous_html: true,
95 allow_dangerous_protocol: true,
96
97 ..markdown::CompileOptions::default()
98 },
99 ..markdown::Options::default()
100 },
101 ) {
102 Ok(x) => x,
103 Err(y) => return Err(BlogError::Markdown(y.to_string())),
104 };
105
106 let preview: String = get_preview(&html, preview_chars);
107
108 let toc = toc(&markdown, toc_generation_func)?;
109
110 return Ok(HighBlogEntry::new(json, html, toc, preview));
111 }
112
113 fn get_title(&self) -> String {
114 return self.title.clone();
115 }
116
117 fn get_date_listed(&self) -> NaiveDate {
118 return self.date.clone();
119 }
120
121 fn get_description(&self) -> Option<String> {
122 return self.desc.clone();
123 }
124
125 fn get_html(&self) -> String {
126 return self.html.clone();
127 }
128
129 fn get_full_slug(&self) -> String {
130 return format!("{}/{}", self.get_date_listed(), self.get_part_slug());
131 }
132
133 fn get_part_slug(&self) -> String {
134 return self.slug.clone();
135 }
136
137 fn get_tags(&self) -> Vec<String> {
138 return self.tags.clone();
139 }
140
141 fn get_table_of_contents(&self) -> Option<String> {
142 return self.toc.clone();
143 }
144
145 fn get_keywords(&self) -> Option<Vec<String>> {
146 return self.keywords.clone();
147 }
148
149 fn get_canonicle_link(&self) -> Option<String> {
150 return self.canonical_link.clone();
151 }
152
153 fn get_author_name(&self) -> Option<String> {
154 return self.author_name.clone();
155 }
156
157 fn get_author_webpage(&self) -> Option<String> {
158 return self.author_webpage.clone();
159 }
160
161 fn get_preview(&self) -> String {
162 return self.preview.clone();
163 }
164
165 fn get_last_modified(&self) -> Option<NaiveDate> {
166 return self.last_modified.clone();
167 }
168
169 fn get_priority(&self) -> Option<f64> {
170 return self.priority.clone();
171 }
172}
173
174impl HighBlogEntry {
175 pub(crate) fn new(json: BlogJson, html: String, toc: Option<String>, preview: String) -> Self {
176 return HighBlogEntry {
177 title: json.title,
178 date: json.date,
179 desc: json.desc,
180 html: html,
181 slug: json.slug,
182 tags: json.tags,
183 toc: toc,
184 keywords: json.keywords,
185 canonical_link: json.canonical_link,
186 author_name: json.author_name,
187 author_webpage: json.author_webpage,
188 preview: preview,
189 last_modified: json.last_modified,
190 priority: json.priority,
191 };
192 }
193
194 pub(crate) fn new_from_medium(medium: &MediumBlogEntry, html: String) -> Self {
195 return Self {
196 title: medium.get_title(),
197 date: medium.get_date_listed(),
198 desc: medium.get_description(),
199 html: html,
200 slug: medium.get_part_slug(),
201 tags: medium.get_tags(),
202 toc: medium.get_table_of_contents(),
203 keywords: medium.get_keywords(),
204 canonical_link: medium.get_canonicle_link(),
205 author_name: medium.get_author_name(),
206 author_webpage: medium.get_author_webpage(),
207 preview: medium.get_preview(),
208 last_modified: medium.get_last_modified(),
209 priority: medium.get_priority(),
210 };
211 }
212}