@@ -63,7 +63,7 @@ lazy_static! {
6363) ;
6464}
6565
66- #[ derive( Debug , Serialize , Deserialize , Clone ) ]
66+ #[ derive( Debug , Serialize , Deserialize , Clone , PartialEq ) ]
6767pub enum DocType {
6868Blog ,
6969Docs ,
@@ -115,15 +115,27 @@ pub struct Document {
115115// Gets document markdown
116116impl Document {
117117pub 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+ } ,
124132 _ =>None ,
125133} ;
126134
135+ if doc_type. is_none ( ) {
136+ warn ! ( "doc_type not parsed from path: {path:?}" ) ;
137+ }
138+
127139let contents = tokio:: fs:: read_to_string ( & path) . await ?;
128140
129141let parts = contents. split ( "---" ) . collect :: < Vec < & str > > ( ) ;
@@ -143,7 +155,7 @@ impl Document {
143155( None , contents)
144156} ;
145157
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 ( ) ;
147159
148160// parse meta section
149161let ( description, image, featured, tags) =match meta{
@@ -154,14 +166,22 @@ impl Document {
154166Some ( meta[ "description" ] . as_str ( ) . unwrap ( ) . to_string ( ) )
155167} ;
156168
169+ // For now the only images shown are blog images TODO: use doc_type to set asset path when working.
157170let image =if meta[ "image" ] . is_badvalue ( ) {
158- Some ( format ! ( "/{}/{}" , doc_type . clone( ) . unwrap ( ) . to_string ( ) , default_image ) )
171+ Some ( default_image_path . clone ( ) )
159172} 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+ }
165185} ;
166186
167187let featured =if meta[ "featured" ] . is_badvalue ( ) {
@@ -184,15 +204,15 @@ impl Document {
184204}
185205None =>(
186206None ,
187- Some ( format ! ( "/{}/{}" , doc_type . clone( ) . unwrap ( ) . to_string ( ) , default_image ) ) ,
207+ Some ( default_image_path . clone ( ) ) ,
188208false ,
189209Vec :: new ( ) ,
190210) ,
191211} ;
192212
193213let thumbnail =match & image{
194214Some ( image) =>{
195- if image. contains ( default_image ) {
215+ if image. contains ( & default_image_path ) || doc_type != Some ( DocType :: Blog ) {
196216None
197217} else {
198218Some ( format ! ( "{}{}" , config:: site_domain( ) , image) )
@@ -266,6 +286,8 @@ pub struct Collection {
266286pub index : Vec < IndexLink > ,
267287/// A list of old paths to new paths in this collection
268288redirects : HashMap < & ' static str , & ' static str > ,
289+ /// Url to assets for this collection
290+ pub asset_url_root : PathBuf
269291}
270292
271293impl Collection {
@@ -276,13 +298,15 @@ impl Collection {
276298let root_dir = config:: cms_dir ( ) . join ( & slug) ;
277299let asset_dir = root_dir. join ( ".gitbook" ) . join ( "assets" ) ;
278300let url_root =PathBuf :: from ( "/" ) . join ( & slug) ;
301+ let asset_url_root =PathBuf :: from ( "/" ) . join ( & slug) . join ( ".gitbook" ) . join ( "assets" ) ;
279302
280303let mut collection =Collection {
281304 name,
282305 root_dir,
283306 asset_dir,
284307 url_root,
285308 redirects,
309+ asset_url_root,
286310 ..Default :: default ( )
287311} ;
288312 collection. build_index ( hide_root) ;
@@ -419,6 +443,49 @@ impl Collection {
419443Ok ( links)
420444}
421445
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 itemin & 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 iin ( 0 ..current. children . len ( ) ) . rev ( ) {
482+ children. push ( & current. children [ i] )
483+ }
484+ }
485+
486+ urls
487+ }
488+
422489// Sets specified index as currently viewed.
423490fn open_index ( & self , path : & PathBuf ) ->Vec < IndexLink > {
424491self . index
@@ -802,4 +869,43 @@ This is the end of the markdown
802869 == expected. chars( ) . filter( |c| !c. is_whitespace( ) ) . collect:: <String >( )
803870)
804871}
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 urlin 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 urlin 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 urlin urls{
907+ let path = collection. url_to_path ( url. as_ref ( ) ) ;
908+ crate :: api:: cms:: Document :: from_path ( & path) . await . unwrap ( ) ;
909+ }
910+ }
805911}