YurtCMS 0.3.1 → 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/parse_ssi.rb +72 -0
- data/lib/yurtcms.rb +11 -15
- data/site/yurt/index.html +8 -7
- data/site/yurt/media/css/styles.css +21 -0
- data/site/yurt/yurt.cgi +80 -18
- data/test/cms_filesystem.rb +6 -3
- data/test/cms_strings.rb +4 -1
- metadata +3 -2
data/lib/parse_ssi.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
|
2
|
+
class ParseSSI
|
3
|
+
attr_reader :web_root, :top, :bottom, :vars
|
4
|
+
|
5
|
+
def initialize web_root
|
6
|
+
@vars = {}
|
7
|
+
@web_root = web_root
|
8
|
+
return
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse file
|
12
|
+
|
13
|
+
# the parse routine currently understands only 3 SSI attributes
|
14
|
+
#
|
15
|
+
# <!--#echo var="FOO" -->
|
16
|
+
#
|
17
|
+
# <!--#include virtual="/path/to/file" -->
|
18
|
+
#
|
19
|
+
# <!--#set var="FOO" value="bar" -->
|
20
|
+
#
|
21
|
+
# more may be added if required.
|
22
|
+
|
23
|
+
result = File.read( @web_root + "/" + file )
|
24
|
+
|
25
|
+
1 while result.sub!(/<!--#(\w+)\s(.*?)\s*-->(\n+)?/) do |match|
|
26
|
+
attrs = parse_attributes($2)
|
27
|
+
case $1
|
28
|
+
when 'echo'
|
29
|
+
@vars[ attrs['var'] ]
|
30
|
+
when 'include'
|
31
|
+
attrs['virtual'].gsub!(/\$\{(\w+)\}/) do |m|
|
32
|
+
if $1
|
33
|
+
@vars[$1]
|
34
|
+
else
|
35
|
+
m
|
36
|
+
end
|
37
|
+
end
|
38
|
+
File.read( @web_root + "/" + attrs['virtual'] )
|
39
|
+
when 'set'
|
40
|
+
@vars[ attrs['var'] ] = attrs['value']
|
41
|
+
''
|
42
|
+
else
|
43
|
+
match
|
44
|
+
end
|
45
|
+
end
|
46
|
+
result
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_attributes(source)
|
50
|
+
attrs = Hash.new
|
51
|
+
source.scan( /(\w+)="([^"]*)"/ ) do |match|
|
52
|
+
attrs[$1] = $2
|
53
|
+
end
|
54
|
+
return attrs
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_tag var, value
|
58
|
+
[ '<!--#set var="' + var + '" value="', value.to_s, '" -->', "\n" ].join
|
59
|
+
end
|
60
|
+
|
61
|
+
def virtual_include_tag path
|
62
|
+
[ '<!--#include virtual="' + path.to_s + '" -->', "\n" ].join
|
63
|
+
end
|
64
|
+
|
65
|
+
def file_include_tag path
|
66
|
+
[ '<!--#include virtual="' + @web_root + path.to_s + '" -->', "\n" ].join
|
67
|
+
end
|
68
|
+
|
69
|
+
def echo_tag var
|
70
|
+
[ '<!--#echo var="' + var + '" -->', "\n" ].join
|
71
|
+
end
|
72
|
+
end
|
data/lib/yurtcms.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
|
2
1
|
require 'yaml'
|
3
2
|
|
4
|
-
|
5
3
|
class YurtCMS
|
6
|
-
attr_reader :data_store, :web_root, :includes, :metatags, :partial, :ext
|
4
|
+
attr_reader :yurt_root, :data_store, :web_root, :includes, :metatags, :partial, :ext
|
7
5
|
def initialize yurt_root
|
8
6
|
require 'rubygems'
|
9
|
-
require_gem '
|
7
|
+
require 'bluecloth' # i used to have require_gem, but i don't think it's needed
|
8
|
+
require 'rubypants'
|
9
|
+
require 'parse_ssi'
|
10
10
|
|
11
11
|
@yurt_root = sanitize_path( yurt_root )
|
12
12
|
@data_store = [ @yurt_root, "content/" ].join
|
@@ -15,6 +15,7 @@
|
|
15
15
|
@metatags = ".metatags"
|
16
16
|
@partial = ".partial"
|
17
17
|
@ext = ".html"
|
18
|
+
@ssi = ParseSSI.new(@web_root)
|
18
19
|
end
|
19
20
|
|
20
21
|
def merge path, file
|
@@ -93,14 +94,15 @@
|
|
93
94
|
end
|
94
95
|
|
95
96
|
def make_metatags input
|
96
|
-
t =
|
97
|
-
d =
|
98
|
-
k =
|
97
|
+
t = @ssi.set_tag('TITLE', input.title) if input.title =~ /\w/
|
98
|
+
d = @ssi.set_tag('DESCRIPTION', input.description) if input.description =~ /\w/
|
99
|
+
k = @ssi.set_tag('KEYWORDS', input.keywords) if input.keywords =~ /\w/
|
99
100
|
|
100
101
|
[ t, d, k ].join
|
101
102
|
end
|
102
103
|
|
103
104
|
def parse_content c
|
105
|
+
#RubyPants.new(BlueCloth.new(c).to_html,1).to_html
|
104
106
|
BlueCloth.new(c).to_html
|
105
107
|
end
|
106
108
|
|
@@ -110,14 +112,8 @@
|
|
110
112
|
end
|
111
113
|
|
112
114
|
[
|
113
|
-
'
|
114
|
-
|
115
|
-
'" -->',
|
116
|
-
"\n",
|
117
|
-
'<!--#include virtual="/includes/',
|
118
|
-
template,
|
119
|
-
'" -->',
|
120
|
-
"\n"
|
115
|
+
@ssi.set_tag('PAGE', path),
|
116
|
+
@ssi.virtual_include_tag('/includes/' + template),
|
121
117
|
].join
|
122
118
|
end
|
123
119
|
|
data/site/yurt/index.html
CHANGED
@@ -86,7 +86,7 @@
|
|
86
86
|
Element.show('spinner');
|
87
87
|
// use an argument looking like this: document.forms["newfile"].content.value
|
88
88
|
|
89
|
-
var url = "/
|
89
|
+
var url = "/preview/"
|
90
90
|
var pars = 'c=' + escape( content );
|
91
91
|
var target = 'nf_preview';
|
92
92
|
|
@@ -125,16 +125,17 @@
|
|
125
125
|
<div id="workspace">
|
126
126
|
</div>
|
127
127
|
<ul id="directory_actions" class="actions" style="display: none;">
|
128
|
-
<li><a href="/
|
129
|
-
<li><a href="/
|
130
|
-
<li><a href="/
|
131
|
-
<li><a href="/
|
128
|
+
<li><a href="/open" class="first" onclick="openFolder(this.href); return false;">Open</a></li>
|
129
|
+
<li><a href="/new_folder" onclick="dispatch(this.href); return false;">New folder...</a></li>
|
130
|
+
<li><a href="/new_file" onclick="dispatch(this.href); return false;">New file...</a></li>
|
131
|
+
<li><a href="/delete" onclick="dispatch(this.href); return false;">Delete</a></li>
|
132
132
|
</ul>
|
133
133
|
<ul id="file_actions" class="actions" style="display: none;">
|
134
|
-
<li><a href="/
|
135
|
-
<li><a href="/
|
134
|
+
<li><a href="/edit" class="first" onclick="dispatch(this.href); return false;">Edit file...</a></li>
|
135
|
+
<li><a href="/delete" onclick="dispatch(this.href); return false;">Delete</a></li>
|
136
136
|
</ul>
|
137
137
|
<div id="spinner" style="display: none;"><img src="/yurt/media/images/spinner.gif" width="16" height="16" border="0" alt="" /></div>
|
138
|
+
<div id="staging"><a href="/staging/">View the site in a staging environment</a></div>
|
138
139
|
</body>
|
139
140
|
</html>
|
140
141
|
|
@@ -182,3 +182,24 @@
|
|
182
182
|
font-family: monospace;
|
183
183
|
}
|
184
184
|
|
185
|
+
#staging {
|
186
|
+
position: absolute;
|
187
|
+
top: 50px;
|
188
|
+
left: 600px;
|
189
|
+
height: 20px;
|
190
|
+
background-color: #eeeeea;
|
191
|
+
border: 1px solid black;
|
192
|
+
border-bottom: 0px none;
|
193
|
+
font-family: Geneva, verdana;
|
194
|
+
font-size: 12px;
|
195
|
+
padding: 4px;
|
196
|
+
}
|
197
|
+
|
198
|
+
#staging a {
|
199
|
+
color: #000;
|
200
|
+
text-decoration: none;
|
201
|
+
}
|
202
|
+
|
203
|
+
#staging a:hover {
|
204
|
+
text-decoration: underline;
|
205
|
+
}
|
data/site/yurt/yurt.cgi
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby -rubygems
|
2
2
|
|
3
3
|
require 'yurtcms'
|
4
|
+
require 'parse_ssi'
|
4
5
|
require 'camping'
|
5
6
|
require 'bluecloth'
|
6
7
|
|
@@ -105,6 +106,74 @@ module Yurt::Controllers
|
|
105
106
|
render :cancel
|
106
107
|
end
|
107
108
|
end
|
109
|
+
|
110
|
+
class Static < R '/(static|staging|media|yurt)/(.*)$'
|
111
|
+
MIME_TYPES = {'.css' => 'text/css', '.js' => 'text/javascript', '.jpg' => 'image/jpeg', '.gif' => 'image/gif', '.png' => 'image/png', '.html' => 'text/html'}
|
112
|
+
|
113
|
+
def get path_source, path
|
114
|
+
@y = get_yurtcms
|
115
|
+
|
116
|
+
case path_source
|
117
|
+
when "yurt"
|
118
|
+
web_root = [ @y.yurt_root, 'yurt/' ].join
|
119
|
+
path_to_file = [ @y.yurt_root, 'yurt/', path ].join
|
120
|
+
when "media"
|
121
|
+
web_root = [ @y.web_root, 'media/' ].join
|
122
|
+
path_to_file = [ @y.web_root, 'media/', path ].join
|
123
|
+
else
|
124
|
+
web_root = @y.web_root
|
125
|
+
path_to_file = [ @y.web_root, path ].join
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
if path =~ /\.\./ # sample test to prevent directory traversal attacks
|
130
|
+
@status = "404"
|
131
|
+
"404 - Not Found"
|
132
|
+
return
|
133
|
+
end
|
134
|
+
|
135
|
+
# not sure if this would be a reasonable assumption to make -- or
|
136
|
+
# if this is the right place to do this
|
137
|
+
if File.directory?(path_to_file)
|
138
|
+
path_to_file = path_to_file + "/index.html"
|
139
|
+
path = path + "index.html"
|
140
|
+
end
|
141
|
+
|
142
|
+
# bulletproofing access to the files
|
143
|
+
unless File.exists?(path_to_file)
|
144
|
+
@status = "404"
|
145
|
+
"404 - Not Found"
|
146
|
+
return
|
147
|
+
end
|
148
|
+
unless File.file?(path_to_file)
|
149
|
+
@status = "403"
|
150
|
+
"403 - Forbidden"
|
151
|
+
return
|
152
|
+
end
|
153
|
+
unless File.readable?(path_to_file)
|
154
|
+
@status = "403"
|
155
|
+
"403 - Forbidden"
|
156
|
+
return
|
157
|
+
end
|
158
|
+
unless File.size?(path_to_file)
|
159
|
+
@status = "403"
|
160
|
+
"403 - Forbidden"
|
161
|
+
return
|
162
|
+
end
|
163
|
+
|
164
|
+
@headers['Content-Type'] = MIME_TYPES[path_to_file[/\.\w+$/, 0]] || "text/plain"
|
165
|
+
|
166
|
+
# I set this up as a case in case I need to handle alternative mime types.
|
167
|
+
case @headers['Content-Type']
|
168
|
+
when 'text/html'
|
169
|
+
p = ParseSSI.new(web_root)
|
170
|
+
@p = p.parse(path).gsub(/href="\//, 'href="/static/').gsub(/"\/media/, '"/static/media')
|
171
|
+
render :static
|
172
|
+
else
|
173
|
+
@headers['X-Sendfile'] = path_to_file
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
108
177
|
end
|
109
178
|
|
110
179
|
module Yurt::Helpers
|
@@ -126,25 +195,15 @@ end
|
|
126
195
|
|
127
196
|
module Yurt::Views
|
128
197
|
|
129
|
-
# If you have a `layout' method like this, it
|
130
|
-
# will wrap the HTML in the other methods. The
|
131
|
-
# `self << yield' is where the HTML is inserted.
|
132
|
-
# def layout
|
133
|
-
# html do
|
134
|
-
# title { 'My Yurt' }
|
135
|
-
# body { self << yield }
|
136
|
-
# end
|
137
|
-
# end
|
138
|
-
|
139
198
|
# The `index' view. Inside your views, you express
|
140
199
|
# the HTML in Ruby. See http://code.whytheluckystiff.net/markaby/.
|
141
200
|
def index
|
142
|
-
|
201
|
+
text File.read("index.html")
|
143
202
|
end
|
144
203
|
|
145
204
|
def open_folder
|
146
205
|
text '<ul class="listing">'
|
147
|
-
@contents.each do |file, type|
|
206
|
+
@contents.sort.each do |file, type|
|
148
207
|
li :class => type[0] do
|
149
208
|
a :href => "#", :onclick => "return false;", :id => @p + "/" + file do
|
150
209
|
text file
|
@@ -170,7 +229,7 @@ module Yurt::Views
|
|
170
229
|
|
171
230
|
def new_file
|
172
231
|
text %Q(
|
173
|
-
<form action="/
|
232
|
+
<form action="/new_file/" method="post" name="newfile" class="dialog_box" id="newfile" onsubmit="dispatch_post('/new_file/', 'newfile');return false;">
|
174
233
|
<fieldset>
|
175
234
|
<legend>
|
176
235
|
<a href="#" onclick="toggleTabs('nf_dialog', 'nf_preview', 'nf_help');return false;">New File</a> |
|
@@ -188,8 +247,8 @@ module Yurt::Views
|
|
188
247
|
</div>
|
189
248
|
<textarea name="content" class="contentarea">#{ @f['content'] }</textarea>
|
190
249
|
<input type="hidden" name="path" value="#{@f['path']}" />
|
191
|
-
<input type="button" name="add" value="Save" onclick="dispatch_post('/
|
192
|
-
<input type="button" name="cancel" value="Cancel" onclick="dispatch('/
|
250
|
+
<input type="button" name="add" value="Save" onclick="dispatch_post('/new_file/', 'newfile')" />
|
251
|
+
<input type="button" name="cancel" value="Cancel" onclick="dispatch('/cancel')" />
|
193
252
|
</div>
|
194
253
|
<div id="nf_preview" class="preview" style="display: none;">
|
195
254
|
</div>
|
@@ -326,7 +385,7 @@ module Yurt::Views
|
|
326
385
|
|
327
386
|
def new_folder
|
328
387
|
text %Q(
|
329
|
-
<form action="/
|
388
|
+
<form action="/new_folder/" method="post" name="newfolder" class="dialog_box" id="newfolder" onsubmit="dispatch_post('/new_folder/', 'newfolder');return false;">
|
330
389
|
<fieldset>
|
331
390
|
<legend>
|
332
391
|
<a href="#" onclick="toggleTabs('nf_dialog', 'nf_help');return false;">New Folder</a> |
|
@@ -335,8 +394,8 @@ module Yurt::Views
|
|
335
394
|
<div id="nf_dialog" class="dialog">
|
336
395
|
<label><input type="text" name="foldername" value="" /> Folder name</label>
|
337
396
|
<input type="hidden" name="path" value="#{@p}" />
|
338
|
-
<input type="button" name="add" value="Save" onclick="dispatch_post('/
|
339
|
-
<input type="button" name="cancel" value="Cancel" onclick="dispatch('/
|
397
|
+
<input type="button" name="add" value="Save" onclick="dispatch_post('/new_folder/', 'newfolder')" />
|
398
|
+
<input type="button" name="cancel" value="Cancel" onclick="dispatch('/cancel')" />
|
340
399
|
</div>
|
341
400
|
<div id="nf_help" class="help" style="display: none;">
|
342
401
|
<p>Please use characters that you would normally expect to be valid for your folder/directory name. We suggest using upper and lower case letters, numbers, and the following punctuation (sans quotes): ".", "_", "-". If you try to type in illegal characters, the application will convert them to underscores.</p>
|
@@ -384,6 +443,9 @@ module Yurt::Views
|
|
384
443
|
end
|
385
444
|
end
|
386
445
|
|
446
|
+
def static
|
447
|
+
text @p
|
448
|
+
end
|
387
449
|
end
|
388
450
|
|
389
451
|
if __FILE__ == $0
|
data/test/cms_filesystem.rb
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
4
|
+
require 'yurtcms'
|
5
|
+
require 'parse_ssi'
|
4
6
|
require 'test/unit'
|
5
7
|
|
6
8
|
class Input
|
7
|
-
attr_reader :title, :keywords, :description, :partial, :content, :path, :filename
|
8
|
-
attr_writer :title, :keywords, :description, :partial, :content, :path, :filename
|
9
|
+
attr_reader :title, :keywords, :description, :partial, :content, :path, :filename, :template
|
10
|
+
attr_writer :title, :keywords, :description, :partial, :content, :path, :filename, :template
|
9
11
|
end
|
10
12
|
|
11
13
|
class TestYurtFS < Test::Unit::TestCase
|
@@ -43,6 +45,7 @@ class TestYurtFS < Test::Unit::TestCase
|
|
43
45
|
i.content = "This is *the* content of the file."
|
44
46
|
i.path = "/"
|
45
47
|
i.filename = "my_file"
|
48
|
+
i.template = "template.html"
|
46
49
|
|
47
50
|
@y.write_all_files( i )
|
48
51
|
|
data/test/cms_strings.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
#! /usr/bin/env ruby
|
2
2
|
|
3
|
-
|
3
|
+
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
4
|
+
require 'yurtcms'
|
5
|
+
require 'parse_ssi'
|
4
6
|
require 'test/unit'
|
5
7
|
|
6
8
|
class Input
|
@@ -126,6 +128,7 @@ class TestYurtCMS < Test::Unit::TestCase
|
|
126
128
|
end
|
127
129
|
|
128
130
|
def test_make_placeholder
|
131
|
+
warn @y.make_placeholder( 'solutions/foo', 'template.html' )
|
129
132
|
assert_equal( "<!--#set var=\"PAGE\" value=\"solutions/foo\" -->\n<!--#include virtual=\"/includes/template.html\" -->\n", @y.make_placeholder( 'solutions/foo', 'template.html' ) )
|
130
133
|
end
|
131
134
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: YurtCMS
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date:
|
6
|
+
version: 0.4.1
|
7
|
+
date: 2007-01-08 00:00:00 -05:00
|
8
8
|
summary: The Web CMS that does less!
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -29,6 +29,7 @@ authors:
|
|
29
29
|
- Robert Hahn
|
30
30
|
files:
|
31
31
|
- bin/yurt
|
32
|
+
- lib/parse_ssi.rb
|
32
33
|
- lib/yurtcms.rb
|
33
34
|
- site/content
|
34
35
|
- site/htdocs
|