@@ -63,7 +63,7 @@ lazy_static! {
63
63
) ;
64
64
}
65
65
66
- #[ derive( Debug , Serialize , Deserialize , Clone ) ]
66
+ #[ derive( Debug , Serialize , Deserialize , Clone , PartialEq ) ]
67
67
pub enum DocType {
68
68
Blog ,
69
69
Docs ,
@@ -115,15 +115,27 @@ pub struct Document {
115
115
// Gets document markdown
116
116
impl Document {
117
117
pub async fn from_path ( path : & PathBuf ) -> anyhow:: Result < Document , std:: io:: Error > {
118
- debug ! ( "path: {:?}" , path) ;
119
-
120
- let regex = regex:: Regex :: new ( r#".*/pgml-cms/([^"]*)/(.*)\.md"# ) . unwrap ( ) ;
121
-
122
- let doc_type = match regex. captures ( & path. clone ( ) . display ( ) . to_string ( ) ) {
123
- Some ( c) => DocType :: from_str ( & c[ 1 ] ) . ok ( ) ,
118
+ let doc_type = match path. strip_prefix ( config:: cms_dir ( ) ) {
119
+ Ok ( path) => {
120
+ match path. into_iter ( ) . next ( ) {
121
+ Some ( dir) => {
122
+ match & PathBuf :: from ( dir) . display ( ) . to_string ( ) [ ..] {
123
+ "blog" => Some ( DocType :: Blog ) ,
124
+ "docs" => Some ( DocType :: Docs ) ,
125
+ "careers" => Some ( DocType :: Careers ) ,
126
+ _ => None
127
+ }
128
+ } ,
129
+ _ => None
130
+ }
131
+ } ,
124
132
_ => None ,
125
133
} ;
126
134
135
+ if doc_type. is_none ( ) {
136
+ warn ! ( "doc_type not parsed from path: {path:?}" ) ;
137
+ }
138
+
127
139
let contents = tokio:: fs:: read_to_string ( & path) . await ?;
128
140
129
141
let parts = contents. split ( "---" ) . collect :: < Vec < & str > > ( ) ;
@@ -143,7 +155,7 @@ impl Document {
143
155
( None , contents)
144
156
} ;
145
157
146
- let default_image = ".gitbook/assets/ blog_image_placeholder.png";
158
+ let default_image_path = BLOG . asset_url_root . join ( " blog_image_placeholder.png") . display ( ) . to_string ( ) ;
147
159
148
160
// parse meta section
149
161
let ( description, image, featured, tags) = match meta {
@@ -154,14 +166,22 @@ impl Document {
154
166
Some ( meta[ "description" ] . as_str ( ) . unwrap ( ) . to_string ( ) )
155
167
} ;
156
168
169
+ // For now the only images shown are blog images TODO: use doc_type to set asset path when working.
157
170
let image = if meta[ "image" ] . is_badvalue ( ) {
158
- Some ( format ! ( "/{}/{}" , doc_type . clone( ) . unwrap ( ) . to_string ( ) , default_image ) )
171
+ Some ( default_image_path . clone ( ) )
159
172
} else {
160
- Some ( format ! (
161
- "/{}/{}" ,
162
- doc_type. clone( ) . unwrap( ) . to_string( ) . to_string( ) ,
163
- meta[ "image" ] . as_str( ) . unwrap( )
164
- ) )
173
+ match PathBuf :: from_str ( meta[ "image" ] . as_str ( ) . unwrap ( ) ) {
174
+ Ok ( image_path) => {
175
+ match image_path. file_name ( ) {
176
+ Some ( file_name) => {
177
+ let file = PathBuf :: from ( file_name) . display ( ) . to_string ( ) ;
178
+ Some ( BLOG . asset_url_root . join ( file) . display ( ) . to_string ( ) )
179
+ } ,
180
+ _ => Some ( default_image_path. clone ( ) )
181
+ }
182
+ } ,
183
+ _ => Some ( default_image_path. clone ( ) )
184
+ }
165
185
} ;
166
186
167
187
let featured = if meta[ "featured" ] . is_badvalue ( ) {
@@ -184,15 +204,15 @@ impl Document {
184
204
}
185
205
None => (
186
206
None ,
187
- Some ( format ! ( "/{}/{}" , doc_type . clone( ) . unwrap ( ) . to_string ( ) , default_image ) ) ,
207
+ Some ( default_image_path . clone ( ) ) ,
188
208
false ,
189
209
Vec :: new ( ) ,
190
210
) ,
191
211
} ;
192
212
193
213
let thumbnail = match & image {
194
214
Some ( image) => {
195
- if image. contains ( default_image ) {
215
+ if image. contains ( & default_image_path ) || doc_type != Some ( DocType :: Blog ) {
196
216
None
197
217
} else {
198
218
Some ( format ! ( "{}{}" , config:: site_domain( ) , image) )
@@ -266,6 +286,8 @@ pub struct Collection {
266
286
pub index : Vec < IndexLink > ,
267
287
/// A list of old paths to new paths in this collection
268
288
redirects : HashMap < & ' static str , & ' static str > ,
289
+ /// Url to assets for this collection
290
+ pub asset_url_root : PathBuf
269
291
}
270
292
271
293
impl Collection {
@@ -276,13 +298,15 @@ impl Collection {
276
298
let root_dir = config:: cms_dir ( ) . join ( & slug) ;
277
299
let asset_dir = root_dir. join ( ".gitbook" ) . join ( "assets" ) ;
278
300
let url_root = PathBuf :: from ( "/" ) . join ( & slug) ;
301
+ let asset_url_root = PathBuf :: from ( "/" ) . join ( & slug) . join ( ".gitbook" ) . join ( "assets" ) ;
279
302
280
303
let mut collection = Collection {
281
304
name,
282
305
root_dir,
283
306
asset_dir,
284
307
url_root,
285
308
redirects,
309
+ asset_url_root,
286
310
..Default :: default ( )
287
311
} ;
288
312
collection. build_index ( hide_root) ;
@@ -419,6 +443,49 @@ impl Collection {
419
443
Ok ( links)
420
444
}
421
445
446
+ // Convert a IndexLink from summary to a file path.
447
+ pub fn url_to_path ( & self , url : & str ) -> PathBuf {
448
+ let url = if url. ends_with ( '/' ) {
449
+ format ! ( "{url}README.md" )
450
+ } else {
451
+ format ! ( "{url}.md" )
452
+ } ;
453
+
454
+ let mut path = PathBuf :: from ( url) ;
455
+ if path. has_root ( ) {
456
+ path = path. strip_prefix ( "/" ) . unwrap ( ) . to_owned ( ) ;
457
+ }
458
+
459
+ let mut path_v = path. components ( ) . collect :: < Vec < _ > > ( ) ;
460
+ path_v. remove ( 0 ) ;
461
+
462
+ let path_pb = PathBuf :: from_iter ( path_v. iter ( ) ) ;
463
+
464
+ self . root_dir . join ( path_pb)
465
+ }
466
+
467
+ // get all urls in the collection and preserve order.
468
+ pub fn get_all_urls ( & self ) -> Vec < String > {
469
+ let mut urls: Vec < String > = Vec :: new ( ) ;
470
+ let mut children: Vec < & IndexLink > = Vec :: new ( ) ;
471
+ for item in & self . index {
472
+ children. push ( item) ;
473
+ }
474
+
475
+ children. reverse ( ) ;
476
+
477
+ while children. len ( ) > 0 {
478
+ let current = children. pop ( ) . unwrap ( ) ;
479
+ urls. push ( current. href . clone ( ) ) ;
480
+
481
+ for i in ( 0 ..current. children . len ( ) ) . rev ( ) {
482
+ children. push ( & current. children [ i] )
483
+ }
484
+ }
485
+
486
+ urls
487
+ }
488
+
422
489
// Sets specified index as currently viewed.
423
490
fn open_index ( & self , path : & PathBuf ) -> Vec < IndexLink > {
424
491
self . index
@@ -802,4 +869,43 @@ This is the end of the markdown
802
869
== expected. chars( ) . filter( |c| !c. is_whitespace( ) ) . collect:: <String >( )
803
870
)
804
871
}
872
+
873
+ // Test we can parse doc meta with out issue.
874
+ #[ sqlx:: test]
875
+ async fn docs_meta_parse ( ) {
876
+ let collection = & crate :: api:: cms:: DOCS ;
877
+
878
+ let urls = collection. get_all_urls ( ) ;
879
+
880
+ for url in urls {
881
+ let path = collection. url_to_path ( url. as_ref ( ) ) ;
882
+ crate :: api:: cms:: Document :: from_path ( & path) . await . unwrap ( ) ;
883
+ }
884
+ }
885
+
886
+ // Test we can parse blog meta with out issue.
887
+ #[ sqlx:: test]
888
+ async fn blog_meta_parse ( ) {
889
+ let collection = & crate :: api:: cms:: BLOG ;
890
+
891
+ let urls = collection. get_all_urls ( ) ;
892
+
893
+ for url in urls {
894
+ let path = collection. url_to_path ( url. as_ref ( ) ) ;
895
+ crate :: api:: cms:: Document :: from_path ( & path) . await . unwrap ( ) ;
896
+ }
897
+ }
898
+
899
+ // Test we can parse career meta with out issue.
900
+ #[ sqlx:: test]
901
+ async fn career_meta_parse ( ) {
902
+ let collection = & crate :: api:: cms:: CAREERS ;
903
+
904
+ let urls = collection. get_all_urls ( ) ;
905
+
906
+ for url in urls {
907
+ let path = collection. url_to_path ( url. as_ref ( ) ) ;
908
+ crate :: api:: cms:: Document :: from_path ( & path) . await . unwrap ( ) ;
909
+ }
910
+ }
805
911
}
0 commit comments