spontaneous 0.2.0.beta4 → 0.2.0.beta5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (205) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/Gemfile +11 -6
  4. data/Readme.markdown +136 -69
  5. data/application/css/core.css.scss +27 -7
  6. data/application/css/editing.css.scss +4 -26
  7. data/application/css/schema_error.css.scss +22 -0
  8. data/application/js/content.js +11 -3
  9. data/application/js/edit_panel.js +1 -4
  10. data/application/js/field/file.js +17 -0
  11. data/application/js/field/image.js +30 -21
  12. data/application/js/field/string.js +4 -1
  13. data/application/js/field_preview.js +21 -16
  14. data/application/js/publish.js +6 -6
  15. data/application/js/types.js +5 -13
  16. data/application/js/views.js +2 -2
  17. data/application/js/views/box_view.js +3 -2
  18. data/application/js/views/page_piece_view.js +1 -1
  19. data/application/js/views/piece_view.js +1 -1
  20. data/application/views/schema_modification_error.html.erb +13 -3
  21. data/db/migrations/20131104101935_site_must_publish_all.rb +14 -0
  22. data/lib/spontaneous.rb +0 -1
  23. data/lib/spontaneous/box_style.rb +15 -9
  24. data/lib/spontaneous/capistrano/deploy.rb +13 -1
  25. data/lib/spontaneous/change.rb +11 -13
  26. data/lib/spontaneous/cli.rb +5 -2
  27. data/lib/spontaneous/cli/assets.rb +7 -1
  28. data/lib/spontaneous/cli/console.rb +7 -1
  29. data/lib/spontaneous/cli/content.rb +35 -0
  30. data/lib/spontaneous/cli/fields.rb +3 -2
  31. data/lib/spontaneous/cli/generate.rb +5 -2
  32. data/lib/spontaneous/cli/server.rb +12 -8
  33. data/lib/spontaneous/cli/site.rb +12 -12
  34. data/lib/spontaneous/cli/user.rb +28 -14
  35. data/lib/spontaneous/collections/box_set.rb +4 -4
  36. data/lib/spontaneous/collections/field_set.rb +4 -4
  37. data/lib/spontaneous/collections/prototype_set.rb +12 -4
  38. data/lib/spontaneous/data_mapper.rb +11 -7
  39. data/lib/spontaneous/data_mapper/content_model.rb +8 -0
  40. data/lib/spontaneous/data_mapper/content_model/associations.rb +1 -1
  41. data/lib/spontaneous/data_mapper/dataset.rb +14 -2
  42. data/lib/spontaneous/data_mapper/scope.rb +33 -13
  43. data/lib/spontaneous/facet.rb +4 -0
  44. data/lib/spontaneous/field.rb +12 -12
  45. data/lib/spontaneous/field/base.rb +27 -22
  46. data/lib/spontaneous/field/boolean.rb +4 -4
  47. data/lib/spontaneous/field/date.rb +2 -2
  48. data/lib/spontaneous/field/file.rb +24 -18
  49. data/lib/spontaneous/field/html.rb +1 -1
  50. data/lib/spontaneous/field/image.rb +6 -19
  51. data/lib/spontaneous/field/location.rb +1 -1
  52. data/lib/spontaneous/field/long_string.rb +3 -3
  53. data/lib/spontaneous/field/markdown.rb +3 -3
  54. data/lib/spontaneous/field/select.rb +2 -2
  55. data/lib/spontaneous/field/string.rb +2 -2
  56. data/lib/spontaneous/field/tags.rb +2 -2
  57. data/lib/spontaneous/field/update.rb +21 -20
  58. data/lib/spontaneous/field/webvideo.rb +6 -6
  59. data/lib/spontaneous/field/webvideo/fallback.rb +2 -2
  60. data/lib/spontaneous/field/webvideo/vimeo.rb +7 -7
  61. data/lib/spontaneous/generators/site.rb +2 -2
  62. data/lib/spontaneous/generators/site/Gemfile.tt +5 -1
  63. data/lib/spontaneous/layout.rb +2 -2
  64. data/lib/spontaneous/media.rb +1 -0
  65. data/lib/spontaneous/media/file.rb +6 -5
  66. data/lib/spontaneous/media/image/attributes.rb +4 -0
  67. data/lib/spontaneous/media/image/renderable.rb +4 -4
  68. data/lib/spontaneous/media/store.rb +22 -0
  69. data/lib/spontaneous/{storage → media/store}/backend.rb +1 -1
  70. data/lib/spontaneous/{storage → media/store}/cloud.rb +1 -1
  71. data/lib/spontaneous/{storage → media/store}/local.rb +1 -1
  72. data/lib/spontaneous/media/temp_file.rb +1 -1
  73. data/lib/spontaneous/model.rb +10 -7
  74. data/lib/spontaneous/model/action.rb +7 -0
  75. data/lib/spontaneous/model/action/clean.rb +87 -0
  76. data/lib/spontaneous/model/box/allowed_types.rb +15 -1
  77. data/lib/spontaneous/model/core.rb +10 -0
  78. data/lib/spontaneous/model/core/aliases.rb +1 -1
  79. data/lib/spontaneous/model/core/content_groups.rb +1 -1
  80. data/lib/spontaneous/model/core/fields.rb +1 -1
  81. data/lib/spontaneous/model/core/modifications.rb +2 -2
  82. data/lib/spontaneous/model/core/page_search.rb +4 -0
  83. data/lib/spontaneous/model/core/publishing.rb +4 -17
  84. data/lib/spontaneous/model/core/render.rb +4 -4
  85. data/lib/spontaneous/model/core/styles.rb +2 -2
  86. data/lib/spontaneous/model/core/visibility.rb +6 -2
  87. data/lib/spontaneous/model/page.rb +6 -2
  88. data/lib/spontaneous/model/page/controllers.rb +55 -17
  89. data/lib/spontaneous/model/page/formats.rb +12 -7
  90. data/lib/spontaneous/model/page/layouts.rb +2 -2
  91. data/lib/spontaneous/model/page/locks.rb +4 -1
  92. data/lib/spontaneous/model/page/page_tree.rb +40 -6
  93. data/lib/spontaneous/output.rb +14 -52
  94. data/lib/spontaneous/output/context.rb +11 -39
  95. data/lib/spontaneous/output/context/navigation.rb +31 -0
  96. data/lib/spontaneous/output/format.rb +15 -19
  97. data/lib/spontaneous/output/renderable.rb +99 -0
  98. data/lib/spontaneous/output/store.rb +24 -0
  99. data/lib/spontaneous/output/store/backend.rb +52 -0
  100. data/lib/spontaneous/output/store/file.rb +77 -0
  101. data/lib/spontaneous/output/store/moneta.rb +117 -0
  102. data/lib/spontaneous/output/store/revision.rb +34 -0
  103. data/lib/spontaneous/output/store/store.rb +15 -0
  104. data/lib/spontaneous/output/store/transaction.rb +44 -0
  105. data/lib/spontaneous/output/template/engine.rb +17 -7
  106. data/lib/spontaneous/output/template/renderer.rb +66 -40
  107. data/lib/spontaneous/page_lock.rb +5 -7
  108. data/lib/spontaneous/page_piece.rb +2 -2
  109. data/lib/spontaneous/permissions/user.rb +14 -7
  110. data/lib/spontaneous/plugins/application/features.rb +8 -4
  111. data/lib/spontaneous/plugins/application/state.rb +12 -6
  112. data/lib/spontaneous/prototypes/box_prototype.rb +9 -10
  113. data/lib/spontaneous/prototypes/field_prototype.rb +66 -15
  114. data/lib/spontaneous/publishing/immediate.rb +30 -26
  115. data/lib/spontaneous/rack.rb +12 -7
  116. data/lib/spontaneous/rack/back.rb +43 -37
  117. data/lib/spontaneous/rack/back/base.rb +4 -4
  118. data/lib/spontaneous/rack/back/changes.rb +2 -2
  119. data/lib/spontaneous/rack/back/file.rb +16 -24
  120. data/lib/spontaneous/rack/back/map.rb +5 -5
  121. data/lib/spontaneous/rack/back/preview.rb +3 -4
  122. data/lib/spontaneous/rack/back/schema.rb +1 -1
  123. data/lib/spontaneous/rack/back/site.rb +6 -7
  124. data/lib/spontaneous/rack/front.rb +19 -16
  125. data/lib/spontaneous/rack/middleware/authenticate.rb +3 -3
  126. data/lib/spontaneous/rack/middleware/reloader.rb +3 -2
  127. data/lib/spontaneous/rack/middleware/scope.rb +25 -19
  128. data/lib/spontaneous/rack/page_controller.rb +164 -13
  129. data/lib/spontaneous/rack/public.rb +23 -62
  130. data/lib/spontaneous/rack/static.rb +2 -3
  131. data/lib/spontaneous/schema.rb +27 -8
  132. data/lib/spontaneous/schema/schema_modification.rb +9 -1
  133. data/lib/spontaneous/schema/uid.rb +2 -2
  134. data/lib/spontaneous/schema/uid_map.rb +3 -2
  135. data/lib/spontaneous/search/database.rb +2 -2
  136. data/lib/spontaneous/search/field.rb +5 -3
  137. data/lib/spontaneous/search/index.rb +12 -7
  138. data/lib/spontaneous/search/results.rb +5 -3
  139. data/lib/spontaneous/server.rb +2 -2
  140. data/lib/spontaneous/site.rb +10 -3
  141. data/lib/spontaneous/site/features.rb +26 -6
  142. data/lib/spontaneous/site/helpers.rb +9 -12
  143. data/lib/spontaneous/site/level.rb +7 -9
  144. data/lib/spontaneous/site/map.rb +9 -11
  145. data/lib/spontaneous/site/paths.rb +5 -5
  146. data/lib/spontaneous/site/publishing.rb +83 -80
  147. data/lib/spontaneous/site/schema.rb +1 -7
  148. data/lib/spontaneous/site/search.rb +8 -18
  149. data/lib/spontaneous/site/selectors.rb +60 -54
  150. data/lib/spontaneous/site/state.rb +36 -30
  151. data/lib/spontaneous/site/storage.rb +10 -16
  152. data/lib/spontaneous/state.rb +8 -0
  153. data/lib/spontaneous/style.rb +32 -33
  154. data/lib/spontaneous/version.rb +1 -1
  155. data/spontaneous.gemspec +22 -21
  156. data/test/fixtures/public/templates/layouts/default.html.cut +1 -1
  157. data/test/fixtures/public/templates/layouts/default.pdf.cut +1 -1
  158. data/test/fixtures/public/templates/layouts/default.rss.cut +1 -1
  159. data/test/fixtures/search/config/indexes.rb +1 -1
  160. data/test/fixtures/serialisation/class_hash.yaml.erb +13 -1
  161. data/test/fixtures/serialisation/root_hash.yaml.erb +10 -0
  162. data/test/functional/test_application.rb +20 -24
  163. data/test/functional/test_back.rb +26 -27
  164. data/test/functional/test_cli.rb +146 -0
  165. data/test/functional/test_front.rb +287 -216
  166. data/test/functional/test_user_manager.rb +1 -1
  167. data/test/test_helper.rb +15 -11
  168. data/test/unit/test_alias.rb +32 -25
  169. data/test/unit/test_asset_bundler.rb +1 -1
  170. data/test/unit/test_assets.rb +34 -33
  171. data/test/unit/test_authentication.rb +1 -1
  172. data/test/unit/test_boxes.rb +16 -2
  173. data/test/unit/test_changesets.rb +23 -11
  174. data/test/unit/test_content.rb +15 -0
  175. data/test/unit/test_context.rb +139 -0
  176. data/test/unit/test_controllers.rb +374 -0
  177. data/test/{experimental → unit}/test_crypt.rb +0 -0
  178. data/test/unit/test_datamapper.rb +260 -237
  179. data/test/unit/test_datamapper_content.rb +42 -12
  180. data/test/{experimental → unit}/test_features.rb +85 -3
  181. data/test/unit/test_fields.rb +117 -42
  182. data/test/unit/test_formats.rb +11 -1
  183. data/test/unit/test_generators.rb +2 -2
  184. data/test/unit/test_helpers.rb +7 -8
  185. data/test/unit/test_images.rb +39 -2
  186. data/test/unit/test_layouts.rb +14 -12
  187. data/test/unit/test_media.rb +32 -23
  188. data/test/unit/test_output_store.rb +342 -0
  189. data/test/unit/test_page.rb +8 -1
  190. data/test/unit/test_permissions.rb +11 -7
  191. data/test/unit/test_plugins.rb +3 -3
  192. data/test/unit/test_prototype_set.rb +8 -1
  193. data/test/unit/test_publishing.rb +67 -54
  194. data/test/unit/test_render.rb +91 -38
  195. data/test/unit/test_revisions.rb +4 -4
  196. data/test/unit/test_schema.rb +109 -84
  197. data/test/unit/test_search.rb +42 -42
  198. data/test/unit/test_serialisation.rb +3 -2
  199. data/test/unit/test_site.rb +39 -27
  200. data/test/unit/test_storage.rb +9 -6
  201. data/test/unit/test_styles.rb +25 -32
  202. data/test/unit/test_templates.rb +8 -4
  203. metadata +89 -54
  204. data/lib/spontaneous/model/page/request.rb +0 -105
  205. data/lib/spontaneous/storage.rb +0 -22
