cmis-ruby 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/Gemfile +6 -0
- data/LICENSE +176 -0
- data/Rakefile +7 -0
- data/cmis-ruby.gemspec +27 -0
- data/lib/cmis-ruby.rb +20 -0
- data/lib/cmis/children.rb +95 -0
- data/lib/cmis/connection.rb +147 -0
- data/lib/cmis/document.rb +62 -0
- data/lib/cmis/folder.rb +76 -0
- data/lib/cmis/helpers.rb +58 -0
- data/lib/cmis/item.rb +11 -0
- data/lib/cmis/object.rb +120 -0
- data/lib/cmis/object_factory.rb +27 -0
- data/lib/cmis/policy.rb +26 -0
- data/lib/cmis/property_definition.rb +32 -0
- data/lib/cmis/query.rb +100 -0
- data/lib/cmis/query_result.rb +15 -0
- data/lib/cmis/relationship.rb +18 -0
- data/lib/cmis/repository.rb +112 -0
- data/lib/cmis/server.rb +43 -0
- data/lib/cmis/type.rb +106 -0
- data/lib/cmis/version.rb +3 -0
- data/readme.md +23 -0
- data/spec/document_spec.rb +45 -0
- data/spec/folder_spec.rb +75 -0
- data/spec/helper.rb +27 -0
- data/spec/object_spec.rb +100 -0
- data/spec/relationship_spec.rb +19 -0
- data/spec/repository_spec.rb +150 -0
- data/spec/server_spec.rb +22 -0
- data/spec/type_spec.rb +69 -0
- metadata +141 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
module CMIS
|
2
|
+
class QueryResult
|
3
|
+
|
4
|
+
attr_reader :results
|
5
|
+
attr_reader :num_items
|
6
|
+
attr_reader :has_more_items
|
7
|
+
|
8
|
+
def initialize(results, num_items, has_more_items)
|
9
|
+
@results = results
|
10
|
+
@num_items = num_items
|
11
|
+
@has_more_items = has_more_items
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module CMIS
|
2
|
+
class Relationship < Object
|
3
|
+
|
4
|
+
def initialize(raw, repository)
|
5
|
+
super
|
6
|
+
cmis_properties %w( cmis:sourceId cmis:targetId )
|
7
|
+
end
|
8
|
+
|
9
|
+
def source
|
10
|
+
repository.object(source_id)
|
11
|
+
end
|
12
|
+
|
13
|
+
def target
|
14
|
+
repository.object(target_id)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module CMIS
|
2
|
+
class Repository
|
3
|
+
|
4
|
+
attr_reader :connection
|
5
|
+
|
6
|
+
def initialize(raw, connection)
|
7
|
+
@hash = raw
|
8
|
+
@hash.each_key do |key|
|
9
|
+
class_eval "def #{key.underscore};@hash['#{key}'];end"
|
10
|
+
class_eval "def #{key.gsub('repository', '').underscore};@hash['#{key}'];end" if key =~ /^repository/
|
11
|
+
end
|
12
|
+
|
13
|
+
@connection = connection
|
14
|
+
end
|
15
|
+
|
16
|
+
def new_document
|
17
|
+
Document.new({}, self)
|
18
|
+
end
|
19
|
+
|
20
|
+
def new_folder
|
21
|
+
Folder.new({}, self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def new_relationship
|
25
|
+
Relationship.new({}, self)
|
26
|
+
end
|
27
|
+
|
28
|
+
def new_item
|
29
|
+
Item.new({}, self)
|
30
|
+
end
|
31
|
+
|
32
|
+
def new_policy
|
33
|
+
Policy.new({}, self)
|
34
|
+
end
|
35
|
+
|
36
|
+
def root
|
37
|
+
result = connection.execute!({ cmisselector: 'object',
|
38
|
+
repositoryId: id,
|
39
|
+
objectId: root_folder_id })
|
40
|
+
|
41
|
+
ObjectFactory.create(result, self)
|
42
|
+
end
|
43
|
+
|
44
|
+
def object(cmis_object_id)
|
45
|
+
result = connection.execute!({ cmisselector: 'object',
|
46
|
+
repositoryId: id,
|
47
|
+
objectId: cmis_object_id })
|
48
|
+
|
49
|
+
ObjectFactory.create(result, self)
|
50
|
+
end
|
51
|
+
|
52
|
+
def types
|
53
|
+
result = connection.execute!({ cmisselector: 'typeDescendants',
|
54
|
+
repositoryId: id,
|
55
|
+
includePropertyDefinitions: true })
|
56
|
+
|
57
|
+
construct_types(result)
|
58
|
+
end
|
59
|
+
|
60
|
+
def type(type_id)
|
61
|
+
result = connection.execute!({ cmisselector: 'typeDefinition',
|
62
|
+
repositoryId: id,
|
63
|
+
typeId: type_id })
|
64
|
+
|
65
|
+
Type.new(result, self)
|
66
|
+
end
|
67
|
+
|
68
|
+
def has_type?(type_id)
|
69
|
+
types.map(&:id).include?(type_id)
|
70
|
+
end
|
71
|
+
|
72
|
+
def create_type(type)
|
73
|
+
result = connection.execute!({ cmisaction: 'createType',
|
74
|
+
repositoryId: id,
|
75
|
+
type: MultiJson.dump(type.to_hash) })
|
76
|
+
|
77
|
+
Type.new(result, self)
|
78
|
+
end
|
79
|
+
|
80
|
+
def create_relationship(object)
|
81
|
+
raise 'Object is not a Relationship' unless object.is_a?(Relationship)
|
82
|
+
|
83
|
+
result = connection.execute!({ cmisaction: 'createRelationship',
|
84
|
+
repositoryId: id,
|
85
|
+
properties: object.properties })
|
86
|
+
|
87
|
+
ObjectFactory.create(result, self)
|
88
|
+
end
|
89
|
+
|
90
|
+
def content_changes(change_log_token)
|
91
|
+
connection.execute!({ cmisselector: 'contentChanges',
|
92
|
+
repositoryId: id,
|
93
|
+
changeLogToken: change_log_token })
|
94
|
+
end
|
95
|
+
|
96
|
+
def query(statement, options = {})
|
97
|
+
Query.new(self, statement, options)
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def construct_types(a)
|
103
|
+
types = []
|
104
|
+
a.each do |t|
|
105
|
+
types << Type.new(t['type'], self)
|
106
|
+
types << construct_types(t['children']) if t.has_key?('children')
|
107
|
+
end
|
108
|
+
types.flatten
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
data/lib/cmis/server.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
|
3
|
+
module CMIS
|
4
|
+
class Server
|
5
|
+
|
6
|
+
attr_reader :connection
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
options.stringify_keys!
|
10
|
+
|
11
|
+
service_url = options['service_url'] || ENV['CMIS_BROWSER_URL']
|
12
|
+
username = options['username'] || ENV['CMIS_USER']
|
13
|
+
password = options['password'] || ENV['CMIS_PASSWORD']
|
14
|
+
headers = options['headers']
|
15
|
+
|
16
|
+
raise "'service_url' must be set" unless service_url
|
17
|
+
|
18
|
+
@connection = Connection.new(service_url, username, password, headers)
|
19
|
+
end
|
20
|
+
|
21
|
+
def repositories
|
22
|
+
result = connection.execute!
|
23
|
+
|
24
|
+
result.values.map do |r|
|
25
|
+
Repository.new(r, connection)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def repository(repository_id)
|
30
|
+
result = connection.execute!({ cmisselector: 'repositoryInfo',
|
31
|
+
repositoryId: repository_id })
|
32
|
+
|
33
|
+
Repository.new(result[repository_id], connection)
|
34
|
+
end
|
35
|
+
|
36
|
+
def has_repository?(repository_id)
|
37
|
+
result = connection.execute!
|
38
|
+
|
39
|
+
result.keys.include?(repository_id)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
data/lib/cmis/type.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
|
3
|
+
module CMIS
|
4
|
+
class Type
|
5
|
+
|
6
|
+
attr_accessor :connection
|
7
|
+
attr_accessor :repository
|
8
|
+
|
9
|
+
def initialize(hash = {}, repository = nil)
|
10
|
+
@repository = repository
|
11
|
+
@connection = repository.connection if repository
|
12
|
+
|
13
|
+
@hash = hash.with_indifferent_access
|
14
|
+
|
15
|
+
properties = %w( id localName localNamespace queryName displayName baseId
|
16
|
+
parentId description creatable fileable queryable
|
17
|
+
controllablePolicy controllableACL fulltextIndexed
|
18
|
+
includedInSupertypeQuery propertyDefinitions versionable
|
19
|
+
contentStreamAllowed allowedSourceTypes allowedTargetTypes )
|
20
|
+
|
21
|
+
properties.each do |key|
|
22
|
+
class_eval "def #{key.underscore};@hash['#{key}'];end"
|
23
|
+
class_eval "def #{key.underscore}=(value);@hash['#{key}']=value;end"
|
24
|
+
end
|
25
|
+
|
26
|
+
@hash['propertyDefinitions'] ||= ActiveSupport::HashWithIndifferentAccess.new
|
27
|
+
@hash['propertyDefinitions'].each do |key, value|
|
28
|
+
@hash['propertyDefinitions'][key] = PropertyDefinition.new(value)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def add_property_definition(property)
|
33
|
+
property_definitions[property[:id]] = property
|
34
|
+
end
|
35
|
+
|
36
|
+
def create
|
37
|
+
repository.create_type(self)
|
38
|
+
end
|
39
|
+
|
40
|
+
def update(changed_property_defs)
|
41
|
+
new_defs = changed_property_defs.map(&:to_hash).reduce({}) do |result, element|
|
42
|
+
result[element[:id]] = element
|
43
|
+
result
|
44
|
+
end
|
45
|
+
|
46
|
+
hash = to_hash
|
47
|
+
hash['propertyDefinitions'] = new_defs
|
48
|
+
|
49
|
+
result = connection.execute! ({ cmisaction: 'updateType',
|
50
|
+
repositoryId: repository.id,
|
51
|
+
type: MultiJson.dump(hash) })
|
52
|
+
|
53
|
+
Type.new(result, repository)
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete
|
57
|
+
connection.execute!({ cmisaction: 'deleteType',
|
58
|
+
repositoryId: repository.id,
|
59
|
+
typeId: id })
|
60
|
+
end
|
61
|
+
|
62
|
+
def document_type?
|
63
|
+
base_id == 'cmis:document'
|
64
|
+
end
|
65
|
+
|
66
|
+
def folder_type?
|
67
|
+
base_id == 'cmis:folder'
|
68
|
+
end
|
69
|
+
|
70
|
+
def relationship_type?
|
71
|
+
base_id == 'cmis:relationship'
|
72
|
+
end
|
73
|
+
|
74
|
+
def policy_type?
|
75
|
+
base_id == 'cmis:policy'
|
76
|
+
end
|
77
|
+
|
78
|
+
def item_type?
|
79
|
+
base_id == 'cmis:item'
|
80
|
+
end
|
81
|
+
|
82
|
+
def new_object
|
83
|
+
object = case base_id
|
84
|
+
when 'cmis:document'
|
85
|
+
Document.new({}, repository)
|
86
|
+
when 'cmis:folder'
|
87
|
+
Folder.new({}, repository)
|
88
|
+
when 'cmis:relationship'
|
89
|
+
Relationship.new({}, repository)
|
90
|
+
when 'cmis:policy'
|
91
|
+
Policy.new({}, repository)
|
92
|
+
when 'cmis:item'
|
93
|
+
Item.new({}, repository)
|
94
|
+
else
|
95
|
+
raise "Unsupported base type: #{base_id}"
|
96
|
+
end
|
97
|
+
object.object_type_id = id
|
98
|
+
object
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_hash
|
102
|
+
@hash
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
data/lib/cmis/version.rb
ADDED
data/readme.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# cmis-ruby
|
2
|
+
|
3
|
+
**cmis-ruby** is a [CMIS](http://chemistry.apache.org/project/cmis.html) client library, using the the CMIS browser binding ([CMIS 1.1](http://docs.oasis-open.org/cmis/CMIS/v1.1/CMIS-v1.1.html)) for Ruby.
|
4
|
+
|
5
|
+
## Running Test
|
6
|
+
|
7
|
+
Running the tests requires a running CMIS server.
|
8
|
+
|
9
|
+
rake
|
10
|
+
|
11
|
+
## TODO
|
12
|
+
|
13
|
+
* query properties, not *
|
14
|
+
* string / symbol consistency
|
15
|
+
* better exceptions and handling
|
16
|
+
* headers / params in low level (options)
|
17
|
+
* facilitate copy between servers (make a flow)
|
18
|
+
* improve exists for repo / type
|
19
|
+
* caching
|
20
|
+
|
21
|
+
## Contributing
|
22
|
+
|
23
|
+
Write some code. Run tests. Open a pull request.
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative './helper'
|
2
|
+
|
3
|
+
describe CMIS::Document do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
@repo = create_repository('test')
|
7
|
+
end
|
8
|
+
|
9
|
+
after :all do
|
10
|
+
delete_repository('test')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'create_in_folder with content' do
|
14
|
+
new_object = @repo.new_document
|
15
|
+
new_object.name = 'doc1'
|
16
|
+
new_object.object_type_id = 'cmis:document'
|
17
|
+
new_object.set_content(StringIO.new('content1'), 'text/plain', 'doc1.txt') # set content on detached doc
|
18
|
+
doc = new_object.create_in_folder(@repo.root)
|
19
|
+
doc.name.should eq 'doc1'
|
20
|
+
doc.content_stream_mime_type.should eq 'text/plain'
|
21
|
+
doc.content_stream_file_name.should eq 'doc1.txt'
|
22
|
+
doc.content.should eq 'content1'
|
23
|
+
doc.delete
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'create_in_folder without content' do
|
27
|
+
new_object = @repo.new_document
|
28
|
+
new_object.name = 'doc2'
|
29
|
+
new_object.object_type_id = 'cmis:document'
|
30
|
+
doc = new_object.create_in_folder(@repo.root)
|
31
|
+
doc.name.should eq 'doc2'
|
32
|
+
doc.content.should be nil
|
33
|
+
doc.delete
|
34
|
+
end
|
35
|
+
|
36
|
+
# it 'set content - attached' do
|
37
|
+
# new_object = @repo.new_document
|
38
|
+
# new_object.name = 'doc3'
|
39
|
+
# new_object.object_type_id = 'cmis:document'
|
40
|
+
# doc = @repo.root.create(new_object)
|
41
|
+
# doc.set_content(StringIO.new('content3'), 'text/plain', 'doc3.txt') # set content on attached doc
|
42
|
+
# doc.content.should eq 'content3'
|
43
|
+
# doc.delete
|
44
|
+
# end
|
45
|
+
end
|
data/spec/folder_spec.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require_relative './helper'
|
2
|
+
|
3
|
+
describe CMIS::Folder do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
@repo = create_repository('test')
|
7
|
+
end
|
8
|
+
|
9
|
+
after :all do
|
10
|
+
delete_repository('test')
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'parent - root' do
|
14
|
+
@repo.root.parent.should be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'parent - root child' do
|
18
|
+
new_object = @repo.new_folder
|
19
|
+
new_object.name = 'folder1'
|
20
|
+
new_object.object_type_id = 'cmis:folder'
|
21
|
+
folder = @repo.root.create(new_object)
|
22
|
+
folder.parent.cmis_object_id.should eq @repo.root_folder_id
|
23
|
+
folder.delete
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'create document' do
|
27
|
+
new_object = @repo.new_document
|
28
|
+
new_object.name = 'doc1'
|
29
|
+
new_object.object_type_id = 'cmis:document'
|
30
|
+
new_object.set_content(StringIO.new('apple is a fruit'), 'text/plain', 'apple.txt')
|
31
|
+
object = @repo.root.create(new_object)
|
32
|
+
object.should be_a_kind_of CMIS::Document
|
33
|
+
object.name.should eq 'doc1'
|
34
|
+
object.content_stream_mime_type.should eq 'text/plain'
|
35
|
+
object.content_stream_file_name.should eq 'apple.txt'
|
36
|
+
object.content.should eq 'apple is a fruit'
|
37
|
+
object.delete
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'create folder' do
|
41
|
+
new_object = @repo.new_folder
|
42
|
+
new_object.name = 'folder1'
|
43
|
+
new_object.object_type_id = 'cmis:folder'
|
44
|
+
object = @repo.root.create(new_object)
|
45
|
+
object.should be_a_kind_of CMIS::Folder
|
46
|
+
object.name.should eq 'folder1'
|
47
|
+
object.delete
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'create relationship' do
|
51
|
+
new_object = @repo.new_relationship
|
52
|
+
new_object.name = 'rel1'
|
53
|
+
new_object.object_type_id = 'cmis:relationship'
|
54
|
+
lambda { @repo.root.create(new_object) }.should raise_exception
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'create item' do
|
58
|
+
begin
|
59
|
+
new_object = @repo.new_item
|
60
|
+
new_object.name = 'item1'
|
61
|
+
new_object.object_type_id = 'cmis:item'
|
62
|
+
object = @repo.root.create(new_object)
|
63
|
+
object.should be_a_kind_of CMIS::Item
|
64
|
+
object.name.should eq 'item1'
|
65
|
+
object.delete
|
66
|
+
end unless @repo.cmis_version_supported < '1.1'
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'create object' do
|
70
|
+
new_object = CMIS::Object.new({}, @repo)
|
71
|
+
new_object.name = 'object1'
|
72
|
+
new_object.object_type_id = 'cmis:folder'
|
73
|
+
lambda { @repo.root.create(new_object) }.should raise_exception
|
74
|
+
end
|
75
|
+
end
|