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,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,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
|