rox 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -0
- data/examples/workspace.rb +11 -0
- data/lib/rox.rb +10 -0
- data/lib/rox/client.rb +78 -0
- data/lib/rox/config_tree.rb +27 -0
- data/lib/rox/dependencies.rb +2 -0
- data/lib/rox/exception.rb +14 -0
- data/lib/rox/folders.rb +59 -0
- data/lib/rox/response.rb +29 -0
- data/lib/rox/rox.rb +170 -0
- data/lib/rox/simple_module.rb +42 -0
- data/lib/rox/webconversation.rb +96 -0
- metadata +86 -0
data/README
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Try it out at: http://www.ox.io
|
data/lib/rox.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require File.dirname(__FILE__)+'/rox/dependencies'
|
2
|
+
require File.dirname(__FILE__)+'/rox/rox'
|
3
|
+
require File.dirname(__FILE__)+'/rox/webconversation'
|
4
|
+
require File.dirname(__FILE__)+'/rox/client'
|
5
|
+
require File.dirname(__FILE__)+'/rox/response'
|
6
|
+
require File.dirname(__FILE__)+'/rox/exception'
|
7
|
+
require File.dirname(__FILE__)+'/rox/config_tree'
|
8
|
+
require File.dirname(__FILE__)+'/rox/folders'
|
9
|
+
require File.dirname(__FILE__)+'/rox/simple_module'
|
10
|
+
|
data/lib/rox/client.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
module ROX
|
2
|
+
|
3
|
+
class Client
|
4
|
+
|
5
|
+
attr_accessor :webconversation
|
6
|
+
attr_accessor :session
|
7
|
+
|
8
|
+
def initialize(options = nil)
|
9
|
+
if options
|
10
|
+
host = options[:host]
|
11
|
+
raise "Please specify an option 'host'" unless host
|
12
|
+
@webconversation = ROX::WebConversation.new(host)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def login(username, password)
|
17
|
+
response = @webconversation.get("/ajax/login", :action => :login, :name => username, :password => password)
|
18
|
+
response = ROX::Response.new(JSON.parse(response))
|
19
|
+
raise OXException.new(response) if response.error?
|
20
|
+
@session = response["session"]
|
21
|
+
|
22
|
+
if block_given?
|
23
|
+
begin
|
24
|
+
return yield(self)
|
25
|
+
ensure
|
26
|
+
logout
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
def logout
|
33
|
+
response = @webconversation.get("/ajax/login", :action => :logout, :session => session)
|
34
|
+
if(response and response != "")
|
35
|
+
response = ROX::Response.new(JSON.parse(response))
|
36
|
+
raise OXException.new(response) if response.error?
|
37
|
+
end
|
38
|
+
@session = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def logged_in?
|
42
|
+
!@session.nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
def get(path, parameters = {})
|
46
|
+
parameters[:session] ||= @session
|
47
|
+
@webconversation.get(path, parameters)
|
48
|
+
end
|
49
|
+
|
50
|
+
def put(path, parameters = {})
|
51
|
+
parameters[:session] ||= @session
|
52
|
+
@webconversation.put(path, parameters)
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_response(path, parameters = {})
|
56
|
+
response = ROX::Response.new(JSON.parse(get(path, parameters)))
|
57
|
+
raise ROX::OXException.new(response) if response.error?
|
58
|
+
return response;
|
59
|
+
end
|
60
|
+
|
61
|
+
def put_response(path, parameters = {})
|
62
|
+
response = ROX::Response.new(JSON.parse(put(path, parameters)))
|
63
|
+
raise ROX::OXException.new(response) if response.error?
|
64
|
+
return response
|
65
|
+
end
|
66
|
+
|
67
|
+
def in_module(moduleName, &block)
|
68
|
+
mod = self.module(moduleName)
|
69
|
+
return mod.instance_eval(&block) if block_given?
|
70
|
+
return mod
|
71
|
+
end
|
72
|
+
|
73
|
+
def module(moduleName)
|
74
|
+
ROX::SimpleModule.new("/ajax/"+moduleName.to_s, self)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ROX
|
2
|
+
class ConfigTree
|
3
|
+
def initialize(client)
|
4
|
+
@client = client
|
5
|
+
end
|
6
|
+
|
7
|
+
def [](path)
|
8
|
+
return @client.get_response("/ajax/config/#{path}")["data"]
|
9
|
+
end
|
10
|
+
|
11
|
+
def []=(path, value)
|
12
|
+
@client.put("/ajax/config/#{path}", :body => value.to_json)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
class Client
|
19
|
+
|
20
|
+
def config
|
21
|
+
@config ||= ROX::ConfigTree.new(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/lib/rox/folders.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
module ROX
|
2
|
+
|
3
|
+
columns(:common) {
|
4
|
+
|
5
|
+
column(1, :id, :string)
|
6
|
+
column(2, :created_by, :string)
|
7
|
+
column(3, :modified_by, :string)
|
8
|
+
column(4, :creation_date, :time)
|
9
|
+
column(5, :last_modified, :time)
|
10
|
+
column(6, :last_modified_utc, :timestamp)
|
11
|
+
column(20, :folder_id, :string)
|
12
|
+
|
13
|
+
}
|
14
|
+
|
15
|
+
columns(:folder => :common) {
|
16
|
+
|
17
|
+
column(300, :title, :string)
|
18
|
+
column(301, :module, :string)
|
19
|
+
column(302, :type, :mappable, {1 => :private, 2 => :public, 3 => :shared, 5 => :system})
|
20
|
+
column(304, :boolean, :subfolders)
|
21
|
+
#column(305, :own_rights, :)
|
22
|
+
#column(306, :permissions, :)
|
23
|
+
column(307, :summary, :string)
|
24
|
+
column(308, :standard_folder, :boolean)
|
25
|
+
column(309, :total, :number)
|
26
|
+
column(310, :new, :number)
|
27
|
+
column(311, :unread, :number)
|
28
|
+
column(312, :deleted, :number)
|
29
|
+
column(313, :capabilities, :number)
|
30
|
+
column(314, :subscribed, :boolean)
|
31
|
+
column(315, :subscr_subflds, :boolean)
|
32
|
+
}
|
33
|
+
|
34
|
+
|
35
|
+
class Folders
|
36
|
+
def initialize(client)
|
37
|
+
@client = client
|
38
|
+
@columns = COLUMN_DEFINITIONS[:folder]
|
39
|
+
end
|
40
|
+
|
41
|
+
def root(*columns)
|
42
|
+
column_list = get_columns(*columns)
|
43
|
+
@client.get_response("/ajax/folders", :action => :root, :columns => column_list.to_s)
|
44
|
+
end
|
45
|
+
|
46
|
+
def get_columns(*columns)
|
47
|
+
@columns.sublist(*columns)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
class Client
|
54
|
+
def folders
|
55
|
+
Folders.new(self)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
data/lib/rox/response.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module ROX
|
2
|
+
class Response
|
3
|
+
def initialize(ox_response)
|
4
|
+
@oxresponse = ox_response
|
5
|
+
end
|
6
|
+
|
7
|
+
def error?
|
8
|
+
@oxresponse.include?('error')
|
9
|
+
end
|
10
|
+
|
11
|
+
def error
|
12
|
+
return nil unless error?
|
13
|
+
sprintf(@oxresponse['error'], *@oxresponse['error_params'])
|
14
|
+
end
|
15
|
+
|
16
|
+
def [](key)
|
17
|
+
@oxresponse[key.to_s]
|
18
|
+
end
|
19
|
+
|
20
|
+
def data
|
21
|
+
@oxresponse['data']
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
@oxresponse.inspect
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/rox/rox.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
module ROX
|
2
|
+
|
3
|
+
class Column
|
4
|
+
|
5
|
+
attr_accessor :number, :name, :type, :options
|
6
|
+
|
7
|
+
def initialize(number, name, type, options = nil)
|
8
|
+
@number = number
|
9
|
+
@name = name
|
10
|
+
@type = type
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_ox(client, value)
|
15
|
+
value
|
16
|
+
end
|
17
|
+
|
18
|
+
def from_ox(client, value)
|
19
|
+
value
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class MappableColumn < Column
|
25
|
+
def initialize(number, name, type, options)
|
26
|
+
super(number, name, type, options)
|
27
|
+
@from_ox = options
|
28
|
+
@inverse = @from_ox.inject({}) {|memo, pair| memo[pair[1]] = pair[0]; memo} if options
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_ox(client, value)
|
32
|
+
@inverse[value]
|
33
|
+
end
|
34
|
+
|
35
|
+
def from_ox(client, value)
|
36
|
+
@from_ox[value]
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class TimeColumn < Column
|
42
|
+
|
43
|
+
def from_ox(client, value)
|
44
|
+
Time.at(client.config.timezone.local_to_utc(value / 1000))
|
45
|
+
end
|
46
|
+
|
47
|
+
def to_ox(client, value)
|
48
|
+
client.config.timezone.utc_to_local(value.to_i) * 1000
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
class DateColumn < Column
|
54
|
+
|
55
|
+
def from_ox(client, value)
|
56
|
+
Time.at(value / 1000)
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_ox(client, value)
|
60
|
+
value.to_i * 1000
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
class ComplexColumn < Column
|
66
|
+
def initialize(number, name, type, klass)
|
67
|
+
super(number, name, type, klass)
|
68
|
+
@klass = klass
|
69
|
+
end
|
70
|
+
|
71
|
+
def from_ox(client, value)
|
72
|
+
@klass.new(value)
|
73
|
+
end
|
74
|
+
|
75
|
+
def to_ox(client, value)
|
76
|
+
value.to_ox
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class ColumnList
|
81
|
+
attr_reader :columns, :ancestors
|
82
|
+
|
83
|
+
def initialize(ancestors = nil)
|
84
|
+
@ancestors = ancestors || Array.new
|
85
|
+
@columns = Hash.new
|
86
|
+
@columns_by_number = Hash.new
|
87
|
+
end
|
88
|
+
|
89
|
+
def column(number, name, type, options = nil)
|
90
|
+
case(type)
|
91
|
+
when :date
|
92
|
+
klass = DateColumn
|
93
|
+
when :time
|
94
|
+
klass = TimeColumn
|
95
|
+
when :mappable
|
96
|
+
klass = MappableColumn
|
97
|
+
when :complex
|
98
|
+
klass = ComplexColumn
|
99
|
+
else
|
100
|
+
klass = Column
|
101
|
+
end
|
102
|
+
column = klass.new(number, name, type, options)
|
103
|
+
add_column(column)
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
def add_column(column_def)
|
108
|
+
@columns[column_def.name] = column_def
|
109
|
+
@columns_by_number[column_def.number] = column_def
|
110
|
+
end
|
111
|
+
|
112
|
+
def [](key)
|
113
|
+
return @columns[key] if @columns.include?(key)
|
114
|
+
return @columns_by_number[key] if @columns_by_number.include?(key)
|
115
|
+
@ancestors.each do
|
116
|
+
|ancestor|
|
117
|
+
column = ancestor[key]
|
118
|
+
return column if column
|
119
|
+
end
|
120
|
+
nil
|
121
|
+
end
|
122
|
+
|
123
|
+
def sublist(*keys)
|
124
|
+
sublist = ColumnList.new
|
125
|
+
keys.each do
|
126
|
+
|key|
|
127
|
+
value = self[key]
|
128
|
+
sublist.add_column(value)
|
129
|
+
end
|
130
|
+
sublist
|
131
|
+
end
|
132
|
+
|
133
|
+
def to_s
|
134
|
+
@columns_by_number.keys.join(",")
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
class ColumnDefinitions
|
141
|
+
|
142
|
+
def initialize
|
143
|
+
@definitions = Hash.new
|
144
|
+
end
|
145
|
+
|
146
|
+
def columns(typedef, &block)
|
147
|
+
name = typedef
|
148
|
+
ancestors = Array.new
|
149
|
+
if(typedef.kind_of?(Hash))
|
150
|
+
name = typedef.keys.first
|
151
|
+
ancestors = [*typedef[name]].map{|ancestor| self[ancestor]}
|
152
|
+
end
|
153
|
+
column_list = ColumnList.new(ancestors)
|
154
|
+
column_list.instance_eval(&block)
|
155
|
+
@definitions[name] = column_list
|
156
|
+
end
|
157
|
+
|
158
|
+
def [](key)
|
159
|
+
@definitions[key]
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
COLUMN_DEFINITIONS = ColumnDefinitions.new
|
165
|
+
|
166
|
+
def self.columns(options, &block)
|
167
|
+
COLUMN_DEFINITIONS.columns(options, &block)
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module ROX
|
2
|
+
|
3
|
+
class SimpleModule
|
4
|
+
def initialize(path, client)
|
5
|
+
@path = path
|
6
|
+
@client = client
|
7
|
+
end
|
8
|
+
|
9
|
+
def _get(params)
|
10
|
+
@client.get_response(@path, params)
|
11
|
+
end
|
12
|
+
|
13
|
+
def _put(params)
|
14
|
+
@client.put_response(@path, params)
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(action, params)
|
18
|
+
_call(action, params)
|
19
|
+
end
|
20
|
+
|
21
|
+
def _call(action, params)
|
22
|
+
params[:action] = action
|
23
|
+
if(params[:body])
|
24
|
+
params[:body] = params[:body].to_json
|
25
|
+
_put(params)
|
26
|
+
elsif params[:body_raw]
|
27
|
+
params[:body] = params[:body_raw]
|
28
|
+
params.delete(:body_raw)
|
29
|
+
_put(params)
|
30
|
+
else
|
31
|
+
_get(params)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def method_missing(meth, *args, &block)
|
36
|
+
params = args.first || {}
|
37
|
+
_call(meth, params)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'open-uri'
|
4
|
+
|
5
|
+
module ROX
|
6
|
+
class WebConversation
|
7
|
+
attr_accessor :cookies
|
8
|
+
|
9
|
+
def initialize(uri)
|
10
|
+
@cookies = Hash.new
|
11
|
+
@uri = URI.parse(uri)
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(url, params = {})
|
15
|
+
req = Net::HTTP::Get.new(url+"?"+query(params))
|
16
|
+
res = request(req)
|
17
|
+
return res.body
|
18
|
+
end
|
19
|
+
|
20
|
+
def post(url, params = {})
|
21
|
+
stringified_params = Hash.new
|
22
|
+
params.each do
|
23
|
+
|key, value|
|
24
|
+
next if key == :body or key == 'body'
|
25
|
+
stringified_params[key.to_s] = value.to_s
|
26
|
+
end
|
27
|
+
req = Net::HTTP::Post.new(url)
|
28
|
+
req.set_form_data(stringified_params)
|
29
|
+
req.body = params[:body] || params['body']
|
30
|
+
res = request(req)
|
31
|
+
return res.body
|
32
|
+
end
|
33
|
+
|
34
|
+
def put(url, params = {})
|
35
|
+
req = Net::HTTP::Put.new(url+"?"+query(params))
|
36
|
+
req.body = params[:body] || params['body']
|
37
|
+
res = request(req)
|
38
|
+
return res.body
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(url, params = {})
|
42
|
+
req = Net::HTTP::Delete.new(url+"?"+query(params))
|
43
|
+
res = request(req)
|
44
|
+
return res.body
|
45
|
+
end
|
46
|
+
|
47
|
+
def remember_cookies(res)
|
48
|
+
setCookie = res['Set-Cookie']
|
49
|
+
return unless setCookie
|
50
|
+
cookies = setCookie.split(/\s*[,;]\s*/)
|
51
|
+
|
52
|
+
cookies.each do
|
53
|
+
|cookieDef|
|
54
|
+
if (cookieDef =~ /^(JS|open-xchange)/)
|
55
|
+
key, value = cookieDef.split(/\=/)
|
56
|
+
@cookies[key] = value
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def add_cookies(req)
|
62
|
+
return if @cookies.empty?
|
63
|
+
cookie_string = ""
|
64
|
+
@cookies.each do
|
65
|
+
|key, value|
|
66
|
+
cookie_string << "#{key}=#{value},"
|
67
|
+
end
|
68
|
+
req["Cookie"] = cookie_string[0...cookie_string.size-1]
|
69
|
+
end
|
70
|
+
|
71
|
+
def query(params)
|
72
|
+
query = ""
|
73
|
+
params.each do
|
74
|
+
|key, value|
|
75
|
+
next if key == :body || key == 'body'
|
76
|
+
query += '&'
|
77
|
+
query += URI.escape(key.to_s)+"="+URI.escape(value.to_s)
|
78
|
+
end
|
79
|
+
query = query[1..query.size]
|
80
|
+
return query
|
81
|
+
end
|
82
|
+
|
83
|
+
def request(req)
|
84
|
+
add_cookies(req)
|
85
|
+
http_session = Net::HTTP.new(@uri.host, @uri.port)
|
86
|
+
http_session.use_ssl = @uri.scheme == "https"
|
87
|
+
res = http_session.start do
|
88
|
+
|http|
|
89
|
+
http.request(req)
|
90
|
+
end
|
91
|
+
remember_cookies(res)
|
92
|
+
return res
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rox
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.1.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Francisco Laguna
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-11 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: json
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: tzinfo
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
description: An Open-Xchange HTTP API client library
|
38
|
+
email: fla@synapps.de
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files: []
|
44
|
+
|
45
|
+
files:
|
46
|
+
- lib/rox.rb
|
47
|
+
- lib/rox/client.rb
|
48
|
+
- lib/rox/config_tree.rb
|
49
|
+
- lib/rox/dependencies.rb
|
50
|
+
- lib/rox/exception.rb
|
51
|
+
- lib/rox/folders.rb
|
52
|
+
- lib/rox/response.rb
|
53
|
+
- lib/rox/rox.rb
|
54
|
+
- lib/rox/simple_module.rb
|
55
|
+
- lib/rox/webconversation.rb
|
56
|
+
- examples/workspace.rb
|
57
|
+
- README
|
58
|
+
homepage: http://www.ox.io
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
none: false
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.8.1
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: An Open-Xchange HTTP API client library
|
85
|
+
test_files: []
|
86
|
+
|