cmis-ruby 0.2
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/.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
|