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
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
|