active_cmis2 0.3.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,121 @@
1
+ module ActiveCMIS
2
+ # This class is used to manage different CMIS servers.
3
+ class Server
4
+ include Internal::Caching
5
+ # @return [URI] The location of the server
6
+ attr_reader :endpoint
7
+ # @return [Logger] A default logger for derived repositories
8
+ attr_reader :logger
9
+ # @return [Hash] Options to be used by the HTTP objects
10
+ attr_reader :options
11
+
12
+ # @return [Server] Cached by endpoint and logger
13
+ def self.new(endpoint, logger = nil, authentication_info = nil, options = nil)
14
+ endpoint = case endpoint
15
+ when URI; endpoint
16
+ else URI(endpoint.to_s)
17
+ end
18
+ server = super(endpoint, logger || ActiveCMIS.default_logger, authentication_info, options)
19
+ endpoints[endpoint.to_s][authentication_info][logger] ||= server
20
+ end
21
+
22
+ # @return [{(URI, Logger) => Server}] The cache of known Servers
23
+ def self.endpoints
24
+ @endpoints ||= Hash.new {|h, k| h[k] = Hash.new {|h2, k2| h2[k2] = {}}}
25
+ end
26
+
27
+ # @return [String]
28
+ def inspect
29
+ "Server #{@endpoint}"
30
+ end
31
+ # @return [String]
32
+ def to_s
33
+ "Server " + @endpoint.to_s + " : " + repositories.map {|h| h[:name] + "(#{h[:id]})"}.join(", ")
34
+ end
35
+
36
+ # A connection needs the URL to a CMIS REST endpoint.
37
+ #
38
+ # It's used to manage all communication with the CMIS Server
39
+ # @param endpoint [URI] The URL where the CMIS AtomPub REST endpoint can be found
40
+ # @param logger [Logger] The logger that will be used to log debug/info messages
41
+ # @param authentication_info [Array?] Optional authentication info to be used when retrieving the data from the AtomPub endpoint
42
+ def initialize(endpoint, logger, authentication_info = nil, options = nil)
43
+ @endpoint = endpoint
44
+ @logger = logger
45
+ @options = options || {}
46
+
47
+ method, *params = authentication_info
48
+ @authentication_info = authentication_info
49
+ if method
50
+ conn.authenticate(method, *params)
51
+ end
52
+ end
53
+
54
+ # This returns a new Server object using the specified authentication info
55
+ #
56
+ # @param (see ActiveCMIS::Internal::Connection#authenticate)
57
+ # @see Internal::Connection#authenticate
58
+ # @return [void]
59
+ def authenticate(*authentication_info)
60
+ self.class.new(endpoint, logger, authentication_info)
61
+ end
62
+
63
+ # Returns the _Repository identified by the ID
64
+ # Authentication will take place with the optional second paramater, if it
65
+ # is absent and there is server authentcation then the server authentication
66
+ # will be used
67
+ #
68
+ # Cached by the repository_id and, authentcation info. The cache can be reset
69
+ # by calling clear_repositories.
70
+ #
71
+ # @param [String] repository_id
72
+ # @param [Array] authentication_info
73
+ # @return [Repository]
74
+ def repository(repository_id, authentication_info = @authentication_info)
75
+ key = [repository_id, authentication_info]
76
+ cached_repositories[key] ||= uncached_repository(*key)
77
+ end
78
+
79
+ def uncached_repository(repository_id, authentication_info)
80
+ path = "/app:service/app:workspace[cra:repositoryInfo/c:repositoryId[child::text() = '#{repository_id}']]"
81
+ repository_data = repository_info.xpath(path, NS::COMBINED)
82
+ if repository_data.empty?
83
+ raise Error::ObjectNotFound.new("The repository #{repository_id} doesn't exist")
84
+ else
85
+ Repository.new(self, conn.dup, logger.dup, repository_data, authentication_info)
86
+ end
87
+ end
88
+ private :uncached_repository
89
+
90
+ # Reset cache of Repository objects
91
+ #
92
+ # @return [void]
93
+ def clear_repositories
94
+ @cached_repositories = {}
95
+ end
96
+
97
+
98
+ # Lists all the available repositories
99
+ #
100
+ # @return [<{:id, :name} => String>]
101
+ def repositories
102
+ repositories = repository_info.xpath("/app:service/app:workspace/cra:repositoryInfo", NS::COMBINED)
103
+ repositories.map {|ri| next {:id => ri.xpath("ns:repositoryId", "ns" => NS::CMIS_CORE).text,
104
+ :name => ri.xpath("ns:repositoryName", "ns" => NS::CMIS_CORE).text }}
105
+ end
106
+
107
+ private
108
+ def repository_info
109
+ @repository_info ||= conn.get_xml(endpoint)
110
+ end
111
+ cache :repository_info
112
+
113
+ def cached_repositories
114
+ @cached_repositories ||= {}
115
+ end
116
+
117
+ def conn
118
+ @conn ||= Internal::Connection.new(logger.dup, @options)
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,200 @@
1
+ module ActiveCMIS
2
+ module Type
3
+ # @private
4
+ def self.create(param_conn, repository, klass_data)
5
+ parent_id = klass_data.xpath("cra:type/c:parentId/text()", NS::COMBINED)
6
+ superclass = if parent = parent_id.first
7
+ repository.type_by_id(parent.to_s)
8
+ else
9
+ base_type_id = klass_data.xpath("cra:type/c:baseId", NS::COMBINED).text
10
+ case base_type_id
11
+ when "cmis:document"
12
+ Document
13
+ when "cmis:folder"
14
+ Folder
15
+ when "cmis:relationship"
16
+ Relationship
17
+ when "cmis:policy"
18
+ Policy
19
+ else
20
+ raise ActiveCMIS::Error.new("Type #{klass_data.xpath("cra:type/c:id", NS::COMBINED).text} without supertype, and not actually a valid base_type (#{base_type_id.inspect})\n" + klass_data.to_s)
21
+ end
22
+ end
23
+
24
+ klass = ::Class.new(superclass) do
25
+ extend ActiveCMIS::Type::ClassMethods
26
+ include ActiveCMIS::Type::InstanceMethods
27
+
28
+ @repository = repository
29
+ @conn = param_conn
30
+ @data = klass_data
31
+ @self_link = klass_data.xpath("at:link[@rel = 'self']/@href", NS::COMBINED).text
32
+
33
+ end
34
+ klass
35
+ end
36
+
37
+ # Instance Methods on CMIS Types
38
+ module InstanceMethods
39
+ # Creates a new CMIS Object
40
+ # @overload initialize(attributes)
41
+ # @param [Hash] attributes Attributes for a newly created object of the current type
42
+ # @return [Object]
43
+ def initialize(rep = nil, data = nil, parameters = {})
44
+ case rep
45
+ when Hash
46
+ attributes = rep
47
+ rep = nil
48
+ data = nil # Force data and parameters to be empty in that case (NOTE: assert may be better?)
49
+ parameters = {}
50
+ when NilClass
51
+ else
52
+ if rep != self.class.repository
53
+ raise "Trying to create element in different repository than type"
54
+ end
55
+ end
56
+ super(rep || self.class.repository, data, parameters)
57
+ unless attributes.nil?
58
+ update(attributes)
59
+ end
60
+ end
61
+ end
62
+
63
+ # Class Methods on CMIS Types
64
+ #
65
+ # The following info is also available:
66
+ # id, local_name, local_namespace, display_name, query_name, description, base_id, parent_id, creatable, fileable,
67
+ # queryable, fulltext_indexed, controllable_policy, controllable_acl, versionable, content_stream_allowed
68
+ module ClassMethods
69
+ include Internal::Caching
70
+
71
+ cached_reader :id, :local_name, :local_namespace, :display_name, :query_name, :description, :base_id,
72
+ :parent_id, :creatable, :fileable, :queryable, :fulltext_indexed, :controllable_policy, :controllable_acl,
73
+ :versionable, :content_stream_allowed
74
+
75
+ # @param [Boolean] inherited (false) *Ignored*
76
+ # @return [{String => PropertyDefinition}] A list of propery definitions for all properties on the type
77
+ def attributes(inherited = false)
78
+ load_from_data unless defined?(@attributes)
79
+ if inherited && superclass.respond_to?(:attributes)
80
+ super.merge(@attributes)
81
+ else
82
+ @attributes
83
+ end
84
+ end
85
+
86
+ # @return [{String => PropertyDefinition}] A list of all required definitions (includes inherited attributes)
87
+ def required_attributes
88
+ attributes(true).reject {|key, value| !value.required}
89
+ end
90
+
91
+ # @return [<String>] A list of prefixes that can be used for adressing attributes (like cmis:)
92
+ def attribute_prefixes
93
+ @prefixes ||= attributes(true).keys.map do |key|
94
+ if key =~ /^([^:]+):/
95
+ $1
96
+ end
97
+ end.compact.uniq
98
+ end
99
+
100
+ # @return [void]
101
+ def reload
102
+ remove_instance_variable(:@attributes) if defined? @attributes
103
+ [:attributes] + __reload # Could also do if defined?(super) then super else __reload end, but we don't do anything but remove_instance_variable @attributes in superclasses anyway
104
+ end
105
+
106
+ # @return [String]
107
+ def inspect
108
+ "#<#{repository.key}::Class #{key}>"
109
+ end
110
+
111
+ # @return [String] The CMIS ID of the type
112
+ def key
113
+ @key ||= data.xpath("cra:type/c:id", NS::COMBINED).text
114
+ end
115
+
116
+ # @return [Collection<Class>] All direct subtypes (1 level deep)
117
+ def subtypes
118
+ types_feed = Internal::Utils.extract_links(data, 'down', 'application/atom+xml', 'type' => 'feed')
119
+ raise "No subtypes link for #{id}" if types_feed.empty?
120
+
121
+ Collection.new(repository, types_feed.first) do |entry|
122
+ id = entry.xpath("cra:type/c:id", NS::COMBINED).text
123
+ repository.type_by_id id
124
+ end
125
+ end
126
+ cache :subtypes
127
+
128
+ # @return [Array<Class>] All subtypes
129
+ def all_subtypes
130
+ subtypes.map do |t|
131
+ t.all_subtypes
132
+ end.flatten << self
133
+ end
134
+ cache :all_subtypes
135
+
136
+ private
137
+ # @private
138
+ attr_reader :self_link, :conn
139
+ def data
140
+ @data ||= conn.get_atom_entry(self_link)
141
+ end
142
+ cache :data
143
+
144
+ def load_from_data
145
+ @attributes = {}
146
+ data.xpath('cra:type', NS::COMBINED).children.each do |node|
147
+ next unless node.namespace
148
+ next unless node.namespace.href == NS::CMIS_CORE
149
+
150
+ case node.node_name
151
+ when "id"
152
+ @id = node.text
153
+ when "localName"
154
+ @local_name = node.text
155
+ when "localNamespace"
156
+ @local_namespace = node.text
157
+ when "displayName"
158
+ @display_name = node.text
159
+ when "queryName"
160
+ @query_name = node.text
161
+ when "description"
162
+ @description = node.text
163
+ when "baseId"
164
+ @base_id = node.text
165
+ when "parentId"
166
+ @parent_id = node.text
167
+ when "creatable"
168
+ @creatable = AtomicType::Boolean.xml_to_bool(node.text)
169
+ when "fileable"
170
+ @fileable = AtomicType::Boolean.xml_to_bool(node.text)
171
+ when "queryable"
172
+ @queryable = AtomicType::Boolean.xml_to_bool(node.text)
173
+ when "fulltextIndexed"
174
+ @fulltext_indexed = AtomicType::Boolean.xml_to_bool(node.text)
175
+ when "controllablePolicy"
176
+ @controllable_policy = AtomicType::Boolean.xml_to_bool(node.text)
177
+ when "controllableACL"
178
+ @controllable_acl = AtomicType::Boolean.xml_to_bool(node.text)
179
+ when "versionable"
180
+ @versionable = AtomicType::Boolean.xml_to_bool(node.text)
181
+ when "contentStreamAllowed"
182
+ # FIXME? this is an enumeration, should perhaps wrap
183
+ @content_stream_allowed = node.text
184
+ when /^property(?:DateTime|String|Html|Id|Boolean|Integer|Decimal)Definition$/
185
+ attr = PropertyDefinition.new(self, node.children)
186
+ @attributes[attr.id] = attr
187
+ end
188
+ end
189
+ if %w(cmis:folder cmis:document).include? @base_id and not @fileable
190
+ repository.logger.warn "The server behaved strange: #{@id}, with basetype #{@base_id} MUST be fileable"
191
+ @fileable = true
192
+ elsif @base_id == "cmis:relationship" and @fileable
193
+ repository.logger.warn "The server behaved strange: #{@id}, with basetype #{@base_id} MUST NOT be fileable"
194
+ @fileable = false
195
+ end
196
+ @attributes.freeze
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,10 @@
1
+ require 'yaml'
2
+ module ActiveCMIS
3
+ module Version
4
+ yaml = YAML.load_file(File.join(File.dirname(__FILE__), '/../../VERSION.yml'))
5
+ MAJOR = yaml[:major]
6
+ MINOR = yaml[:minor]
7
+ PATCH = yaml[:patch]
8
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_cmis2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.8
5
+ platform: ruby
6
+ authors:
7
+ - Joeri Samson
8
+ - Linagora
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-01-21 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: nokogiri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: 1.4.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: 1.4.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: ntlm-http
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 0.1.1
35
+ - - "~>"
36
+ - !ruby/object:Gem::Version
37
+ version: '0.1'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 0.1.1
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.1'
48
+ - !ruby/object:Gem::Dependency
49
+ name: require_relative
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.2
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '1.0'
58
+ type: :runtime
59
+ prerelease: false
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.0.2
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.0'
68
+ description: A CMIS library implementing both reading and updating capabilities through
69
+ the AtomPub/REST binding to CMIS.
70
+ email: joeri@xaop.com
71
+ executables: []
72
+ extensions: []
73
+ extra_rdoc_files:
74
+ - LICENSE
75
+ - README.md
76
+ - TODO
77
+ files:
78
+ - AUTHORS
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - TODO
83
+ - VERSION.yml
84
+ - active_cmis.gemspec
85
+ - lib/active_cmis.rb
86
+ - lib/active_cmis/acl.rb
87
+ - lib/active_cmis/acl_entry.rb
88
+ - lib/active_cmis/active_cmis.rb
89
+ - lib/active_cmis/atomic_types.rb
90
+ - lib/active_cmis/attribute_prefix.rb
91
+ - lib/active_cmis/collection.rb
92
+ - lib/active_cmis/document.rb
93
+ - lib/active_cmis/exceptions.rb
94
+ - lib/active_cmis/folder.rb
95
+ - lib/active_cmis/internal/caching.rb
96
+ - lib/active_cmis/internal/connection.rb
97
+ - lib/active_cmis/internal/utils.rb
98
+ - lib/active_cmis/ns.rb
99
+ - lib/active_cmis/object.rb
100
+ - lib/active_cmis/policy.rb
101
+ - lib/active_cmis/property_definition.rb
102
+ - lib/active_cmis/query_result.rb
103
+ - lib/active_cmis/rel.rb
104
+ - lib/active_cmis/relationship.rb
105
+ - lib/active_cmis/rendition.rb
106
+ - lib/active_cmis/repository.rb
107
+ - lib/active_cmis/server.rb
108
+ - lib/active_cmis/type.rb
109
+ - lib/active_cmis/version.rb
110
+ homepage: https://github.com/linagora/activecmis
111
+ licenses: []
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options: []
115
+ require_paths:
116
+ - lib
117
+ required_ruby_version: !ruby/object:Gem::Requirement
118
+ requirements:
119
+ - - ">="
120
+ - !ruby/object:Gem::Version
121
+ version: 1.8.6
122
+ required_rubygems_version: !ruby/object:Gem::Requirement
123
+ requirements:
124
+ - - ">="
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
127
+ requirements: []
128
+ rubyforge_project:
129
+ rubygems_version: 2.7.6
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: A library to interact with CMIS repositories through the AtomPub/REST binding
133
+ test_files: []