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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +51 -0
- data/app/assets/javascripts/cmis_server/application.js +13 -0
- data/app/assets/stylesheets/cmis_server/application.css +15 -0
- data/app/controllers/cmis_server/application_controller.rb +19 -0
- data/app/controllers/cmis_server/atom_pub/base_controller.rb +23 -0
- data/app/controllers/cmis_server/atom_pub/bulk_controller.rb +302 -0
- data/app/controllers/cmis_server/atom_pub/content_controller.rb +178 -0
- data/app/controllers/cmis_server/atom_pub/entries_controller.rb +41 -0
- data/app/controllers/cmis_server/atom_pub/folder_collection_controller.rb +70 -0
- data/app/controllers/cmis_server/atom_pub/query_controller.rb +138 -0
- data/app/controllers/cmis_server/atom_pub/repository_controller.rb +75 -0
- data/app/controllers/cmis_server/atom_pub/secondary_types_controller.rb +149 -0
- data/app/controllers/cmis_server/atom_pub/service_documents_controller.rb +34 -0
- data/app/controllers/cmis_server/atom_pub/types_controller.rb +229 -0
- data/app/controllers/cmis_server/atom_pub/uri_templates_controller.rb +58 -0
- data/app/controllers/concerns/cmis_server/atom_pub/repository_scopable.rb +18 -0
- data/app/helpers/cmis_server/application_helper.rb +31 -0
- data/app/models/cmis_server/application_record.rb +5 -0
- data/app/services/cmis_server/bulk_update_service.rb +69 -0
- data/app/services/cmis_server/content_stream_service.rb +75 -0
- data/app/services/cmis_server/discovery_service.rb +31 -0
- data/app/services/cmis_server/navigation_service.rb +43 -0
- data/app/services/cmis_server/object_service.rb +176 -0
- data/app/services/cmis_server/repository_service.rb +40 -0
- data/app/services/cmis_server/secondary_type_service.rb +120 -0
- data/app/services/cmis_server/type_management_service.rb +117 -0
- data/app/views/cmis_server/atom_pub/bulk_update_feed.atom.builder +47 -0
- data/app/views/cmis_server/atom_pub/entries/_cmis_document_links.atom_entry.builder +0 -0
- data/app/views/cmis_server/atom_pub/entries/_cmis_folder_links.atom_entry.builder +3 -0
- data/app/views/cmis_server/atom_pub/entries/_object_entry.atom_entry.builder +64 -0
- data/app/views/cmis_server/atom_pub/entries/_property.atom_entry.builder +8 -0
- data/app/views/cmis_server/atom_pub/entries/object_entry.atom_entry.builder +1 -0
- data/app/views/cmis_server/atom_pub/entries/type_entry.atom_entry.builder +59 -0
- data/app/views/cmis_server/atom_pub/feeds/_feed_entry.atom_feed.builder +1 -0
- data/app/views/cmis_server/atom_pub/feeds/feed.atom_feed.builder +30 -0
- data/app/views/cmis_server/atom_pub/service_documents/_uri_template.atom_service.builder +5 -0
- data/app/views/cmis_server/atom_pub/service_documents/_workspace.atom_service.builder +89 -0
- data/app/views/cmis_server/atom_pub/service_documents/service_document.atom_service.builder +1 -0
- data/app/views/cmis_server/atom_pub/shared/_collection.xml.builder +7 -0
- data/app/views/cmis_server/atom_pub/shared/atom_entry_layout.atom_entry.builder +0 -0
- data/app/views/cmis_server/atom_pub/type_entry.atom.builder +69 -0
- data/app/views/cmis_server/atom_pub/types_feed.atom.builder +91 -0
- data/app/views/layouts/cmis_server/application.atom_entry.builder +2 -0
- data/app/views/layouts/cmis_server/application.atom_feed.builder +3 -0
- data/app/views/layouts/cmis_server/application.atom_service.builder +10 -0
- data/app/views/layouts/cmis_server/application.html.erb +14 -0
- data/config/routes.rb +49 -0
- data/lib/cmis_server/atom_pub/entry_parser.rb +72 -0
- data/lib/cmis_server/base_objects/base_type.rb +128 -0
- data/lib/cmis_server/base_objects/document.rb +68 -0
- data/lib/cmis_server/base_objects/folder.rb +104 -0
- data/lib/cmis_server/base_objects/item.rb +25 -0
- data/lib/cmis_server/base_types.rb +123 -0
- data/lib/cmis_server/cmis_object.rb +190 -0
- data/lib/cmis_server/configuration.rb +43 -0
- data/lib/cmis_server/constants.rb +8 -0
- data/lib/cmis_server/content_stream.rb +52 -0
- data/lib/cmis_server/context.rb +11 -0
- data/lib/cmis_server/document_object.rb +12 -0
- data/lib/cmis_server/document_type.rb +67 -0
- data/lib/cmis_server/engine.rb +60 -0
- data/lib/cmis_server/exceptions.rb +185 -0
- data/lib/cmis_server/folder_object.rb +18 -0
- data/lib/cmis_server/folder_type.rb +34 -0
- data/lib/cmis_server/id.rb +18 -0
- data/lib/cmis_server/item_adapter.rb +26 -0
- data/lib/cmis_server/item_object.rb +15 -0
- data/lib/cmis_server/item_type.rb +7 -0
- data/lib/cmis_server/object_adapter.rb +79 -0
- data/lib/cmis_server/property.rb +29 -0
- data/lib/cmis_server/property_definition.rb +118 -0
- data/lib/cmis_server/query/parser.output +2250 -0
- data/lib/cmis_server/query/parser.racc +222 -0
- data/lib/cmis_server/query/parser.racc.rb +1039 -0
- data/lib/cmis_server/query/parser.rex +114 -0
- data/lib/cmis_server/query/parser.rex.rb +238 -0
- data/lib/cmis_server/query/statement.rb +395 -0
- data/lib/cmis_server/query.rb +2 -0
- data/lib/cmis_server/renderable_collection.rb +45 -0
- data/lib/cmis_server/renderable_object.rb +49 -0
- data/lib/cmis_server/repository.rb +91 -0
- data/lib/cmis_server/secondary_type.rb +11 -0
- data/lib/cmis_server/type.rb +62 -0
- data/lib/cmis_server/type_registry.rb +115 -0
- data/lib/cmis_server/version.rb +4 -0
- data/lib/cmis_server.rb +22 -0
- data/lib/tasks/cmis_server_tasks.rake +4 -0
- data/test/cmis_server_test.rb +7 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/to_time_preserves_timezone.rb +10 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/integration/navigation_test.rb +8 -0
- data/test/services/bulk_update_service_test.rb +121 -0
- data/test/services/content_stream_service_test.rb +176 -0
- data/test/services/secondary_type_service_test.rb +174 -0
- data/test/services/type_management_service_test.rb +146 -0
- data/test/test_helper.rb +16 -0
- 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
|