Commit 96addfa9 authored by Léo Andrès's avatar Léo Andrès
Browse files

Merge branch 'z-2021-09-22-blog-article' into 'master'

add WEBROOT and draft mode

See merge request OCamlPro/www!8
parents 505a94c2 43aae3dd
_build/
*~
/_opam
/ocp-nginx
all: build
build:
dune build @all
cp -f _build/default/src/server.exe ocp-nginx
exec: build
dune exec -- src/server.exe --webroot $(PWD)/src/content
draft: build
dune exec -- src/server.exe --webroot $(PWD)/src/content --draft
www:
xdg-open http://127.0.0.1:8080
clean:
dune clean
rm -f ocp-nginx
......@@ -22,4 +22,7 @@
(markup
(>= 1.0.2))
(lambdasoup
(>= 0.7.2))))
(>= 0.7.2))
(ez_file (>= 0.1))
(ez_subst (>= 0.2))
))
......@@ -10,6 +10,8 @@ depends: [
"ubase" {>= "0.04"}
"markup" {>= "1.0.2"}
"lambdasoup" {>= "0.7.2"}
"ez_file" {>= "0.1"}
"ez_subst" {>= "0.2"}
]
build: [
["dune" "subst"] {pinned}
......
......@@ -83,6 +83,8 @@ depends: [
"uri" {= "4.2.0"}
"uutf" {= "1.0.2"}
"yojson" {= "1.7.0"}
"ez_subst" {= "0.2.0"}
"ez_file" {= "0.2.0"}
]
build: [
["dune" "subst"] {pinned}
......@@ -97,4 +99,4 @@ build: [
"@runtest" {with-test}
"@doc" {with-doc}
]
]
\ No newline at end of file
]
let render_unsafe ~title ~content ?(authors = "OCamlPro") ?(keywords = Meta.default_keywords) ?(description = Meta.default_description) () =
<!DOCTYPE html>
<html lang="en">
<html lang="![lang]>">
<head>
<meta charset="utf-8"/>
<title><%s title %> | OCamlPro</title>
<meta name="author" content="<%s! authors %>" />
<meta name="description" content="<%s! description %>" />
<meta name="keywords" content="<%s! keywords %>" />
<title>![title] | OCamlPro</title>
<meta name="description" content="![description]" />
<meta name="keywords" content="![keywords]" />
<link rel="icon" type="image/svg+xml" href="/assets/img/logo_ocp_icon.svg">
<link href="/assets/css/bootstrap.min.css" rel="stylesheet"/>
<link href="/assets/css/prism.css" rel="stylesheet"/>
......@@ -66,7 +63,10 @@ let render_unsafe ~title ~content ?(authors = "OCamlPro") ?(keywords = Meta.defa
<li class="nav-item">
<a class="nav-link" href="/blog">Blog</a>
</li>
</ul>
![if:draft] <li class="nav-item">
<a class="nav-link" href="/startup_studio">Startup Studio</a>
</li>
![if:end] </ul>
</div>
</div>
</nav>
......@@ -77,11 +77,11 @@ let render_unsafe ~title ~content ?(authors = "OCamlPro") ?(keywords = Meta.defa
<br />
<main>
<div class="container">
<%s! content %>
![content]
</div>
<hr class="featurette-divider">
<footer class="container">
<p>&copy; 2011–2021 OCamlPro &middot;
<p>&copy; 2011–![year] OCamlPro &middot;
<a href="https://twitter.com/ocamlpro">Twitter</a> &middot;
<a href="https://www.linkedin.com/company/2152404/">LinkedIn</a> &middot;
<a href="mailto:contact@ocamlpro.com">Email</a> &middot;
......@@ -99,3 +99,4 @@ let render_unsafe ~title ~content ?(authors = "OCamlPro") ?(keywords = Meta.defa
</script>
</body>
</html>
(executable
(public_name server)
(modules content server template blog blog_content feed error meta)
(libraries dream omd ubase markup lambdasoup))
(rule
(targets template.ml)
(deps template.eml.html)
(action
(run dream_eml %{deps} --workspace %{workspace_root})))
(modules content server blog blog_content feed error meta)
(libraries dream omd ubase markup lambdasoup ez_file ez_subst))
(rule
(target content.ml)
......
open EzFile.OP (* add // = Filename.concat *)
open Ez_subst.V2
let webroot =
ref (
match Sys.getenv "WEBROOT" with
| exception _ -> None
| s -> Some s
)
let read_content file =
match !webroot with
| None -> Content.read file
| Some dir ->
try
Some ( EzFile.read_file ( dir // file ) )
with _ -> Content.read file
let read_blog file =
match !webroot with
| None -> Blog_content.read file
| Some dir ->
try
Some ( EzFile.read_file ( dir // "blog" // "assets" // file ) )
with _ -> Blog_content.read file
let draft = ref false
let render_unsafe ~title ~content
?(lang="en")
?(authors = "OCamlPro")
?(keywords = Meta.default_keywords)
?(description = Meta.default_description)
() =
let s = match read_content "template.html" with
| None -> assert false
| Some s -> s in
let skipper = ref [] in
EZ_SUBST.string ~sep:'!' ~ctxt:() s
~skipper
~bracket:(fun () s ->
match s with
| "year" -> "2021"
| "if:draft" ->
skipper := not !draft :: !skipper; ""
| "if:else" ->
begin match !skipper with
| cond :: tail -> skipper := not cond :: tail; ""
| [] -> failwith "!{if:else} without !{if:COND}"
end
| "if:end" ->
begin match !skipper with
| _cond :: tail -> skipper := tail; ""
| [] -> failwith "!{if:end} without !{if:COND}"
end
| "lang" -> lang
| "title" -> Dream.html_escape title
| "content" -> content
| "authors" -> Dream.html_escape authors
| "keywords" -> Dream.html_escape keywords
| "description" -> Dream.html_escape description
| _ ->
Printf.eprintf "Unbound expression !{%s}\n%!" s;
s)
let render ~lang ~title ~content =
render_unsafe ~lang ~title ~content:(Dream.html_escape content)
let my_error_template _debug_info suggested_response =
let status = Dream.status suggested_response in
let code = Dream.status_to_int status
and reason = Dream.status_to_string status in
let content = Error.page code reason in
Dream.html (Template.render_unsafe ~title:"Oops" ~content ())
Dream.html (render_unsafe ~title:"Oops" ~content ())
let asset_loader _root path _request =
match Content.read ("assets/" ^ path) with
match read_content ("assets/" ^ path) with
| None -> Dream.empty `Not_Found
| Some asset -> Dream.respond asset
let blog_asset_loader _root path _request =
match Blog_content.read path with
match read_blog path with
| None -> Dream.empty `Not_Found
| Some asset -> Dream.respond asset
let feed_loader _root _path _loader = Dream.respond Feed.generate
let page path =
match Content.read (path ^ ".md") with
match read_content (path ^ ".md") with
| None -> None
| Some page -> Some (Omd.of_string page |> Omd.to_html)
let given_article path =
match Content.read ("blog/" ^ path ^ ".md") with
match read_content ("blog/" ^ path ^ ".md") with
| None -> None
| Some blog_article -> begin
match Blog.article_of_string blog_article path with
......@@ -50,53 +118,72 @@ let title content =
let old_to_new = [ ("old", "new") ]
let () =
begin
match Filename.basename Sys.argv.(0) with
| "nginx" -> ()
| _ ->
Arg.parse
[
"--webroot", Arg.String (fun s -> webroot := Some s),
"DIR Set DIR as a content web root";
"--draft", Arg.Set draft,
" Draft mode";
]
(fun s ->
Printf.eprintf "Warning: unexpected argument %S\n%!" s ;
exit 2
)
"server";
end;
Dream.run ~interface:"0.0.0.0"
~error_handler:(Dream.error_template my_error_template)
@@ Dream.logger
@@ Dream.router
[ Dream.get "/assets/**" (Dream.static ~loader:asset_loader "")
; Dream.get "/blog/assets/**" (Dream.static ~loader:blog_asset_loader "")
; Dream.get "/blog/feed" (Dream.static ~loader:feed_loader "")
; Dream.get "/" (fun _request ->
match page "index" with
| None -> Dream.empty `Not_Found
| Some content ->
let title = title content in
Dream.html (Template.render_unsafe ~title ~content ()) )
; Dream.get "/blog/category" (fun _request ->
let content = Blog.category_home in
let title = title content in
Dream.html (Template.render_unsafe ~title ~content ()) )
; Dream.get "/blog/category/:cat" (fun request ->
let content = Blog.given_category (Dream.param "cat" request) in
let title = title content in
Dream.html (Template.render_unsafe ~title ~content ()) )
; Dream.get "/blog/authors/:author" (fun request ->
let content, authors =
Blog.given_author (Dream.param "author" request)
in
let title = title content in
Dream.html (Template.render_unsafe ~title ~content ~authors ()) )
; Dream.get "/blog/:title" (fun request ->
match given_article (Dream.param "title" request) with
| None -> Dream.empty `Not_Found
| Some (content, tags, authors) ->
let title = title content in
let authors = Dream.html_escape (String.concat ", " authors) in
let keywords =
Dream.html_escape (String.concat ", " (tags @ Meta.keywords_l))
in
Dream.html
(Template.render_unsafe ~title ~content ~authors ~keywords ()) )
; Dream.get "/blog" (fun _request ->
let content = Blog.home_page in
let title = title content in
Dream.html (Template.render_unsafe ~title ~content ()) )
; Dream.get "/:page" (fun request ->
match page (Dream.param "page" request) with
| None -> Dream.empty `Not_Found
| Some content ->
let title = title content in
Dream.html (Template.render_unsafe ~title ~content ()) )
]
[ Dream.get "/assets/**" (Dream.static ~loader:asset_loader "")
; Dream.get "/blog/assets/**" (Dream.static ~loader:blog_asset_loader "")
; Dream.get "/blog/feed" (Dream.static ~loader:feed_loader "")
; Dream.get "/" (fun _request ->
match page "index" with
| None -> Dream.empty `Not_Found
| Some content ->
let title = title content in
Dream.html (render_unsafe ~title ~content ()) )
; Dream.get "/blog/category" (fun _request ->
let content = Blog.category_home in
let title = title content in
Dream.html (render_unsafe ~title ~content ()) )
; Dream.get "/blog/category/:cat" (fun request ->
let content = Blog.given_category (Dream.param "cat" request) in
let title = title content in
Dream.html (render_unsafe ~title ~content ()) )
; Dream.get "/blog/authors/:author" (fun request ->
let content, authors =
Blog.given_author (Dream.param "author" request)
in
let title = title content in
Dream.html (render_unsafe ~title ~content ~authors ()) )
; Dream.get "/blog/:title" (fun request ->
match given_article (Dream.param "title" request) with
| None -> Dream.empty `Not_Found
| Some (content, tags, authors) ->
let title = title content in
let authors = Dream.html_escape (String.concat ", " authors) in
let keywords =
Dream.html_escape (String.concat ", " (tags @ Meta.keywords_l))
in
Dream.html
(render_unsafe ~title ~content ~authors ~keywords ()) )
; Dream.get "/blog" (fun _request ->
let content = Blog.home_page in
let title = title content in
Dream.html (render_unsafe ~title ~content ()) )
; Dream.get "/:page" (fun request ->
match page (Dream.param "page" request) with
| None -> Dream.empty `Not_Found
| Some content ->
let title = title content in
Dream.html (render_unsafe ~title ~content ()) )
]
@@ Dream.not_found
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment