YurtCMS 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|