@@ -6,9 +6,6 @@ module Spontaneous
6
6
 
7
7
  plugin :timestamps
8
8
 
9
- many_to_one :page, :class => "Spontaneous::Content", :key => :page_id
10
- many_to_one :content, :class => "Spontaneous::Content", :key => :content_id
11
-
12
9
  def self.lock_field(field)
13
10
  create(field_attributes(field).merge(
14
11
  :description => field.page_lock_description
@@ -40,7 +37,7 @@ module Spontaneous
40
37
  end
41
38
 
42
39
  def field
43
- @field ||= Spontaneous::Field.find(field_id)
40
+ @field ||= Spontaneous::Field.find(content.model, field_id)
44
41
  end
45
42
 
46
43
  def field_name
@@ -49,12 +46,13 @@ module Spontaneous
49
46
 
50
47
  def location
51
48
  field, owner = self.field, self.field.owner
49
+ model = owner.model.content_model
52
50
  case owner
53
- when Spontaneous::Content::Box
51
+ when model::Box
54
52
  "Field ‘#{field.name}’ of box ‘#{owner.box_name}’"
55
- when Spontaneous::Content::Page
53
+ when model::Page
56
54
  "Field ‘#{field.name}’"
57
- when Spontaneous::Content::Piece
55
+ when model::Piece
58
56
  "Field ‘#{field.name}’ of entry #{owner.position + 1} in box ‘#{owner.container.box_name}’"
59
57
  end
60
58
  end
@@ -72,8 +72,8 @@ module Spontaneous
72
72
  target.resolve_style(style_id)
73
73
  end
74
74
 
75
- def template(format = :html)
76
- style.template(format)
75
+ def template(format = :html, renderer = Spontaneous::Output.default_renderer)
76
+ style.template(format, renderer)
77
77
  end
78
78
  end
79
79
  end
@@ -10,7 +10,7 @@ module Spontaneous::Permissions
10
10
  many_to_many :groups, :class => :'Spontaneous::Permissions::AccessGroup', :join_table => :spontaneous_groups_users
11
11
  one_to_many :access_keys, :class => :'Spontaneous::Permissions::AccessKey', :reciprocal => :user
12
12
 
13
- set_restricted_columns(:crypted_password)
13
+ set_allowed_columns(:name, :login, :email, :disabled, :password, :level)
14
14
 
15
15
  def_delegators :group, :level, :access_selector
16
16
 
@@ -188,17 +188,24 @@ module Spontaneous::Permissions
188
188
  errors.add(:email, 'is required') if email.blank?
189
189
  errors.add(:email, 'is invalid') unless email.blank? or email =~ /\A[^@]+@.+\z/
190
190
 
191
- if login.blank?
192
- errors.add(:login, 'is required')
193
- else
194
- errors.add(:login, 'should only contain letters, numbers & underscore') unless login =~ /\A[a-zA-Z0-9_]+\z/
195
- errors.add(:login, 'should be at least 3 letters long') if login.length < 3
196
- end
191
+ validate_login
192
+ validate_login_uniqueness
193
+ validate_password
194
+ end
197
195
 
196
+ def validate_login
197
+ return errors.add(:login, 'is required') if login.blank?
198
+ errors.add(:login, 'should only contain letters, numbers & underscore') unless login =~ /\A[a-zA-Z0-9_]+\z/
199
+ errors.add(:login, 'should be at least 3 letters long') if login.length < 3
200
+ end
201
+
202
+ def validate_login_uniqueness
198
203
  if (u = User[:login => login]) && (u.id != id)
199
204
  errors.add(:login, "must be unique, login '#{login}' already exists")
200
205
  end
206
+ end
201
207
 
208
+ def validate_password
202
209
  if new? || updating_password?
203
210
  if password.blank?
204
211
  errors.add(:password, 'is required')
@@ -5,12 +5,16 @@ module Spontaneous::Plugins::Application
5
5
  extend Spontaneous::Concern
6
6
 
7
7
  module ClassMethods
8
- def register_back_controller(namespace, controller_class)
9
- instance.register_back_controller(namespace, controller_class)
8
+ def register_back_controller(namespace, controller_class, opts = {})
9
+ instance.register_back_controller(namespace, controller_class, opts)
10
10
  end
11
11
 
12
- def register_front_controller(namespace, controller_class)
13
- instance.register_front_controller(namespace, controller_class)
12
+ def register_front_controller(namespace, controller_class, opts = {})
13
+ instance.register_front_controller(namespace, controller_class, opts)
14
+ end
15
+
16
+ def front
17
+ instance.front
14
18
  end
15
19
  end # ClassMethods
16
20
  end # Features
@@ -24,6 +24,7 @@ module Spontaneous::Plugins::Application
24
24
  " 'auto_login' setting from your environment file."
25
25
  end
26
26
  Thread.current[:spontaneous_loaded] = true
27
+ site
27
28
  end
28
29
  end
29
30
 
@@ -39,7 +40,7 @@ module Spontaneous::Plugins::Application
39
40
  # a nice way to create the ::Site constant in the user/site code
40
41
  def site(content_model)
41
42
  site!(content_model) unless defined?(Spontaneous::Content)
42
- Spontaneous::Site
43
+ Spontaneous::Site.instance
43
44
  end
44
45
 
45
46
  # This forces the assignment of Spontaneous::Content, overwriting any
@@ -48,10 +49,11 @@ module Spontaneous::Plugins::Application
48
49
  # Used in tests.
49
50
  #
50
51
  def site!(content_model)
51
- spot = ::Spontaneous
52
- Spontaneous.send :remove_const, :Content if defined?(Spontaneous::Content)
53
- Spontaneous.const_set(:Content, content_model)
54
- Spontaneous::Site
52
+ site = Spontaneous::Site.instance
53
+ # Spontaneous.send :remove_const, :Content if defined?(Spontaneous::Content)
54
+ # Spontaneous.const_set(:Content, content_model)
55
+ site.model = content_model
56
+ site
55
57
  end
56
58
 
57
59
  def loaded?
@@ -59,8 +61,12 @@ module Spontaneous::Plugins::Application
59
61
  end
60
62
 
61
63
 
64
+ def instance
65
+ Spontaneous::Site.instance
66
+ end
67
+
62
68
  def config
63
- Spontaneous::Site.instance.config
69
+ instance.config
64
70
  end
65
71
 
66
72
  def db_settings
@@ -176,19 +176,18 @@ module Spontaneous::Prototypes
176
176
  end
177
177
 
178
178
  def allowed_types(user)
179
- if writable?(user)
180
- types = []
181
- instance_class.allowed.select { |a| a.readable?(user) }.each do |a|
182
- types.concat(a.instance_classes)
183
- end
184
- types
185
- else
186
- []
187
- end
179
+ _allowed(user).flat_map { |allow| allow.instance_classes }
188
180
  end
189
181
 
182
+ def _allowed(user)
183
+ return [] unless writable?(user)
184
+ instance_class.allowed.select { |a| a.readable?(user) }
185
+ end
186
+
187
+ private :_allowed
188
+
190
189
  def export(user)
191
- allowed = allowed_types(user).map { |c| c.ui_class }
190
+ allowed = _allowed(user).flat_map { |a| a.export }
192
191
  {
193
192
  :name => name.to_s,
194
193
  :id => schema_id.to_s,
@@ -2,6 +2,49 @@
2
2
 
3
3
 
4
4
  module Spontaneous::Prototypes
5
+ # FieldPrototype represents the class-level view of a type field.
6
+ # It contains information on the type of the field and the options
7
+ # passed in the type declaration and is responsible for transforming
8
+ # serialized field data from the db into a field instance.
9
+ #
10
+ # options - A hash containing options that control the behaviour of the
11
+ # field (default: {})
12
+ #
13
+ # :default - The default value for new fields. This accepts either a
14
+ # value (which is either a String or responds to #to_s)
15
+ # or a Proc value generator which can accept 1 argument
16
+ # that is the instance that the field is attached to.
17
+ # :title - The title that should be used to label the field in the UI.
18
+ # This defaults to the 'titleized' version of the field name,
19
+ # e.g. ':field_name' becomes 'Field Name'.
20
+ # :comment - An optional String comment to be displayed in the UI
21
+ # (default: "").
22
+ # :list - A Boolean flag determining whether to show the field in the
23
+ # list view (default: true).
24
+ # :fallback - Provides a way of supplying a fallback value for an empty
25
+ # field.
26
+ #
27
+ # Other options are dependent on the type of field.
28
+ #
29
+ # Examples
30
+ #
31
+ # Pass a Proc as the default value for a field:
32
+ #
33
+ # field :title, default: proc { |page| "This is page #{page.slug}" }
34
+ #
35
+ # Assign a field with a fallback:
36
+ #
37
+ # class Something < Piece
38
+ # field :a
39
+ # field :b, fallback: :a
40
+ # end
41
+ #
42
+ # instance = Something.new(a: "The value of A")
43
+ # instance.a.value #=> "The value of A"
44
+ # instance.b.value #=> "The value of A"
45
+ # instance.b = "Now B"
46
+ # instance.b.value #=> "Now B"
47
+ #
5
48
  class FieldPrototype
6
49
  attr_reader :owner, :name, :options
7
50
 
@@ -59,7 +102,7 @@ module Spontaneous::Prototypes
59
102
  end
60
103
 
61
104
  def default_options(field_class)
62
- {:default => '', :comment => false }.merge(field_class.default_options)
105
+ {default: '', comment: false, list: true}.merge(field_class.default_options)
63
106
  end
64
107
 
65
108
  def instance_class
@@ -116,19 +159,26 @@ module Spontaneous::Prototypes
116
159
  end
117
160
 
118
161
  def in_index?(index)
119
- search.in_index?(index)
162
+ search(index.site).in_index?(index)
120
163
  end
121
164
 
122
165
  def index_id(index)
123
- search.index_id(index)
166
+ search(index.site).index_id(index)
124
167
  end
125
168
 
126
169
  def options_for_index(index)
127
- search.field_definition(index)
170
+ search(index.site).field_definition(index)
128
171
  end
129
172
 
130
- def search
131
- @search ||= S::Search::Field.new(self, @options[:index])
173
+ # TODO: it's wrong to have to be passing the site to this call
174
+ # as there's only ever one site and we shouldn't be memoizing
175
+ # a method call with a param.
176
+ # Must centralize the testing of a prototype for inclusion into
177
+ # an index - either into the index or the site itself.
178
+ # We can't just recalculate this on the fly because indexing
179
+ # needs to be reasonably performant.
180
+ def search(site)
181
+ @search ||= S::Search::Field.new(site, self, @options[:index])
132
182
  end
133
183
 
134
184
  def inherit_schema_id(schema_id)
@@ -148,19 +198,20 @@ module Spontaneous::Prototypes
148
198
  values = { :name => self.name }
149
199
  values[:unprocessed_value] = default(instance) if using_default_values
150
200
  values.update(database_values || {})
151
- self.instance_class.new(values, using_default_values).tap do |field|
152
- field.prototype = self
153
- end
201
+ field = self.instance_class.new(values, using_default_values)
202
+ field.prototype = self
203
+ field
154
204
  end
155
205
 
156
206
  def export(user)
157
207
  {
158
- :name => name.to_s,
159
- :schema_id => schema_id.to_s,
160
- :type => instance_class.editor_class,
161
- :title => title,
162
- :comment => comment || "",
163
- :writable => Spontaneous::Permissions.has_level?(user, write_level)
208
+ name: name.to_s,
209
+ schema_id: schema_id.to_s,
210
+ type: instance_class.editor_class,
211
+ title: title,
212
+ comment: comment || "",
213
+ list: @options[:list] || false,
214
+ writable: Spontaneous::Permissions.has_level?(user, write_level)
164
215
  }.merge(instance_class.export(user))
165
216
  end
166
217
  end
@@ -12,14 +12,14 @@ module Spontaneous
12
12
 
13
13
  attr_reader :revision, :now
14
14
 
15
- def initialize(revision, content_model)
16
- @revision, @content_model = revision, content_model
17
- @previous_revision = Spontaneous::Site.published_revision
15
+ def initialize(site, revision)
16
+ @site, @revision, @content_model = site, revision, site.model
17
+ @previous_revision = @site.published_revision
18
18
  @now = Time.now
19
19
  end
20
20
 
21
21
  def renderer
22
- @renderer ||= Spontaneous::Output::Template::PublishRenderer.new(true)
22
+ @renderer ||= Spontaneous::Output::Template::PublishRenderer.new(@site, true)
23
23
  end
24
24
 
25
25
  def publish_pages(page_list)
@@ -71,14 +71,14 @@ module Spontaneous
71
71
 
72
72
 
73
73
  def pages
74
- @pages ||= Spontaneous::Site.pages(@content_model)
74
+ @pages ||= @site.pages
75
75
  end
76
76
 
77
77
  # The number of times the publisher has to run through the site's pages
78
78
  # in order to generate the search indexes.
79
79
  # Returns either 0 or 1
80
80
  def index_stages
81
- [1, S::Site.indexes.length].min
81
+ [1, @site.indexes.length].min
82
82
  end
83
83
 
84
84
  def publish(modified_page_list)
@@ -97,7 +97,6 @@ module Spontaneous
97
97
  end
98
98
 
99
99
  def render_revision
100
- S::Output.renderer = renderer
101
100
  update_progress("rendering", 0)
102
101
  @pages_rendered = 0
103
102
  @content_model.scope(@revision, true) do
@@ -109,24 +108,27 @@ module Spontaneous
109
108
  end
110
109
 
111
110
  def render_pages
112
- # the delay is purely used in interface testing
113
- delay = Spontaneous::Site.config.publishing_delay
111
+ template_revision = @site.output_store.revision(@revision)
112
+ @render_transaction = template_revision.transaction
113
+ delay = @site.config.publishing_delay # the delay is purely used in interface testing
114
114
  pages.each do |page|
115
115
  page.outputs.each do |output|
116
- render_page(page, output)
116
+ render_page(page, output, @render_transaction)
117
117
  end
118
118
  sleep(delay) if delay
119
119
  end
120
+ @render_transaction.commit
121
+ @render_transaction = nil
120
122
  end
121
123
 
122
- def render_page(page, output)
124
+ def render_page(page, output, transaction)
123
125
  logger.info { "#{page.path}" }
124
- output.publish_page(renderer, revision)
126
+ output.publish_page(renderer, revision, transaction)
125
127
  page_rendered(page, "rendering", output.format)
126
128
  end
127
129
 
128
130
  def index_pages
129
- S::Site.indexer(revision) do |indexer|
131
+ @site.indexer(revision) do |indexer|
130
132
  pages.each { |page|
131
133
  indexer << page
132
134
  page_rendered(page, 'indexing')
@@ -283,7 +285,7 @@ module Spontaneous
283
285
  # when working with multiple instances it's possible to rollback the revision number
284
286
  # leaving behind old revisions > the current published_revision.
285
287
  @content_model.delete_revision(revision)
286
- Spontaneous::Site.send(:pending_revision=, revision)
288
+ @site.send(:pending_revision=, revision)
287
289
  end
288
290
 
289
291
  def after_publish
@@ -292,28 +294,29 @@ module Spontaneous
292
294
  tmp = Spontaneous.revision_dir(revision) / "tmp"
293
295
  FileUtils.mkdir_p(tmp) unless ::File.exists?(tmp)
294
296
  activate_revision
297
+ @site.must_publish_all!(false)
295
298
  update_progress("complete")
296
299
  rescue => e
297
300
  # if a post publish hook raises an exception then we want to roll everything back
298
- deactivate_revision
301
+ deactivate_revision(e)
299
302
  raise e
300
303
  end
301
304
  end
302
305
 
303
306
  def activate_revision
304
307
  S::PublishedRevision.create(:revision => revision, :published_at => now)
305
- Spontaneous::Site.send(:set_published_revision, revision)
308
+ @site.send(:set_published_revision, revision)
306
309
  write_revision(revision)
307
- Spontaneous::Site.trigger(:after_publish, revision)
308
- Spontaneous::Site.send(:pending_revision=, nil)
309
- Spontaneous::Content.cleanup_revisions(revision, keep_revisions)
310
+ @site.trigger(:after_publish, revision)
311
+ @site.send(:pending_revision=, nil)
312
+ @content_model.cleanup_revisions(revision, keep_revisions)
310
313
  end
311
314
 
312
- def deactivate_revision
315
+ def deactivate_revision(exception)
313
316
  S::PublishedRevision.filter(:revision => revision).delete
314
- Spontaneous::Site.send(:set_published_revision, @previous_revision)
317
+ @site.send(:set_published_revision, @previous_revision)
315
318
  write_revision(@previous_revision)
316
- abort_publish(e)
319
+ abort_publish(exception)
317
320
  end
318
321
 
319
322
  # Makes the revision live on the filesystem by symlinking the revisions/current
@@ -333,17 +336,18 @@ module Spontaneous
333
336
  end
334
337
 
335
338
  def abort_publish(exception)
336
- if (r = S::Site.pending_revision)
339
+ if (r = @site.pending_revision)
337
340
  update_progress("aborting")
338
- FileUtils.rm_r(Spontaneous.revision_dir(revision)) if File.exists?(Spontaneous.revision_dir(revision))
339
- Spontaneous::Site.send(:pending_revision=, nil)
341
+ @render_transaction.rollback if @render_transaction
342
+ @site.output_store.revision(r).delete # we might have committed the transaction
343
+ @site.send(:pending_revision=, nil)
340
344
  @content_model.delete_revision(revision)
341
345
  puts exception.backtrace.join("\n") if exception
342
346
  end
343
347
  end
344
348
 
345
349
  def keep_revisions
346
- Spontaneous::Site.config.keep_revisions || KEEP_REVISIONS
350
+ @site.config.keep_revisions || KEEP_REVISIONS
347
351
  end
348
352
  end # Immediate
349
353
  end # Publishing