utopia 0.9.17
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/ext/utopia/xnode/fast_scanner/extconf.rb +6 -0
- data/ext/utopia/xnode/fast_scanner/parser.c +289 -0
- data/lib/utopia.rb +2 -0
- data/lib/utopia/etanni.rb +96 -0
- data/lib/utopia/extensions.rb +87 -0
- data/lib/utopia/link.rb +243 -0
- data/lib/utopia/middleware.rb +33 -0
- data/lib/utopia/middleware/all.rb +24 -0
- data/lib/utopia/middleware/benchmark.rb +47 -0
- data/lib/utopia/middleware/content.rb +139 -0
- data/lib/utopia/middleware/content/node.rb +363 -0
- data/lib/utopia/middleware/controller.rb +198 -0
- data/lib/utopia/middleware/directory_index.rb +54 -0
- data/lib/utopia/middleware/localization.rb +94 -0
- data/lib/utopia/middleware/localization/name.rb +64 -0
- data/lib/utopia/middleware/logger.rb +68 -0
- data/lib/utopia/middleware/redirector.rb +171 -0
- data/lib/utopia/middleware/requester.rb +116 -0
- data/lib/utopia/middleware/static.rb +186 -0
- data/lib/utopia/path.rb +193 -0
- data/lib/utopia/response_helper.rb +22 -0
- data/lib/utopia/session/encrypted_cookie.rb +115 -0
- data/lib/utopia/tag.rb +84 -0
- data/lib/utopia/tags.rb +32 -0
- data/lib/utopia/tags/all.rb +25 -0
- data/lib/utopia/tags/env.rb +24 -0
- data/lib/utopia/tags/fortune.rb +20 -0
- data/lib/utopia/tags/gallery.rb +175 -0
- data/lib/utopia/tags/google_analytics.rb +37 -0
- data/lib/utopia/tags/node.rb +24 -0
- data/lib/utopia/tags/override.rb +28 -0
- data/lib/utopia/time_store.rb +102 -0
- data/lib/utopia/version.rb +24 -0
- data/lib/utopia/xnode.rb +17 -0
- data/lib/utopia/xnode/processor.rb +97 -0
- data/lib/utopia/xnode/scanner.rb +153 -0
- metadata +168 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
module Rack
|
17
|
+
class Response
|
18
|
+
def self.create(response, &block)
|
19
|
+
self.new(response[2], response[0], response[1], &block)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'openssl'
|
17
|
+
require 'digest/sha2'
|
18
|
+
|
19
|
+
module Utopia
|
20
|
+
module Session
|
21
|
+
|
22
|
+
class EncryptedCookie
|
23
|
+
RACK_SESSION = "rack.session"
|
24
|
+
RACK_SESSION_OPTIONS = "rack.session.options"
|
25
|
+
|
26
|
+
def initialize(app, options={})
|
27
|
+
@app = app
|
28
|
+
@cookie = options[:cookie] || (RACK_SESSION + ".encrypted")
|
29
|
+
@secret = Digest::SHA256.digest(options[:secret])
|
30
|
+
|
31
|
+
@default_options = {
|
32
|
+
:domain => nil,
|
33
|
+
:path => "/",
|
34
|
+
:expires_after => nil
|
35
|
+
}.merge(options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def call(env)
|
39
|
+
original_session = load_session(env).dup
|
40
|
+
|
41
|
+
status, headers, body = @app.call(env)
|
42
|
+
|
43
|
+
if original_session != env[RACK_SESSION]
|
44
|
+
commit_session(env, status, headers, body)
|
45
|
+
end
|
46
|
+
|
47
|
+
return [status, headers, body]
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def load_session(env)
|
53
|
+
session = {}
|
54
|
+
|
55
|
+
request = Rack::Request.new(env)
|
56
|
+
data = request.cookies[@cookie]
|
57
|
+
|
58
|
+
if data
|
59
|
+
session = decrypt(data) rescue session
|
60
|
+
end
|
61
|
+
|
62
|
+
env[RACK_SESSION] = session
|
63
|
+
env[RACK_SESSION_OPTIONS] = @default_options.dup
|
64
|
+
|
65
|
+
return session
|
66
|
+
end
|
67
|
+
|
68
|
+
def commit_session(env, status, headers, body)
|
69
|
+
session = env[RACK_SESSION]
|
70
|
+
|
71
|
+
data = encrypt(session)
|
72
|
+
|
73
|
+
if data.size > (1024 * 4)
|
74
|
+
env["rack.errors"].puts "Error: #{self.class.name} data exceeds 4K. Content Dropped!"
|
75
|
+
else
|
76
|
+
options = env[RACK_SESSION_OPTIONS]
|
77
|
+
cookie = {:value => data}
|
78
|
+
cookie[:expires] = Time.now + options[:expires_after] unless options[:expires_after].nil?
|
79
|
+
|
80
|
+
Rack::Utils.set_cookie_header!(headers, @cookie, cookie.merge(options))
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def encrypt(hash)
|
85
|
+
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
|
86
|
+
c.encrypt
|
87
|
+
|
88
|
+
# your pass is what is used to encrypt/decrypt
|
89
|
+
c.key = @secret
|
90
|
+
c.iv = iv = c.random_iv
|
91
|
+
|
92
|
+
e = c.update(Marshal.dump(hash))
|
93
|
+
e << c.final
|
94
|
+
|
95
|
+
return [iv, e].pack("m16m*")
|
96
|
+
end
|
97
|
+
|
98
|
+
def decrypt(data)
|
99
|
+
iv, e = data.unpack("m16m*")
|
100
|
+
|
101
|
+
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
|
102
|
+
c.decrypt
|
103
|
+
|
104
|
+
c.key = @secret
|
105
|
+
c.iv = iv
|
106
|
+
|
107
|
+
d = c.update(e)
|
108
|
+
d << c.final
|
109
|
+
|
110
|
+
return Marshal.load(d)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
end
|
data/lib/utopia/tag.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
module Utopia
|
17
|
+
|
18
|
+
class Tag
|
19
|
+
def initialize(name, attributes = {})
|
20
|
+
@name = name
|
21
|
+
@attributes = attributes
|
22
|
+
@closed = false
|
23
|
+
end
|
24
|
+
|
25
|
+
attr :name
|
26
|
+
attr :attributes
|
27
|
+
attr :closed, true
|
28
|
+
|
29
|
+
def [](key)
|
30
|
+
@attributes[key]
|
31
|
+
end
|
32
|
+
|
33
|
+
def append(text)
|
34
|
+
@content ||= StringIO.new
|
35
|
+
@content.write text
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_html(content = nil, buf = StringIO.new)
|
39
|
+
write_full_html(buf, content)
|
40
|
+
|
41
|
+
return buf.string
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_hash
|
45
|
+
@attributes
|
46
|
+
end
|
47
|
+
|
48
|
+
def to_s
|
49
|
+
buf = StringIO.new
|
50
|
+
write_open_html(buf)
|
51
|
+
return buf.string
|
52
|
+
end
|
53
|
+
|
54
|
+
def write_open_html(buf, terminate = false)
|
55
|
+
buf ||= StringIO.new
|
56
|
+
buf.write "<#{name}"
|
57
|
+
|
58
|
+
@attributes.each do |key, value|
|
59
|
+
buf.write " #{key}=\"#{value}\""
|
60
|
+
end
|
61
|
+
|
62
|
+
if terminate
|
63
|
+
buf.write "/>"
|
64
|
+
else
|
65
|
+
buf.write ">"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def write_close_html(buf)
|
70
|
+
buf.write "</#{name}>"
|
71
|
+
end
|
72
|
+
|
73
|
+
def write_full_html(buf, content = nil)
|
74
|
+
if @closed && content == nil
|
75
|
+
write_open_html(buf, true)
|
76
|
+
else
|
77
|
+
write_open_html(buf)
|
78
|
+
buf.write(content)
|
79
|
+
write_close_html(buf)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
data/lib/utopia/tags.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
module Utopia
|
17
|
+
module Tags
|
18
|
+
@@all = {}
|
19
|
+
|
20
|
+
def self.register(name, tag)
|
21
|
+
@@all[name] = tag
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.create(name, &block)
|
25
|
+
@@all[name] = Proc.new(&block)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.all
|
29
|
+
@@all
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'pathname'
|
17
|
+
|
18
|
+
Pathname.new(__FILE__).dirname.entries.grep(/\.rb$/).each do |path|
|
19
|
+
name = File.basename(path.to_s, ".rb")
|
20
|
+
|
21
|
+
if name != "all"
|
22
|
+
require "utopia/tags/#{name}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'utopia/tags'
|
17
|
+
|
18
|
+
Utopia::Tags.create("env") do |transaction, state|
|
19
|
+
only = state[:only].split(",").collect(&:to_sym) rescue []
|
20
|
+
|
21
|
+
if defined?(UTOPIA_ENV) && only.include?(UTOPIA_ENV)
|
22
|
+
transaction.parse_xml(state.content)
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'utopia/tags'
|
17
|
+
|
18
|
+
Utopia::Tags.create("fortune") do |transaction, state|
|
19
|
+
"<pre>#{`fortune`.to_html}</pre>"
|
20
|
+
end
|
@@ -0,0 +1,175 @@
|
|
1
|
+
# Copyright (c) 2010 Samuel Williams. Released under the GNU GPLv3.
|
2
|
+
#
|
3
|
+
# This program is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require 'utopia/tags'
|
17
|
+
|
18
|
+
require 'RMagick'
|
19
|
+
require 'fileutils'
|
20
|
+
|
21
|
+
class Utopia::Tags::Gallery
|
22
|
+
PROCESSES = {
|
23
|
+
:photo_thumbnail => lambda do |img|
|
24
|
+
img = img.resize_to_fit(300, 300)
|
25
|
+
|
26
|
+
shadow = img.flop
|
27
|
+
shadow = shadow.colorize(1, 1, 1, "gray50")
|
28
|
+
shadow.background_color = "white"
|
29
|
+
shadow.border!(10, 10, "white")
|
30
|
+
shadow = shadow.blur_image(0, 5)
|
31
|
+
|
32
|
+
shadow.composite(img, 5, 5, Magick::OverCompositeOp)
|
33
|
+
end,
|
34
|
+
:thumbnail => lambda do |img|
|
35
|
+
img = img.resize_to_fit(300, 300)
|
36
|
+
end,
|
37
|
+
:large => lambda{|img| img.resize_to_fit(768, 768)}
|
38
|
+
}
|
39
|
+
|
40
|
+
CACHE_DIR = "_cache"
|
41
|
+
|
42
|
+
class ImagePath
|
43
|
+
def initialize(original_path)
|
44
|
+
@original_path = original_path
|
45
|
+
@cache_root = @original_path.dirname + CACHE_DIR
|
46
|
+
end
|
47
|
+
|
48
|
+
attr :cache_root
|
49
|
+
|
50
|
+
def original
|
51
|
+
@original_path
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.append_suffix(name, suffix)
|
55
|
+
name.split(".").insert(-2, suffix).join(".")
|
56
|
+
end
|
57
|
+
|
58
|
+
def processed(process = nil)
|
59
|
+
if process
|
60
|
+
name = @original_path.basename
|
61
|
+
return cache_root + ImagePath.append_suffix(name, process.to_s)
|
62
|
+
else
|
63
|
+
return @original_path
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_html(process = nil)
|
68
|
+
Tag.new("img", {"src" => path(process)}).to_html
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_s
|
72
|
+
@original_path.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
def method_missing(name, *args)
|
76
|
+
return processed(name.to_s)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def initialize(node, path)
|
81
|
+
@node = node
|
82
|
+
@path = path
|
83
|
+
|
84
|
+
Utopia::LOG.debug("node: #{node.inspect} path: #{path}")
|
85
|
+
end
|
86
|
+
|
87
|
+
def metadata
|
88
|
+
metadata_path = @node.local_path(@path + "gallery.yaml")
|
89
|
+
|
90
|
+
if File.exist? metadata_path
|
91
|
+
return YAML::load(File.read(metadata_path))
|
92
|
+
else
|
93
|
+
return {}
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def images(options = {})
|
98
|
+
options[:filter] ||= /(\.jpg|\.png)$/
|
99
|
+
|
100
|
+
paths = []
|
101
|
+
local_path = @node.local_path(@path)
|
102
|
+
|
103
|
+
Utopia::LOG.debug("Scanning #{local_path}")
|
104
|
+
|
105
|
+
Dir.entries(local_path).each do |filename|
|
106
|
+
next unless filename.match(options[:filter])
|
107
|
+
|
108
|
+
Utopia::LOG.debug("Filename #{filename} matched filter...")
|
109
|
+
|
110
|
+
fullpath = File.join(local_path, filename)
|
111
|
+
|
112
|
+
paths << ImagePath.new(@path + filename)
|
113
|
+
end
|
114
|
+
|
115
|
+
if options[:process]
|
116
|
+
paths.each do |path|
|
117
|
+
processed_image(path, options[:process])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
return paths
|
122
|
+
end
|
123
|
+
|
124
|
+
def processed_image(image_path, processes)
|
125
|
+
# Create the local cache directory if it doesn't exist already
|
126
|
+
local_cache_path = @node.local_path(image_path.cache_root)
|
127
|
+
|
128
|
+
unless File.exist? local_cache_path
|
129
|
+
FileUtils.mkdir local_cache_path
|
130
|
+
end
|
131
|
+
|
132
|
+
# Calculate the new name for the processed image
|
133
|
+
local_original_path = @node.local_path(image_path.original)
|
134
|
+
|
135
|
+
if processes.kind_of? String
|
136
|
+
processes = processes.split(",")
|
137
|
+
end
|
138
|
+
|
139
|
+
processes.each do |process|
|
140
|
+
local_processed_path = @node.local_path(image_path.processed(process))
|
141
|
+
|
142
|
+
unless File.exists? local_processed_path
|
143
|
+
image = Magick::ImageList.new(local_original_path)
|
144
|
+
|
145
|
+
processed_image = PROCESSES[process.to_sym].call(image)
|
146
|
+
processed_image.write(local_processed_path)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.call(transaction, state)
|
152
|
+
gallery = new(transaction.end_tags[-2].node, Utopia::Path.create(state["path"] || "./"))
|
153
|
+
metadata = gallery.metadata
|
154
|
+
metadata.default = {}
|
155
|
+
|
156
|
+
tag_name = state["tag"] || "img"
|
157
|
+
|
158
|
+
options = {}
|
159
|
+
options[:process] = state["process"]
|
160
|
+
|
161
|
+
transaction.tag("div", "class" => "gallery") do |node|
|
162
|
+
images = gallery.images(options).sort_by do |path|
|
163
|
+
name = path.original.basename
|
164
|
+
metadata[name]["order"] || name
|
165
|
+
end
|
166
|
+
|
167
|
+
images.each do |path|
|
168
|
+
alt_text = metadata[path.original.basename]["caption"]
|
169
|
+
transaction.tag(tag_name, "src" => path, "alt" => alt_text)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
Utopia::Tags.register("gallery", Utopia::Tags::Gallery)
|