omf_web 0.9.9 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +31 -0
- data/bin/omf_web_server.rb +157 -0
- data/doc/screenshot2.png +0 -0
- data/doc/widget_detail.png +0 -0
- data/example/demo/data_sources/downloads.rb +2 -1
- data/example/simple/README.md +12 -13
- data/example/simple/create_waveform.rb +29 -0
- data/example/simple/introduction.md +17 -0
- data/example/simple/sample.sq3 +0 -0
- data/example/simple/sample.sql +1008 -0
- data/example/simple/simple.yaml +62 -0
- data/example/simple/simple_dynamic.yaml +66 -0
- data/lib/irods4r/file.rb +15 -14
- data/lib/irods4r/icommands.rb +18 -18
- data/lib/irods4r.rb +9 -9
- data/lib/omf-web/config.ru +41 -16
- data/lib/omf-web/content/git_repository.rb +32 -31
- data/lib/omf-web/content/irods_repository.rb +34 -33
- data/lib/omf-web/content/repository.rb +48 -44
- data/lib/omf-web/data_source_proxy.rb +33 -22
- data/lib/omf-web/rack/session_authenticator.rb +48 -12
- data/lib/omf-web/rack/tab_mapper.rb +30 -36
- data/lib/omf-web/rack/websocket_handler.rb +26 -25
- data/lib/omf-web/session_store.rb +16 -13
- data/lib/omf-web/theme/abstract_page.rb +26 -22
- data/lib/omf-web/theme/bright/page.rb +84 -34
- data/lib/omf-web/theme/bright/stacked_renderer.rb +20 -19
- data/lib/omf-web/theme.rb +14 -9
- data/lib/omf-web/thin/runner.rb +38 -36
- data/lib/omf-web/thin/server.rb +255 -0
- data/lib/omf-web/version.rb +1 -1
- data/lib/omf-web/widget/data_widget.rb +6 -6
- data/lib/omf-web/widget/text/maruku/helpers.rb +33 -30
- data/lib/omf-web/widget/text/maruku/input/parse_block.rb +117 -117
- data/lib/omf-web/widget/text/maruku/output/to_html.rb +155 -154
- data/lib/omf-web/widget/text/maruku.rb +17 -16
- data/omf_web.gemspec +6 -2
- data/sample.sq3 +0 -0
- data/share/htdocs/graph/js/gauge.js +524 -0
- data/share/htdocs/vendor/VERSION_MAP.yaml +3 -3
- data/share/htdocs/vendor/backbone-1.0.0/backbone.js +1571 -0
- data/share/htdocs/vendor/d3-3.0/LICENSE.brewer.txt +38 -0
- data/share/htdocs/vendor/d3-3.0/colorbrewer.js +1 -0
- data/share/htdocs/vendor/d3-3.0/d3.js +8810 -0
- data/share/htdocs/vendor/d3-3.0/d3.min.js +5 -0
- data/share/htdocs/vendor/geo_json/Readme.txt +71 -0
- data/share/htdocs/vendor/geo_json/regions.json +41 -0
- data/share/htdocs/vendor/geo_json/switzerland.json +24 -0
- data/share/htdocs/vendor/geo_json/world.json +497 -0
- data/share/htdocs/vendor/nv_d3/js/nv.d3.js +8801 -4447
- data/share/htdocs/vendor/spin/jquery.spin.js +46 -0
- data/share/htdocs/vendor/spin/spin.js +349 -0
- data/share/htdocs/vendor/spin/spin.min.js +1 -0
- data/share/htdocs/vendor/underscore-1.4.4/underscore.js +1227 -0
- metadata +63 -48
- data/example/simple/data_sources/gimi31.sq3 +0 -0
- data/example/simple/data_sources/ping_source.rb +0 -56
- data/example/simple/simple_viz_server.rb +0 -39
- data/example/simple/widgets/charts_tab.yaml +0 -38
- data/share/.DS_Store +0 -0
- data/share/htdocs/.DS_Store +0 -0
- data/share/htdocs/vendor/backbone-0.5.3/backbone.js +0 -1158
- data/share/htdocs/vendor/underscore-1.2.1/underscore.js +0 -958
@@ -11,10 +11,10 @@ module OMF::Web
|
|
11
11
|
# This class provides an interface to a directory based repository
|
12
12
|
# It retrieves, archives and versions content.
|
13
13
|
#
|
14
|
-
class IRodsContentRepository < ContentRepository
|
15
|
-
|
14
|
+
class IRodsContentRepository < ContentRepository
|
15
|
+
|
16
16
|
@@irods_repositories = {}
|
17
|
-
|
17
|
+
|
18
18
|
# Return the repository which is referenced to by elements in 'opts'.
|
19
19
|
#
|
20
20
|
#
|
@@ -24,8 +24,8 @@ module OMF::Web
|
|
24
24
|
end
|
25
25
|
repo
|
26
26
|
end
|
27
|
-
|
28
|
-
# Register an existing directory to the system. It will be
|
27
|
+
|
28
|
+
# Register an existing directory to the system. It will be
|
29
29
|
# consulted for all content url's starting with
|
30
30
|
# 'irods:_top_dir_:'. If 'is_primary' is set to true, it will
|
31
31
|
# become the default repo for all newly created content
|
@@ -42,17 +42,18 @@ module OMF::Web
|
|
42
42
|
@@primary_repository = repo
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
46
|
attr_reader :name, :top_dir
|
47
|
-
|
47
|
+
|
48
48
|
def initialize(name, opts)
|
49
49
|
super
|
50
50
|
unless @top_dir
|
51
51
|
raise "No top_dir defined (#{opts.keys.inspect})"
|
52
52
|
end
|
53
53
|
@url_prefix = "irods:#{name}:"
|
54
|
+
@ticket = opts[:ticket]
|
54
55
|
end
|
55
|
-
|
56
|
+
|
56
57
|
# Load content described by either a hash or a straightforward path
|
57
58
|
# and return a 'ContentProxy' holding it.
|
58
59
|
#
|
@@ -67,38 +68,38 @@ module OMF::Web
|
|
67
68
|
descr = descr ? descr.dup : {}
|
68
69
|
url = get_url_for_path(path)
|
69
70
|
key = Digest::MD5.hexdigest(url)
|
70
|
-
descr[:url] = url
|
71
|
+
descr[:url] = url
|
71
72
|
descr[:url_key] = key
|
72
|
-
descr[:path] = path
|
73
|
+
descr[:path] = path
|
73
74
|
descr[:name] = url # Should be something human digestable
|
74
75
|
if (descr[:strictly_new])
|
75
|
-
return nil if IRODS4r.exists?(path)
|
76
|
+
return nil if IRODS4r.exists?(path, @ticket)
|
76
77
|
end
|
77
78
|
proxy = ContentProxy.create(descr, self)
|
78
79
|
return proxy
|
79
80
|
end
|
80
|
-
|
81
|
+
|
81
82
|
def write(content_descr, content, message)
|
82
83
|
path = _get_path(content_descr)
|
83
84
|
#puts "WRITE PATHS>>> #{path}"
|
84
|
-
f = IRODS4r::File.create(path, false)
|
85
|
+
f = IRODS4r::File.create(path, false, ticket: @ticket)
|
85
86
|
f.write(content)
|
86
87
|
end
|
87
|
-
|
88
|
+
|
88
89
|
def read(content_descr)
|
89
90
|
path = _get_path(content_descr)
|
90
91
|
#puts "READ PATHS>>> #{path}"
|
91
|
-
f = IRODS4r::File.create(path, false)
|
92
|
+
f = IRODS4r::File.create(path, false, ticket: @ticket)
|
92
93
|
f.read()
|
93
|
-
end
|
94
|
-
|
94
|
+
end
|
95
|
+
|
95
96
|
#
|
96
97
|
# Return an array of file names which are in the repository and
|
97
98
|
# match 'search_pattern'
|
98
99
|
#
|
99
100
|
def find_files(search_pattern, opts = {})
|
100
101
|
begin
|
101
|
-
dir = IRODS4r.find(@top_dir)
|
102
|
+
dir = IRODS4r.find(@top_dir, {}, @ticket)
|
102
103
|
rescue IRODS4r::IRODS4rException
|
103
104
|
return []
|
104
105
|
end
|
@@ -106,7 +107,7 @@ module OMF::Web
|
|
106
107
|
_find_files(search_pattern, dir, res, opts[:mime_type])
|
107
108
|
res
|
108
109
|
end
|
109
|
-
|
110
|
+
|
110
111
|
def _find_files(search_pattern, dir, res, mime_type)
|
111
112
|
dir.list.each do |e|
|
112
113
|
if e.directory?
|
@@ -115,7 +116,7 @@ module OMF::Web
|
|
115
116
|
path = e.path
|
116
117
|
if path.match(search_pattern)
|
117
118
|
mt = mime_type_for_file(path)
|
118
|
-
next if mime_type != nil && mime_type != mt
|
119
|
+
next if mime_type != nil && mime_type != mt
|
119
120
|
res << {:url => get_url_for_path(path), :path => path, #:name => 'foo',
|
120
121
|
:mime_type => mt}
|
121
122
|
end
|
@@ -123,10 +124,10 @@ module OMF::Web
|
|
123
124
|
end
|
124
125
|
res
|
125
126
|
end
|
126
|
-
|
127
|
-
|
127
|
+
|
128
|
+
|
128
129
|
# Return a URL for a path in this repo
|
129
|
-
#
|
130
|
+
#
|
130
131
|
def get_url_for_path(path)
|
131
132
|
puts "PATH>>>>> '#{path}:#{path.class}'-'#{@top_dir}:#{@top_dir.class}'"
|
132
133
|
if m = path.match("#{@top_dir}(.*)")
|
@@ -134,12 +135,12 @@ module OMF::Web
|
|
134
135
|
end
|
135
136
|
url = @url_prefix + path
|
136
137
|
end
|
137
|
-
|
138
|
+
|
138
139
|
# HACK ALERT!!!
|
139
|
-
#
|
140
|
+
#
|
140
141
|
# This method may be called by an entity which wants to access the content
|
141
|
-
# directly through the file system. In the absence of a FUSE mounted iRODS
|
142
|
-
# repo, we 'iget' the resource to a temporary directory and return that
|
142
|
+
# directly through the file system. In the absence of a FUSE mounted iRODS
|
143
|
+
# repo, we 'iget' the resource to a temporary directory and return that
|
143
144
|
# path. The calling entity needs to be aware that any changes to that file
|
144
145
|
# will NOT show up in iRODS without an iput.
|
145
146
|
#
|
@@ -147,19 +148,19 @@ module OMF::Web
|
|
147
148
|
#
|
148
149
|
def absolute_path(content_descr)
|
149
150
|
path = _get_path(content_descr)
|
150
|
-
|
151
|
+
|
151
152
|
require 'etc'
|
152
153
|
tmp_dir = "#{Dir::tmpdir}/LabWiki-#{Etc.getlogin}"
|
153
154
|
# unless Dir.exists? tmp_dir
|
154
155
|
# Dir.mkdir tmp_dir, 0700
|
155
156
|
# end
|
156
|
-
|
157
|
+
|
157
158
|
target = File.join(tmp_dir, path)
|
158
|
-
IRODS4r::ICommands.export(path, target)
|
159
|
+
IRODS4r::ICommands.export(path, target, true, @ticket)
|
159
160
|
target
|
160
161
|
end
|
161
162
|
|
162
|
-
|
163
|
+
|
163
164
|
def _get_path(content_descr)
|
164
165
|
#puts ">>>GET PATH #{content_descr.inspect}"
|
165
166
|
if content_descr.is_a? String
|
@@ -186,6 +187,6 @@ module OMF::Web
|
|
186
187
|
end
|
187
188
|
return path
|
188
189
|
end
|
189
|
-
|
190
|
+
|
190
191
|
end # class
|
191
|
-
end # module
|
192
|
+
end # module
|
@@ -12,48 +12,48 @@ module OMF::Web
|
|
12
12
|
# It retrieves, archives and versions content.
|
13
13
|
#
|
14
14
|
class ContentRepository < OMF::Common::LObject
|
15
|
-
|
15
|
+
|
16
16
|
MIME_TYPE = {
|
17
|
-
:js => 'text/javascript',
|
17
|
+
:js => 'text/javascript',
|
18
18
|
:md => 'text/markup',
|
19
|
-
:rb => 'text/ruby',
|
20
|
-
:r => 'text/r',
|
21
|
-
:svg => 'text/svg',
|
22
|
-
:txt => 'text'
|
19
|
+
:rb => 'text/ruby',
|
20
|
+
:r => 'text/r',
|
21
|
+
:svg => 'text/svg',
|
22
|
+
:txt => 'text'
|
23
23
|
}
|
24
|
-
|
24
|
+
|
25
25
|
REPO_PLUGINS = {
|
26
26
|
git: lambda do |name, opts|
|
27
|
-
require 'omf-web/content/git_repository'
|
27
|
+
require 'omf-web/content/git_repository'
|
28
28
|
return GitContentRepository.new(name, opts)
|
29
29
|
end,
|
30
30
|
file: lambda do |name, opts|
|
31
|
-
require 'omf-web/content/file_repository'
|
31
|
+
require 'omf-web/content/file_repository'
|
32
32
|
return FileContentRepository.new(name, opts)
|
33
33
|
end,
|
34
34
|
irods: lambda do |name, opts|
|
35
|
-
require 'omf-web/content/irods_repository'
|
35
|
+
require 'omf-web/content/irods_repository'
|
36
36
|
return IRodsContentRepository.new(name, opts)
|
37
37
|
end,
|
38
38
|
static: lambda do |name, opts|
|
39
|
-
require 'omf-web/content/static_repository'
|
39
|
+
require 'omf-web/content/static_repository'
|
40
40
|
return StaticContentRepository.new(name, opts)
|
41
41
|
end
|
42
42
|
}
|
43
|
-
|
43
|
+
|
44
44
|
# Repo to be used for all newly created content
|
45
45
|
@@primary_repository = nil
|
46
46
|
@@repositories = {}
|
47
|
-
|
47
|
+
|
48
48
|
def self.register_repo(name, opts)
|
49
49
|
raise "ArgumentMismatch: Expected Hash, but got #{opts}" unless opts.is_a? Hash
|
50
|
-
|
50
|
+
|
51
51
|
name = name.to_sym
|
52
52
|
if @@repositories[name]
|
53
53
|
warn "Ignoring repeated registration of repo '#{name}'"
|
54
54
|
return
|
55
55
|
end
|
56
|
-
|
56
|
+
|
57
57
|
unless type = opts[:type]
|
58
58
|
raise "Missing type in repo opts (#{opts})"
|
59
59
|
end
|
@@ -62,9 +62,10 @@ module OMF::Web
|
|
62
62
|
end
|
63
63
|
@@repositories[name] = r = repo_creator.call(name, opts)
|
64
64
|
@@primary_repository = r if opts[:is_primary]
|
65
|
+
r
|
65
66
|
end
|
66
|
-
|
67
|
-
|
67
|
+
|
68
|
+
|
68
69
|
# Load content described by either a hash or a straightforward url
|
69
70
|
# and return a 'ContentProxy' holding it.
|
70
71
|
#
|
@@ -75,7 +76,7 @@ module OMF::Web
|
|
75
76
|
if url_or_descr.is_a? ContentProxy
|
76
77
|
return url_or_descr
|
77
78
|
end
|
78
|
-
|
79
|
+
|
79
80
|
if url_or_descr.is_a? String
|
80
81
|
url = url_or_descr
|
81
82
|
else
|
@@ -90,20 +91,20 @@ module OMF::Web
|
|
90
91
|
unless url
|
91
92
|
throw "Can't find url in '#{url_or_descr.inspect}"
|
92
93
|
end
|
93
|
-
|
94
|
+
|
94
95
|
repo = find_repo_for(url)
|
95
96
|
repo.create_content_proxy_for(url_or_descr)
|
96
97
|
end
|
97
|
-
|
98
|
-
|
98
|
+
|
99
|
+
|
99
100
|
def self.absolute_path_for(url)
|
100
101
|
find_repo_for(url).absolute_path(url)
|
101
102
|
end
|
102
|
-
|
103
|
+
|
103
104
|
def self.read_content(url, opts)
|
104
105
|
find_repo_for(url).read(url)
|
105
106
|
end
|
106
|
-
|
107
|
+
|
107
108
|
def self.find_repo_for(url)
|
108
109
|
parts = url.split(':')
|
109
110
|
name = parts[1]
|
@@ -112,23 +113,26 @@ module OMF::Web
|
|
112
113
|
end
|
113
114
|
return repo
|
114
115
|
end
|
115
|
-
|
116
|
-
|
117
|
-
# Find files whose file name matches 'selector'.
|
118
|
-
#
|
116
|
+
|
117
|
+
|
118
|
+
# Find files whose file name matches 'selector'.
|
119
|
+
#
|
119
120
|
# Supported options:
|
120
121
|
# * :max - Maximum numbers of matches to return
|
121
122
|
# * :mime_type - Only return files with that specific mime type.
|
123
|
+
# * :repo_iterator [Iterator] - Iterator over repos to search
|
122
124
|
#
|
123
125
|
def self.find_files(selector, opts = {})
|
124
|
-
|
125
|
-
|
126
|
+
fsa = (opts[:repo_iterator] || [@@primary_repository]).map do |repo|
|
127
|
+
repo.find_files(selector, opts)
|
128
|
+
end
|
129
|
+
fs = fsa.flatten
|
126
130
|
if (max = opts[:max])
|
127
131
|
fs = fs[0, max]
|
128
132
|
end
|
129
133
|
fs
|
130
|
-
end
|
131
|
-
|
134
|
+
end
|
135
|
+
|
132
136
|
#
|
133
137
|
# Create a URL for a file with 'path' in the user's primary repository.
|
134
138
|
# If 'strictly_new' is true, returns nil if 'path' already exists.
|
@@ -137,17 +141,17 @@ module OMF::Web
|
|
137
141
|
# TODO: Need to add code to select proper repository
|
138
142
|
return GitContentRepository.create_url(path, strictly_new)
|
139
143
|
end
|
140
|
-
|
141
|
-
|
144
|
+
|
145
|
+
|
142
146
|
attr_reader :name, :top_dir
|
143
|
-
|
147
|
+
|
144
148
|
def initialize(name, opts)
|
145
149
|
@name = name
|
146
150
|
if @top_dir = opts[:top_dir]
|
147
151
|
@top_dir = File.expand_path(@top_dir)
|
148
152
|
end
|
149
153
|
end
|
150
|
-
|
154
|
+
|
151
155
|
#
|
152
156
|
# Return an array of file names which are in the repository and
|
153
157
|
# match 'search_pattern'
|
@@ -155,8 +159,8 @@ module OMF::Web
|
|
155
159
|
def find_files(search_pattern, opts = {})
|
156
160
|
raise "Missing implementation"
|
157
161
|
end
|
158
|
-
|
159
|
-
|
162
|
+
|
163
|
+
|
160
164
|
def mime_type_for_file(content_descriptor)
|
161
165
|
fname = content_descriptor
|
162
166
|
if content_descriptor.is_a? Hash
|
@@ -165,7 +169,7 @@ module OMF::Web
|
|
165
169
|
ext = fname.split('.')[-1]
|
166
170
|
mt = MIME_TYPE[ext.to_sym] || 'text'
|
167
171
|
end
|
168
|
-
|
172
|
+
|
169
173
|
def read(content_descr)
|
170
174
|
path = _get_path(content_descr)
|
171
175
|
Dir.chdir(@top_dir) do
|
@@ -175,21 +179,21 @@ module OMF::Web
|
|
175
179
|
content = File.open(path).read
|
176
180
|
return content
|
177
181
|
end
|
178
|
-
end
|
179
|
-
|
182
|
+
end
|
183
|
+
|
180
184
|
def absolute_path(content_descr)
|
181
185
|
path = _get_path(content_descr)
|
182
186
|
File.join(@top_dir, path)
|
183
187
|
end
|
184
|
-
|
188
|
+
|
185
189
|
def path(content_descr)
|
186
190
|
path = _get_path(content_descr)
|
187
191
|
end
|
188
|
-
|
192
|
+
|
189
193
|
# Return a URL for a path in this repo
|
190
|
-
#
|
194
|
+
#
|
191
195
|
def get_url_for_path(path)
|
192
196
|
raise "Missing implementation"
|
193
197
|
end
|
194
198
|
end # class
|
195
|
-
end # module
|
199
|
+
end # module
|
@@ -4,20 +4,30 @@ require 'omf_common/lobject'
|
|
4
4
|
require 'omf_oml/network'
|
5
5
|
|
6
6
|
module OMF::Web
|
7
|
-
|
8
|
-
# This object maintains synchronization between a JS DataSource object
|
7
|
+
|
8
|
+
# This object maintains synchronization between a JS DataSource object
|
9
9
|
# in a web browser and the corresponding +OmlTable+ in this server.
|
10
10
|
#
|
11
11
|
#
|
12
12
|
class DataSourceProxy < OMF::Common::LObject
|
13
|
-
|
13
|
+
|
14
14
|
@@datasources = {}
|
15
|
-
|
15
|
+
|
16
16
|
# Register a data source.
|
17
17
|
#
|
18
18
|
# params data_source - Data source to register
|
19
19
|
# params opts:
|
20
20
|
# name - Name to use instead of data source's native name
|
21
|
+
|
22
|
+
#
|
23
|
+
# A data_source needs to support eh following methods:
|
24
|
+
#
|
25
|
+
# * rows Returns an array of rows
|
26
|
+
# * on_content_changed(lambda{action, rows}) Call provided block with actions :added, :removed
|
27
|
+
# * create_sliced_table (optional)
|
28
|
+
# * release Not exactly sure when that is being used
|
29
|
+
# * schema Schema of row
|
30
|
+
# * offset
|
21
31
|
#
|
22
32
|
def self.register_datasource(data_source, opts = {})
|
23
33
|
name = (opts[:name] || data_source.name).to_sym
|
@@ -32,9 +42,9 @@ module OMF::Web
|
|
32
42
|
# else
|
33
43
|
# @@datasources[name] = data_source
|
34
44
|
# end
|
35
|
-
@@datasources[name] = data_source
|
45
|
+
@@datasources[name] = data_source
|
36
46
|
end
|
37
|
-
|
47
|
+
|
38
48
|
def self.[](name)
|
39
49
|
name = name.to_sym
|
40
50
|
unless dsp = OMF::Web::SessionStore[name, :dsp]
|
@@ -46,7 +56,7 @@ module OMF::Web
|
|
46
56
|
end
|
47
57
|
dsp
|
48
58
|
end
|
49
|
-
|
59
|
+
|
50
60
|
# Return proxies for 'ds_name'. Note, there can be more then
|
51
61
|
# one proxy be needed for a datasource, such as a network which
|
52
62
|
# has one ds for the nodes and one for the links
|
@@ -69,8 +79,8 @@ module OMF::Web
|
|
69
79
|
top = "#{ds_name}/"
|
70
80
|
names = @@datasources.keys.find_all { |ds_name| ds_name.to_s.start_with? top }
|
71
81
|
unless names.empty?
|
72
|
-
return names.map do |ds_name|
|
73
|
-
OMF::Web::SessionStore[ds_name, :dsp] ||= self.new(ds_name, @@datasources[ds_name])
|
82
|
+
return names.map do |ds_name|
|
83
|
+
OMF::Web::SessionStore[ds_name, :dsp] ||= self.new(ds_name, @@datasources[ds_name])
|
74
84
|
end
|
75
85
|
end
|
76
86
|
# debug ">>>> #{dsa}"
|
@@ -93,25 +103,25 @@ module OMF::Web
|
|
93
103
|
end
|
94
104
|
return proxies
|
95
105
|
end
|
96
|
-
|
106
|
+
|
97
107
|
#debug ">>>>> DS: #{ds_descr.inspect} - #{ds}"
|
98
108
|
proxy = OMF::Web::SessionStore[ds_name, :dsp] ||= self.new(ds_name, ds)
|
99
109
|
return [proxy]
|
100
110
|
end
|
101
|
-
|
111
|
+
|
102
112
|
attr_reader :name
|
103
|
-
|
113
|
+
|
104
114
|
def reset()
|
105
|
-
# TODO: Figure out partial sending
|
115
|
+
# TODO: Figure out partial sending
|
106
116
|
end
|
107
|
-
|
117
|
+
|
108
118
|
def on_update(req)
|
109
119
|
res = {:events => @data_source.rows}
|
110
120
|
[res.to_json, "text/json"]
|
111
121
|
end
|
112
|
-
|
122
|
+
|
113
123
|
# Register callback to be informed of changes to the underlying data source.
|
114
|
-
# Call block when new rows are becoming available. Block needs ot return
|
124
|
+
# Call block when new rows are becoming available. Block needs ot return
|
115
125
|
# true if it wants to continue receiving updates.
|
116
126
|
#
|
117
127
|
# offset: Number of records already downloaded
|
@@ -128,7 +138,7 @@ module OMF::Web
|
|
128
138
|
block.call action, rows
|
129
139
|
end
|
130
140
|
end
|
131
|
-
|
141
|
+
|
132
142
|
# Create a new data source which only contains a slice of the underlying data source
|
133
143
|
def create_slice(col_name, col_value)
|
134
144
|
ds = @data_source.create_sliced_table(col_name, col_value)
|
@@ -136,7 +146,7 @@ module OMF::Web
|
|
136
146
|
def dsp.release; @data_source.release end
|
137
147
|
dsp
|
138
148
|
end
|
139
|
-
|
149
|
+
|
140
150
|
def to_javascript(opts = {})
|
141
151
|
#puts "to_java>>>>> #{opts.inspect}"
|
142
152
|
sid = Thread.current["sessionID"]
|
@@ -145,23 +155,24 @@ module OMF::Web
|
|
145
155
|
opts[:schema] = @data_source.schema.describe
|
146
156
|
opts[:update_url] = "/_update/#{@name}?sid=#{sid}"
|
147
157
|
opts[:sid] = sid
|
158
|
+
#opts[:is_static] = (@data_source.respond_to? :static?) ? @data_source.static? : false
|
148
159
|
unless opts[:slice] # don't send any data if this is a sliced one
|
149
160
|
#opts[:rows] = @data_source.rows[0 .. 20]
|
150
161
|
opts[:rows] = []
|
151
162
|
opts[:offset] = @data_source.offset
|
152
163
|
end
|
153
164
|
#puts "to_java2>>>>> #{opts.inspect}"
|
154
|
-
|
165
|
+
|
155
166
|
%{
|
156
167
|
OML.data_sources.register(#{opts.to_json});
|
157
168
|
}
|
158
|
-
|
169
|
+
|
159
170
|
end
|
160
|
-
|
171
|
+
|
161
172
|
def initialize(name, data_source)
|
162
173
|
@name = name
|
163
174
|
@data_source = data_source
|
164
175
|
end
|
165
176
|
end
|
166
|
-
|
177
|
+
|
167
178
|
end
|
@@ -28,22 +28,61 @@ module OMF::Web::Rack
|
|
28
28
|
# Return true if the session is authenticated
|
29
29
|
#
|
30
30
|
def self.authenticated?
|
31
|
-
|
32
|
-
|
31
|
+
auth = self[:authenticated] == true && self[:valid_until] > Time.now
|
32
|
+
#debug "AUTH: #{auth}"
|
33
|
+
auth
|
33
34
|
end
|
34
35
|
|
35
36
|
# Calling this method will authenticate the current session
|
36
37
|
#
|
37
|
-
def self.authenticate
|
38
|
+
def self.authenticate(expires = nil)
|
38
39
|
self[:authenticated] = true
|
39
40
|
self[:valid_until] = Time.now + @@expire_after
|
40
41
|
end
|
41
42
|
|
43
|
+
# Information about the authenticated user
|
44
|
+
#
|
45
|
+
def self.user()
|
46
|
+
self[:user]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Attempt to authenticate with the provided 'req'
|
50
|
+
def self.authenticate_with(req)
|
51
|
+
p = req.params
|
52
|
+
#puts ">>>>>>> AA(#{req.host_with_port}): #{p}"
|
53
|
+
case t = p['method']
|
54
|
+
when 'persona'
|
55
|
+
require 'net/http'
|
56
|
+
unless assertion = p['assertion']
|
57
|
+
raise AuthenticationFailedException.new("Missing assertion")
|
58
|
+
end
|
59
|
+
|
60
|
+
http = Net::HTTP.new('verifier.login.persona.org', 443)
|
61
|
+
http.use_ssl = true
|
62
|
+
data = "assertion=#{assertion}&audience=#{req.host_with_port}"
|
63
|
+
headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
|
64
|
+
reply = http.post('/verify', data, headers)
|
65
|
+
unless reply.code_type == Net::HTTPOK && reply.content_type == "application/json"
|
66
|
+
raise AuthenticationFailedException.new("Could not verify Persona - '#{reply.body}'")
|
67
|
+
end
|
68
|
+
debug "Persona reply: '#{reply.body}'"
|
69
|
+
r = JSON.load(reply.body)
|
70
|
+
unless ((email = r['email']) && (expires = r['expires']))
|
71
|
+
raise AuthenticationFailedException.new("Could not verify Persona - '#{r}'")
|
72
|
+
end
|
73
|
+
self[:user] = {name: email, email: email, method: 'persona'}
|
74
|
+
authenticate(Time.at(expires))
|
75
|
+
else
|
76
|
+
raise AuthenticationFailedException.new("Unsupported authentication type '#{t}'")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
42
80
|
# Logging out will un-authenticate this session
|
43
81
|
#
|
44
82
|
def self.logout
|
45
83
|
debug "LOGOUT"
|
46
84
|
self[:authenticated] = false
|
85
|
+
self[:user] = nil
|
47
86
|
end
|
48
87
|
|
49
88
|
# DO NOT CALL DIRECTLY
|
@@ -79,23 +118,20 @@ module OMF::Web::Rack
|
|
79
118
|
end
|
80
119
|
|
81
120
|
def check_authenticated
|
82
|
-
authenticated = self.class
|
83
|
-
#puts "AUTHENTICATED: #{authenticated}"
|
121
|
+
authenticated = self.class.authenticated?
|
84
122
|
raise AuthenticationFailedException.new unless authenticated
|
85
|
-
#self.class[:valid_until] = Time.now + @@expire_after
|
86
|
-
|
87
123
|
end
|
88
124
|
|
89
125
|
def call(env)
|
90
|
-
#puts env.keys.inspect
|
91
126
|
req = ::Rack::Request.new(env)
|
92
127
|
path_info = req.path_info
|
93
|
-
|
128
|
+
sid = req.cookies['sid']
|
129
|
+
unless sid
|
94
130
|
sid = "s#{(rand * 10000000).to_i}_#{(rand * 10000000).to_i}"
|
95
131
|
end
|
96
132
|
Thread.current["sessionID"] = sid # needed for Session Store
|
133
|
+
debug "Request for '#{path_info}' - sid: #{sid} - #{self.class.authenticated?}"
|
97
134
|
unless @opts[:no_session].find {|rx| rx.match(path_info) }
|
98
|
-
|
99
135
|
# If 'login_page_url' is defined, check if this session is authenticated
|
100
136
|
login_url = @opts[:login_page_url]
|
101
137
|
if login_url && login_url != req.path_info
|
@@ -107,13 +143,13 @@ module OMF::Web::Rack
|
|
107
143
|
end
|
108
144
|
headers = {'Location' => login_url, "Content-Type" => ""}
|
109
145
|
Rack::Utils.set_cookie_header!(headers, 'sid', sid)
|
110
|
-
return [
|
146
|
+
return [307, headers, ['Login first']]
|
111
147
|
end
|
112
148
|
end
|
113
149
|
end
|
114
150
|
|
115
151
|
status, headers, body = @app.call(env)
|
116
|
-
Rack::Utils.set_cookie_header!(headers, 'sid', sid) if sid
|
152
|
+
Rack::Utils.set_cookie_header!(headers, 'sid', sid) # if sid
|
117
153
|
[status, headers, body]
|
118
154
|
end
|
119
155
|
end # class
|