spontaneous 0.2.0.alpha7 → 0.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +10 -4
- data/Readme.markdown +1 -1
- data/application/css/definitions.css.scss +5 -0
- data/application/css/dialogue.css.scss +62 -0
- data/application/js/content.js +1 -1
- data/application/js/dom.js +1 -1
- data/application/js/event_source.js +3 -0
- data/application/js/{field_types/date_field.js → field/date.js} +2 -2
- data/application/js/{field_types/file_field.js → field/file.js} +2 -2
- data/application/js/{field_types/image_field.js → field/image.js} +54 -20
- data/application/js/{field_types/long_string_field.js → field/long_string.js} +2 -2
- data/application/js/{field_types/markdown_field.js → field/markdown.js} +2 -2
- data/application/js/{field_types/select_field.js → field/select.js} +2 -2
- data/application/js/{field_types/string_field.js → field/string.js} +21 -7
- data/application/js/{field_types/webvideo_field.js → field/webvideo.js} +2 -2
- data/application/js/field.js +2 -2
- data/application/js/publish.js +99 -19
- data/application/js/spontaneous.js +8 -8
- data/application/js/top_bar.js +6 -4
- data/db/migrations/20130109125023_add_page_publish_lock.rb +17 -0
- data/db/migrations/20130111161934_convert_bcrypt_passwords.rb +22 -0
- data/db/migrations/20130114120000_create_revision_tables.rb +106 -0
- data/db/migrations/20130116220423_add_index_to_archive.rb +9 -0
- data/lib/spontaneous/box.rb +53 -18
- data/lib/spontaneous/box_style.rb +2 -3
- data/lib/spontaneous/change.rb +39 -13
- data/lib/spontaneous/cli/fields.rb +29 -0
- data/lib/spontaneous/cli/init.rb +2 -2
- data/lib/spontaneous/cli/migrate.rb +0 -1
- data/lib/spontaneous/cli/server.rb +14 -10
- data/lib/spontaneous/cli/site.rb +20 -9
- data/lib/spontaneous/cli.rb +8 -6
- data/lib/spontaneous/collections/box_set.rb +11 -0
- data/lib/spontaneous/collections/field_set.rb +24 -1
- data/lib/spontaneous/concern.rb +37 -0
- data/lib/spontaneous/config.rb +3 -4
- data/lib/spontaneous/crypt/version.rb +130 -0
- data/lib/spontaneous/crypt.rb +84 -0
- data/lib/spontaneous/data_mapper/content_model/associations.rb +199 -0
- data/lib/spontaneous/data_mapper/content_model/column_accessors.rb +52 -0
- data/lib/spontaneous/data_mapper/content_model/instance_hooks.rb +34 -0
- data/lib/spontaneous/data_mapper/content_model/serialization.rb +54 -0
- data/lib/spontaneous/data_mapper/content_model/timestamps.rb +39 -0
- data/lib/spontaneous/data_mapper/content_model.rb +343 -0
- data/lib/spontaneous/data_mapper/content_table.rb +103 -0
- data/lib/spontaneous/data_mapper/dataset.rb +194 -0
- data/lib/spontaneous/data_mapper/scope.rb +195 -0
- data/lib/spontaneous/data_mapper.rb +161 -0
- data/lib/spontaneous/facet.rb +2 -2
- data/lib/spontaneous/field/base.rb +418 -0
- data/lib/spontaneous/field/date.rb +54 -0
- data/lib/spontaneous/{field_version.rb → field/field_version.rb} +1 -1
- data/lib/spontaneous/field/file.rb +100 -0
- data/lib/spontaneous/{field_types/image_field.rb → field/image.rb} +33 -33
- data/lib/spontaneous/{field_types/location_field.rb → field/location.rb} +2 -2
- data/lib/spontaneous/{field_types/long_string_field.rb → field/long_string.rb} +3 -3
- data/lib/spontaneous/field/markdown.rb +36 -0
- data/lib/spontaneous/{field_types/select_field.rb → field/select.rb} +4 -5
- data/lib/spontaneous/field/string.rb +17 -0
- data/lib/spontaneous/field/update.rb +156 -0
- data/lib/spontaneous/field/webvideo.rb +310 -0
- data/lib/spontaneous/field.rb +80 -0
- data/lib/spontaneous/generators/site/Gemfile.tt +2 -2
- data/lib/spontaneous/generators/site/config/environments/development.rb.tt +1 -1
- data/lib/spontaneous/generators/site/config/environments/production.rb.tt +1 -1
- data/lib/spontaneous/generators/site/lib/content.rb.tt +6 -0
- data/lib/spontaneous/generators/site/schema/box.rb.tt +3 -2
- data/lib/spontaneous/generators/site/schema/page.rb.tt +3 -1
- data/lib/spontaneous/generators/site/schema/piece.rb.tt +3 -1
- data/lib/spontaneous/generators/site/templates/layouts/standard.html.cut.tt +3 -1
- data/lib/spontaneous/generators/site.rb +4 -3
- data/lib/spontaneous/image_size.rb +8 -1
- data/lib/spontaneous/layout.rb +5 -1
- data/lib/spontaneous/loader.rb +2 -5
- data/lib/spontaneous/media/file.rb +11 -2
- data/lib/spontaneous/media/temp_file.rb +23 -0
- data/lib/spontaneous/media.rb +20 -39
- data/lib/spontaneous/{plugins → model/box}/allowed_types.rb +38 -17
- data/lib/spontaneous/model/box.rb +18 -0
- data/lib/spontaneous/{plugins → model/core}/aliases.rb +10 -14
- data/lib/spontaneous/{plugins → model/core}/boxes.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/content_groups.rb +2 -2
- data/lib/spontaneous/model/core/editor_class.rb +4 -0
- data/lib/spontaneous/{plugins → model/core}/entries.rb +19 -7
- data/lib/spontaneous/{plugins → model/core}/entry.rb +3 -3
- data/lib/spontaneous/{plugins → model/core}/fields.rb +38 -5
- data/lib/spontaneous/{plugins → model/core}/instance_code.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/media.rb +2 -12
- data/lib/spontaneous/{plugins → model/core}/modifications.rb +7 -6
- data/lib/spontaneous/model/core/page_search.rb +36 -0
- data/lib/spontaneous/{plugins → model/core}/permissions.rb +4 -4
- data/lib/spontaneous/{plugins → model/core}/prototypes.rb +4 -4
- data/lib/spontaneous/{plugins → model/core}/publishing.rb +93 -115
- data/lib/spontaneous/{plugins → model/core}/render.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/schema_hierarchy.rb +7 -11
- data/lib/spontaneous/model/core/schema_id.rb +65 -0
- data/lib/spontaneous/{plugins → model/core}/schema_title.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/serialisation.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/styles.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/supertype.rb +2 -2
- data/lib/spontaneous/{plugins → model/core}/visibility.rb +7 -48
- data/lib/spontaneous/model/core.rb +143 -0
- data/lib/spontaneous/{plugins → model/page}/controllers.rb +3 -3
- data/lib/spontaneous/{plugins → model}/page/formats.rb +2 -2
- data/lib/spontaneous/{plugins → model/page}/layouts.rb +2 -2
- data/lib/spontaneous/model/page/locks.rb +14 -0
- data/lib/spontaneous/{plugins → model/page}/page_tree.rb +3 -3
- data/lib/spontaneous/{plugins → model/page}/paths.rb +30 -12
- data/lib/spontaneous/{plugins → model}/page/request.rb +2 -2
- data/lib/spontaneous/{plugins → model/page}/site_map.rb +2 -2
- data/lib/spontaneous/model/page/site_timestamps.rb +44 -0
- data/lib/spontaneous/{page.rb → model/page.rb} +49 -28
- data/lib/spontaneous/{piece.rb → model/piece.rb} +7 -6
- data/lib/spontaneous/model.rb +97 -0
- data/lib/spontaneous/output/context.rb +1 -1
- data/lib/spontaneous/output/format.rb +4 -0
- data/lib/spontaneous/output/template/renderer.rb +2 -2
- data/lib/spontaneous/output.rb +2 -2
- data/lib/spontaneous/page_lock.rb +62 -0
- data/lib/spontaneous/page_piece.rb +1 -1
- data/lib/spontaneous/permissions/access_key.rb +9 -4
- data/lib/spontaneous/permissions/user.rb +19 -9
- data/lib/spontaneous/permissions.rb +2 -5
- data/lib/spontaneous/plugins/application/facets.rb +1 -2
- data/lib/spontaneous/plugins/application/features.rb +1 -1
- data/lib/spontaneous/plugins/application/paths.rb +1 -1
- data/lib/spontaneous/plugins/application/render.rb +1 -1
- data/lib/spontaneous/plugins/application/serialisation.rb +1 -1
- data/lib/spontaneous/plugins/application/state.rb +30 -1
- data/lib/spontaneous/plugins/application/system.rb +12 -12
- data/lib/spontaneous/prototypes/box_prototype.rb +1 -1
- data/lib/spontaneous/prototypes/field_prototype.rb +3 -6
- data/lib/spontaneous/prototypes/style_prototype.rb +1 -1
- data/lib/spontaneous/publishing/immediate.rb +77 -49
- data/lib/spontaneous/publishing/revision.rb +355 -0
- data/lib/spontaneous/publishing/simultaneous.rb +10 -49
- data/lib/spontaneous/publishing.rb +1 -0
- data/lib/spontaneous/rack/around_back.rb +1 -1
- data/lib/spontaneous/rack/around_front.rb +2 -4
- data/lib/spontaneous/rack/around_preview.rb +1 -1
- data/lib/spontaneous/rack/back.rb +80 -63
- data/lib/spontaneous/rack/cacheable_file.rb +2 -2
- data/lib/spontaneous/rack/cookie_authentication.rb +1 -1
- data/lib/spontaneous/rack/front.rb +1 -1
- data/lib/spontaneous/rack/helpers.rb +8 -9
- data/lib/spontaneous/{page_controller.rb → rack/page_controller.rb} +1 -1
- data/lib/spontaneous/rack/public.rb +3 -3
- data/lib/spontaneous/rack.rb +15 -15
- data/lib/spontaneous/schema/uid.rb +4 -1
- data/lib/spontaneous/schema.rb +57 -24
- data/lib/spontaneous/search/database.rb +12 -1
- data/lib/spontaneous/search/index.rb +34 -6
- data/lib/spontaneous/search/results.rb +1 -1
- data/lib/spontaneous/server.rb +3 -3
- data/lib/spontaneous/simultaneous.rb +53 -0
- data/lib/spontaneous/{plugins/site → site}/features.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/helpers.rb +2 -3
- data/lib/spontaneous/{plugins/site → site}/hooks.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/instance.rb +4 -6
- data/lib/spontaneous/{plugins/site → site}/level.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/map.rb +4 -4
- data/lib/spontaneous/{plugins/site → site}/paths.rb +2 -2
- data/lib/spontaneous/site/publishing.rb +89 -0
- data/lib/spontaneous/{plugins/site → site}/schema.rb +4 -4
- data/lib/spontaneous/{plugins/site → site}/search.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/selectors.rb +15 -7
- data/lib/spontaneous/{plugins/site → site}/state.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/storage.rb +2 -2
- data/lib/spontaneous/{plugins/site → site}/url.rb +2 -2
- data/lib/spontaneous/site.rb +31 -14
- data/lib/spontaneous/state.rb +5 -6
- data/lib/spontaneous/style.rb +3 -2
- data/lib/spontaneous/utils/database/mysql_dumper.rb +13 -0
- data/lib/spontaneous/utils/database/postgres_dumper.rb +5 -0
- data/lib/spontaneous/version.rb +1 -1
- data/lib/spontaneous.rb +34 -89
- data/spontaneous.gemspec +112 -114
- data/test/experimental/test_crypt.rb +158 -0
- data/test/experimental/test_features.rb +3 -3
- data/test/fixtures/example_application/config/environments/development.rb +1 -1
- data/test/fixtures/example_application/lib/content.rb +5 -0
- data/test/fixtures/example_application/schema/page.rb +2 -1
- data/test/fixtures/example_application/schema/piece.rb +3 -2
- data/test/fixtures/serialisation/class_hash.yaml.erb +5 -5
- data/test/fixtures/serialisation/root_hash.yaml.erb +8 -0
- data/test/functional/test_application.rb +12 -1
- data/test/functional/test_back.rb +80 -48
- data/test/functional/test_front.rb +39 -46
- data/test/functional/test_user_manager.rb +3 -9
- data/test/javascript/test_markdown.rb +2 -2
- data/test/test_helper.rb +78 -23
- data/test/unit/test_alias.rb +21 -15
- data/test/unit/test_asset_bundler.rb +3 -3
- data/test/unit/test_assets.rb +2 -2
- data/test/unit/test_async.rb +7 -6
- data/test/unit/test_authentication.rb +43 -37
- data/test/unit/test_boxes.rb +46 -21
- data/test/unit/test_changesets.rb +65 -20
- data/test/unit/test_config.rb +9 -9
- data/test/unit/test_content.rb +50 -51
- data/test/unit/test_content_inheritance.rb +6 -20
- data/test/unit/test_datamapper.rb +1330 -0
- data/test/unit/test_datamapper_content.rb +214 -0
- data/test/unit/test_fields.rb +543 -54
- data/test/unit/test_formats.rb +2 -3
- data/test/unit/test_generators.rb +6 -6
- data/test/unit/test_helpers.rb +1 -1
- data/test/unit/test_image_size.rb +10 -5
- data/test/unit/test_images.rb +17 -18
- data/test/unit/test_layouts.rb +18 -3
- data/test/unit/test_media.rb +74 -49
- data/test/unit/test_modifications.rb +43 -43
- data/test/unit/test_page.rb +7 -10
- data/test/unit/test_permissions.rb +3 -10
- data/test/unit/test_piece.rb +5 -6
- data/test/unit/test_plugins.rb +7 -14
- data/test/unit/test_prototypes.rb +3 -3
- data/test/unit/test_publishing.rb +49 -27
- data/test/unit/test_render.rb +46 -15
- data/test/unit/test_revisions.rb +124 -127
- data/test/unit/test_schema.rb +53 -58
- data/test/unit/test_search.rb +64 -16
- data/test/unit/test_serialisation.rb +4 -11
- data/test/unit/test_site.rb +11 -12
- data/test/unit/test_structure.rb +2 -5
- data/test/unit/test_styles.rb +22 -24
- data/test/unit/test_type_hierarchy.rb +7 -5
- data/test/unit/test_visibility.rb +79 -55
- metadata +128 -102
- data/lib/sequel/plugins/content_table_inheritance.rb +0 -203
- data/lib/sequel/plugins/scoped_table_name.rb +0 -54
- data/lib/spontaneous/content.rb +0 -129
- data/lib/spontaneous/field_types/date_field.rb +0 -56
- data/lib/spontaneous/field_types/field.rb +0 -302
- data/lib/spontaneous/field_types/file_field.rb +0 -68
- data/lib/spontaneous/field_types/markdown_field.rb +0 -38
- data/lib/spontaneous/field_types/string_field.rb +0 -19
- data/lib/spontaneous/field_types/webvideo_field.rb +0 -313
- data/lib/spontaneous/field_types.rb +0 -38
- data/lib/spontaneous/generators/site/lib/site.rb.tt +0 -4
- data/lib/spontaneous/plugins/field/editor_class.rb +0 -13
- data/lib/spontaneous/plugins/page/site_timestamps.rb +0 -28
- data/lib/spontaneous/plugins/page_search.rb +0 -63
- data/lib/spontaneous/plugins/schema_id.rb +0 -68
- data/lib/spontaneous/plugins/site/publishing.rb +0 -75
- data/lib/spontaneous/rack/fiber_pool.rb +0 -26
- data/test/unit/test_table_scoping.rb +0 -80
@@ -0,0 +1,62 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
module Spontaneous
|
4
|
+
class PageLock < Sequel::Model(:spontaneous_page_lock)
|
5
|
+
class InvalidPage < Spontaneous::Error; end
|
6
|
+
|
7
|
+
plugin :timestamps
|
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
|
+
def self.lock_field(field)
|
13
|
+
create(field_attributes(field).merge(
|
14
|
+
:description => field.page_lock_description
|
15
|
+
))
|
16
|
+
rescue InvalidPage
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.unlock_field(field)
|
21
|
+
field_dataset(field).delete
|
22
|
+
rescue InvalidPage
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.field_dataset(field)
|
27
|
+
filter(field_attributes(field))
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.field_attributes(field)
|
31
|
+
owner = field.owner
|
32
|
+
raise InvalidPage.new(field.id) unless owner.page
|
33
|
+
{ :content_id => owner.content_instance.id,
|
34
|
+
:page_id => owner.page.id,
|
35
|
+
:field_id => field.id }
|
36
|
+
end
|
37
|
+
|
38
|
+
def field=(field)
|
39
|
+
self.field_id = field.id
|
40
|
+
end
|
41
|
+
|
42
|
+
def field
|
43
|
+
@field ||= Spontaneous::Field.find(field_id)
|
44
|
+
end
|
45
|
+
|
46
|
+
def field_name
|
47
|
+
field.name
|
48
|
+
end
|
49
|
+
|
50
|
+
def location
|
51
|
+
field, owner = self.field, self.field.owner
|
52
|
+
case owner
|
53
|
+
when Spontaneous::Content::Box
|
54
|
+
"Field ‘#{field.name}’ of box ‘#{owner.box_name}’"
|
55
|
+
when Spontaneous::Content::Page
|
56
|
+
"Field ‘#{field.name}’"
|
57
|
+
when Spontaneous::Content::Piece
|
58
|
+
"Field ‘#{field.name}’ of entry #{owner.position + 1} in box ‘#{owner.container.box_name}’"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Spontaneous::Permissions
|
4
4
|
class AccessKey < Sequel::Model(:spontaneous_access_keys)
|
5
5
|
plugin :timestamps
|
6
|
-
many_to_one :user, :class => :'Spontaneous::Permissions::User'
|
6
|
+
many_to_one :user, :class => :'Spontaneous::Permissions::User', :reciprocal => :access_keys
|
7
7
|
|
8
8
|
def self.authenticate(key_id, ip_address = nil)
|
9
9
|
if key = self.for_id(key_id)
|
@@ -14,12 +14,17 @@ module Spontaneous::Permissions
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def self.valid?(key_id, user)
|
17
|
-
|
18
|
-
false
|
17
|
+
(key = self.for_id(key_id)) && (key.user == user) && (key.user.enabled?)
|
19
18
|
end
|
20
19
|
|
21
20
|
def self.for_id(key_id)
|
22
|
-
|
21
|
+
key_dataset.call(:key_id => key_id).first
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.key_dataset
|
25
|
+
@key_dataset ||= self.where(:key_id => :$key_id).
|
26
|
+
eager_graph(:user).
|
27
|
+
prepare(:select, :select_access_key_by_key)
|
23
28
|
end
|
24
29
|
|
25
30
|
def before_create
|
@@ -8,20 +8,27 @@ module Spontaneous::Permissions
|
|
8
8
|
|
9
9
|
one_to_one :group, :class => :'Spontaneous::Permissions::AccessGroup'
|
10
10
|
many_to_many :groups, :class => :'Spontaneous::Permissions::AccessGroup', :join_table => :spontaneous_groups_users
|
11
|
-
one_to_many :access_keys, :class => :'Spontaneous::Permissions::AccessKey'
|
11
|
+
one_to_many :access_keys, :class => :'Spontaneous::Permissions::AccessKey', :reciprocal => :user
|
12
12
|
|
13
|
-
set_restricted_columns(:crypted_password
|
13
|
+
set_restricted_columns(:crypted_password)
|
14
14
|
|
15
15
|
def_delegators :group, :level, :access_selector
|
16
16
|
|
17
|
-
def self.
|
18
|
-
|
17
|
+
def self.login(login)
|
18
|
+
login_dataset.call(:login => login).first
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.login_dataset
|
22
|
+
@login_dataset ||= self.where(:login => :$login).
|
23
|
+
eager_graph(:access_keys).
|
24
|
+
prepare(:select, :select_user_by_login)
|
19
25
|
end
|
20
26
|
|
21
27
|
def self.authenticate(login, clear_password, ip_address = nil)
|
22
|
-
if user = self[:login => login, :disabled => false]
|
23
|
-
|
24
|
-
if
|
28
|
+
if (user = self[:login => login, :disabled => false])
|
29
|
+
authenticator = Spontaneous::Crypt.new(clear_password, user.crypted_password)
|
30
|
+
if authenticator.valid?
|
31
|
+
user.upgrade_authentication(authenticator) if authenticator.outdated?
|
25
32
|
access_key = user.logged_in!(ip_address)
|
26
33
|
return access_key
|
27
34
|
end
|
@@ -91,11 +98,14 @@ module Spontaneous::Permissions
|
|
91
98
|
end
|
92
99
|
|
93
100
|
def encrypt_password(clear_password)
|
94
|
-
|
101
|
+
Spontaneous::Crypt.hash(clear_password)
|
102
|
+
end
|
103
|
+
|
104
|
+
def upgrade_authentication(auth)
|
105
|
+
update_all :crypted_password => auth.upgrade
|
95
106
|
end
|
96
107
|
|
97
108
|
def before_save
|
98
|
-
self.salt = Spontaneous::Permissions.random_string(32) if salt.blank?
|
99
109
|
self.crypted_password = encrypt_password(password) unless password.blank?
|
100
110
|
clear_access_keys! if disabled?
|
101
111
|
super
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
3
|
require 'base58'
|
4
|
+
require 'securerandom'
|
4
5
|
|
5
6
|
module Spontaneous
|
6
7
|
module Permissions
|
@@ -10,8 +11,6 @@ module Spontaneous
|
|
10
11
|
autoload :AccessGroup, "spontaneous/permissions/access_group"
|
11
12
|
autoload :AccessKey, "spontaneous/permissions/access_key"
|
12
13
|
|
13
|
-
@@active_user = nil
|
14
|
-
|
15
14
|
class << self
|
16
15
|
# Convenience shortcut so we can do Permissions[:root]
|
17
16
|
def [](level_name)
|
@@ -28,9 +27,7 @@ module Spontaneous
|
|
28
27
|
end
|
29
28
|
|
30
29
|
def random_string(length)
|
31
|
-
|
32
|
-
string = Base58.encode(OpenSSL::Random.random_bytes(bytes).unpack("h*").first.to_i(16))
|
33
|
-
string[0...(length)]
|
30
|
+
SecureRandom.urlsafe_base64(length)[0...(length)]
|
34
31
|
end
|
35
32
|
end
|
36
33
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Spontaneous::Plugins::Application
|
4
4
|
module Facets
|
5
|
-
extend
|
5
|
+
extend Spontaneous::Concern
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
def instance
|
@@ -16,7 +16,6 @@ module Spontaneous::Plugins::Application
|
|
16
16
|
def schema
|
17
17
|
instance.schema
|
18
18
|
end
|
19
|
-
|
20
19
|
end
|
21
20
|
end
|
22
21
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Spontaneous::Plugins::Application
|
4
4
|
module State
|
5
|
-
extend
|
5
|
+
extend Spontaneous::Concern
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
def init(options={})
|
@@ -11,6 +11,8 @@ module Spontaneous::Plugins::Application
|
|
11
11
|
self.mode = options.delete(:mode) || ENV["SPOT_MODE"] || :back
|
12
12
|
root = options.delete(:root) || ENV["SPOT_ROOT"] || Dir.pwd
|
13
13
|
site = Spontaneous::Site.instantiate(root, environment, mode)
|
14
|
+
lib = File.expand_path(File.join(root, "lib"))
|
15
|
+
$:.push(lib) unless $:.include?(lib)
|
14
16
|
Spontaneous::Logger.setup(:log_level => options[:log_level], :logfile => options[:logfile], :cli => options[:cli])
|
15
17
|
site.initialize!
|
16
18
|
site.schema.validate! if self.mode == :console
|
@@ -18,6 +20,33 @@ module Spontaneous::Plugins::Application
|
|
18
20
|
Thread.current[:spontaneous_loaded] = true
|
19
21
|
end
|
20
22
|
|
23
|
+
# This is called after definition of the Content model.
|
24
|
+
#
|
25
|
+
# Site = Spontaneous.site(Content)
|
26
|
+
#
|
27
|
+
# It is a safe way to define the content model that should be used
|
28
|
+
# globally as it checks for its existance before overwriting.
|
29
|
+
#
|
30
|
+
# I could do the assignment of Spontaneous::Content automatically
|
31
|
+
# after creation of the first content model, but this method provides
|
32
|
+
# a nice way to create the ::Site constant in the user/site code
|
33
|
+
def site(content_model)
|
34
|
+
site!(content_model) unless defined?(Spontaneous::Content)
|
35
|
+
Spontaneous::Site
|
36
|
+
end
|
37
|
+
|
38
|
+
# This forces the assignment of Spontaneous::Content, overwriting any
|
39
|
+
# previous value.
|
40
|
+
#
|
41
|
+
# Used in tests.
|
42
|
+
#
|
43
|
+
def site!(content_model)
|
44
|
+
spot = ::Spontaneous
|
45
|
+
Spontaneous.send :remove_const, :Content if defined?(Spontaneous::Content)
|
46
|
+
Spontaneous.const_set(:Content, content_model)
|
47
|
+
Spontaneous::Site
|
48
|
+
end
|
49
|
+
|
21
50
|
def loaded?
|
22
51
|
Thread.current[:spontaneous_loaded]
|
23
52
|
end
|
@@ -4,31 +4,31 @@ require 'fiber'
|
|
4
4
|
|
5
5
|
module Spontaneous::Plugins::Application
|
6
6
|
module System
|
7
|
-
extend
|
7
|
+
extend Spontaneous::Concern
|
8
8
|
|
9
9
|
module ClassMethods
|
10
10
|
def async?
|
11
11
|
defined?(::EM) && ::EM.reactor_running?
|
12
12
|
end
|
13
13
|
|
14
|
-
def system(cmd, timeout = 10)
|
15
|
-
|
16
|
-
|
14
|
+
def system(cmd, timeout = 10, &callback)
|
15
|
+
if async?
|
16
|
+
async_system(cmd, &callback)
|
17
|
+
else
|
18
|
+
result = super(cmd)
|
19
|
+
callback.call(result) if callback
|
20
|
+
end
|
17
21
|
end
|
18
22
|
|
19
|
-
# Invokes an asynchronous system call
|
20
|
-
|
21
|
-
def async_system(cmd, timeout = 10)
|
23
|
+
# Invokes an asynchronous system call
|
24
|
+
def async_system(cmd, timeout = 10, &callback)
|
22
25
|
deferrable = EM::DefaultDeferrable.new
|
23
|
-
fiber = Fiber.current
|
24
26
|
EM.system cmd do |output, status|
|
25
|
-
deferrable.succeed
|
26
|
-
fiber.resume [output, status]
|
27
|
+
deferrable.succeed(output, status)
|
27
28
|
end
|
28
29
|
deferrable.timeout timeout
|
29
30
|
deferrable.errback { }
|
30
|
-
|
31
|
-
status.success?
|
31
|
+
deferrable.callback(&callback)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
@@ -114,7 +114,7 @@ module Spontaneous::Prototypes
|
|
114
114
|
end
|
115
115
|
|
116
116
|
def default_box_class
|
117
|
-
defined?(::Box) ? ::Box :
|
117
|
+
defined?(::Box) ? ::Box : owner.content_model::Box
|
118
118
|
end
|
119
119
|
|
120
120
|
## failed attempt to exclude anonymous boxes from the list of schema classes
|
@@ -14,7 +14,7 @@ module Spontaneous::Prototypes
|
|
14
14
|
|
15
15
|
# if the type is nil then try the name, this will assign sensible defaults
|
16
16
|
# to fields like 'image' or 'date'
|
17
|
-
@base_class = Spontaneous::
|
17
|
+
@base_class = Spontaneous::Field[type || name]
|
18
18
|
|
19
19
|
owner.const_set("#{name.to_s.camelize}Field", instance_class)
|
20
20
|
|
@@ -25,11 +25,8 @@ module Spontaneous::Prototypes
|
|
25
25
|
"field/#{owner.schema_id}/#{name}"
|
26
26
|
end
|
27
27
|
|
28
|
-
# def schema_id
|
29
|
-
# Spontaneous.schema.schema_id(self)
|
30
|
-
# end
|
31
28
|
def schema_id
|
32
|
-
Spontaneous.schema.uids[@_inherited_schema_id] || Spontaneous.schema.
|
29
|
+
Spontaneous.schema.uids[@_inherited_schema_id] || Spontaneous.schema.to_id(self)
|
33
30
|
end
|
34
31
|
|
35
32
|
def schema_owner
|
@@ -145,7 +142,7 @@ module Spontaneous::Prototypes
|
|
145
142
|
values = { :name => self.name }
|
146
143
|
values[:unprocessed_value] = default(instance) if using_default_values
|
147
144
|
values.update(database_values || {})
|
148
|
-
self.instance_class.new(values,
|
145
|
+
self.instance_class.new(values, using_default_values).tap do |field|
|
149
146
|
field.prototype = self
|
150
147
|
end
|
151
148
|
end
|
@@ -8,11 +8,14 @@ module Spontaneous
|
|
8
8
|
class Immediate
|
9
9
|
include ::Simultaneous::Task
|
10
10
|
|
11
|
-
|
11
|
+
KEEP_REVISIONS = 8
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
attr_reader :revision, :now
|
14
|
+
|
15
|
+
def initialize(revision, content_model)
|
16
|
+
@revision, @content_model = revision, content_model
|
17
|
+
@previous_revision = Spontaneous::Site.published_revision
|
18
|
+
@now = Time.now
|
16
19
|
end
|
17
20
|
|
18
21
|
def renderer
|
@@ -21,9 +24,9 @@ module Spontaneous
|
|
21
24
|
|
22
25
|
def publish_pages(page_list)
|
23
26
|
pages = page_list.flatten.map { |c|
|
24
|
-
c.is_a?(
|
27
|
+
c.is_a?(@content_model::Page) ? c.reload : @content_model::Page[c]
|
25
28
|
}
|
26
|
-
all_pages =
|
29
|
+
all_pages = @content_model::Page.all
|
27
30
|
|
28
31
|
if (all_pages - pages).empty?
|
29
32
|
# publish_all is quicker
|
@@ -55,9 +58,7 @@ module Spontaneous
|
|
55
58
|
|
56
59
|
def rerender_revision
|
57
60
|
logger.info { "Re-rendering revision #{@revision}"}
|
58
|
-
|
59
|
-
render_revision
|
60
|
-
end
|
61
|
+
render_revision
|
61
62
|
end
|
62
63
|
|
63
64
|
protected
|
@@ -70,7 +71,7 @@ module Spontaneous
|
|
70
71
|
|
71
72
|
|
72
73
|
def pages
|
73
|
-
@pages ||=
|
74
|
+
@pages ||= Spontaneous::Site.pages(@content_model)
|
74
75
|
end
|
75
76
|
|
76
77
|
# The number of times the publisher has to run through the site's pages
|
@@ -87,7 +88,7 @@ module Spontaneous
|
|
87
88
|
}
|
88
89
|
before_publish
|
89
90
|
begin
|
90
|
-
|
91
|
+
@content_model.publish(revision, modified_page_list) do
|
91
92
|
render_revision
|
92
93
|
end
|
93
94
|
after_publish
|
@@ -101,11 +102,9 @@ module Spontaneous
|
|
101
102
|
S::Output.renderer = renderer
|
102
103
|
update_progress("rendering", 0)
|
103
104
|
@pages_rendered = 0
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
index_pages unless index_stages == 0
|
108
|
-
end
|
105
|
+
@content_model.scope(@revision, true) do
|
106
|
+
render_pages
|
107
|
+
index_pages unless index_stages == 0
|
109
108
|
end
|
110
109
|
copy_static_files
|
111
110
|
generate_rackup_file
|
@@ -138,12 +137,15 @@ module Spontaneous
|
|
138
137
|
end
|
139
138
|
|
140
139
|
# Used to calculate the progress percentage
|
141
|
-
# Calculated by (pages * indexes)
|
140
|
+
# Calculated by (pages * indexes) + (pages * formats)
|
142
141
|
# where indexes = Site.indexes.length > 0 ? 1 : 0
|
143
142
|
# although not all pages are included by a format
|
144
143
|
def total_pages_to_render
|
145
|
-
@total_pages ||=
|
146
|
-
|
144
|
+
@total_pages ||= \
|
145
|
+
begin
|
146
|
+
index_steps = (index_stages * pages.count)
|
147
|
+
output_steps = pages.map { |page| page.outputs.length }.inject(0, :+)
|
148
|
+
index_steps + output_steps
|
147
149
|
end
|
148
150
|
end
|
149
151
|
|
@@ -188,6 +190,15 @@ module Spontaneous
|
|
188
190
|
File.open(rack_file, 'w') { |f| f.write(template) }
|
189
191
|
end
|
190
192
|
|
193
|
+
# Creates a revisions/REVISION file that contains the directory name of the current
|
194
|
+
# revision. This is useful in deployment because it's a real (non-symlinked) file
|
195
|
+
# that changes with each publish and can hence be used as the target for an
|
196
|
+
# `inotifywait` script that does something with every publish.
|
197
|
+
def generate_revision_file(r)
|
198
|
+
rev_file = Spontaneous.revision_root / 'REVISION'
|
199
|
+
File.open(rev_file, 'w') { |f| f.write(Spontaneous::Media.pad_revision(r)) }
|
200
|
+
end
|
201
|
+
|
191
202
|
def copy_static_files
|
192
203
|
update_progress("copying_files")
|
193
204
|
public_dest = Pathname.new(Spontaneous.revision_dir(revision) / 'public')
|
@@ -202,29 +213,34 @@ module Spontaneous
|
|
202
213
|
def copy_facet_public_files(facet, public_dest)
|
203
214
|
public_dirs = facet.paths.expanded(:public).map { |dir| Pathname.new(dir) }
|
204
215
|
public_dirs.each do |public_src|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
when ".scss"
|
218
|
-
render_sass_template(src, dest)
|
219
|
-
else
|
220
|
-
link_file(src, dest)
|
221
|
-
end
|
222
|
-
end
|
216
|
+
next unless public_src.exist?
|
217
|
+
public_src = public_src.realpath
|
218
|
+
Dir[public_src.to_s / "**/*"].each do |src|
|
219
|
+
src = Pathname.new(src)
|
220
|
+
# insert facet namespace in front of path to keep URLs consistent across
|
221
|
+
# the back & front servers
|
222
|
+
dest = [facet.file_namespace, src.relative_path_from(public_src).to_s].compact
|
223
|
+
dest = (public_dest + File.join(dest))
|
224
|
+
if src.directory?
|
225
|
+
dest.mkpath
|
226
|
+
else
|
227
|
+
copy_public_file(src, dest)
|
223
228
|
end
|
224
229
|
end
|
225
230
|
end
|
226
231
|
end
|
227
232
|
|
233
|
+
def copy_public_file(src, dest)
|
234
|
+
# TODO: Add coffeescript compilation.
|
235
|
+
# Should be implemented using sprockets
|
236
|
+
case src.extname
|
237
|
+
when ".scss"
|
238
|
+
render_sass_template(src, dest)
|
239
|
+
else
|
240
|
+
link_file(src, dest)
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
228
244
|
def link_file(src, dest)
|
229
245
|
src_dev = File::stat(src).dev
|
230
246
|
dst_dev = File::stat(File.dirname(dest)).dev
|
@@ -264,32 +280,41 @@ module Spontaneous
|
|
264
280
|
update_progress("initialising")
|
265
281
|
# when working with multiple instances it's possible to rollback the revision number
|
266
282
|
# leaving behind old revisions > the current published_revision.
|
267
|
-
|
268
|
-
|
283
|
+
@content_model.delete_revision(revision)
|
284
|
+
Spontaneous::Site.send(:pending_revision=, revision)
|
269
285
|
end
|
270
286
|
|
271
287
|
def after_publish
|
272
288
|
update_progress("finalising")
|
273
|
-
S::Revision.create(:revision => revision, :published_at =>
|
274
|
-
|
289
|
+
S::Revision.create(:revision => revision, :published_at => now)
|
290
|
+
Spontaneous::Site.send(:set_published_revision, revision)
|
275
291
|
tmp = Spontaneous.revision_dir(revision) / "tmp"
|
276
292
|
FileUtils.mkdir_p(tmp) unless ::File.exists?(tmp)
|
277
|
-
|
293
|
+
write_revision(revision)
|
278
294
|
|
279
295
|
begin
|
280
|
-
|
281
|
-
|
296
|
+
Spontaneous::Site.trigger(:after_publish, revision)
|
297
|
+
Spontaneous::Site.send(:pending_revision=, nil)
|
298
|
+
Spontaneous::Content.cleanup_revisions(revision, keep_revisions)
|
282
299
|
update_progress("complete")
|
283
300
|
rescue Exception => e
|
284
301
|
# if a post publish hook raises an exception then we want to roll everything back
|
285
302
|
S::Revision.filter(:revision => revision).delete
|
286
|
-
|
287
|
-
|
303
|
+
Spontaneous::Site.send(:set_published_revision, @previous_revision)
|
304
|
+
write_revision(@previous_revision)
|
288
305
|
abort_publish(e)
|
289
306
|
raise e
|
290
307
|
end
|
291
308
|
end
|
292
309
|
|
310
|
+
# Makes the revision live on the filesystem by symlinking the revisions/current
|
311
|
+
# directory to the revision directory and writing the current revision to the
|
312
|
+
# revisions/REVISION file.
|
313
|
+
def write_revision(revision)
|
314
|
+
symlink_revision(revision)
|
315
|
+
generate_revision_file(revision)
|
316
|
+
end
|
317
|
+
|
293
318
|
def symlink_revision(rev)
|
294
319
|
system("ln -nsf #{Spontaneous.revision_dir(rev)} #{Spontaneous.revision_dir}")
|
295
320
|
end
|
@@ -302,12 +327,15 @@ module Spontaneous
|
|
302
327
|
if r = S::Site.pending_revision
|
303
328
|
update_progress("aborting")
|
304
329
|
FileUtils.rm_r(Spontaneous.revision_dir(revision)) if File.exists?(Spontaneous.revision_dir(revision))
|
305
|
-
|
306
|
-
|
330
|
+
Spontaneous::Site.send(:pending_revision=, nil)
|
331
|
+
@content_model.delete_revision(revision)
|
307
332
|
puts exception.backtrace.join("\n") if exception
|
308
|
-
update_progress("error", exception)
|
309
333
|
end
|
310
334
|
end
|
335
|
+
|
336
|
+
def keep_revisions
|
337
|
+
Spontaneous::Site.config.keep_revisions || KEEP_REVISIONS
|
338
|
+
end
|
311
339
|
end # Immediate
|
312
340
|
end # Publishing
|
313
341
|
end # Spontaneous
|