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,70 @@
1
+ module CmisServer
2
+ module AtomPub
3
+ class FolderCollectionController < CmisServer::AtomPub::BaseController
4
+
5
+ include CmisServer::AtomPub::RepositoryScopable
6
+ #before_action :set_filter
7
+
8
+
9
+ def get_children
10
+ service =NavigationService.new(@repository, context)
11
+ response=service.get_children(params[:id], max_items: max_items_param, order_by: params[:orderBy])
12
+
13
+ @collection=RenderableCollection.new(base_object: CmisServer::FolderAdapter.class_adapter(context: @context).find(params[:id]),
14
+ items: response[:objects])
15
+ render 'cmis_server/atom_pub/feeds/feed', formats: :atom_feed
16
+ end
17
+
18
+ def create_children
19
+ #Check if Document exists
20
+ begin
21
+ if request_entry_parser.cmis_object_id
22
+ #We move the document to the folder
23
+
24
+ else
25
+ #We create the document
26
+ object_type=request_entry_parser.object_type
27
+ service =ObjectService.new(@repository, context)
28
+ case object_type.base_type.id
29
+ when "cmis:document"
30
+ id =service.create_document(request_entry_parser.object_properties, folder_id: params[:id], content_stream: request_entry_parser.content_stream)
31
+ @object=CmisServer::DocumentAdapter::ClassAdapter.new(context: @context).find(id).to_renderable_object
32
+ render 'cmis_server/atom_pub/entries/object_entry', formats: :atom_entry, status: :created
33
+ when "cmis:folder"
34
+ id =service.create_folder(request_entry_parser.object_properties)
35
+ @object=CmisServer::FolderAdapter.class_adapter(context: @context).find(id).to_renderable_object
36
+ render 'cmis_server/atom_pub/entries/object_entry', formats: :atom_entry, status: :created
37
+ when "cmis:policy"
38
+ # Implémentation future de la gestion des politiques
39
+ when "cmis:item"
40
+ id =service.create_item(request_entry_parser.object_properties)
41
+ @object=CmisServer::ItemAdapter.class_adapter(context: @context).find(id).to_renderable_object
42
+ render 'cmis_server/atom_pub/entries/object_entry', formats: :atom_entry, status: :created
43
+ else
44
+ raise "Unknown type #{object_type.base_type.id}"
45
+ end
46
+ end
47
+ rescue CmisServer::ObjectService::DuplicateFile => e
48
+ @object=e.duplicate.to_renderable_object
49
+ render 'cmis_server/atom_pub/entries/object_entry', formats: :atom_entry, status: :conflict
50
+ end
51
+ end
52
+
53
+ def get_descendants
54
+ service=NavigationService.new(@repository, context)
55
+ service.get_descendants(params[:id])
56
+ end
57
+
58
+ protected
59
+
60
+ def max_items_param
61
+ params[:max_items]&.to_i||CmisServer.configuration.default_page_size
62
+ end
63
+
64
+ def set_filter
65
+ @filter=params[:filter].to_s.split(',')
66
+ end
67
+
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,138 @@
1
+ module CmisServer
2
+ module AtomPub
3
+ class QueryController < BaseController
4
+ include CmisServer::AtomPub::RepositoryScopable
5
+
6
+ before_action :check_query_capabilities
7
+
8
+ # POST /query
9
+ def query
10
+ query_data = parse_query_request
11
+
12
+ begin
13
+ discovery_service = CmisServer::DiscoveryService.new(context: context)
14
+ results = discovery_service.query(
15
+ statement: query_data[:statement],
16
+ search_all_versions: query_data[:search_all_versions],
17
+ include_allowable_actions: query_data[:include_allowable_actions],
18
+ include_relationships: query_data[:include_relationships],
19
+ rendition_filter: query_data[:rendition_filter],
20
+ max_items: query_data[:max_items],
21
+ skip_count: query_data[:skip_count]
22
+ )
23
+
24
+ respond_to do |format|
25
+ format.atom_feed { render "cmis_server/atom_pub/query_results_feed", locals: { results: results } }
26
+ format.json { render json: format_query_results_for_json(results) }
27
+ end
28
+ rescue => e
29
+ render_error(e)
30
+ end
31
+ end
32
+
33
+ # GET /query/types
34
+ def queryable_types
35
+ repository = repository_from_request
36
+ queryable_types = repository.types.select { |_, type| type.queryable }
37
+
38
+ respond_to do |format|
39
+ format.atom_feed { render "cmis_server/atom_pub/queryable_types_feed", locals: { types: queryable_types } }
40
+ format.json { render json: format_queryable_types_for_json(queryable_types) }
41
+ end
42
+ end
43
+
44
+ # POST /query/validate
45
+ def validate_query
46
+ query_data = parse_query_request
47
+
48
+ begin
49
+ discovery_service = CmisServer::DiscoveryService.new(context: context)
50
+ validation_result = discovery_service.validate_query(query_data[:statement])
51
+
52
+ respond_to do |format|
53
+ format.json { render json: { valid: validation_result[:valid], errors: validation_result[:errors] } }
54
+ end
55
+ rescue => e
56
+ render_error(e)
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def check_query_capabilities
63
+ repository = repository_from_request
64
+
65
+ case action_name
66
+ when 'query'
67
+ unless repository.capabilities[:query]
68
+ raise CmisServer::NotSupported.new("Repository does not support query operations")
69
+ end
70
+ when 'queryable_types'
71
+ # Toujours disponible si le query de base est supporté
72
+ when 'validate_query'
73
+ unless repository.capabilities[:extended_query]
74
+ raise CmisServer::NotSupported.new("Repository does not support query validation")
75
+ end
76
+ end
77
+ end
78
+
79
+ def parse_query_request
80
+ if supports_browser_binding?
81
+ parse_browser_binding_query_request
82
+ else
83
+ parse_atom_pub_query_request
84
+ end
85
+ end
86
+
87
+ def parse_browser_binding_query_request
88
+ json_data = JSON.parse(request.body.read)
89
+
90
+ {
91
+ statement: json_data["statement"],
92
+ search_all_versions: json_data["searchAllVersions"] || false,
93
+ include_allowable_actions: json_data["includeAllowableActions"] || false,
94
+ include_relationships: json_data["includeRelationships"] || "none",
95
+ rendition_filter: json_data["renditionFilter"] || "",
96
+ max_items: (json_data["maxItems"] || 100).to_i,
97
+ skip_count: (json_data["skipCount"] || 0).to_i
98
+ }
99
+ end
100
+
101
+ def parse_atom_pub_query_request
102
+ doc = Nokogiri::XML(request.body.read)
103
+ doc.remove_namespaces!
104
+
105
+ {
106
+ statement: doc.at_xpath("//statement")&.text || params[:q],
107
+ search_all_versions: doc.at_xpath("//searchAllVersions")&.text == "true",
108
+ include_allowable_actions: doc.at_xpath("//includeAllowableActions")&.text == "true",
109
+ include_relationships: doc.at_xpath("//includeRelationships")&.text || "none",
110
+ rendition_filter: doc.at_xpath("//renditionFilter")&.text || "",
111
+ max_items: (doc.at_xpath("//maxItems")&.text || params[:maxItems] || 100).to_i,
112
+ skip_count: (doc.at_xpath("//skipCount")&.text || params[:skipCount] || 0).to_i
113
+ }
114
+ end
115
+
116
+ def format_query_results_for_json(results)
117
+ {
118
+ results: results[:objects].map { |obj| obj.to_json },
119
+ hasMoreItems: results[:has_more_items],
120
+ numItems: results[:num_items]
121
+ }
122
+ end
123
+
124
+ def format_queryable_types_for_json(types)
125
+ {
126
+ types: types.map do |id, type|
127
+ {
128
+ id: id,
129
+ queryName: type.query_name,
130
+ displayName: type.display_name,
131
+ description: type.description
132
+ }
133
+ end
134
+ }
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,75 @@
1
+ module CmisServer
2
+ module AtomPub
3
+ class RepositoryController < BaseController
4
+ include CmisServer::AtomPub::RepositoryScopable
5
+
6
+ # GET /repositories/{id}/capabilities
7
+ def capabilities
8
+ repository = repository_from_request
9
+ capabilities = repository.capabilities
10
+
11
+ # Enrichir les capabilities avec les fonctionnalités CMIS 1.1
12
+ enhanced_capabilities = enhance_capabilities_for_cmis_1_1(capabilities)
13
+
14
+ respond_to do |format|
15
+ format.atom_entry { render "cmis_server/atom_pub/repository_capabilities", locals: { capabilities: enhanced_capabilities } }
16
+ format.json { render json: { capabilities: enhanced_capabilities } }
17
+ end
18
+ end
19
+
20
+ # GET /repositories/{id}/extensions
21
+ def extensions
22
+ repository = repository_from_request
23
+ extensions = repository.extensions || {}
24
+
25
+ respond_to do |format|
26
+ format.atom_entry { render "cmis_server/atom_pub/repository_extensions", locals: { extensions: extensions } }
27
+ format.json { render json: { extensions: extensions } }
28
+ end
29
+ end
30
+
31
+ # GET /repositories/{id}/info
32
+ def info
33
+ repository = repository_from_request
34
+
35
+ info = {
36
+ id: repository.id,
37
+ name: repository.name,
38
+ description: repository.description,
39
+ vendor_name: repository.vendor_name,
40
+ product_name: repository.product_name,
41
+ product_version: repository.product_version,
42
+ cmis_version_supported: repository.cmis_version_supported,
43
+ root_folder_id: repository.root_folder_id,
44
+ latest_change_log_token: repository.latest_change_log_token,
45
+ capabilities: repository.capabilities,
46
+ acl_capabilities: repository.acl_capabilities,
47
+ repository_specific_information: repository.repository_specific_information
48
+ }
49
+
50
+ respond_to do |format|
51
+ format.atom_entry { render "cmis_server/atom_pub/repository_info", locals: { repository_info: info } }
52
+ format.json { render json: { repositoryInfo: info } }
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def enhance_capabilities_for_cmis_1_1(capabilities)
59
+ capabilities.merge({
60
+ # Nouvelles capabilities CMIS 1.1
61
+ type_management: capabilities[:create_type] || false,
62
+ bulk_update: capabilities[:bulk_update] || false,
63
+ bulk_delete_properties: capabilities[:bulk_delete_properties] || false,
64
+ append_content_stream: capabilities[:append_content_stream] || false,
65
+ secondary_types: capabilities[:secondary_types] || false,
66
+
67
+ # Extensions utiles
68
+ bulk_move: capabilities[:bulk_move] || false,
69
+ extended_query: capabilities[:extended_query] || false,
70
+ extended_acl: capabilities[:extended_acl] || false
71
+ })
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,149 @@
1
+ module CmisServer
2
+ module AtomPub
3
+ class SecondaryTypesController < BaseController
4
+ include CmisServer::AtomPub::RepositoryScopable
5
+
6
+ before_action :find_object
7
+ before_action :check_secondary_types_capability
8
+
9
+ # GET /objects/{id}/types - Lister les types secondaires d'un objet
10
+ def index
11
+ secondary_types = @object.secondary_types || []
12
+
13
+ respond_to do |format|
14
+ format.atom_feed { render "cmis_server/atom_pub/secondary_types_feed", locals: { object: @object, secondary_types: secondary_types } }
15
+ format.json { render json: format_secondary_types_for_json(secondary_types) }
16
+ end
17
+ end
18
+
19
+ # POST /objects/{id}/types
20
+ def add_secondary_type
21
+ type_data = parse_secondary_type_request
22
+
23
+ # Support pour l'ajout de plusieurs types secondaires en une fois
24
+ type_ids = type_data.is_a?(Array) ? type_data : [type_data[:type_id]]
25
+
26
+ results = []
27
+
28
+ type_ids.each do |type_id|
29
+ begin
30
+ # Trouver le type secondaire
31
+ secondary_type = CmisServer::TypeRegistry.get_type(type_id)
32
+
33
+ unless secondary_type
34
+ results << { type_id: type_id, status: "error", message: "Type '#{type_id}' not found" }
35
+ next
36
+ end
37
+
38
+ # Vérifier que c'est bien un type secondaire
39
+ unless secondary_type.base_id == 'cmis:secondary'
40
+ results << { type_id: type_id, status: "error", message: "Type '#{type_id}' is not a secondary type" }
41
+ next
42
+ end
43
+
44
+ # Vérifier les conflits de propriétés
45
+ if has_property_conflicts?(@object, secondary_type)
46
+ results << { type_id: type_id, status: "error", message: "Property conflicts detected with type '#{type_id}'" }
47
+ next
48
+ end
49
+
50
+ # Ajouter le type secondaire à l'objet
51
+ @object.add_secondary_type(secondary_type)
52
+ results << { type_id: type_id, status: "success" }
53
+
54
+ rescue => e
55
+ results << { type_id: type_id, status: "error", message: e.message }
56
+ end
57
+ end
58
+
59
+ @object.save if results.any? { |r| r[:status] == "success" }
60
+
61
+ respond_to do |format|
62
+ format.atom_entry { render "cmis_server/atom_pub/entries/object_entry", locals: { object: @object.to_renderable_object } }
63
+ format.json { render json: { object: @object.to_json, results: results } }
64
+ end
65
+ rescue => e
66
+ render_error(e)
67
+ end
68
+
69
+ # DELETE /objects/{id}/types/{typeId}
70
+ def remove_secondary_type
71
+ type_id = params[:typeId]
72
+
73
+ begin
74
+ @object.remove_secondary_type(type_id)
75
+ @object.save
76
+
77
+ respond_to do |format|
78
+ format.atom_entry { render "cmis_server/atom_pub/entries/object_entry", locals: { object: @object.to_renderable_object } }
79
+ format.json { render json: @object.to_json }
80
+ end
81
+ rescue => e
82
+ render_error(e)
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ def find_object
89
+ object_id = params[:id]
90
+ @object = repository_from_request.get_object(object_id)
91
+
92
+ raise CmisServer::ObjectNotFound.new unless @object
93
+ end
94
+
95
+ def check_secondary_types_capability
96
+ repository = repository_from_request
97
+
98
+ unless repository.capabilities[:secondary_types]
99
+ raise CmisServer::NotSupported.new(
100
+ "Repository does not support secondary types operations"
101
+ )
102
+ end
103
+ end
104
+
105
+ def parse_secondary_type_request
106
+ if supports_browser_binding?
107
+ json_data = JSON.parse(request.body.read)
108
+ if json_data["typeIds"]
109
+ json_data["typeIds"]
110
+ else
111
+ { type_id: json_data["typeId"] }
112
+ end
113
+ else
114
+ doc = Nokogiri::XML(request.body.read)
115
+ doc.remove_namespaces!
116
+
117
+ type_ids = doc.xpath("//typeId").map(&:text)
118
+ if type_ids.length > 1
119
+ type_ids
120
+ else
121
+ { type_id: params[:typeId] || type_ids.first }
122
+ end
123
+ end
124
+ end
125
+
126
+ def has_property_conflicts?(object, secondary_type)
127
+ # Vérifier s'il y a des conflits de propriétés entre les types existants et le nouveau type secondaire
128
+ existing_properties = object.properties.keys
129
+ new_properties = secondary_type.property_definitions.keys
130
+
131
+ conflicts = existing_properties & new_properties
132
+ !conflicts.empty?
133
+ end
134
+
135
+ def format_secondary_types_for_json(secondary_types)
136
+ {
137
+ secondaryTypes: secondary_types.map do |type|
138
+ {
139
+ id: type.id,
140
+ localName: type.local_name,
141
+ displayName: type.display_name,
142
+ description: type.description
143
+ }
144
+ end
145
+ }
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,34 @@
1
+ module CmisServer
2
+ module AtomPub
3
+ class ServiceDocumentsController < CmisServer::AtomPub::BaseController
4
+ require 'atom/service'
5
+
6
+
7
+ def service_document
8
+ @repository=Repository.find('my_repo')
9
+ render 'cmis_server/atom_pub/service_documents/service_document', formats: :atom_service
10
+ end
11
+
12
+
13
+ private
14
+
15
+ def repo_info_elem(repo_id)
16
+ REXML::Element.new("cmisra:repositoryInfo").tap do |e|
17
+ e.add_attribute('xmlns:ns3', "http://docs.oasis-open.org/ns/cmis/messaging/200908/")
18
+ CmisServer::RepositoryService.new(repo_id).get_repository_info.each do |k, v|
19
+ e.add_element('cmis:'+k.to_s).text=v
20
+ end
21
+ end
22
+ end
23
+
24
+ def uri_template_elem(template, type, media_type)
25
+ REXML::Element.new("cmisra:uritemplate").tap do |e|
26
+ e.add_element('cmisra:template').text =template
27
+ e.add_element('cmisra:type').text =type
28
+ e.add_element('cmisra:mediatype').text=media_type
29
+ end
30
+ end
31
+
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,229 @@
1
+ module CmisServer
2
+ module AtomPub
3
+ class TypesController < BaseController
4
+ include CmisServer::AtomPub::RepositoryScopable
5
+
6
+ before_action :check_repository_capabilities, only: [:create, :update, :destroy]
7
+ before_action :find_type, only: [:show, :update, :destroy]
8
+
9
+ # GET /types/{typeId}
10
+ def show
11
+ respond_to do |format|
12
+ format.atom_entry { render "cmis_server/atom_pub/type_entry", locals: { type: @type } }
13
+ format.json { render json: format_type_for_json(@type) }
14
+ end
15
+ end
16
+
17
+ # GET /types
18
+ def index
19
+ @types = CmisServer::TypeRegistry.types.values
20
+
21
+ # Filtrage par includePropertyDefinitions
22
+ if params[:includePropertyDefinitions] == "false"
23
+ # Ne pas inclure les définitions de propriétés
24
+ @include_property_definitions = false
25
+ else
26
+ @include_property_definitions = true
27
+ end
28
+
29
+ respond_to do |format|
30
+ format.atom_feed { render "cmis_server/atom_pub/types_feed" }
31
+ format.json { render json: { types: @types }.to_json }
32
+ end
33
+ end
34
+
35
+ # POST /types
36
+ def create
37
+ type_definition = parse_type_definition_from_request
38
+
39
+ begin
40
+ @type = CmisServer::TypeRegistry.create_type(type_definition)
41
+
42
+ respond_to do |format|
43
+ format.atom_entry { render "cmis_server/atom_pub/type_entry", status: :created }
44
+ format.json { render json: @type.to_json, status: :created }
45
+ end
46
+ rescue CmisServer::InvalidTypeDefinition, CmisServer::InvalidOperation => e
47
+ render_error(e)
48
+ end
49
+ end
50
+
51
+ # PUT /types/{typeId}
52
+ def update
53
+ type_definition = parse_type_definition_from_request
54
+
55
+ begin
56
+ @type = CmisServer::TypeRegistry.update_type(type_definition)
57
+
58
+ respond_to do |format|
59
+ format.atom_entry { render "cmis_server/atom_pub/type_entry" }
60
+ format.json { render json: @type.to_json }
61
+ end
62
+ rescue CmisServer::InvalidTypeDefinition, CmisServer::InvalidOperation => e
63
+ render_error(e)
64
+ end
65
+ end
66
+
67
+ # DELETE /types/{typeId}
68
+ def destroy
69
+ begin
70
+ CmisServer::TypeRegistry.delete_type(params[:id])
71
+
72
+ head :no_content
73
+ rescue CmisServer::InvalidTypeDefinition, CmisServer::InvalidOperation => e
74
+ render_error(e)
75
+ end
76
+ end
77
+
78
+ private
79
+
80
+ def find_type
81
+ @type = CmisServer::TypeRegistry.get_type(params[:id])
82
+ raise CmisServer::ObjectNotFound.new("Type '#{params[:id]}' not found") unless @type
83
+ end
84
+
85
+ def format_type_for_json(type)
86
+ {
87
+ id: type.id,
88
+ localName: type.local_name,
89
+ displayName: type.display_name,
90
+ description: type.description,
91
+ baseId: type.base_id,
92
+ parentId: type.parent_id,
93
+ creatable: type.creatable,
94
+ fileable: type.fileable,
95
+ queryable: type.queryable,
96
+ controllablePolicy: type.controllable_policy,
97
+ controllableACL: type.controllable_acl,
98
+ fulltextIndexed: type.fulltext_indexed,
99
+ includedInSupertypeQuery: type.included_in_supertype_query,
100
+ propertyDefinitions: format_property_definitions_for_json(type.property_definitions)
101
+ }
102
+ end
103
+
104
+ def format_property_definitions_for_json(property_definitions)
105
+ result = {}
106
+ property_definitions.each do |id, prop_def|
107
+ result[id] = {
108
+ id: prop_def.id,
109
+ localName: prop_def.local_name,
110
+ queryName: prop_def.query_name,
111
+ displayName: prop_def.display_name,
112
+ description: prop_def.description,
113
+ propertyType: prop_def.property_type,
114
+ cardinality: prop_def.cardinality,
115
+ updatability: prop_def.updatability,
116
+ required: prop_def.required,
117
+ queryable: prop_def.queryable,
118
+ orderable: prop_def.orderable
119
+ }
120
+ end
121
+ result
122
+ end
123
+
124
+ def check_repository_capabilities
125
+ repository = repository_from_request
126
+
127
+ unless repository.capabilities[:create_type]
128
+ raise CmisServer::NotSupported.new(
129
+ "Repository does not support type management operations"
130
+ )
131
+ end
132
+ end
133
+
134
+ def parse_type_definition_from_request
135
+ if request.content_type =~ /application\/atom\+xml/
136
+ # Parsing XML AtomPub
137
+ doc = Nokogiri::XML(request.body.read)
138
+
139
+ # Extraire les données du type depuis l'XML
140
+ # Cette implémentation dépend de la structure XML utilisée
141
+ {
142
+ id: doc.at_xpath("//cmis:typeId").text,
143
+ parent_id: doc.at_xpath("//cmis:parentId").text,
144
+ local_name: doc.at_xpath("//cmis:localName").text,
145
+ display_name: doc.at_xpath("//cmis:displayName").text,
146
+ query_name: doc.at_xpath("//cmis:queryName").text,
147
+ description: doc.at_xpath("//cmis:description").text,
148
+ base_id: doc.at_xpath("//cmis:baseId").text,
149
+ creatable: doc.at_xpath("//cmis:creatable").text == "true",
150
+ fileable: doc.at_xpath("//cmis:fileable").text == "true",
151
+ queryable: doc.at_xpath("//cmis:queryable").text == "true",
152
+ controllable_policy: doc.at_xpath("//cmis:controllablePolicy").text == "true",
153
+ controllable_acl: doc.at_xpath("//cmis:controllableACL").text == "true",
154
+ fulltext_indexed: doc.at_xpath("//cmis:fulltextIndexed").text == "true",
155
+ included_in_supertype_query: doc.at_xpath("//cmis:includedInSupertypeQuery").text == "true",
156
+ property_definitions: parse_property_definitions_from_xml(doc)
157
+ }
158
+ else
159
+ # Parsing JSON (CMIS Browser Binding)
160
+ json_data = JSON.parse(request.body.read)
161
+
162
+ {
163
+ id: json_data["id"],
164
+ parent_id: json_data["parentId"],
165
+ local_name: json_data["localName"],
166
+ display_name: json_data["displayName"],
167
+ query_name: json_data["queryName"],
168
+ description: json_data["description"],
169
+ base_id: json_data["baseId"],
170
+ creatable: json_data["creatable"],
171
+ fileable: json_data["fileable"],
172
+ queryable: json_data["queryable"],
173
+ controllable_policy: json_data["controllablePolicy"],
174
+ controllable_acl: json_data["controllableACL"],
175
+ fulltext_indexed: json_data["fulltextIndexed"],
176
+ included_in_supertype_query: json_data["includedInSupertypeQuery"],
177
+ property_definitions: parse_property_definitions_from_json(json_data)
178
+ }
179
+ end
180
+ end
181
+
182
+ def parse_property_definitions_from_xml(doc)
183
+ property_defs = []
184
+
185
+ doc.xpath("//cmis:propertyDefinition").each do |prop_def_node|
186
+ property_defs << {
187
+ id: prop_def_node.at_xpath("cmis:id").text,
188
+ local_name: prop_def_node.at_xpath("cmis:localName").text,
189
+ query_name: prop_def_node.at_xpath("cmis:queryName").text,
190
+ display_name: prop_def_node.at_xpath("cmis:displayName").text,
191
+ description: prop_def_node.at_xpath("cmis:description").text,
192
+ property_type: prop_def_node.at_xpath("cmis:propertyType").text,
193
+ cardinality: prop_def_node.at_xpath("cmis:cardinality").text,
194
+ updatability: prop_def_node.at_xpath("cmis:updatability").text,
195
+ required: prop_def_node.at_xpath("cmis:required").text == "true",
196
+ queryable: prop_def_node.at_xpath("cmis:queryable").text == "true",
197
+ orderable: prop_def_node.at_xpath("cmis:orderable").text == "true"
198
+ }
199
+ end
200
+
201
+ property_defs
202
+ end
203
+
204
+ def parse_property_definitions_from_json(json_data)
205
+ property_defs = []
206
+
207
+ if json_data["propertyDefinitions"]
208
+ json_data["propertyDefinitions"].each do |id, prop_def|
209
+ property_defs << {
210
+ id: id,
211
+ local_name: prop_def["localName"],
212
+ query_name: prop_def["queryName"],
213
+ display_name: prop_def["displayName"],
214
+ description: prop_def["description"],
215
+ property_type: prop_def["propertyType"],
216
+ cardinality: prop_def["cardinality"],
217
+ updatability: prop_def["updatability"],
218
+ required: prop_def["required"],
219
+ queryable: prop_def["queryable"],
220
+ orderable: prop_def["orderable"]
221
+ }
222
+ end
223
+ end
224
+
225
+ property_defs
226
+ end
227
+ end
228
+ end
229
+ end