cmis_server 1.0.3

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.
Files changed (133) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +3 -0
  4. data/Rakefile +51 -0
  5. data/app/assets/javascripts/cmis_server/application.js +13 -0
  6. data/app/assets/stylesheets/cmis_server/application.css +15 -0
  7. data/app/controllers/cmis_server/application_controller.rb +19 -0
  8. data/app/controllers/cmis_server/atom_pub/base_controller.rb +23 -0
  9. data/app/controllers/cmis_server/atom_pub/bulk_controller.rb +302 -0
  10. data/app/controllers/cmis_server/atom_pub/content_controller.rb +178 -0
  11. data/app/controllers/cmis_server/atom_pub/entries_controller.rb +41 -0
  12. data/app/controllers/cmis_server/atom_pub/folder_collection_controller.rb +70 -0
  13. data/app/controllers/cmis_server/atom_pub/query_controller.rb +138 -0
  14. data/app/controllers/cmis_server/atom_pub/repository_controller.rb +75 -0
  15. data/app/controllers/cmis_server/atom_pub/secondary_types_controller.rb +149 -0
  16. data/app/controllers/cmis_server/atom_pub/service_documents_controller.rb +34 -0
  17. data/app/controllers/cmis_server/atom_pub/types_controller.rb +229 -0
  18. data/app/controllers/cmis_server/atom_pub/uri_templates_controller.rb +58 -0
  19. data/app/controllers/concerns/cmis_server/atom_pub/repository_scopable.rb +18 -0
  20. data/app/helpers/cmis_server/application_helper.rb +31 -0
  21. data/app/models/cmis_server/application_record.rb +5 -0
  22. data/app/services/cmis_server/bulk_update_service.rb +69 -0
  23. data/app/services/cmis_server/content_stream_service.rb +75 -0
  24. data/app/services/cmis_server/discovery_service.rb +31 -0
  25. data/app/services/cmis_server/navigation_service.rb +43 -0
  26. data/app/services/cmis_server/object_service.rb +176 -0
  27. data/app/services/cmis_server/repository_service.rb +40 -0
  28. data/app/services/cmis_server/secondary_type_service.rb +120 -0
  29. data/app/services/cmis_server/type_management_service.rb +117 -0
  30. data/app/views/cmis_server/atom_pub/bulk_update_feed.atom.builder +47 -0
  31. data/app/views/cmis_server/atom_pub/entries/_cmis_document_links.atom_entry.builder +0 -0
  32. data/app/views/cmis_server/atom_pub/entries/_cmis_folder_links.atom_entry.builder +3 -0
  33. data/app/views/cmis_server/atom_pub/entries/_object_entry.atom_entry.builder +64 -0
  34. data/app/views/cmis_server/atom_pub/entries/_property.atom_entry.builder +8 -0
  35. data/app/views/cmis_server/atom_pub/entries/object_entry.atom_entry.builder +1 -0
  36. data/app/views/cmis_server/atom_pub/entries/type_entry.atom_entry.builder +59 -0
  37. data/app/views/cmis_server/atom_pub/feeds/_feed_entry.atom_feed.builder +1 -0
  38. data/app/views/cmis_server/atom_pub/feeds/feed.atom_feed.builder +30 -0
  39. data/app/views/cmis_server/atom_pub/service_documents/_uri_template.atom_service.builder +5 -0
  40. data/app/views/cmis_server/atom_pub/service_documents/_workspace.atom_service.builder +89 -0
  41. data/app/views/cmis_server/atom_pub/service_documents/service_document.atom_service.builder +1 -0
  42. data/app/views/cmis_server/atom_pub/shared/_collection.xml.builder +7 -0
  43. data/app/views/cmis_server/atom_pub/shared/atom_entry_layout.atom_entry.builder +0 -0
  44. data/app/views/cmis_server/atom_pub/type_entry.atom.builder +69 -0
  45. data/app/views/cmis_server/atom_pub/types_feed.atom.builder +91 -0
  46. data/app/views/layouts/cmis_server/application.atom_entry.builder +2 -0
  47. data/app/views/layouts/cmis_server/application.atom_feed.builder +3 -0
  48. data/app/views/layouts/cmis_server/application.atom_service.builder +10 -0
  49. data/app/views/layouts/cmis_server/application.html.erb +14 -0
  50. data/config/routes.rb +49 -0
  51. data/lib/cmis_server/atom_pub/entry_parser.rb +72 -0
  52. data/lib/cmis_server/base_objects/base_type.rb +128 -0
  53. data/lib/cmis_server/base_objects/document.rb +68 -0
  54. data/lib/cmis_server/base_objects/folder.rb +104 -0
  55. data/lib/cmis_server/base_objects/item.rb +25 -0
  56. data/lib/cmis_server/base_types.rb +123 -0
  57. data/lib/cmis_server/cmis_object.rb +190 -0
  58. data/lib/cmis_server/configuration.rb +43 -0
  59. data/lib/cmis_server/constants.rb +8 -0
  60. data/lib/cmis_server/content_stream.rb +52 -0
  61. data/lib/cmis_server/context.rb +11 -0
  62. data/lib/cmis_server/document_object.rb +12 -0
  63. data/lib/cmis_server/document_type.rb +67 -0
  64. data/lib/cmis_server/engine.rb +60 -0
  65. data/lib/cmis_server/exceptions.rb +185 -0
  66. data/lib/cmis_server/folder_object.rb +18 -0
  67. data/lib/cmis_server/folder_type.rb +34 -0
  68. data/lib/cmis_server/id.rb +18 -0
  69. data/lib/cmis_server/item_adapter.rb +26 -0
  70. data/lib/cmis_server/item_object.rb +15 -0
  71. data/lib/cmis_server/item_type.rb +7 -0
  72. data/lib/cmis_server/object_adapter.rb +79 -0
  73. data/lib/cmis_server/property.rb +29 -0
  74. data/lib/cmis_server/property_definition.rb +118 -0
  75. data/lib/cmis_server/query/parser.output +2250 -0
  76. data/lib/cmis_server/query/parser.racc +222 -0
  77. data/lib/cmis_server/query/parser.racc.rb +1039 -0
  78. data/lib/cmis_server/query/parser.rex +114 -0
  79. data/lib/cmis_server/query/parser.rex.rb +238 -0
  80. data/lib/cmis_server/query/statement.rb +395 -0
  81. data/lib/cmis_server/query.rb +2 -0
  82. data/lib/cmis_server/renderable_collection.rb +45 -0
  83. data/lib/cmis_server/renderable_object.rb +49 -0
  84. data/lib/cmis_server/repository.rb +91 -0
  85. data/lib/cmis_server/secondary_type.rb +11 -0
  86. data/lib/cmis_server/type.rb +62 -0
  87. data/lib/cmis_server/type_registry.rb +115 -0
  88. data/lib/cmis_server/version.rb +4 -0
  89. data/lib/cmis_server.rb +22 -0
  90. data/lib/tasks/cmis_server_tasks.rake +4 -0
  91. data/test/cmis_server_test.rb +7 -0
  92. data/test/dummy/README.rdoc +28 -0
  93. data/test/dummy/Rakefile +6 -0
  94. data/test/dummy/app/assets/javascripts/application.js +13 -0
  95. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  96. data/test/dummy/app/controllers/application_controller.rb +5 -0
  97. data/test/dummy/app/helpers/application_helper.rb +2 -0
  98. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  99. data/test/dummy/bin/bundle +3 -0
  100. data/test/dummy/bin/rails +4 -0
  101. data/test/dummy/bin/rake +4 -0
  102. data/test/dummy/bin/setup +29 -0
  103. data/test/dummy/config/application.rb +26 -0
  104. data/test/dummy/config/boot.rb +5 -0
  105. data/test/dummy/config/database.yml +25 -0
  106. data/test/dummy/config/environment.rb +5 -0
  107. data/test/dummy/config/environments/development.rb +41 -0
  108. data/test/dummy/config/environments/production.rb +79 -0
  109. data/test/dummy/config/environments/test.rb +42 -0
  110. data/test/dummy/config/initializers/assets.rb +11 -0
  111. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  112. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  113. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  114. data/test/dummy/config/initializers/inflections.rb +16 -0
  115. data/test/dummy/config/initializers/mime_types.rb +4 -0
  116. data/test/dummy/config/initializers/session_store.rb +3 -0
  117. data/test/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
  118. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  119. data/test/dummy/config/locales/en.yml +23 -0
  120. data/test/dummy/config/routes.rb +4 -0
  121. data/test/dummy/config/secrets.yml +22 -0
  122. data/test/dummy/config.ru +4 -0
  123. data/test/dummy/public/404.html +67 -0
  124. data/test/dummy/public/422.html +67 -0
  125. data/test/dummy/public/500.html +66 -0
  126. data/test/dummy/public/favicon.ico +0 -0
  127. data/test/integration/navigation_test.rb +8 -0
  128. data/test/services/bulk_update_service_test.rb +121 -0
  129. data/test/services/content_stream_service_test.rb +176 -0
  130. data/test/services/secondary_type_service_test.rb +174 -0
  131. data/test/services/type_management_service_test.rb +146 -0
  132. data/test/test_helper.rb +16 -0
  133. metadata +326 -0
