omf_web 0.9.9 → 1.0.0
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.
- 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
|