infopark_fiona7 0.71.1.12 → 1.1.0.0.0

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/fiona7_ui.js +67 -0
  3. data/app/assets/stylesheets/fiona7_ui.css.scss +29 -0
  4. data/app/controllers/fiona7/release_controller.rb +37 -75
  5. data/app/controllers/scrivito/cms_dispatch_controller.rb +2 -12
  6. data/app/controllers/scrivito/objs_controller.rb +41 -13
  7. data/app/controllers/scrivito/webservice_controller.rb +4 -3
  8. data/app/views/fiona7/release/preview.html.erb +73 -0
  9. data/config/routes.rb +3 -1
  10. data/infopark_fiona7.gemspec +1 -1
  11. data/lib/fiona7/assert.rb +4 -0
  12. data/lib/fiona7/attribute_name_mangler.rb +19 -0
  13. data/lib/fiona7/attribute_names_from_cms.rb +17 -0
  14. data/lib/fiona7/attribute_names_from_queries.rb +17 -0
  15. data/lib/fiona7/builder/obj_builder.rb +3 -2
  16. data/lib/fiona7/builder/obj_updater.rb +2 -2
  17. data/lib/fiona7/builder/widget_builder.rb +1 -1
  18. data/lib/fiona7/builder/widget_updater.rb +2 -2
  19. data/lib/fiona7/complex_object.rb +24 -0
  20. data/lib/fiona7/controllers/rest_api/obj_controller.rb +96 -24
  21. data/lib/fiona7/controllers/rest_api/workspace_controller.rb +23 -2
  22. data/lib/fiona7/engine.rb +11 -23
  23. data/lib/fiona7/facet_builder.rb +136 -0
  24. data/lib/fiona7/json/reverse_obj_decorator.rb +2 -0
  25. data/lib/fiona7/mode_switch/cms_routes/scrivito_sdk.rb +68 -10
  26. data/lib/fiona7/mode_switch/cms_routes/scrivito_sdk_slave.rb +66 -14
  27. data/lib/fiona7/mode_switch/views.rb +2 -2
  28. data/lib/fiona7/naive_search_engine.rb +40 -5
  29. data/lib/fiona7/obj_class_name_demangler.rb +11 -0
  30. data/lib/fiona7/obj_class_name_mangler.rb +11 -0
  31. data/lib/fiona7/obj_classes_from_cms.rb +14 -0
  32. data/lib/fiona7/obj_classes_from_queries.rb +11 -0
  33. data/lib/fiona7/recursive_object_finder.rb +149 -0
  34. data/lib/fiona7/routers/rest_api.rb +14 -1
  35. data/lib/fiona7/routing_monkey_patch.rb +5 -2
  36. data/lib/fiona7/scrivito_patches/attribute_serializer.rb +1 -1
  37. data/lib/fiona7/scrivito_patches/basic_obj.rb +4 -9
  38. data/lib/fiona7/scrivito_patches/basic_widget.rb +0 -9
  39. data/lib/fiona7/scrivito_patches/cms_backend.rb +11 -16
  40. data/lib/fiona7/scrivito_patches/cms_rest_api.rb +1 -1
  41. data/lib/fiona7/scrivito_patches/cms_routing.rb +50 -33
  42. data/lib/fiona7/scrivito_patches/link_parser.rb +6 -13
  43. data/lib/fiona7/scrivito_patches/log_subscriber.rb +18 -0
  44. data/lib/fiona7/scrivito_patches/preset_routes.rb +47 -0
  45. data/lib/fiona7/scrivito_patches/routing_extensions.rb +48 -0
  46. data/lib/fiona7/search_engine.rb +4 -0
  47. data/lib/fiona7/type_loader.rb +5 -4
  48. data/lib/fiona7/type_register.rb +13 -27
  49. data/lib/fiona7/type_synchronizer.rb +8 -6
  50. data/lib/fiona7/verity_search_engine.rb +77 -30
  51. data/lib/fiona7/version.rb +1 -1
  52. metadata +18 -13
  53. data/app/models/rails_connector/abstract_obj.rb +0 -24
  54. data/lib/fiona7/controllers/content_service/obj_controller.rb +0 -121
  55. data/lib/fiona7/controllers/content_service/workspace_controller.rb +0 -19
  56. data/lib/fiona7/recursive_link_resolver.rb +0 -93
  57. data/lib/fiona7/routers/content_service.rb +0 -19
  58. data/lib/fiona7/scrivito_patches/client_config.rb +0 -0
  59. data/lib/fiona7/scrivito_patches/controller_actions.rb +0 -6
  60. data/lib/fiona7/scrivito_patches/obj_class.rb +0 -16
  61. data/lib/fiona7/scrivito_patches/obj_data_from_rest.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f4022da75c9cc31358e96b0c7acc02a2f600f076
