cmis-ruby 0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,62 @@
1
+ module CMIS
2
+ class Document < Object
3
+
4
+ def initialize(raw, repository)
5
+ super
6
+ cmis_properties %w( cmis:isImmutable cmis:isLatestVersion
7
+ cmis:isMajorVersion cmis:isLatestMajorVersion
8
+ cmis:isPrivateWorkingCopy cmis:versionLabel
9
+ cmis:versionSeriesId cmis:isVersionSeriesCheckedOut
10
+ cmis:versionSeriesCheckedOutBy
11
+ cmis:versionSeriesCheckedOutId cmis:checkinComment
12
+ cmis:contentStreamLength cmis:contentStreamMimeType
13
+ cmis:contentStreamFileName cmis:contentStreamId )
14
+ end
15
+
16
+ def create_in_folder(folder)
17
+ r = connection.execute!({ cmisaction: 'createDocument',
18
+ repositoryId: repository.id,
19
+ properties: properties,
20
+ objectId: folder.cmis_object_id,
21
+ folderId: folder.cmis_object_id,
22
+ content: @local_content })
23
+
24
+ ObjectFactory.create(r, repository)
25
+ end
26
+
27
+ def copy_in_folder(folder)
28
+ id = connection.execute!({ cmisaction: 'createDocument',
29
+ repositoryId: repository.id,
30
+ sourceId: cmis_object_id,
31
+ objectId: folder.cmis_object_id })
32
+
33
+ repository.object(id)
34
+ end
35
+
36
+ def content
37
+ connection.execute!({ cmisselector: 'content',
38
+ repositoryId: repository.id,
39
+ objectId: cmis_object_id })
40
+
41
+ rescue CMIS::CMISRequestError
42
+ nil
43
+ end
44
+
45
+ def set_content(stream, mime_type, filename)
46
+ content = { stream: stream,
47
+ mime_type: mime_type,
48
+ filename: filename }
49
+
50
+ if detached?
51
+ @local_content = content
52
+ else
53
+ update_change_token connection.execute!({ cmisaction: 'setContent',
54
+ repositoryId: repository.id,
55
+ objectId: cmis_object_id,
56
+ content: content,
57
+ changeToken: change_token })
58
+ end
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,76 @@
1
+ module CMIS
2
+ class Folder < Object
3
+
4
+ def initialize(raw, repository)
5
+ super
6
+ cmis_properties %w( cmis:parentId cmis:path
7
+ cmis:allowedChildObjectTypeIds )
8
+ end
9
+
10
+ def parent
11
+ repository.object(parent_id) if parent_id
12
+ end
13
+
14
+ def allowed_child_object_types
15
+ return nil unless allowed_child_object_type_ids
16
+ allowed_child_object_type_ids.map { |type_id| repository.type(type_id) }
17
+ end
18
+
19
+ def children(options = {})
20
+ Children.new(self, options)
21
+ end
22
+
23
+ def create(object)
24
+ case object
25
+ when Relationship
26
+ raise "'cmis:relationship' is not fileable. Use Repository#create_relationship"
27
+
28
+ when Document
29
+ return object.create_in_folder(self)
30
+
31
+ when Folder
32
+ o = connection.execute!({ cmisaction: 'createFolder',
33
+ repositoryId: repository.id,
34
+ properties: object.properties,
35
+ objectId: cmis_object_id })
36
+
37
+ when Policy
38
+ o = connection.execute!({ cmisaction: 'createPolicy',
39
+ repositoryId: repository.id,
40
+ properties: object.properties,
41
+ objectId: cmis_object_id })
42
+ when Item
43
+ o = connection.execute!({ cmisaction: 'createItem',
44
+ repositoryId: repository.id,
45
+ properties: object.properties,
46
+ objectId: cmis_object_id })
47
+
48
+ else
49
+ raise "Unexpected base_type_id: #{object.base_type_id}"
50
+ end
51
+
52
+ ObjectFactory.create(o, repository)
53
+ end
54
+
55
+ def delete_tree
56
+ connection.execute!({ cmisaction: 'deleteTree',
57
+ repositoryId: repository.id,
58
+ objectId: cmis_object_id })
59
+ end
60
+
61
+ def add(object)
62
+ connection.execute!({ cmisaction: 'addObjectToFolder',
63
+ repositoryId: repository.id,
64
+ objectId: object.cmis_object_id,
65
+ folderId: cmis_object_id })
66
+ end
67
+
68
+ def remove(object)
69
+ connection.execute!({ cmisaction: 'removeObjectFromFolder',
70
+ repositoryId: repository.id,
71
+ objectId: object.cmis_object_id,
72
+ folderId: cmis_object_id })
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,58 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module CMIS
4
+ module Helpers
5
+
6
+ def initialize_properties(raw)
7
+ @properties = get_properties_map(raw)
8
+ end
9
+
10
+ def cmis_properties(properties)
11
+ properties.each do |property_name|
12
+ method_name = method_name(property_name)
13
+ class_eval "def #{method_name};@properties['#{property_name}'];end"
14
+ class_eval "def #{method_name}=(value);@properties['#{property_name}']=value;end"
15
+ end
16
+ end
17
+
18
+ def update_change_token(r)
19
+ if r['properties']
20
+ @change_token = r['properties']['cmis:changeToken']['value']
21
+ elsif r['succinctProperties']
22
+ @change_token = r['succinctProperties']['cmis:changeToken']
23
+ else
24
+ raise "Unexpected hash: #{r}"
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def method_name(property_name)
31
+ if property_name == 'cmis:objectId'
32
+ 'cmis_object_id'
33
+ else
34
+ property_name.gsub('cmis:', '').underscore
35
+ end
36
+ end
37
+
38
+ def get_properties_map(raw)
39
+ raw = raw.with_indifferent_access
40
+
41
+ if raw['succinctProperties']
42
+ result = raw['succinctProperties']
43
+ elsif raw['properties']
44
+ result = raw['properties'].reduce({}) do |h, (k, v)|
45
+ val = v['value']
46
+ val = v['value'].first if v['value'].is_a?(Array) and v['cardinality'] == 'single'
47
+ val = Time.at(val / 1000) if val and v['type'] == 'datetime'
48
+ h.merge(k => val)
49
+ end
50
+ else
51
+ result = {}
52
+ end
53
+
54
+ result.with_indifferent_access
55
+ end
56
+
57
+ end
58
+ end
data/lib/cmis/item.rb ADDED
@@ -0,0 +1,11 @@
1
+ module CMIS
2
+
3
+ class Item < Object
4
+
5
+ def initialize(raw, repository)
6
+ super
7
+ end
8
+
9
+ end
10
+
11
+ end
@@ -0,0 +1,120 @@
1
+ module CMIS
2
+ class Object
3
+
4
+ include Helpers
5
+
6
+ attr_reader :connection
7
+ attr_reader :repository
8
+ attr_accessor :properties
9
+
10
+ def initialize(raw, repository)
11
+ initialize_properties(raw)
12
+ cmis_properties %w( cmis:objectId cmis:baseTypeId cmis:objectTypeId
13
+ cmis:secondaryObjectTypeIds cmis:name cmis:description
14
+ cmis:createdBy cmis:creationDate cmis:lastModifiedBy
15
+ cmis:lastModificationDate cmis:changeToken )
16
+
17
+ @repository = repository
18
+ @connection = repository.connection
19
+ end
20
+
21
+ def object_type
22
+ repository.type(object_type_id)
23
+ end
24
+
25
+ def delete
26
+ connection.execute!({ cmisaction: 'delete',
27
+ repositoryId: repository.id,
28
+ objectId: cmis_object_id,
29
+ allVersions: true })
30
+ end
31
+
32
+ def update_properties(properties)
33
+ update_change_token connection.execute!({ cmisaction: 'update',
34
+ repositoryId: repository.id,
35
+ objectId: cmis_object_id,
36
+ properties: properties,
37
+ changeToken: change_token })
38
+ end
39
+
40
+ def parents
41
+ result = connection.execute!({ cmisselector: 'parents',
42
+ repositoryId: repository.id,
43
+ objectId: cmis_object_id })
44
+
45
+ result.map { |o| ObjectFactory.create(o['object'], repository) }
46
+ end
47
+
48
+ def allowable_actions
49
+ connection.execute!({ cmisselector: 'allowableActions',
50
+ repositoryId: repository.id,
51
+ objectId: cmis_object_id })
52
+ end
53
+
54
+ def relationships(direction = :either)
55
+ result = connection.execute!({ cmisselector: 'relationships',
56
+ repositoryId: repository.id,
57
+ objectId: cmis_object_id,
58
+ relationshipDirection: direction })
59
+
60
+ result['objects'].map { |r| Relationship.new(r, repository) }
61
+ end
62
+
63
+ def policies
64
+ result = connection.execute!({ cmisselector: 'policies',
65
+ repositoryId: repository.id,
66
+ objectId: cmis_object_id })
67
+
68
+ result.map { |r| Policy.new(r, repository) }
69
+ end
70
+
71
+ # By default removes from all folders
72
+ def unfile(folder = nil)
73
+ options = { repositoryId: repository.id,
74
+ cmisaction: 'removeObjectFromFolder',
75
+ objectId: cmis_object_id }
76
+ options[:folderId] = folder.cmis_object_id if folder
77
+
78
+ connection.execute!(options)
79
+ end
80
+
81
+ def move(target_folder)
82
+ object_parents = parents
83
+
84
+ unless object_parents.size == 1
85
+ raise 'Cannot move object because it is not in excatly one folder'
86
+ end
87
+
88
+ connection.execute!({ cmisaction: 'move',
89
+ repositoryId: repository.id,
90
+ objectId: cmis_object_id,
91
+ targetFolderId: target_folder.cmis_object_id,
92
+ sourceFolderId: object_parents.first.cmis_object_id })
93
+ end
94
+
95
+ def acls
96
+ connection.execute!({ cmisselector: 'acl',
97
+ repositoryId: repository.id,
98
+ objectId: cmis_object_id })
99
+ end
100
+
101
+ def add_aces(aces)
102
+ connection.execute!({ cmisaction: 'applyACL',
103
+ repositoryId: repository.id,
104
+ objectId: cmis_object_id,
105
+ addACEs: aces })
106
+ end
107
+
108
+ def remove_aces(aces)
109
+ connection.execute!({ cmisaction: 'applyACL',
110
+ repositoryId: repository.id,
111
+ objectId: cmis_object_id,
112
+ removeACEs: aces })
113
+ end
114
+
115
+ def detached?
116
+ cmis_object_id.nil?
117
+ end
118
+
119
+ end
120
+ end
@@ -0,0 +1,27 @@
1
+ module CMIS
2
+ class ObjectFactory
3
+
4
+ def self.create(raw, repository)
5
+ case base_type_id(raw)
6
+ when 'cmis:folder' then Folder.new(raw, repository)
7
+ when 'cmis:document' then Document.new(raw, repository)
8
+ when 'cmis:relationship' then Relationship.new(raw, repository)
9
+ when 'cmis:policy' then Policy.new(raw, repository)
10
+ when 'cmis:item' then Item.new(raw, repository)
11
+ else raise "Unexpected baseTypeId: #{base_type_id}."
12
+ end
13
+ end
14
+
15
+ private
16
+
17
+ def self.base_type_id(raw)
18
+ if raw['properties']
19
+ raw['properties']['cmis:baseTypeId']['value']
20
+ elsif raw['succinctProperties']
21
+ raw['succinctProperties']['cmis:baseTypeId']
22
+ else
23
+ raise "Unexpected json: #{raw}"
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,26 @@
1
+ module CMIS
2
+ class Policy < Object
3
+
4
+ attr_reader :policy_text
5
+
6
+ def initialize(raw, repository)
7
+ super
8
+ cmis_properties %w( cmis:policyText )
9
+ end
10
+
11
+ def apply_to(object)
12
+ connection.execute!({ cmisaction: 'applyPolicy',
13
+ repositoryId: repository_id,
14
+ policyId: cmis_object_id,
15
+ objectId: object.cmis_object_id })
16
+ end
17
+
18
+ def remove_from(object)
19
+ connection.execute!({ cmisaction: 'removePolicy',
20
+ repositoryId: repository_id,
21
+ policyId: cmis_object_id,
22
+ objectId: object.cmis_object_id })
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ require 'active_support/core_ext'
2
+
3
+ module CMIS
4
+ class PropertyDefinition
5
+
6
+ def initialize(hash = {})
7
+ @hash = hash.with_indifferent_access
8
+
9
+ @hash.each_key do |key|
10
+ class_eval "def #{key.underscore};@hash['#{key}'];end"
11
+ class_eval "def #{key.underscore}=(value);@hash['#{key}']=value;end"
12
+ end
13
+ end
14
+
15
+ def readonly?
16
+ updatability == 'readonly'
17
+ end
18
+
19
+ def oncreate?
20
+ updatability == 'oncreate'
21
+ end
22
+
23
+ def readwrite?
24
+ updatability == 'readwrite'
25
+ end
26
+
27
+ def to_hash
28
+ @hash
29
+ end
30
+
31
+ end
32
+ end
data/lib/cmis/query.rb ADDED
@@ -0,0 +1,100 @@
1
+ module CMIS
2
+ class Query
3
+
4
+ # Options: from, page_size
5
+ def initialize(repository, statement, options = {})
6
+ @repository = repository
7
+ @statement = statement
8
+ @options = options.stringify_keys
9
+
10
+ init_options
11
+ end
12
+
13
+ # Options: limit
14
+ def each_result(options = {}, &block)
15
+ return enum_for(:each_result, options) unless block_given?
16
+
17
+ init_options
18
+ limit = parse_limit(options)
19
+ counter = 0
20
+
21
+ while has_next?
22
+ results.each do |object|
23
+ break unless counter < limit
24
+ yield object
25
+ counter = counter.next
26
+ end
27
+ end
28
+ end
29
+
30
+ # Options: limit
31
+ def each_page(options = {}, &block)
32
+ return enum_for(:each_page, options) unless block_given?
33
+
34
+ init_options
35
+ limit = parse_limit(options)
36
+ counter = 0
37
+
38
+ while has_next?
39
+ break unless counter < limit
40
+ yield r = results
41
+ counter += r.size
42
+ end
43
+ end
44
+
45
+ def results
46
+ result = do_query
47
+
48
+ @skip_count += result.results.size
49
+ @has_next = result.has_more_items
50
+ @total = result.num_items
51
+
52
+ result.results
53
+ end
54
+
55
+ def has_next?
56
+ @has_next
57
+ end
58
+
59
+ def total
60
+ @total ||= do_query.num_items
61
+ end
62
+
63
+ private
64
+
65
+ def init_options
66
+ @method = (@options['method'] || 'get').to_s.downcase
67
+ @max_items = @options['page_size'] || 10
68
+ @skip_count = @options['from'] || 0
69
+ @has_next = true
70
+ end
71
+
72
+ def parse_limit(options)
73
+ options.stringify_keys!
74
+ limit = options['limit'] || 10
75
+ limit = BigDecimal::INFINITY if limit == :all
76
+ raise 'Not a valid limit' unless limit.is_a? Numeric
77
+ limit
78
+ end
79
+
80
+ def do_query
81
+ params = { repositoryId: @repository.id,
82
+ maxItems: @max_items,
83
+ skipCount: @skip_count }
84
+ if @method == 'post'
85
+ params.merge!(cmisselector: 'query', q: @statement)
86
+ else
87
+ params.merge!(cmisaction: 'query', statement: @statement)
88
+ end
89
+
90
+ result = @repository.connection.execute!(params)
91
+
92
+ results = result['results'].map do |r|
93
+ ObjectFactory.create(r, @repository)
94
+ end
95
+
96
+ QueryResult.new(results, result['numItems'], result['hasMoreItems'])
97
+ end
98
+
99
+ end
100
+ end