yodel 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +9 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +63 -0
- data/LICENSE +1 -0
- data/README.rdoc +20 -0
- data/Rakefile +1 -0
- data/bin/yodel +4 -0
- data/lib/yodel.rb +22 -0
- data/lib/yodel/application/application.rb +44 -0
- data/lib/yodel/application/extension.rb +59 -0
- data/lib/yodel/application/request_handler.rb +48 -0
- data/lib/yodel/application/yodel.rb +25 -0
- data/lib/yodel/command/command.rb +94 -0
- data/lib/yodel/command/deploy.rb +67 -0
- data/lib/yodel/command/dns_server.rb +16 -0
- data/lib/yodel/command/installer.rb +229 -0
- data/lib/yodel/config/config.rb +30 -0
- data/lib/yodel/config/environment.rb +16 -0
- data/lib/yodel/config/yodel.rb +21 -0
- data/lib/yodel/exceptions/destroyed_record.rb +2 -0
- data/lib/yodel/exceptions/domain_not_found.rb +16 -0
- data/lib/yodel/exceptions/duplicate_layout.rb +2 -0
- data/lib/yodel/exceptions/exceptions.rb +3 -0
- data/lib/yodel/exceptions/inconsistent_lock_state.rb +2 -0
- data/lib/yodel/exceptions/invalid_field.rb +2 -0
- data/lib/yodel/exceptions/invalid_index.rb +2 -0
- data/lib/yodel/exceptions/invalid_mixin.rb +2 -0
- data/lib/yodel/exceptions/invalid_model_field.rb +2 -0
- data/lib/yodel/exceptions/layout_not_found.rb +2 -0
- data/lib/yodel/exceptions/mass_assignment.rb +2 -0
- data/lib/yodel/exceptions/missing_migration.rb +2 -0
- data/lib/yodel/exceptions/missing_root_directory.rb +15 -0
- data/lib/yodel/exceptions/unable_to_acquire_lock.rb +2 -0
- data/lib/yodel/exceptions/unauthorised.rb +2 -0
- data/lib/yodel/exceptions/unknown_field.rb +2 -0
- data/lib/yodel/middleware/development_server.rb +180 -0
- data/lib/yodel/middleware/error_pages.rb +72 -0
- data/lib/yodel/middleware/public_assets.rb +78 -0
- data/lib/yodel/middleware/request.rb +16 -0
- data/lib/yodel/middleware/site_detector.rb +22 -0
- data/lib/yodel/mime_types/default_mime_set.rb +28 -0
- data/lib/yodel/mime_types/mime_type.rb +68 -0
- data/lib/yodel/mime_types/mime_type_set.rb +41 -0
- data/lib/yodel/mime_types/mime_types.rb +6 -0
- data/lib/yodel/mime_types/yodel.rb +15 -0
- data/lib/yodel/models/api/api.rb +1 -0
- data/lib/yodel/models/api/api_call.rb +87 -0
- data/lib/yodel/models/core/associations/association.rb +37 -0
- data/lib/yodel/models/core/associations/associations.rb +22 -0
- data/lib/yodel/models/core/associations/counts/many_association.rb +18 -0
- data/lib/yodel/models/core/associations/counts/one_association.rb +22 -0
- data/lib/yodel/models/core/associations/embedded/embedded_association.rb +47 -0
- data/lib/yodel/models/core/associations/embedded/embedded_record_array.rb +12 -0
- data/lib/yodel/models/core/associations/embedded/many_embedded_association.rb +62 -0
- data/lib/yodel/models/core/associations/embedded/one_embedded_association.rb +49 -0
- data/lib/yodel/models/core/associations/query/many_query_association.rb +10 -0
- data/lib/yodel/models/core/associations/query/one_query_association.rb +10 -0
- data/lib/yodel/models/core/associations/query/query_association.rb +64 -0
- data/lib/yodel/models/core/associations/record_association.rb +38 -0
- data/lib/yodel/models/core/associations/store/many_store_association.rb +32 -0
- data/lib/yodel/models/core/associations/store/one_store_association.rb +14 -0
- data/lib/yodel/models/core/associations/store/store_association.rb +51 -0
- data/lib/yodel/models/core/attachments/attachment.rb +73 -0
- data/lib/yodel/models/core/attachments/image.rb +38 -0
- data/lib/yodel/models/core/core.rb +15 -0
- data/lib/yodel/models/core/fields/alias_field.rb +32 -0
- data/lib/yodel/models/core/fields/array_field.rb +64 -0
- data/lib/yodel/models/core/fields/attachment_field.rb +42 -0
- data/lib/yodel/models/core/fields/boolean_field.rb +28 -0
- data/lib/yodel/models/core/fields/change_sensitive_array.rb +96 -0
- data/lib/yodel/models/core/fields/change_sensitive_hash.rb +53 -0
- data/lib/yodel/models/core/fields/color_field.rb +4 -0
- data/lib/yodel/models/core/fields/date_field.rb +35 -0
- data/lib/yodel/models/core/fields/decimal_field.rb +19 -0
- data/lib/yodel/models/core/fields/email_field.rb +10 -0
- data/lib/yodel/models/core/fields/enum_field.rb +33 -0
- data/lib/yodel/models/core/fields/field.rb +154 -0
- data/lib/yodel/models/core/fields/fields.rb +29 -0
- data/lib/yodel/models/core/fields/fields_field.rb +31 -0
- data/lib/yodel/models/core/fields/filter_mixin.rb +9 -0
- data/lib/yodel/models/core/fields/filtered_string_field.rb +5 -0
- data/lib/yodel/models/core/fields/filtered_text_field.rb +5 -0
- data/lib/yodel/models/core/fields/function_field.rb +28 -0
- data/lib/yodel/models/core/fields/hash_field.rb +54 -0
- data/lib/yodel/models/core/fields/html_field.rb +15 -0
- data/lib/yodel/models/core/fields/image_field.rb +11 -0
- data/lib/yodel/models/core/fields/integer_field.rb +25 -0
- data/lib/yodel/models/core/fields/password_field.rb +21 -0
- data/lib/yodel/models/core/fields/self_field.rb +27 -0
- data/lib/yodel/models/core/fields/string_field.rb +15 -0
- data/lib/yodel/models/core/fields/tags_field.rb +7 -0
- data/lib/yodel/models/core/fields/text_field.rb +7 -0
- data/lib/yodel/models/core/fields/time_field.rb +36 -0
- data/lib/yodel/models/core/functions/function.rb +471 -0
- data/lib/yodel/models/core/functions/functions.rb +2 -0
- data/lib/yodel/models/core/functions/trigger.rb +14 -0
- data/lib/yodel/models/core/log/log.rb +33 -0
- data/lib/yodel/models/core/log/log_entry.rb +12 -0
- data/lib/yodel/models/core/model/abstract_model.rb +59 -0
- data/lib/yodel/models/core/model/model.rb +460 -0
- data/lib/yodel/models/core/model/mongo_model.rb +25 -0
- data/lib/yodel/models/core/model/site_model.rb +17 -0
- data/lib/yodel/models/core/mongo/mongo.rb +3 -0
- data/lib/yodel/models/core/mongo/primary_key_factory.rb +12 -0
- data/lib/yodel/models/core/mongo/query.rb +68 -0
- data/lib/yodel/models/core/mongo/record_index.rb +89 -0
- data/lib/yodel/models/core/record/abstract_record.rb +411 -0
- data/lib/yodel/models/core/record/embedded_record.rb +47 -0
- data/lib/yodel/models/core/record/mongo_record.rb +83 -0
- data/lib/yodel/models/core/record/record.rb +386 -0
- data/lib/yodel/models/core/record/section.rb +21 -0
- data/lib/yodel/models/core/record/site_record.rb +31 -0
- data/lib/yodel/models/core/site/migration.rb +52 -0
- data/lib/yodel/models/core/site/remote.rb +61 -0
- data/lib/yodel/models/core/site/site.rb +202 -0
- data/lib/yodel/models/core/validations/email_address_validation.rb +24 -0
- data/lib/yodel/models/core/validations/embedded_records_validation.rb +31 -0
- data/lib/yodel/models/core/validations/errors.rb +51 -0
- data/lib/yodel/models/core/validations/excluded_from_validation.rb +10 -0
- data/lib/yodel/models/core/validations/excludes_combinations_validation.rb +18 -0
- data/lib/yodel/models/core/validations/format_validation.rb +10 -0
- data/lib/yodel/models/core/validations/included_in_validation.rb +10 -0
- data/lib/yodel/models/core/validations/includes_combinations_validation.rb +14 -0
- data/lib/yodel/models/core/validations/length_validation.rb +28 -0
- data/lib/yodel/models/core/validations/password_confirmation_validation.rb +11 -0
- data/lib/yodel/models/core/validations/required_validation.rb +9 -0
- data/lib/yodel/models/core/validations/unique_validation.rb +9 -0
- data/lib/yodel/models/core/validations/validation.rb +39 -0
- data/lib/yodel/models/core/validations/validations.rb +15 -0
- data/lib/yodel/models/email/email.rb +79 -0
- data/lib/yodel/models/migrations/01_record_model.rb +29 -0
- data/lib/yodel/models/migrations/02_page_model.rb +45 -0
- data/lib/yodel/models/migrations/03_layout_model.rb +38 -0
- data/lib/yodel/models/migrations/04_group_model.rb +61 -0
- data/lib/yodel/models/migrations/05_user_model.rb +24 -0
- data/lib/yodel/models/migrations/06_snippet_model.rb +13 -0
- data/lib/yodel/models/migrations/07_search_page_model.rb +32 -0
- data/lib/yodel/models/migrations/08_default_site_options.rb +21 -0
- data/lib/yodel/models/migrations/09_security_page_models.rb +36 -0
- data/lib/yodel/models/migrations/10_record_proxy_page_model.rb +17 -0
- data/lib/yodel/models/migrations/11_email_model.rb +28 -0
- data/lib/yodel/models/migrations/12_api_call_model.rb +23 -0
- data/lib/yodel/models/migrations/13_redirect_page_model.rb +13 -0
- data/lib/yodel/models/migrations/14_menu_model.rb +20 -0
- data/lib/yodel/models/models.rb +8 -0
- data/lib/yodel/models/pages/form_builder.rb +379 -0
- data/lib/yodel/models/pages/html_decorator.rb +132 -0
- data/lib/yodel/models/pages/layout.rb +120 -0
- data/lib/yodel/models/pages/menu.rb +32 -0
- data/lib/yodel/models/pages/page.rb +378 -0
- data/lib/yodel/models/pages/pages.rb +7 -0
- data/lib/yodel/models/pages/record_proxy_page.rb +188 -0
- data/lib/yodel/models/pages/redirect_page.rb +11 -0
- data/lib/yodel/models/search/search.rb +1 -0
- data/lib/yodel/models/search/search_page.rb +58 -0
- data/lib/yodel/models/security/facebook_login_page.rb +55 -0
- data/lib/yodel/models/security/group.rb +10 -0
- data/lib/yodel/models/security/guests_group.rb +5 -0
- data/lib/yodel/models/security/login_page.rb +20 -0
- data/lib/yodel/models/security/logout_page.rb +13 -0
- data/lib/yodel/models/security/noone_group.rb +5 -0
- data/lib/yodel/models/security/owner_group.rb +8 -0
- data/lib/yodel/models/security/password.rb +5 -0
- data/lib/yodel/models/security/password_reset_page.rb +47 -0
- data/lib/yodel/models/security/security.rb +10 -0
- data/lib/yodel/models/security/user.rb +33 -0
- data/lib/yodel/public/core/css/core.css +257 -0
- data/lib/yodel/public/core/css/reset.css +48 -0
- data/lib/yodel/public/core/images/cross.png +0 -0
- data/lib/yodel/public/core/images/spinner.gif +0 -0
- data/lib/yodel/public/core/images/tick.png +0 -0
- data/lib/yodel/public/core/images/yodel.png +0 -0
- data/lib/yodel/public/core/js/jquery.min.js +18 -0
- data/lib/yodel/public/core/js/json2.js +480 -0
- data/lib/yodel/public/core/js/yodel_jquery.js +238 -0
- data/lib/yodel/request/authentication.rb +76 -0
- data/lib/yodel/request/flash.rb +28 -0
- data/lib/yodel/request/request.rb +4 -0
- data/lib/yodel/requires.rb +47 -0
- data/lib/yodel/task_queue/queue_daemon.rb +33 -0
- data/lib/yodel/task_queue/queue_worker.rb +32 -0
- data/lib/yodel/task_queue/stats_thread.rb +27 -0
- data/lib/yodel/task_queue/task.rb +62 -0
- data/lib/yodel/task_queue/task_queue.rb +40 -0
- data/lib/yodel/types/date.rb +5 -0
- data/lib/yodel/types/object_id.rb +11 -0
- data/lib/yodel/types/time.rb +5 -0
- data/lib/yodel/version.rb +3 -0
- data/system/Library/LaunchDaemons/com.yodelcms.dns.plist +26 -0
- data/system/Library/LaunchDaemons/com.yodelcms.server.plist +26 -0
- data/system/etc/resolver/yodel +2 -0
- data/system/usr/local/bin/yodel_command_runner +2 -0
- data/system/usr/local/etc/yodel/development_settings.rb +28 -0
- data/system/usr/local/etc/yodel/production_settings.rb +27 -0
- data/system/var/log/yodel.log +0 -0
- data/test/helper.rb +18 -0
- data/test/test_yodel.rb +4 -0
- data/yodel.gemspec +47 -0
- metadata +501 -0
@@ -0,0 +1,10 @@
|
|
1
|
+
class ExcludedFromValidation < Validation
|
2
|
+
def self.validate(params, field, name, value, record, errors)
|
3
|
+
prohibited_values = params['prohibited_values']
|
4
|
+
errors[field.name] << new(prohibited_values) if prohibited_values.include?(value)
|
5
|
+
end
|
6
|
+
|
7
|
+
def describe
|
8
|
+
"must not be: #{params.join(', ')}"
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class ExcludesCombinationsValidation < Validation
|
2
|
+
def self.validate(params, field, name, value, record, errors)
|
3
|
+
combinations = params['combinations']
|
4
|
+
combinations.each do |excluded_combination|
|
5
|
+
fail = excluded_combination.all? {|prohibited| value.include?(prohibited)}
|
6
|
+
(errors[field.name] << new(combinations)) and return if fail
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def describe
|
11
|
+
if params.size > 1
|
12
|
+
combinations = params.collect.with_index {|combo, index| "#{index + 1}. #{combo.to_sentence}"}
|
13
|
+
else
|
14
|
+
combinations = [params.first.to_sentence]
|
15
|
+
end
|
16
|
+
"may not contain #{combinations.size == 1 ? 'this' : 'these'} combination#{'s' if combinations.size > 1}: #{combinations.to_sentence(two_words_connector: ', and ')}"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class FormatValidation < Validation
|
2
|
+
def self.validate(params, field, name, value, record, errors)
|
3
|
+
format = params['format']
|
4
|
+
errors[field.name] << new(format) unless value =~ Regexp.new(format)
|
5
|
+
end
|
6
|
+
|
7
|
+
def describe
|
8
|
+
"is not in the required format"
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class IncludedInValidation < Validation
|
2
|
+
def self.validate(params, field, name, value, record, errors)
|
3
|
+
valid_values = params['valid_values']
|
4
|
+
errors[field.name] << new(valid_values) unless valid_values.include?(value)
|
5
|
+
end
|
6
|
+
|
7
|
+
def describe
|
8
|
+
"must be one of: #{params.join(', ')}"
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class IncludesCombinationsValidation < Validation
|
2
|
+
def self.validate(params, field, name, value, record, errors)
|
3
|
+
combinations = params['combinations']
|
4
|
+
combinations.each do |included_combination|
|
5
|
+
return if included_combination.all? {|required| value.include?(required)}
|
6
|
+
end
|
7
|
+
errors[field.name] << new(combinations)
|
8
|
+
end
|
9
|
+
|
10
|
+
def describe
|
11
|
+
combinations = params.collect(&:to_s).join(', ')
|
12
|
+
"must contain one of these combinations: #{combinations}"
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class LengthValidation < Validation
|
2
|
+
def self.validate(params, field, name, value, record, errors)
|
3
|
+
length = params['length']
|
4
|
+
min, max = length
|
5
|
+
|
6
|
+
if min == 0
|
7
|
+
valid = (value.size <= max)
|
8
|
+
elsif max == 0
|
9
|
+
valid = (value.size >= min)
|
10
|
+
else
|
11
|
+
valid = (value.size >= min) && (value.size <= max)
|
12
|
+
end
|
13
|
+
|
14
|
+
errors[field.name] << new(length) unless valid
|
15
|
+
end
|
16
|
+
|
17
|
+
def describe
|
18
|
+
min, max = params
|
19
|
+
|
20
|
+
if min == 0
|
21
|
+
"is too long (maximum length is #{max})"
|
22
|
+
elsif max == 0
|
23
|
+
"is too short (minimum length is #{min})"
|
24
|
+
else
|
25
|
+
"must be between #{min} and #{max}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class PasswordConfirmationValidation < Validation
|
2
|
+
def self.validate(params, field, name, value, record, errors)
|
3
|
+
return if record.field_was(field.name).nil? || record.stash["current_#{name}"].nil? || !record.respond_to?(:passwords_match?)
|
4
|
+
match = record.passwords_match?(record.stash["current_#{name}"])
|
5
|
+
errors[field.name] << new(name) unless match
|
6
|
+
end
|
7
|
+
|
8
|
+
def describe
|
9
|
+
"didn't match your existing #{params}"
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class Validation
|
2
|
+
attr_accessor :params, :field
|
3
|
+
|
4
|
+
def self.validate(type, params, field, name, value, record, errors)
|
5
|
+
validation = case type
|
6
|
+
when 'excluded_from'
|
7
|
+
ExcludedFromValidation
|
8
|
+
when 'excludes_combinations'
|
9
|
+
ExcludesCombinationsValidation
|
10
|
+
when 'format'
|
11
|
+
FormatValidation
|
12
|
+
when 'included_in'
|
13
|
+
IncludedInValidation
|
14
|
+
when 'includes_combinations'
|
15
|
+
IncludesCombinationsValidation
|
16
|
+
when 'length'
|
17
|
+
LengthValidation
|
18
|
+
when 'required'
|
19
|
+
RequiredValidation
|
20
|
+
when 'unique'
|
21
|
+
UniqueValidation
|
22
|
+
when 'password_confirmation'
|
23
|
+
PasswordConfirmationValidation
|
24
|
+
end
|
25
|
+
validation.validate(params, field, name, value, record, errors)
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(params)
|
29
|
+
@params = params
|
30
|
+
end
|
31
|
+
|
32
|
+
def describe
|
33
|
+
"is invalid"
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_json(*a)
|
37
|
+
describe.to_json(*a)
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Dir.chdir(File.dirname(__FILE__)) do
|
2
|
+
require './validation'
|
3
|
+
require './email_address_validation'
|
4
|
+
require './embedded_records_validation'
|
5
|
+
require './errors'
|
6
|
+
require './excluded_from_validation'
|
7
|
+
require './excludes_combinations_validation'
|
8
|
+
require './format_validation'
|
9
|
+
require './included_in_validation'
|
10
|
+
require './includes_combinations_validation'
|
11
|
+
require './length_validation'
|
12
|
+
require './password_confirmation_validation'
|
13
|
+
require './required_validation'
|
14
|
+
require './unique_validation'
|
15
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class Email < Record
|
2
|
+
|
3
|
+
def deliver(options)
|
4
|
+
# we don't store complete records in the queue task, only IDs of records
|
5
|
+
cleaned = {_id: self.id}
|
6
|
+
options.each do |key, value|
|
7
|
+
if value.is_a?(Record)
|
8
|
+
value = {_id: value.id}
|
9
|
+
end
|
10
|
+
cleaned[key] = value
|
11
|
+
end
|
12
|
+
|
13
|
+
Task.add_task(:deliver_email, cleaned, site)
|
14
|
+
end
|
15
|
+
|
16
|
+
def perform_delivery(options)
|
17
|
+
mail = Mail.new
|
18
|
+
|
19
|
+
# retrieve records that were replaced with their ID as above
|
20
|
+
options.each do |key, value|
|
21
|
+
if value.is_a?(Hash) && value.key?('_id')
|
22
|
+
options[key] = site.records.find(value['_id'])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# email headers
|
27
|
+
%w{to from cc bcc subject}.each do |param|
|
28
|
+
options[param] ||= options[param.to_sym] || self.send(param)
|
29
|
+
mail.send("#{param}=", options[param])
|
30
|
+
end
|
31
|
+
render_binding = binding
|
32
|
+
|
33
|
+
# rendered text body
|
34
|
+
unless text_body.blank?
|
35
|
+
text_body = self.text_body
|
36
|
+
text_part = Mail::Part.new do
|
37
|
+
body Ember::Template.new(text_body).render(render_binding)
|
38
|
+
end
|
39
|
+
mail.text_part = text_part
|
40
|
+
end
|
41
|
+
|
42
|
+
# rendered html body
|
43
|
+
unless html_body.blank?
|
44
|
+
html_body = self.html_body
|
45
|
+
# FIXME: reloading should be done elsewhere, not a concern of email
|
46
|
+
#Layout.reload_layouts(site) if Yodel.env.development?
|
47
|
+
if self.html_layout && layout = site.layouts.where(name: self.html_layout, mime_type: :html).first
|
48
|
+
@content = Ember::Template.new(html_body).render(render_binding)
|
49
|
+
@binding = render_binding
|
50
|
+
html_content = layout.render(self)
|
51
|
+
else
|
52
|
+
html_content = Ember::Template.new(html_body).render(render_binding)
|
53
|
+
end
|
54
|
+
html_part = Mail::Part.new do
|
55
|
+
content_type 'text/html; charset=UTF-8'
|
56
|
+
body html_content
|
57
|
+
end
|
58
|
+
mail.html_part = html_part
|
59
|
+
end
|
60
|
+
|
61
|
+
mail.deliver!
|
62
|
+
end
|
63
|
+
|
64
|
+
def content
|
65
|
+
@content
|
66
|
+
end
|
67
|
+
|
68
|
+
def set_content(content)
|
69
|
+
@content = content
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_binding
|
73
|
+
@binding
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_binding(binding)
|
77
|
+
@binding = binding
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class RecordModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
records = Model.new(site, name: 'Record')
|
4
|
+
records.modify do |records|
|
5
|
+
# identity, hierarchy and search
|
6
|
+
add_many :children, model: :record, foreign_key: 'parent', order: 'index asc', display: false
|
7
|
+
add_field :index, :integer, validations: {required: {}}, display: false
|
8
|
+
add_one :owner, model: :user, display: false
|
9
|
+
add_field :name, :string
|
10
|
+
add_field :show_in_search, :boolean, default: true, section: 'Options'
|
11
|
+
add_field :search_keywords, :array, of: :string, display: false
|
12
|
+
add_field :search_title, :string, display: false
|
13
|
+
|
14
|
+
# modelling
|
15
|
+
add_one :eigenmodel, model: :model, destroy: true, display: false
|
16
|
+
add_one :parent, model: :record, index: true, display: false
|
17
|
+
add_one :model, index: true, display: false
|
18
|
+
records.descendants = [records]
|
19
|
+
end
|
20
|
+
|
21
|
+
site.model_types['records'] = records.id
|
22
|
+
site.model_plural_names['Record'] = 'records'
|
23
|
+
site.save
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.down(site)
|
27
|
+
site.records.destroy
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class PageModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.records.create_model :pages do |pages|
|
4
|
+
# core page attributes
|
5
|
+
add_field :permalink, :string, validations: {required: {}}, index: true, searchable: false, display: false
|
6
|
+
add_field :path, :string, validations: {required: {}}, index: true, searchable: false, display: false
|
7
|
+
add_field :created_at, :time, display: false
|
8
|
+
add_field :title, :string, validations: {required: {}}
|
9
|
+
add_field :content, :html
|
10
|
+
|
11
|
+
# options section
|
12
|
+
add_field :show_in_menus, :boolean, default: true, section: 'Options'
|
13
|
+
add_field :description, :text, section: 'Options', searchable: false
|
14
|
+
add_field :keywords, :text, section: 'Options', searchable: false
|
15
|
+
add_field :custom_meta_tags, :text, section: 'Options', searchable: false
|
16
|
+
add_one :new_child_page, model: :page, section: 'Options', show_blank: true, blank_text: 'None'
|
17
|
+
|
18
|
+
# layout
|
19
|
+
add_field :page_layout, :string, section: 'Options', default: nil, searchable: false
|
20
|
+
add_one :page_layout_record, model: :layout, display: false
|
21
|
+
add_field :edit_layout, :string, searchable: false, section: 'Options'
|
22
|
+
add_one :edit_layout_record, model: :layout, display: false
|
23
|
+
|
24
|
+
add_field :name, :alias, of: :title
|
25
|
+
pages.default_child_model = pages.id
|
26
|
+
pages.allowed_children = [pages]
|
27
|
+
pages.allowed_parents = [pages]
|
28
|
+
pages.record_class_name = 'Page'
|
29
|
+
end
|
30
|
+
|
31
|
+
# glob pages are normal pages, but match paths with components at the end
|
32
|
+
# of the page's path, e.g /git/HEAD would match the glob page /git
|
33
|
+
site.pages.create_model :glob_pages do |glob_pages|
|
34
|
+
end
|
35
|
+
|
36
|
+
# default root page
|
37
|
+
page = site.pages.new
|
38
|
+
page.title = "Home"
|
39
|
+
page.save
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.down(site)
|
43
|
+
site.pages.destroy
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class LayoutModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.records.create_model :layouts do |layouts|
|
4
|
+
add_field :name, :string, validations: {required: {}}, index: true
|
5
|
+
add_field :mime_type, :string, validations: {required: {}}, index: true
|
6
|
+
|
7
|
+
layouts.allowed_children = []
|
8
|
+
layouts.allowed_parents = []
|
9
|
+
layouts.searchable = false
|
10
|
+
layouts.record_class_name = 'Layout'
|
11
|
+
end
|
12
|
+
|
13
|
+
site.layouts.create_model :persistent_layouts do |persistent_layouts|
|
14
|
+
add_field :markup, :html, validations: {required: {}}
|
15
|
+
add_many :pages, foreign_key: 'page_layout_record'
|
16
|
+
|
17
|
+
persistent_layouts.allowed_children = [persistent_layouts]
|
18
|
+
persistent_layouts.allowed_parents = [persistent_layouts]
|
19
|
+
persistent_layouts.searchable = false
|
20
|
+
persistent_layouts.record_class_name = 'PersistentLayout'
|
21
|
+
end
|
22
|
+
|
23
|
+
site.layouts.create_model :file_layouts do |file_layouts|
|
24
|
+
add_field :path, :string, validations: {required: {}}
|
25
|
+
|
26
|
+
file_layouts.allowed_children = [file_layouts]
|
27
|
+
file_layouts.allowed_parents = [file_layouts]
|
28
|
+
file_layouts.searchable = false
|
29
|
+
file_layouts.record_class_name = 'FileLayout'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.down(site)
|
34
|
+
site.layouts.destroy
|
35
|
+
site.persistent_layouts.destroy
|
36
|
+
site.file_layouts.destroy
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class GroupModelMigration < Migration
|
2
|
+
def self.up(site)
|
3
|
+
site.records.create_model :groups do |groups|
|
4
|
+
add_field :name, :string, validations: {required: {}}
|
5
|
+
add_many :users, store: false
|
6
|
+
groups.icon = '/admin/images/group_icon.png'
|
7
|
+
groups.record_class_name = 'Group'
|
8
|
+
end
|
9
|
+
site.reload
|
10
|
+
|
11
|
+
# a special singleton group representing an 'owner' of a record
|
12
|
+
site.groups.create_model :owner_groups do |group|
|
13
|
+
group.record_class_name = 'OwnerGroup'
|
14
|
+
end
|
15
|
+
site.reload
|
16
|
+
|
17
|
+
# a special singleton group representing no one
|
18
|
+
site.groups.create_model :noone_groups do |group|
|
19
|
+
group.record_class_name = 'NooneGroup'
|
20
|
+
end
|
21
|
+
site.reload
|
22
|
+
|
23
|
+
# a special singleton group representing 'everyone'
|
24
|
+
site.groups.create_model :guest_groups do |group|
|
25
|
+
group.record_class_name = 'GuestsGroup'
|
26
|
+
end
|
27
|
+
site.reload
|
28
|
+
|
29
|
+
|
30
|
+
# permissions are based on a hierarchy of groups. branches are permitted.
|
31
|
+
noone = site.noone_groups.new(name: 'No One')
|
32
|
+
noone.save
|
33
|
+
|
34
|
+
devs = site.groups.new(name: 'Developers')
|
35
|
+
devs.parent = noone
|
36
|
+
devs.save
|
37
|
+
|
38
|
+
admins = site.groups.new(name: 'Administrators')
|
39
|
+
admins.parent = devs
|
40
|
+
admins.save
|
41
|
+
|
42
|
+
owner = site.owner_groups.new(name: 'Owner')
|
43
|
+
owner.parent = admins
|
44
|
+
owner.save
|
45
|
+
|
46
|
+
users = site.groups.new(name: 'Users')
|
47
|
+
users.parent = owner
|
48
|
+
users.save
|
49
|
+
|
50
|
+
guests = site.guest_groups.new(name: 'Guests')
|
51
|
+
guests.parent = users
|
52
|
+
guests.save
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.down(site)
|
56
|
+
site.groups.destroy
|
57
|
+
site.owner_groups.destroy
|
58
|
+
site.noone_groups.destroy
|
59
|
+
site.guest_groups.destroy
|
60
|
+
end
|
61
|
+
end
|