1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Web server to server generated files and modify the wiki from a web form
22 intrude import wiki_html
24 # Page for editing markdown source
28 # Part of the title before the name of the page
29 var title_prefix
: String
31 # Markdown content, for previews
34 # Custom HTML code, for forms and links
37 init do content
= (md
or else "").md_to_html
.to_s
+ html
39 redef fun dir_href
do return "edit" / href
44 s
.title
= title_prefix
+ title
48 # Fill and return a new `HttpResponse` with this page content
49 fun to_http_response
: HttpResponse
51 var resp
= new HttpResponse(200)
52 resp
.body
= tpl_page
.write_to_string
57 # Action to serve edit forms, show previews and apply changes
61 # Full public URL for the root of this wiki
64 # Path to the wiki config
65 var config_file_path
: String
67 # Configuration of the Wiki, loaded once
68 var wiki_config
= new WikiConfig(config_file_path
) is lazy
70 # Path to the root of the wiki
71 private var wiki_root
: String = config_file_path
.dirname
is lazy
73 # Path to the source files
74 private var source_dir
: String = (wiki_root
/ wiki_config
.source_dir
).simplify_path
+ "/" is lazy
76 # List of acceptable password to apply modifications
78 # If `null`, no password checks are applied and all modifications are accepted.
79 var passwords
: nullable Collection[String]
81 # Reload the wiki instance with the latest changes
84 var wiki
= new Nitiwiki(wiki_config
)
89 redef fun answer
(http_request
, turi
)
91 var action
= http_request
.string_arg
("action")
92 var markdown
= http_request
.post_args
.get_or_default
("content", "")
94 var file_path
= turi
.strip_leading_slash
95 file_path
= wiki_root
/ file_path
97 if not file_path
.simplify_path
.has_prefix
(source_dir
) then
98 # Attempting to access a file outside the source directory
99 var entity
= new WikiEditForm(wiki
, turi
.strip_leading_slash
,
100 "Access denied: ", "", "<p>Target outside of the source directory</p>")
101 return entity
.to_http_response
104 if action
== "Submit" then
105 var passwords
= passwords
106 var password
= http_request
.post_args
.get_or_null
("password")
107 if passwords
!= null and (password
== null or not passwords
.has
(password
.md5
)) then
109 var entity
= new WikiEditForm(wiki
, turi
.strip_leading_slash
,
110 "Changes rejected: ", "", "<p>Password invalid</p>")
111 return entity
.to_http_response
114 # Save markdown source
115 markdown
= markdown
.replace
('\r', "")
116 markdown
.write_to_file file_path
123 if turi
.has_prefix
("/pages/") then
124 link
= root_url
/ turi
.substring_from
(7)
125 else link
= root_url
/ turi
126 link
= link
.strip_extension
(".md") + ".html"
130 <p>Your edits were recorded and the file is updated: <a href="{{{link}}}">{{{link}}}</a></p>
132 var entity
= new WikiEditForm(wiki
, turi
.strip_leading_slash
, "Changes saved: ", "", body
)
133 return entity
.to_http_response
135 # Show edit form, and preview when requested
137 # When not in a preview, use the local content of the file
138 if action
!= "Preview" then markdown
= file_path
.to_path
.read_all
141 <form method="POST" action="/edit{{{turi}}}">
142 You may edit the file. When you are done, click on "Submit".<br/>
143 <textarea name="content" rows="30" cols="80">{{{markdown.html_escape}}}</textarea><br/>
145 if passwords
!= null then form
+= """
146 Password: <input type="password" name="password"><br/>
149 <input type="submit" name="action" value="Preview">
150 <input type="submit" name="action" value="Submit">
154 # Show processed markdown only on preview
155 if action
!= "Preview" then markdown
= ""
157 var entity
= new WikiEditForm(wiki
, turi
.strip_leading_slash
, "Edit source: ", markdown
, form
)
158 return entity
.to_http_response
164 private fun strip_leading_slash
: String
166 if has_prefix
("/") then return substring_from
(1)
171 var config_file_path
= "config.ini"
172 var iface
= "localhost:8080"
173 var password_file_path
= "passwords"
175 # Load passwords for file
176 var passwords
= if password_file_path
.file_exists
then
177 password_file_path
.to_path
.read_lines
180 var vh
= new VirtualHost(iface
)
182 # Serve Markdown editing form
183 var action
= new EditAction("http://" + iface
, config_file_path
, passwords
)
184 vh
.routes
.add
new Route("/edit", action
)
186 # Serve the static (and generated) content
187 var path_to_public_files
= config_file_path
.dirname
/ action
.wiki_config
.out_dir
188 vh
.routes
.add
new Route(null, new FileServer(path_to_public_files
))
190 var factory
= new HttpFactory.and_libevent
191 factory
.config
.virtual_hosts
.add vh