4
- data.tar.gz: 5f460a2ca0c1f02f0ff54949c11f04a1ea3ba6a6
3
+ metadata.gz: 300034555ee49868b2dad5e66fe59ad671403225
4
+ data.tar.gz: c2277f0fe2150975bb5473963e0f0953dcd579a4
5
5
  SHA512:
6
- metadata.gz: 449f8ecefe2906fb1bc8581dad50753611914588e6108a9f38447d1e502012b5cab2f5939454bc440423b31873de3fb2819d4e72d15f922d85240ac9734d3ad8
7
- data.tar.gz: a703033b66e872469499468fb1b3ccbb29169cdb4ad149e13fcc0b6458dace9815a9cd1087ba749eb2a81c4f07780f1c77cf2b4233753daf07a8aab0c7087b10
6
+ metadata.gz: f613ce7c780241d0100b4674d751f50a8698979b512b8dfdd1b638cbfa59c41f4e24865784edd0db417768c0b23c62e4c3b70f17b9b31a1c8d1b7e7a564601fa
7
+ data.tar.gz: bfab39e9bfe82767fb45411f584478d6ad1a43667a1c7d7c1addaa76203ee27197bae9a7cd273103909c4da122dee60ce08c3037046e2b3e6cda0cb5f5524a3b
@@ -38,6 +38,63 @@
38
38
  });
39
39
  };
40
40
 