@@ -0,0 +1,58 @@
1
+ module CmisServer
2
+ module AtomPub
3
+ class UriTemplatesController < CmisServer::AtomPub::BaseController
4
+
5
+ include CmisServer::AtomPub::RepositoryScopable
6
+
7
+ before_action :set_filter
8
+
9
+
10
+ def object_by_id
11
+ service=ObjectService.new(@repository, context)
12
+ @object=service.get_object(params[:id], with_object: true, filter: @filter)
13
+ render 'cmis_server/atom_pub/entries/object_entry', formats: :atom_entry
14
+ end
15
+
16
+ def object_by_path
17
+ service=ObjectService.new(@repository, context)
18
+ @object=service.get_object_by_path(params[:path], with_object: true, filter: @filter)
19
+ render 'cmis_server/atom_pub/entries/object_entry', formats: :atom_entry
20
+ end
21
+
22
+ def type_by_id
23
+ service=RepositoryService.new(@repository)
24
+ @type =service.get_type_definition(params[:id])
25
+
26
+
27
+ return render 'cmis_server/atom_pub/entries/type_entry', formats: :atom_entry
28
+ end
29
+
30
+ def query
31
+ query_params=Hash.from_xml(raw_post_body)["query"].slice("statement", "searchAllVersions", "includeAllowableActions", "includeRelationships", "renditionFilter", "maxItems", "skipCount")
32
+
33
+ service =DiscoveryService.new(@repository, @context)
34
+ response=service.query(query_params['statement'],
35
+ search_all_versions: (query_params['searchAllVersions']=='true'),
36
+ rendition_filter: (query_params['renditionFilter']||'cmis:none'),
37
+ include_relationships: (query_params['includeRelationships']&.to_sym||:none),
38
+ include_allowable_actions: (query_params['includeAllowableActions']=='true'),
39
+ max_items: (query_params['maxItems']||10).to_i,
40
+ skip_count: (query_params['skipCount']||0).to_i
41
+ )
42
+
43
+ @collection=RenderableCollection.new(base_object: nil,
44
+ items: response[:query_results],
45
+ atompub_properties: {title: "Query"})
46
+ render 'cmis_server/atom_pub/feeds/feed', formats: :atom_feed, status: :created
47
+ end
48
+
49
+ protected
50
+
51
+ def set_filter
52
+ @filter=params[:filter].to_s.split(',')
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,18 @@
1
+ require 'active_support/concern'
2
+
3
+ module CmisServer
4
+ module AtomPub
5
+ module RepositoryScopable
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ before_action :set_repository
10
+ end
11
+
12
+ def set_repository
13
+ @repository=CmisServer::Repository.find(params[:repository_id])
14
+ end
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ module CmisServer
2
+ module ApplicationHelper
3
+
4
+
5
+ def atom_entry_properties_for(object)
6
+ {
7
+ id: object&.cmis_object_id,
8
+ title: object&.cmis_name,
9
+ summary: object&.cmis_description,
10
+ edited: object&.cmis_creation_date,
11
+ updated: object&.cmis_last_modification_date,
12
+ author: object&.cmis_created_by,
13
+ content: object.try(:content_stream)
14
+ }
15
+ end
16
+
17
+ def links_for(object)
18
+ result=""
19
+ if lookup_context.find_all("cmis_server/atom_pub/entries/_#{object.type.base_id.path_sanitize}_links").any?
20
+ result+=render(partial: "cmis_server/atom_pub/entries/#{object.type.base_id.path_sanitize}_links", locals: {object: object})
21
+ end
22
+
23
+ if object.type.id != object.type.base_id
24
+ if lookup_context.find_all("cmis_server/atom_pub/entries/_#{object.type.id.path_sanitize}_links").any?
25
+ result+=render(partial: "cmis_server/atom_pub/entries/#{object.type.id.path_sanitize}_links", locals: {object: object})
26
+ end
27
+ end
28
+ result
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ module CmisServer
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,69 @@
1
+ module CmisServer
2
+ class BulkUpdateService
3
+ attr_reader :context
4
+
5
+ def initialize(context = {})
6
+ @context = context
7
+ end
8
+
9
+ def repository
10
+ context[:repository]
11
+ end
12
+
13
+ # Met à jour en masse les propriétés de plusieurs objets
14
+ # @param object_ids [Array<String>] les identifiants des objets à mettre à jour
15
+ # @param properties [Hash] les propriétés à mettre à jour
16
+ # @return [Hash] résultat de la mise à jour (succès et échecs)
17
+ def bulk_update(object_ids, properties)
18
+ # Vérifier que le repository supporte la mise à jour en masse
19
+ unless repository.capabilities[:bulk_update]
20
+ raise CapabilityError.new("Repository does not support bulk update")
21
+ end
22
+
23
+ result = {
24
+ succeeded: [],
25
+ failed: []
26
+ }
27
+
28
+ # Traiter chaque objet individuellement mais dans une seule opération atomique
29
+ repository.transaction do
30
+ object_ids.each do |object_id|
31
+ begin
32
+ # Récupérer l'objet
33
+ object = repository.object(object_id)
34
+ if object.nil?
35
+ result[:failed] << { id: object_id, message: "Object not found" }
36
+ next
37
+ end
38
+
39
+ # Appliquer les nouvelles propriétés
40
+ properties.each do |property_id, value|
41
+ if object.properties.has_key?(property_id)
42
+ object.properties[property_id].value = value
43
+ else
44
+ # Si la propriété n'existe pas, c'est peut-être une propriété d'un type secondaire qui n'est pas encore appliqué
45
+ result[:failed] << { id: object_id, message: "Property '#{property_id}' not found" }
46
+ next
47
+ end
48
+ end
49
+
50
+ # Valider et enregistrer l'objet
51
+ if object.valid?
52
+ repository.update_object(object)
53
+ result[:succeeded] << object_id
54
+ else
55
+ result[:failed] << { id: object_id, message: "Validation failed: #{object.errors.full_messages.join(', ')}" }
56
+ end
57
+ rescue StandardError => e
58
+ # En cas d'erreur, ajouter l'objet à la liste des échecs
59
+ result[:failed] << { id: object_id, message: e.message }
60
+ end
61
+ end
62
+ end
63
+
64
+ result
65
+ end
66
+
67
+ class CapabilityError < StandardError; end
68
+ end
69
+ end
@@ -0,0 +1,75 @@
1
+ module CmisServer
2
+ class ContentStreamService
3
+ attr_reader :context
4
+
5
+ def initialize(context = {})
6
+ @context = context
7
+ end
8
+
9
+ def repository
10
+ context[:repository]
11
+ end
12
+
13
+ # Ajoute du contenu à un stream existant
14
+ # @param object_id [String] l'identifiant de l'objet
15
+ # @param content_stream [ContentStream] le contenu à ajouter
16
+ # @param is_last_chunk [Boolean] indique si c'est le dernier morceau
17
+ # @return [Boolean] true si l'ajout a réussi
18
+ def append_content_stream(object_id, content_stream, is_last_chunk = true)
19
+ # Vérifier que le repository supporte l'ajout de contenu
20
+ unless repository.capabilities[:append_content_stream]
21
+ raise CapabilityError.new("Repository does not support appending content stream")
22
+ end
23
+
24
+ # Récupérer l'objet
25
+ object = repository.object(object_id)
26
+ if object.nil?
27
+ raise ObjectNotFoundError.new("Object '#{object_id}' not found")
28
+ end
29
+
30
+ # Vérifier que l'objet est un document
31
+ unless object.is_a?(DocumentObject)
32
+ raise NotSupportedError.new("Object '#{object_id}' is not a document")
33
+ end
34
+
35
+ # Si l'objet n'a pas encore de contenu, c'est un ajout initial
36
+ if object.content_stream.nil?
37
+ object.content_stream = content_stream
38
+ else
39
+ # Combiner le contenu existant avec le nouveau contenu
40
+ existing_content = object.content_stream.stream.read
41
+ object.content_stream.stream.rewind # Important pour réinitialiser le curseur
42
+
43
+ new_content = content_stream.stream.read
44
+
45
+ combined_content = StringIO.new(existing_content + new_content)
46
+
47
+ # Créer un nouveau content stream avec le contenu combiné
48
+ combined_stream = ContentStream.new(
49
+ id: object.content_stream.id,
50
+ media_type: object.content_stream.media_type, # Conserver le type MIME original
51
+ stream: combined_content,
52
+ filename: object.content_stream.filename
53
+ )
54
+
55
+ object.content_stream = combined_stream
56
+ end
57
+
58
+ # Mettre à jour les propriétés du document si nécessaire
59
+ if is_last_chunk
60
+ object.cmis_content_stream_length = object.content_stream.length if object.respond_to?(:cmis_content_stream_length=)
61
+ object.cmis_content_stream_mime_type = object.content_stream.media_type if object.respond_to?(:cmis_content_stream_mime_type=)
62
+ object.cmis_content_stream_file_name = object.content_stream.filename if object.respond_to?(:cmis_content_stream_file_name=)
63
+ end
64
+
65
+ # Enregistrer l'objet
66
+ repository.update_object(object)
67
+
68
+ true
69
+ end
70
+
71
+ class CapabilityError < StandardError; end
72
+ class ObjectNotFoundError < StandardError; end
73
+ class NotSupportedError < StandardError; end
74
+ end
75
+ end
@@ -0,0 +1,31 @@
1
+ module CmisServer
2
+ class DiscoveryService
3
+
4
+ def initialize(repository, context)
5
+ @repository= repository.is_a?(Repository) ? repository : CmisServer::Repository.find(repository)
6
+ @context =context
7
+ end
8
+
9
+
10
+ def query(statement, search_all_versions: false, include_relationships: :none, rendition_filter: "cmis:none", include_allowable_actions: false, max_items: 10, skip_count: 0)
11
+
12
+ query_statement=CmisServer::Query::Parser.parse(statement)
13
+
14
+ #Verify that there is only one Table
15
+ table=query_statement.query_expression.from.tables.first
16
+ raise "Join are not supported" unless table.is_a? CmisServer::Query::Statement::Table
17
+ target_klass=TypeAdapter.find(table.name)
18
+
19
+ objects=target_klass.adapter_class.class_adapter(context: @context).where(query_statement.query_expression.where.to_h, limit: 10, offset: 0)
20
+
21
+ {
22
+ query_results: objects.map { |o| o.to_renderable_object },
23
+ has_more_items: false, #ToDO
24
+ num_items: nil, #ToDO
25
+ }
26
+
27
+
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,43 @@
1
+ module CmisServer
2
+ class NavigationService
3
+
4
+ def initialize(repository, context)
5
+ @repository= repository.is_a?(Repository) ? repository : CmisServer::Repository.find(repository)
6
+ @context =context
7
+ end
8
+
9
+ def get_children(folder_id, max_items: 10, skip_count: 0, order_by: {'cmis:creationDate' => :asc}, filter: [], include_relationships: :none, rendition_filter: "cmis:none", include_allowable_actions: false, include_path_segment: false, with_object: false)
10
+
11
+ folder=CmisServer::FolderAdapter.class_adapter(context: @context).find(folder_id)
12
+
13
+ {
14
+ objects: folder.adapter(context: @context).children(depth=1, limit: max_items, offset: skip_count, order_by: order_by).map { |o| o.to_renderable_object },
15
+ has_more_items: true,
16
+ }
17
+ end
18
+
19
+ def get_descendants(folder_id, depth: 2, filter: [], include_relationships: :none, rendition_filter: "cmis:none", include_allowable_actions: false, include_path_segment: false, with_object: false)
20
+ folder =CmisServer::Folder.find(folder_id)
21
+ objects=[]
22
+
23
+ return {objects: objects}
24
+ end
25
+
26
+ def get_folder_tree
27
+ raise NotImplemented
28
+ end
29
+
30
+ def get_folder_parent
31
+ raise NotImplemented
32
+ end
33
+
34
+ def get_object_parents
35
+ raise NotImplemented
36
+ end
37
+
38
+ def get_checked_out_docs
39
+ raise NotImplemented
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,176 @@
1
+ module CmisServer
2
+ class ObjectService
3
+
4
+ class DuplicateFile< StandardError
5
+ attr_reader :duplicate
6
+
7
+ def initialize(msg, duplicate:)
8
+ @duplicate=duplicate
9
+ super(msg)
10
+ end
11
+ end
12
+
13
+ def initialize(repository, context)
14
+ @repository= repository.is_a?(Repository) ? repository : CmisServer::Repository.find(repository)
15
+ @context =context
16
+ end
17
+
18
+ def create_document(properties, folder_id: nil, content_stream: nil, versionning_state: :none, policies: [], add_aces: [], remove_aces: [])
19
+ doc =CmisServer::DocumentObject.new(type: DocumentType.base, properties: properties)
20
+ adapter=CmisServer::DocumentAdapter.new(doc, context: @context)
21
+
22
+ if folder_id&&folder=CmisServer::FolderAdapter.class_adapter(context: @context).find(folder_id)
23
+ adapter.add_to_folder(folder)
24
+ end
25
+
26
+ if content_stream
27
+ adapter.add_content_stream(content_stream)
28
+ end
29
+
30
+ adapter.save!
31
+ adapter.object.cmis_object_id
32
+ end
33
+
34
+ def create_document_from_source
35
+ raise NotImplemented
36
+ end
37
+
38
+ def create_folder(properties, add_aces: [], remove_aces: [])
39
+ raise NotImplemented
40
+ end
41
+
42
+ def create_relationship
43
+ raise NotImplemented
44
+ end
45
+
46
+ def create_policy
47
+ raise NotImplemented
48
+ end
49
+
50
+ def create_item(properties, folder_id: nil, policies: [], add_aces: [], remove_aces: [])
51
+ item = CmisServer::ItemObject.new(type: ItemType.base, properties: properties)
52
+ adapter = CmisServer::ItemAdapter.new(item, context: @context)
53
+
54
+ if folder_id && folder = CmisServer::FolderAdapter.class_adapter(context: @context).find(folder_id)
55
+ adapter.add_to_folder(folder)
56
+ end
57
+
58
+ adapter.save!
59
+ adapter.object.cmis_object_id
60
+ end
61
+
62
+ def get_allowable_actions
63
+ raise NotImplemented
64
+ end
65
+
66
+ def get_object(id, filter: [], include_relationships: :none, include_policy_ids: false, rendition_filter: "cmis:none", include_acl: false, include_allowable_actions: false, with_object: false)
67
+ record = DocumentAdapter.class_adapter(context: @context).find(id) ||
68
+ FolderAdapter.class_adapter(context: @context).find(id) ||
69
+ ItemAdapter.class_adapter(context: @context).find(id)
70
+ raise CmisServer::ObjectNotFound unless record
71
+ return record.to_renderable_object
72
+ end
73
+
74
+ def get_properties(id, filter: [])
75
+ raise NotImplemented
76
+ end
77
+
78
+ def get_object_by_path(path, filter: [], include_relationships: :none, include_policy_ids: false, rendition_filter: "cmis:none", include_acl: false, include_allowable_actions: false, with_object: false)
79
+ record=CmisServer::FolderObject.root_folder
80
+ path.split('/')[1..-1].to_a.each do |slug|
81
+ adapter=record.adapter(context: @context)
82
+ record =adapter.find_slug_in_children(slug)
83
+ raise CmisServer::ObjectNotFound unless record
84
+ end
85
+ return record.to_renderable_object
86
+ end
87
+
88
+ def get_content_stream
89
+ raise NotImplemented
90
+ end
91
+
92
+ def get_renditions
93
+ raise NotImplemented
94
+ end
95
+
96
+ def update_properties(id, properties, with_object: false)
97
+ if id==CmisServer::FolderObject.root_folder.cmis_object_id
98
+ record=CmisServer::Folder.Objectroot_folder
99
+ else
100
+ #Todo Mockup
101
+ record=CmisServer::DocumentAdapter::ClassAdapter.new(context: @context).find(id)||CmisServer::Folder.find(id)||CmisServer::ItemAdapter::ClassAdapter.new(context: @context).find(id)
102
+ end
103
+ raise CmisServer::ObjectNotFound unless record
104
+
105
+ # Gérer les types secondaires
106
+ if properties['cmis:secondaryObjectTypeIds']
107
+ current_secondary_types = record.properties['cmis:secondaryObjectTypeIds']&.value || []
108
+ new_secondary_types = properties['cmis:secondaryObjectTypeIds']
109
+
110
+ # Supprimer les types qui ne sont plus présents
111
+ types_to_remove = current_secondary_types - new_secondary_types
112
+
113
+ # Ajouter les nouveaux types
114
+ types_to_add = new_secondary_types - current_secondary_types
115
+
116
+ # Mettre à jour les propriétés secondaryObjectTypeIds
117
+ record.properties['cmis:secondaryObjectTypeIds'].value = new_secondary_types
118
+
119
+ # Supprimer les propriétés des types secondaires qui ont été retirés
120
+ # et ajouter celles des nouveaux types (implementation future)
121
+ end
122
+
123
+ # Mettre à jour les autres propriétés
124
+ properties.each do |prop_id, value|
125
+ next if prop_id == 'cmis:secondaryObjectTypeIds' # Déjà traité au-dessus
126
+ record.properties[prop_id.to_s].value = value if record.properties[prop_id.to_s]
127
+ end
128
+
129
+ adapter = if record.is_a?(CmisServer::DocumentObject)
130
+ CmisServer::DocumentAdapter.new(record, context: @context)
131
+ elsif record.is_a?(CmisServer::FolderObject)
132
+ CmisServer::FolderAdapter.new(record, context: @context)
133
+ elsif record.is_a?(CmisServer::ItemObject)
134
+ CmisServer::ItemAdapter.new(record, context: @context)
135
+ end
136
+
137
+ adapter.save!
138
+ return adapter.object.to_renderable_object
139
+ end
140
+
141
+ def bulk_update_properties
142
+ raise NotImplemented
143
+ end
144
+
145
+ def move_object
146
+ raise NotImplemented
147
+ end
148
+
149
+ def delete_object
150
+ raise NotImplemented
151
+ end
152
+
153
+ def delete_tree
154
+ raise NotImplemented
155
+ end
156
+
157
+ def set_content_stream
158
+ raise NotImplemented
159
+ end
160
+
161
+ def append_content_stream
162
+ raise NotImplemented
163
+ end
164
+
165
+ def delete_content_stream
166
+ raise NotImplemented
167
+ end
168
+
169
+ protected
170
+
171
+ def filter(properties, filter=[])
172
+ filter.any? ? properties.slice(*filter) : properties
173
+ end
174
+
175
+ end
176
+ end
@@ -0,0 +1,40 @@
1
+ module CmisServer
2
+ class RepositoryService
3
+
4
+ def initialize(repository=nil)
5
+ @repository=CmisServer::Repository.find(repository)
6
+ end
7
+
8
+ def get_repositories
9
+ raise NotImplemented
10
+ end
11
+
12
+ def get_repository_info
13
+ @repository.infos
14
+ end
15
+
16
+ def get_type_children
17
+ raise NotImplemented
18
+ end
19
+
20
+ def get_type_descendants
21
+ raise NotImplemented
22
+ end
23
+
24
+ def get_type_definition(type_id)
25
+ type=CmisServer::TypeAdapter.find!(type_id)
26
+ end
27
+
28
+ def create_type(type)
29
+ raise NotImplemented
30
+ end
31
+
32
+ def update_type(type)
33
+ raise NotImplemented
34
+ end
35
+
36
+ def delete_type(type)
37
+ raise NotImplemented
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,120 @@
1
+ module CmisServer
2
+ class SecondaryTypeService
3
+ attr_reader :context
4
+
5
+ def initialize(context = {})
6
+ @context = context
7
+ end
8
+
9
+ def repository
10
+ context[:repository]
11
+ end
12
+
13
+ # Ajoute un type secondaire à un objet
14
+ # @param object_id [String] l'identifiant de l'objet
15
+ # @param type_id [String] l'identifiant du type secondaire
16
+ # @return [Boolean] true si l'ajout a réussi
17
+ def add_secondary_type(object_id, type_id)
18
+ # Récupérer l'objet
19
+ object = repository.object(object_id)
20
+ if object.nil?
21
+ raise ObjectNotFoundError.new("Object '#{object_id}' not found")
22
+ end
23
+
24
+ # Récupérer le type secondaire
25
+ secondary_type = repository.type(type_id)
26
+ if secondary_type.nil?
27
+ raise TypeNotFoundError.new("Type '#{type_id}' not found")
28
+ end
29
+
30
+ # Vérifier que c'est bien un type secondaire
31
+ unless secondary_type.base_id == 'cmis:secondary'
32
+ raise NotSupportedError.new("Type '#{type_id}' is not a secondary type")
33
+ end
34
+
35
+ # Vérifier que l'objet n'a pas déjà ce type secondaire
36
+ if object.secondary_type_ids.include?(type_id)
37
+ return true # Déjà ajouté, considéré comme un succès
38
+ end
39
+
40
+ # Ajouter le type secondaire à l'objet
41
+ object.secondary_type_ids << type_id
42
+
43
+ # Ajouter les propriétés du type secondaire à l'objet
44
+ add_secondary_type_properties(object, secondary_type)
45
+
46
+ # Enregistrer l'objet
47
+ repository.update_object(object)
48
+
49
+ true
50
+ end
51
+
52
+ # Supprime un type secondaire d'un objet
53
+ # @param object_id [String] l'identifiant de l'objet
54
+ # @param type_id [String] l'identifiant du type secondaire
55
+ # @return [Boolean] true si la suppression a réussi
56
+ def remove_secondary_type(object_id, type_id)
57
+ # Récupérer l'objet
58
+ object = repository.object(object_id)
59
+ if object.nil?
60
+ raise ObjectNotFoundError.new("Object '#{object_id}' not found")
61
+ end
62
+
63
+ # Vérifier que l'objet a ce type secondaire
64
+ unless object.secondary_type_ids.include?(type_id)
65
+ return true # Déjà supprimé, considéré comme un succès
66
+ end
67
+
68
+ # Récupérer le type secondaire
69
+ secondary_type = repository.type(type_id)
70
+ if secondary_type.nil?
71
+ raise TypeNotFoundError.new("Type '#{type_id}' not found")
72
+ end
73
+
74
+ # Supprimer le type secondaire de l'objet
75
+ object.secondary_type_ids.delete(type_id)
76
+
77
+ # Supprimer les propriétés du type secondaire de l'objet
78
+ remove_secondary_type_properties(object, secondary_type)
79
+
80
+ # Enregistrer l'objet
81
+ repository.update_object(object)
82
+
83
+ true
84
+ end
85
+
86
+ private
87
+
88
+ # Ajoute les propriétés d'un type secondaire à un objet
89
+ # @param object [Object] l'objet auquel ajouter les propriétés
90
+ # @param secondary_type [Type] le type secondaire
91
+ def add_secondary_type_properties(object, secondary_type)
92
+ # Parcourir toutes les propriétés du type secondaire
93
+ secondary_type.property_definitions.each do |property_id, property_def|
94
+ # Créer une nouvelle propriété pour l'objet
95
+ property = Property.new(
96
+ definition: property_def,
97
+ value: property_def.default_value
98
+ )
99
+
100
+ # Ajouter la propriété à l'objet
101
+ object.properties[property_id] = property
102
+ end
103
+ end
104
+
105
+ # Supprime les propriétés d'un type secondaire d'un objet
106
+ # @param object [Object] l'objet duquel supprimer les propriétés
107
+ # @param secondary_type [Type] le type secondaire
108
+ def remove_secondary_type_properties(object, secondary_type)
109
+ # Parcourir toutes les propriétés du type secondaire
110
+ secondary_type.property_definitions.each do |property_id, _|
111
+ # Supprimer la propriété de l'objet
112
+ object.properties.delete(property_id)
113
+ end
114
+ end
115
+
116
+ class ObjectNotFoundError < StandardError; end
117
+ class TypeNotFoundError < StandardError; end
118
+ class NotSupportedError < StandardError; end
119
+ end
120
+ end