yodel 0.0.1
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.
- 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
data/.document
ADDED
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
yodel (0.0.1)
|
|
5
|
+
activesupport (~> 3.0.3)
|
|
6
|
+
bson (~> 1.3.1)
|
|
7
|
+
bson_ext (~> 1.3.1)
|
|
8
|
+
bundler (~> 1.0.21)
|
|
9
|
+
ember (~> 0.3.1)
|
|
10
|
+
git (~> 1.2.5)
|
|
11
|
+
highline (~> 1.6.2)
|
|
12
|
+
hpricot (~> 0.8.4)
|
|
13
|
+
json (~> 1.6.1)
|
|
14
|
+
mail (~> 2.3.0)
|
|
15
|
+
mini_magick (~> 3.3)
|
|
16
|
+
mongo (~> 1.3.1)
|
|
17
|
+
plucky (~> 0.4.1)
|
|
18
|
+
rack (~> 1.3.3)
|
|
19
|
+
rack-contrib (~> 1.1.0)
|
|
20
|
+
rubydns (~> 0.3.3)
|
|
21
|
+
|
|
22
|
+
GEM
|
|
23
|
+
remote: http://rubygems.org/
|
|
24
|
+
specs:
|
|
25
|
+
activesupport (3.0.11)
|
|
26
|
+
bson (1.3.1)
|
|
27
|
+
bson_ext (1.3.1)
|
|
28
|
+
ember (0.3.1)
|
|
29
|
+
eventmachine (0.12.10)
|
|
30
|
+
git (1.2.5)
|
|
31
|
+
highline (1.6.8)
|
|
32
|
+
hpricot (0.8.4)
|
|
33
|
+
i18n (0.6.0)
|
|
34
|
+
json (1.6.1)
|
|
35
|
+
mail (2.3.0)
|
|
36
|
+
i18n (>= 0.4.0)
|
|
37
|
+
mime-types (~> 1.16)
|
|
38
|
+
treetop (~> 1.4.8)
|
|
39
|
+
mime-types (1.17.2)
|
|
40
|
+
mini_magick (3.3)
|
|
41
|
+
subexec (~> 0.1.0)
|
|
42
|
+
mongo (1.3.1)
|
|
43
|
+
bson (>= 1.3.1)
|
|
44
|
+
plucky (0.4.3)
|
|
45
|
+
mongo (~> 1.3)
|
|
46
|
+
polyglot (0.3.3)
|
|
47
|
+
rack (1.3.5)
|
|
48
|
+
rack-contrib (1.1.0)
|
|
49
|
+
rack (>= 0.9.1)
|
|
50
|
+
rexec (1.4.1)
|
|
51
|
+
rubydns (0.3.3)
|
|
52
|
+
eventmachine
|
|
53
|
+
rexec
|
|
54
|
+
subexec (0.1.0)
|
|
55
|
+
treetop (1.4.10)
|
|
56
|
+
polyglot
|
|
57
|
+
polyglot (>= 0.3.1)
|
|
58
|
+
|
|
59
|
+
PLATFORMS
|
|
60
|
+
ruby
|
|
61
|
+
|
|
62
|
+
DEPENDENCIES
|
|
63
|
+
yodel!
|
data/LICENSE
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Public Domain
|
data/README.rdoc
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
= Yodel
|
|
2
|
+
|
|
3
|
+
Rack based Ruby CMS.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
== Contributing to yodel
|
|
7
|
+
|
|
8
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
|
9
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
|
10
|
+
* Fork the project
|
|
11
|
+
* Start a feature/bugfix branch
|
|
12
|
+
* Commit and push until you are happy with your contribution
|
|
13
|
+
* Make sure you add tests for it
|
|
14
|
+
* Please try not to mess with the Rakefile, version, or history.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
== Areas to clean
|
|
18
|
+
|
|
19
|
+
* Adding/deleting/iterating over fields of models, eigenmodels and embedded models
|
|
20
|
+
* embedded model to_json/to_html field etc, is essentially the same as a normal record
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/bin/yodel
ADDED
data/lib/yodel.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Dir.chdir(File.join(File.dirname(__FILE__), 'yodel')) do
|
|
2
|
+
# ensure gem dependencies are loaded
|
|
3
|
+
require './requires'
|
|
4
|
+
|
|
5
|
+
# rack extensions
|
|
6
|
+
require './middleware/request'
|
|
7
|
+
require './middleware/error_pages'
|
|
8
|
+
require './middleware/site_detector'
|
|
9
|
+
|
|
10
|
+
# type extensions
|
|
11
|
+
require './types/date'
|
|
12
|
+
require './types/object_id'
|
|
13
|
+
require './types/time'
|
|
14
|
+
|
|
15
|
+
# core yodel
|
|
16
|
+
require './application/application'
|
|
17
|
+
require './exceptions/exceptions'
|
|
18
|
+
require './mime_types/mime_types'
|
|
19
|
+
require './request/request'
|
|
20
|
+
require './models/models'
|
|
21
|
+
require './task_queue/task_queue'
|
|
22
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
Dir.chdir(File.dirname(__FILE__)) do
|
|
2
|
+
require './request_handler'
|
|
3
|
+
require './extension'
|
|
4
|
+
require './yodel'
|
|
5
|
+
require '../middleware/public_assets' if Yodel.env.development?
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class Application < Rack::Builder
|
|
9
|
+
def initialize
|
|
10
|
+
super
|
|
11
|
+
|
|
12
|
+
# boot
|
|
13
|
+
Yodel.config.logger.info "Yodel starting up" if Yodel.env.production?
|
|
14
|
+
Dir.chdir(Yodel.config.sites_root)
|
|
15
|
+
Yodel.load_extensions
|
|
16
|
+
|
|
17
|
+
# setup middleware
|
|
18
|
+
use Rack::ShowExceptions if Yodel.env.development?
|
|
19
|
+
use ErrorPages
|
|
20
|
+
use Rack::Session::Cookie, key: Yodel.config.session_key, secret: Yodel.config.session_secret
|
|
21
|
+
use Rack::NestedParams
|
|
22
|
+
use Rack::MethodOverride
|
|
23
|
+
use SiteDetector
|
|
24
|
+
use PublicAssets if Yodel.env.development?
|
|
25
|
+
|
|
26
|
+
# FIXME: for production, load layouts once
|
|
27
|
+
if Yodel.env.production?
|
|
28
|
+
Site.all.each {|site| Layout.reload_layouts(site)}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# initialise a rack endpoint
|
|
32
|
+
run RequestHandler.new
|
|
33
|
+
@app = to_app
|
|
34
|
+
|
|
35
|
+
# boot complete
|
|
36
|
+
unless Yodel.env.development?
|
|
37
|
+
Yodel.config.logger.info "Yodel startup complete"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def call(env)
|
|
42
|
+
@app.call(env)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
class Extension
|
|
2
|
+
attr_reader :name, :lib_dir, :migrations_dir, :public_dir, :layouts_dir, :models_dir
|
|
3
|
+
|
|
4
|
+
def initialize
|
|
5
|
+
@environment = @name.end_with?('environment')
|
|
6
|
+
@migrations_dir = File.join(@lib_dir, Yodel::MIGRATIONS_DIRECTORY_NAME)
|
|
7
|
+
@public_dir = File.join(@lib_dir, Yodel::PUBLIC_DIRECTORY_NAME)
|
|
8
|
+
@layouts_dir = File.join(@lib_dir, Yodel::LAYOUTS_DIRECTORY_NAME)
|
|
9
|
+
@models_dir = File.join(@lib_dir, Yodel::MODELS_DIRECTORY_NAME)
|
|
10
|
+
Yodel.extensions[@name] = self
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def load!
|
|
14
|
+
unless @environment
|
|
15
|
+
require_extension
|
|
16
|
+
Yodel.config.public_directories << @public_dir if File.directory?(@public_dir)
|
|
17
|
+
Yodel.config.layout_directories << @layouts_dir if File.directory?(@layouts_dir)
|
|
18
|
+
Yodel.config.extensions << self
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# load any models. if the init.rb file exists it will be loaded instead,
|
|
22
|
+
# allowing extensions to specify the order models are loaded.
|
|
23
|
+
if File.exist?(@models_dir)
|
|
24
|
+
init_file = File.join(@models_dir, 'init.rb')
|
|
25
|
+
if File.exist?(init_file)
|
|
26
|
+
require init_file
|
|
27
|
+
else
|
|
28
|
+
Dir[File.join(@models_dir, '**')].sort.each do |model|
|
|
29
|
+
next if model.start_with?('.')
|
|
30
|
+
require File.realpath(model, @models_dir)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class GemExtension < Extension
|
|
38
|
+
def initialize(gem)
|
|
39
|
+
@name = gem.name
|
|
40
|
+
@lib_dir = File.join(gem.full_gem_path, Yodel::EXTENSION_LIB_DIRECTORY_NAME)
|
|
41
|
+
super()
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def require_extension
|
|
45
|
+
require @name
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
class FolderExtension < Extension
|
|
50
|
+
def initialize(path)
|
|
51
|
+
@name = File.basename(path)
|
|
52
|
+
@lib_dir = File.join(path, Yodel::EXTENSION_LIB_DIRECTORY_NAME)
|
|
53
|
+
super()
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def require_extension
|
|
57
|
+
require File.join(@lib_dir, @name)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
class RequestHandler
|
|
2
|
+
PATH_FORMAT_REGEX = /^(?<path>.*?)(\.(?<format>\w+))?$/
|
|
3
|
+
|
|
4
|
+
def call(env)
|
|
5
|
+
# find the site this request is for
|
|
6
|
+
request = Rack::Request.new(env)
|
|
7
|
+
response = Rack::Response.new
|
|
8
|
+
site = env['yodel.site']
|
|
9
|
+
|
|
10
|
+
# temporary workaround to force rack to write the session out to a cookie
|
|
11
|
+
env['rack.session']['a'] = 1
|
|
12
|
+
|
|
13
|
+
# split the request path into a standard path and trailing file extension if present
|
|
14
|
+
components = PATH_FORMAT_REGEX.match(request.path)
|
|
15
|
+
return fail_with "Unable to parse request path: #{request.path}" if components.nil?
|
|
16
|
+
path, format = components.captures
|
|
17
|
+
path = path[0...-1] if path.end_with?('/') && path.length != 1
|
|
18
|
+
|
|
19
|
+
# match the request to the closest mime type we're aware of
|
|
20
|
+
mime_type = Yodel.mime_types.mime_type_for_request(format, request.env['HTTP_ACCEPT'])
|
|
21
|
+
|
|
22
|
+
# attempt to find a matching page for this request
|
|
23
|
+
page = site.pages.where(path: path).first
|
|
24
|
+
if page.nil?
|
|
25
|
+
site.glob_pages.all.each do |glob_page|
|
|
26
|
+
if path.start_with?(glob_page.path)
|
|
27
|
+
page = glob_page
|
|
28
|
+
request.params['glob'] = path[glob_page.path.length..-1]
|
|
29
|
+
break
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
return fail_with "File (#{request.path}) not found." if page.nil?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# respond
|
|
36
|
+
Layout.reload_layouts(site) if Yodel.env.development? # FIXME: implement production caching
|
|
37
|
+
page.respond_to_request(request, response, mime_type)
|
|
38
|
+
if page.response.respond_to?(:finish)
|
|
39
|
+
page.response.finish
|
|
40
|
+
else
|
|
41
|
+
page.response
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def fail_with(message)
|
|
46
|
+
[404, {'Content-Type' => 'text/plain'}, [message]]
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Yodel
|
|
2
|
+
def self.db
|
|
3
|
+
@db ||= Mongo::Connection.new(Yodel.config.database_hostname, Yodel.config.database_port).db(Yodel.config.database)
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def self.extensions
|
|
7
|
+
@extensions ||= {}
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.load_extensions
|
|
11
|
+
if Yodel.config.extensions_folder
|
|
12
|
+
Dir[File.join(Yodel.config.extensions_folder, '/*')].each do |path|
|
|
13
|
+
next unless File.directory?(path) && File.basename(path).start_with?('yodel_')
|
|
14
|
+
extension = FolderExtension.new(path)
|
|
15
|
+
extension.load!
|
|
16
|
+
end
|
|
17
|
+
else
|
|
18
|
+
Gem::Specification.find_all do |gem|
|
|
19
|
+
next unless gem.name.start_with?('yodel_')
|
|
20
|
+
extension = GemExtension.new(gem)
|
|
21
|
+
extension.load!
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
require 'optparse'
|
|
2
|
+
Dir.chdir(File.dirname(__FILE__))
|
|
3
|
+
Encoding.default_external = "utf-8"
|
|
4
|
+
|
|
5
|
+
class CommandRunner
|
|
6
|
+
def self.run
|
|
7
|
+
OptionParser.new do |opts|
|
|
8
|
+
opts.banner = "Usage: yodel [options] server|dns|console|migrate|setup|deploy"
|
|
9
|
+
opts.on('-p', '--port PORT', Integer, 'Override the default web server port') do |port|
|
|
10
|
+
$web_port = port
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
opts.on('-e', '--environment ENV', 'Web server environment (default development)', 'development', 'production') do |env|
|
|
14
|
+
$env = env
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
opts.on('-s', '--settings FILE', 'Load this settings file (default: /usr/local/etc/yodel/settings.rb)') do |settings|
|
|
18
|
+
$settings = settings
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
opts.on('-x', '--extensions PATH', 'Load extensions from the supplied folder, rather than from installed gems') do |path|
|
|
22
|
+
$extensions_folder = path
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
opts.on('-r', '--reload', 'Reloads the server whenever any framework source files are modified') do
|
|
26
|
+
$reload = true
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
opts.on('-h', '--help', 'Display this screen') do
|
|
30
|
+
puts opts
|
|
31
|
+
exit
|
|
32
|
+
end
|
|
33
|
+
end.parse!
|
|
34
|
+
|
|
35
|
+
command = ARGV.shift
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
case command
|
|
39
|
+
when 'server'
|
|
40
|
+
require '../requires'
|
|
41
|
+
require '../middleware/development_server'
|
|
42
|
+
|
|
43
|
+
Yodel.config.extensions_folder = $extensions_folder if $extensions_folder
|
|
44
|
+
Yodel.config.web_port = $web_port if $web_port
|
|
45
|
+
|
|
46
|
+
if $env == 'production'
|
|
47
|
+
Yodel.env.production!
|
|
48
|
+
else
|
|
49
|
+
Yodel.env.development!
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
if $reload
|
|
53
|
+
Rack::Server.start(app: DevelopmentServer.new, Port: Yodel.config.web_port)
|
|
54
|
+
else
|
|
55
|
+
require File.expand_path('../../yodel')
|
|
56
|
+
Rack::Server.start(app: Application.new, Port: Yodel.config.web_port)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
when 'dns'
|
|
60
|
+
require '../requires'
|
|
61
|
+
require './dns_server'
|
|
62
|
+
DNSServer.start
|
|
63
|
+
|
|
64
|
+
when 'console'
|
|
65
|
+
require '../../yodel'
|
|
66
|
+
require 'irb'
|
|
67
|
+
|
|
68
|
+
Yodel.config.extensions_folder = $extensions_folder if $extensions_folder
|
|
69
|
+
$application = Application.new
|
|
70
|
+
IRB.start(__FILE__)
|
|
71
|
+
|
|
72
|
+
when 'migrate'
|
|
73
|
+
require '../../yodel'
|
|
74
|
+
Yodel.config.extensions_folder = $extensions_folder if $extensions_folder
|
|
75
|
+
$application = Application.new
|
|
76
|
+
Site.all.each do |site|
|
|
77
|
+
Migration.run_migrations(site)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
when 'deploy'
|
|
81
|
+
require '../../yodel'
|
|
82
|
+
Yodel.config.extensions_folder = $extensions_folder if $extensions_folder
|
|
83
|
+
require './deploy'
|
|
84
|
+
Deploy.new.deploy_site
|
|
85
|
+
|
|
86
|
+
when 'setup'
|
|
87
|
+
require './installer'
|
|
88
|
+
Installer.new.install_system_files
|
|
89
|
+
|
|
90
|
+
else
|
|
91
|
+
puts "Unknown command: #{command}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
class Deploy
|
|
2
|
+
def initialize
|
|
3
|
+
@application = Application.new
|
|
4
|
+
@site_id = ARGV.shift
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
def deploy_site
|
|
8
|
+
puts "A site ID must be supplied as the last parameter to deploy" and return if @site_id.blank?
|
|
9
|
+
site = Site.where(_id: BSON::ObjectId.from_string(@site_id)).first
|
|
10
|
+
puts "Site could not be found" and return if site.nil?
|
|
11
|
+
new_site = site.migrations.empty?
|
|
12
|
+
|
|
13
|
+
# store the list of domains associated with this site; once the site has been reloaded from
|
|
14
|
+
# the updated yaml file, deleted domains need to have their corresponding folders removed
|
|
15
|
+
old_domains = site.domains.dup
|
|
16
|
+
|
|
17
|
+
# read site.yml and update db record
|
|
18
|
+
site.reload_from_site_yaml
|
|
19
|
+
|
|
20
|
+
# FIXME: it's possible for one site to take control of another's domains at the moment;
|
|
21
|
+
# process "should" be that the first site with a domain owns that domain. Only it can
|
|
22
|
+
# add subdomains to it; yodelcms.com etc. is an exception to this.
|
|
23
|
+
# remove "bad" domain names
|
|
24
|
+
site.domains = site.remote_domains
|
|
25
|
+
|
|
26
|
+
# link public directories so a fronting web server can serve public assets easily
|
|
27
|
+
site.domains.each do |domain|
|
|
28
|
+
path = File.join(Yodel.config.public_directory, domain)
|
|
29
|
+
FileUtils.ln_s(site.public_directory, path) unless File.exists?(path)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# remove folders associated with deleted domains
|
|
33
|
+
old_domains -= site.domains
|
|
34
|
+
old_domains.each do |domain|
|
|
35
|
+
path = File.join(Yodel.config.public_directory, domain)
|
|
36
|
+
FileUtils.rm(path) if File.exists?(path)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# migrate (taking the site live)
|
|
40
|
+
Migration.run_migrations(site)
|
|
41
|
+
|
|
42
|
+
# reload layouts from disk
|
|
43
|
+
Layout.reload_layouts(site)
|
|
44
|
+
|
|
45
|
+
# the first time a site is created, all users with access to the site (1 at this stage
|
|
46
|
+
# in most cases) are copied as administrators of the new site. As users are added and
|
|
47
|
+
# removed, their corresponding administrator records are updated in the site.
|
|
48
|
+
if new_site
|
|
49
|
+
production_site = Site.where(name: 'yodel').first
|
|
50
|
+
production_site.users.where(sites: site.id).all.each do |admin|
|
|
51
|
+
user = site.users.new
|
|
52
|
+
user.first_name = admin.name
|
|
53
|
+
user.email = admin.email
|
|
54
|
+
user.username = admin.email
|
|
55
|
+
user.password = admin.password
|
|
56
|
+
user.groups << site.groups['Developers']
|
|
57
|
+
user.save
|
|
58
|
+
|
|
59
|
+
# because of the before_create callback, we need to override
|
|
60
|
+
# the salt and password manually by saving again
|
|
61
|
+
user.password_salt = nil
|
|
62
|
+
user.password = admin.password
|
|
63
|
+
user.save_without_validation
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|