41
+ var open_release_dialog = function(obj_id) {
42
+ var base_url = window.location.protocol + '//' + window.location.host + '/__scrivito/';
43
+ var path = 'objs/' + obj_id + '/release/preview';
44
+
45
+ var deferred = $.Deferred();
46
+
47
+ $.ajax(base_url + path, {
48
+ type: 'GET',
49
+ dataType: 'html',
50
+ cache: false
51
+ }).then(
52
+ function(result, text_status, xhr) {
53
+ var view = $(result);
54
+
55
+ $('#scrivito_editing').append(view);
56
+
57
+ var accept = function() {
58
+ scrivito.dialog.close_with_transition(view);
59
+
60
+ var checkedObjs = view.find(':checked').map(function() {
61
+ return $(this).val();
62
+ }).get();
63
+
64
+ var comment = view.find('#release-comment').val();
65
+
66
+ deferred.resolve(checkedObjs, comment);
67
+ return false;
68
+ };
69
+
70
+ var cancel = function() {
71
+ scrivito.dialog.close_with_transition(view);
72
+ deferred.reject();
73
+ return false;
74
+ };
75
+
76
+ var expand = function() {
77
+ $(this).next().slideToggle();
78
+ return false;
79
+ };
80
+
81
+ view.find('.scrivito_accept').on('click', accept);
82
+ view.find('.scrivito_cancel').on('click', cancel);
83
+
84
+ view.find('.expanding').on('click', expand);
85
+
86
+ scrivito.dialog.open_and_center_with_transition(view).then(function() {
87
+ // view loaded
88
+ });
89
+
90
+ scrivito.with_dialog_behaviour(view, deferred, {enter: accept, escape: cancel});
91
+ },
92
+ function(xhr, text_status, error) {
93
+ });
94
+
95
+ return deferred;
96
+ };
97
+
41
98
  $.i18n().load({
42
99
  'commands.release_obj.title': 'Seite freigeben',
43
100
  'commands.release_obj.not_modified_obj': 'Diese Seite wurde nicht geändert. Daher gibt es nichts zu freigeben.',
@@ -176,6 +233,16 @@
176
233
  },
177
234
 
178
235
  execute: function() {
236
+ open_release_dialog(obj.id()).done(function(objIds, comment) {
237
+ scrivito.with_saving_overlay(scrivito.ajax('PUT', 'objs/release', {data: {objs: objIds, comment: comment}}).then(function() {
238
+ scrivito.reload();
239
+ }).fail(function(error) {
240
+ scrivito.alert_dialog(scrivito.t('commands.'+action+'_obj.failed'));
241
+ }));
242
+ });
243
+
244
+ return;
245
+
179
246
  /* TODO: implement permission check */
180
247
  open_confirmation_dialog(action, dialog_icons[action]).done(function(comment) {
181
248
  scrivito.with_saving_overlay(scrivito.ajax('PUT', 'objs/' + obj.id() + '/release?comment=' + (comment || "")).then(function() {
@@ -13,6 +13,35 @@ body > div.scrivito_topbar > div > div.scrivito_button_bar.scrivito_app.scrivito
13
13
  display: none;
14
14
  }
15
15
 
16
+ .scrivito_modal_body {
17
+ .main_object {
18
+ margin: 10px 0;
19
+ }
20
+
21
+ .expanding {
22
+ cursor: pointer;
23
+ margin-top: 10px;
24
+
25
+ i.scrivito_icon {
26
+ font-size: 9px;
27
+ color: white;
28
+ }
29
+ }
30
+
31
+ .expandable.collapsed {
32
+ display: none;
33
+ }
34
+
35
+ .expandable {
36
+ margin: 3px 0;
37
+
38
+ input#release-comment {
39
+ margin: 3px 0 3px 12px;
40
+ }
41
+ }
42
+
43
+ }
44
+
16
45
  /*
17
46
  .scrivito_input_new_ws_name, #scrivito_delete_workspace, #scrivito_rename_workspace, #scrivito_create_workspace, #scrivito_rebase_workspace, #scrivito_workspace_settings {
18
47
  display: none !important;
@@ -1,100 +1,62 @@
1
1
  module Fiona7
2
2
  class ReleaseController < ActionController::Base
3
3
  def release
4
- @releasable = Set.new
5
- @errors = []
4
+ obj_ids = params[:objs]
5
+ comment = params[:comment]
6
+ errors = []
6
7
 
7
- @obj = WriteObj.find(params[:id])
8
+ if !obj_ids.empty?
9
+ main_obj = obj_ids.shift
8
10
 
9
- recursively_find_objects(@releasable, @obj, Set.new)
10
-
11
- @releasable.each do |obj|
12
- if obj.really_edited?
13
- carefully_release(@errors, obj)
11
+ carefully_release(errors, main_obj, comment)
12
+ obj_ids.each do |other_obj|
13
+ carefully_release(errors, other_obj)
14
14
  end
15
15
  end
16
16
 
17
- # TODO: display errors
18
17
  render json: {}
19
18
  end
20
19
 
21
- protected
22
-
23
- def carefully_release(errors, obj)
24
- obj.take
25
- obj.release!
26
- rescue => e
27
- Rails.logger.error("Error occured when releasing #{@obj.id}: unable to release Object with ID #{obj.id} (#{obj.path} because: #{e.inspect}")
28
-
29
- # TODO: translate
30
- error = "Unable to release Object with ID #{obj.id} because: #{e.message}"
31
- errors << error
32
- end
33
-
34
- def recursively_find_objects(set, obj, already_encountered)
35
- # substract already_encountered to prevent loops
36
- widgets_of_this_object = widgets(obj) - already_encountered
37
- referenced_objects_of_this_object = referenced_objects(obj) - already_encountered
20
+ def preview
21
+ self.in_rtc_workspace do
22
+ @obj = WriteObj.find(params[:id])
38
23
 
39
- already_encountered.merge(widgets_of_this_object)
40
- already_encountered.merge(referenced_objects_of_this_object)
24
+ @recursive = Fiona7::RecursiveObjectFinder.new(@obj)
41
25
 
42
- widgets_of_this_object.each do |widget|
43
- recursively_find_objects(set, widget, already_encountered)
44
- end
26
+ @images = @recursive.images.select {|o| o.really_edited? }
27
+ @downloads = @recursive.downloads.select {|o| o.really_edited? }
28
+ @referenced = @recursive.referenced.select {|o| o.really_edited? }
29
+ @linked = @recursive.linked.select {|o| o.really_edited? }
45
30
 
46
- referenced_objects_of_this_object.each do |referenced|
47
- recursively_find_objects(set, referenced, already_encountered)
31
+ render "preview", layout: false
48
32
  end
49
-
50
- set.merge(widgets_of_this_object)
51
- set.merge(referenced_objects_of_this_object)
52
- set << obj
53
-
54
- set
55
33
  end
56
34
 
57
- def widgets(obj)
58
- links = @obj[:X_widget_pool] || []
59
- WriteObj.where(obj_id: links.map {|l| l.destination_object_id }).to_a.to_set
35
+ protected
36
+ def in_rtc_workspace(&block)
37
+ Scrivito::Workspace.find('rtc').as_current(&block)
60
38
  end
61
39
 
62
- def referenced_objects(obj)
63
- referenced = Set.new
64
-
65
- type_definition = Fiona7::TypeRegister.instance.read_mangled(obj.obj_class)
66
- type_definition.attrs.each do |attribute|
67
- if attribute.type == :reference || attribute.type == :referencelist && attribute.name != "child_order"
68
- (obj[attribute.real_name] || []).each do |link|
69
- if link.internal?
70
- destination_object = link.destination_object
71
- if destination_object && (destination_object.image? || destination_object.generic?)
72
- referenced << link.destination_object
73
- end
74
- end
75
- end
76
- elsif attribute.type == :link || attribute.type == :linklist
77
- (obj[attribute.real_name] || []).each do |link|
78
- if link.internal?
79
- destination_object = link.destination_object
80
- if destination_object && (destination_object.image? || destination_object.generic?)
81
- referenced << link.destination_object
82
- end
83
- end
84
- end
85
- end
86
- end
40
+ def carefully_release(errors, obj, comment=nil)
41
+ obj.take
42
+ obj.release!(comment)
87
43
 
88
- obj.text_links.each do |link|
89
- if link.internal?
90
- destination_object = link.destination_object
91
- if destination_object && (destination_object.image? || destination_object.generic?)
92
- referenced << link.destination_object
93
- end
94
- end
44
+ complex_object = Fiona7::ComplexObject.new(obj)
45
+ complex_object.widgets.each do |widget_obj|
46
+ widget_obj.take
47
+ widget_obj.release!(comment)
95
48
  end
49
+ #complex_object.binaries.each do |widget_obj|
50
+ # widget_obj.take
51
+ # widget_obj.release!(comment)
52
+ #end
53
+ rescue => e
54
+ Rails.logger.error("Error occured when releasing #{@obj.id}: unable to release Object with ID #{obj.id} (#{obj.path} because: #{e.inspect}")
96
55
 
97
- referenced
56
+ # TODO: translate
57
+ error = "Unable to release Object with ID #{obj.id} because: #{e.message}"
58
+ errors << error
98
59
  end
60
+
99
61
  end
100
62
  end
@@ -8,17 +8,8 @@ module Scrivito
8
8
  def process(action)
9
9
  CmsEnv.new(env).load
10
10
 
11
- if !obj_not_found? && action == 'legacy'
12
- if Scrivito::Configuration.legacy_routing
13
- action = 'index'
14
- else
15
- redirect_to scrivito_path(loaded_obj), status: :moved_permanently
16
- return self.response
17
- end
18
- end
19
-
20
11
  if obj_not_found? && editing_context.workspace_changed?
21
- redirect_to :scrivito_root
12
+ redirect_to "/"
22
13
  return self.response
23
14
  end
24
15
 
@@ -53,7 +44,7 @@ module Scrivito
53
44
  return default_controller if obj_not_found?
54
45
  controller = "#{loaded_obj.controller_name}Controller".constantize
55
46
 
56
- if controller.respond_to?(:use_for_obj_dispatch?) && controller.use_for_obj_dispatch? && controller.include?(Scrivito::ControllerActions)
47
+ if controller.respond_to?(:use_for_obj_dispatch?) && controller.use_for_obj_dispatch?
57
48
  controller
58
49
  else
59
50
  default_controller
@@ -70,7 +61,6 @@ module Scrivito
70
61
  loaded_obj.is_a?(StandardError)
71
62
  end
72
63
 
73
- # support DefaultScrivitoCmsController!
74
64
  def default_controller
75
65
  return Fiona7::DefaultScrivitoCmsController if Fiona7.mode == :legacy
76
66
  CmsController
@@ -35,8 +35,12 @@ module Scrivito
35
35
  params_parser = ObjCreateParamsParser.new(request.host, request.port)
36
36
  @obj = Obj.create(params_parser.parse(params[:obj]), scrivito_user: scrivito_user)
37
37
  render :obj
38
- rescue ObjClassNotFound
39
- head :not_found
38
+ rescue ObjClassNotFound => e
39
+ raise ClientError.new(
40
+ "You've tried to create a CMS object based on the \"#{e.message}\" class, which is "\
41
+ "either missing or not suitable for the object.",
42
+ 400
43
+ )
40
44
  end
41
45
 
42
46
  def details
@@ -48,14 +52,12 @@ module Scrivito
48
52
  params_parser = ObjUpdateParamsParser.new(request.host, request.port,
49
53
  current_obj: current_obj, scrivito_user: scrivito_user)
50
54
  current_obj.update(params_parser.parse(params[:obj]))
51
- rescue ObjClassNotFound
52
- head :not_found
53
55
  end
54
56
 
55
57
  def destroy
56
58
  in_selected_workspace do
57
59
  parent = current_obj.parent
58
- @redirect_to = parent ? scrivito_path(parent) : scrivito_root_path
60
+ @redirect_to = parent ? scrivito_path(parent) : "/"
59
61
  current_obj.destroy
60
62
  end
61
63
  end
@@ -85,17 +87,22 @@ module Scrivito
85
87
  render_empty_json
86
88
  end
87
89
 
88
- # optimized away
89
90
  def conflicting_workspaces
90
91
  @workspaces = []
91
92
  render :workspaces
92
93
  end
93
94
 
94
- # optimized away
95
95
  def is_outdated
96
96
  @is_outdated = false
97
97
  end
98
98
 
99
+ def binary_no_cache
100
+ in_selected_workspace do
101
+ binary = current_obj[params[:attribute_name]]
102
+ @no_cache_url = binary.no_cache_url
103
+ end
104
+ end
105
+
99
106
  def mark_resolved
100
107
  in_selected_workspace { current_obj.mark_resolved }
101
108
  render_empty_json
@@ -106,8 +113,20 @@ module Scrivito
106
113
  render :obj
107
114
  end
108
115
 
109
- # optimized away
110
116
  def transfer_modifications
117
+ in_selected_workspace do
118
+ begin
119
+ obj = Obj.find_including_deleted(params[:id])
120
+ workspace = Workspace.find(params[:workspace_id])
121
+ authorize_workspace_access(:write, workspace) do
122
+ obj.transfer_modifications_to(workspace)
123
+ end
124
+ rescue TransferModificationsModifiedError
125
+ @error_reason = :modified
126
+ rescue TransferModificationsConflictError
127
+ @error_reason = :conflict
128
+ end
129
+ end
111
130
  end
112
131
 
113
132
  def duplicate
@@ -135,12 +154,21 @@ module Scrivito
135
154
  @enumerator = ObjSearchBuilder.new(@query).build
136
155
 
137
156
  if params[:query_action] == 'size'
138
- render :search_only_size
139
- elsif @formatter = fetch_formatter(@query[:format])
140
- render :search
141
- else
142
- render :format_missing_error, status: :not_found
157
+ return render action: 'search/size'
158
+ end
159
+
160
+ unless @formatter = fetch_formatter(@query[:format])
161
+ return render action: 'search/missing_formatter', status: :not_found
143
162
  end
163
+
164
+ if facet_params = params[:facet]
165
+ attribute, options = MultiJson.decode(facet_params).values_at('attribute', 'options')
166
+ @facets = @enumerator.facet(attribute, options || {})
167
+ return render action: 'search/facet'
168
+ end
169
+
170
+ @batch = @enumerator.fetch_batch(params[:continuation])
171
+ render :search
144
172
  end
145
173
  end
146
174
 
@@ -1,9 +1,10 @@
1
1
  module Scrivito
2
2
 
3
3
  class WebserviceController < ActionController::Base
4
- rescue_from ClientError do |exception|
5
- @exception = exception
6
- render 'scrivito/webservice/error', formats: :json, status: exception.http_code
4
+ rescue_from ApplicationError, ClientError, ResourceNotFound do |error|
5
+ @error = error
6
+ @timestamp = Time.zone.now
7
+ render 'scrivito/webservice/error', formats: :json, status: error.http_code
7
8
  end
8
9
 
9
10
  before_filter :merge_correctly_parsed_json_params
@@ -0,0 +1,73 @@
1
+ <div class="scrivito_prompt_dialog scrivito_center_dialog scrivito_modal_prompt scrivito_green scrivito_show" style="margin-left: -250px; margin-top: -165px; left: 50%;">
2
+ <div class="scrivito_modal_header">
3
+ <i class="scrivito_icon"></i>
4
+ <h3 class="scrivito_title">Änderungen an dieser Seite veröffentlichen?</h3>
5
+
6
+ <p class="scrivito_description">Eine Arbeitsversion zu veröffentlichen ist endgültig. Dieser Vorgang kann nicht rückgängig gemacht werden.</p>
7
+
8
+ </div>
9
+ <div class="scrivito_modal_body">
10
+ <div class="main_object">
11
+ <label class=""><input type="checkbox" value="<%= @obj.id %>" name="checked" checked="checked" disabled="disabled"> <%= @obj.title.presence || @obj.path %> (<%= @obj.obj_class %>)</label>
12
+ </div>
13
+
14
+ <% if !@images.empty? %>
15
+ <div class="expanding">
16
+ <span><i class="scrivito_icon"></i> Bilder</span>
17
+ </div>
18
+ <div class="expandable collapsed">
19
+ <% @images.each do |obj| %>
20
+ <label class=""><input type="checkbox" value="<%= obj.id %>" name="obj<%= obj.id %>" checked="checked"> <%= obj.title.presence || obj.path %> (<%= obj.obj_class %>)</label>
21
+ <% end %>
22
+ </div>
23
+ <% end %>
24
+
25
+ <% if !@downloads.empty? %>
26
+ <div class="expanding">
27
+ <span><i class="scrivito_icon"></i> Downloads</span>
28
+ </div>
29
+ <div class="expandable collapsed">
30
+ <% @downloads.each do |obj| %>
31
+ <label class=""><input type="checkbox" value="<%= obj.id %>" name="obj<%= obj.id %>" checked="checked"> <%= obj.title.presence || obj.path %> (<%= obj.obj_class %>)</label>
32
+ <% end %>
33
+ </div>
34
+ <% end %>
35
+
36
+ <% if !@referenced.empty? %>
37
+ <div class="expanding">
38
+ <span><i class="scrivito_icon"></i> Referenzierte Seiten</span>
39
+ </div>
40
+ <div class="expandable collapsed">
41
+ <% @referenced.each do |obj| %>
42
+ <label class=""><input type="checkbox" value="<%= obj.id %>" name="obj<%= obj.id %>"> <%= obj.title.presence || obj.path %> (<%= obj.obj_class %>)</label>
43
+ <% end %>
44
+ </div>
45
+ <% end %>
46
+
47
+ <% if !@linked.empty? %>
48
+ <div class="expanding">
49
+ <span><i class="scrivito_icon"></i> Verlinkte Seiten</span>
50
+ </div>
51
+ <div class="expandable collapsed">
52
+ <% @linked.each do |obj| %>
53
+ <label class=""><input type="checkbox" value="<%= obj.id %>" name="obj<%= obj.id %>"> <%= obj.title.presence || obj.path %> (<%= obj.obj_class %>)</label>
54
+ <% end %>
55
+ </div>
56
+ <% end %>
57
+
58
+ <div class="expanding">
59
+ <span><i class="scrivito_icon"></i> Kommentar</span>
60
+ </div>
61
+ <div class="expandable collapsed">
62
+ <input type="text" id="release-comment" placeholder="Kommentar (optional)">
63
+ </div>
64
+ </div>
65
+ <div class="scrivito_modal_footer">
66
+ <a href="#" class="scrivito_button scrivito_ scrivito_cancel">
67
+ Abbrechen
68
+ </a>
69
+ <a href="#" class="scrivito_button scrivito_green scrivito_accept">
70
+ Freigeben
71
+ </a>
72
+ </div>
73
+ </div>